flutter3d_webgl 0.7.4
flutter3d_webgl: ^0.7.4 copied to clipboard
A WebGL2 backend for flutter3d: the second implementation of flutter3d_hardware, and the one that tells us whether the HAL is a seam or a description of Impeller.
0.7.4 #
The generated shader table is rebuilt against flutter3d_shaders 0.7.4,
which flutter3d_core 0.7.4 binds: BloomInfo.tint and ShaftInfo.sun are
uniforms only these stages declare. Nothing else in this package changed.
0.7.1 #
Every texture format uploads with its own type and size. Everything but
the two float RGBA formats went up as RGBA bytes, so an r32Sfloat texture
sampled as zeros and an r8 upload was refused; 2D and cube uploads use one
transfer table now. readPixels of a float target returns its values, an
overwrite of a rendered target is no longer upside down, the MSAA resolve
covers the whole target instead of the last scissor, integer vertex attributes
go through the integer pointer, and a released buffer leaves the target map.
The shader table is regenerated from flutter3d_shaders 0.7.1.
Its flutter3d_* dependencies ask for ^0.7.1, and it asks for vector_math ^2.4.3.
0.7.0 #
Breaking. WebGlDevice.present is gone with GraphicsDevice.present
itself (mcp-01n). Its blit half is now the public blitToCanvas, and its
canvas is now the public canvas field; the CSS-styling half moved to a new
WebGlFramePresenter widget.
ensureWebGlBackendRegistered, new. This backend registers itself as the
web fallback opener and as WebGlDevice's presenter with
flutter3d_hardware's device registry, rather than waiting for
flutter3d_app to know it exists. Floors to flutter3d_hardware ^0.7.0
and flutter3d_conformance ^0.7.0.
overwriteGeometry and overwriteTexture. Geometry is bufferSubData
and a texture region is texSubImage2D, and both complete in the same turn. A
WebGL buffer is bound to one target for life, so the device now remembers
which target each buffer was made against and an overwrite does not have to be
told. A write through GeometryBuffer.slice() is offset by the slice's start.
maxColorAttachments is what the context says. It is read from
MAX_DRAW_BUFFERS once, when the device opens, and a pass that asks for more
throws UnsupportedError from beginRenderPass.
The generated shader table is rebuilt against flutter3d_shaders 0.7.0.
engine_shaders.dart gains Fxaa, SsaoBlur, ContactShadow, LightShafts,
DepthOfField, ViewportShade, ShadowDepthMasked, ShadowDistanceMasked,
Splat and PolylineVertex, and the regenerated Composite, BloomUpsample,
shadow and surface stages. No Dart in the device changed for them.
The archive carries a skill, skills/flutter3d-webgl-browser-backend/,
about opening the device, the generated shader map, browser tests and the
bugs that only show up in a browser. dart run skills@ get installs it for a
coding agent.
0.6.0 #
- The generated shader table is rebuilt against
flutter3d_shaders0.6.0. Six samples that stood under a branch now name mip level zero rather than deriving it, which is that package's entry to read; here it is a regeneratedengine_shaders.dart. No stage was added, removed or renamed, and the pictures are the same — a derivative that could only ever select level zero is now asked for level zero. tool/pack_shaders.darttakes a--webgpusection. A bundle can now carry the WGSL a fourth backend reads, copied in as bytes without being understood, the way the Impeller section already is: what is inside it belongs toflutter3d_webgpu, which writes it, and a container that understood one backend's document would be a container with a reason to change every time that document did. The flag is optional in two senses — a bundle without it is refused only by the backend whose section is missing, and the program that makes the section needsglslangValidatorandnaga, which a machine building a bundle need not have.- The browser golden stand takes the backend as an argument. The scene, the direction and now the backend arrive as query parameters, so one dart2js run serves both browser backends the way it already served every scene. That is what keeps a full pass at minutes.
cube-shadow-crowdedandcube-shadow-manyare recorded again. The demo they are drawn from used to hand out point-shadow atlas rows on frames drawn before its model landed; both scenes now show the rows the ranking chose. The reference images are this package's own test data — nothing a consumer draws changed.- Nothing in the WebGL2 device, its encoder or its capability answers changed.
0.5.2 #
pack_shaders.darttakes--webgpu FILE, a WGSL section written byflutter3d_webgpu/tool/pack_wgsl_section.dartand copied into the bundle unread, the way impellerc's output already was. The one section this packer still makes is its own, which is what its header always said; the third arrives made, because everything it is made of belongs to a package this one does not depend on. The flag is optional and a bundle without it is what the other three backends have always read — the format version does not move, and a section a backend has no name for is a section it never looks at.- RGBA32F storage was filled through
RGBA/UNSIGNED_BYTE. That is anINVALID_OPERATIONno API reports and a texture that samples as zeros, so a model whose morph deltas travel as floats drew its base shape with no error anywhere. The transfer type now comes from the format, and the size check measures a texel rather than assuming four bytes. gl_InstanceIndexis rewritten togl_InstanceIDon the way out, beside the vertex one. The two builtins differ in general — Vulkan's counts from the draw'sfirstInstanceand GL's from zero — and not here: nothing in this engine issues a draw that starts part way into an instance buffer.- A golden for the morphed cube, recorded in a browser like the rest: 0.139% from Impeller, which is a silhouette and what is left once a vertex stage has agreed about where every vertex went.
0.5.1 #
- The occlusion agrees with Impeller to 0.253% and the reflections to
zero, from 0.522% and 0.001%. The surface buffer's alpha no longer holds a
window depth, which is a number a half float cannot hold usefully past twenty
metres and which both GPU backends were rounding into bands; see
flutter3d_shaders0.5.1.engine_shaders.dartis regenerated with the new block members. - This backend's check that a bound uniform member exists is what caught the block going out of step, in the browser, on the run that introduced it.
0.5.0 #
- A
WebGlProgram's attributes, blocks and samplers are unmodifiable. They describe a program that has been linked; nothing should be adding to them afterwards. - The engine parity reference catches up with a fixture that grew two torches.
0.4.3 #
- Anisotropic filtering, where the context has the extension.
EXT_texture_filter_anisotropicis asked for atcreate()like every other extension, andmaxAnisotropyis its ceiling — one without it. Every bind setsTEXTURE_MAX_ANISOTROPY_EXTbeside the four parameters it already set, clamped to that ceiling first, because in GL the value is texture state rather than sampler state and a number above the ceiling isINVALID_VALUE: an error in the queue and a bind that did not land.anisotropic-floorgets a provisional cross-backend budget; its reference is recorded at merge. - Known, and not fixed here: the minification filter never names the mip
chain.
minMagFilterToGlmapsminFilteralone, so a trilinear sampler binds asLINEARrather thanLINEAR_MIPMAP_LINEAR— the levels are uploaded andTEXTURE_MAX_LEVELis set, and none of them is sampled. The anisotropic taps above are therefore taken from the base level, not across the chain asSamplerOptionsdescribes, and the far half ofanisotropic-flooraliases here where Impeller's blurs and then sharpens. The fix is aTEXTURE_MIN_FILTERderived from the pair (minFilter,mipFilter) and the texture's level count; it moves every textured web golden at once and is its own change. - A bundle loaded from bytes, compiled by the browser on first use.
WebGlDevice.loadShadersreads the bundle'swebglsection — GLSL ES sources by name, as JSON, the documentwebgl_bundle_section.dartwrites and reads — andWebGlLoadedShaderLibrary.refreshrecompiles every stage already handed out from the new text before swapping any of them, so a stage that no longer compiles refuses the whole refresh by name and the picture stays. The compiled object is swapped behind the handle, which is how GL keeps the identity promise flutter_gpu keeps by mutating in place. - The program cache keys on the handles, not the names. Two libraries
answering one name — a loaded
Pbrlayered over the engine's — used to share whichever program linked first; identity is what a pipeline depends on, so identity is the key, and a refresh evicts throughforgetPrograms. - A refresh retires the old programs; it does not delete them. The
renderer's pipeline cache holds a
PipelineHandleover the program linked from the old code untilRenderer.relinkShadersruns, and nothing says the two happen in one turn: an application refreshing from a file watcher's callback draws a frame in between, and that frame used to bind a deleted program —INVALID_VALUE, and every material on the loaded look gone for a frame where flutter_gpu kept drawing the old code. The program is now kept until the next refresh ordispose, which is what the HAL promises; the pixel test reads the frame in between and expects the old colour. tool/pack_shaders.dartwrites a.f3dshadersbundle from a manifest and impellerc's output, translating the GLSL for this backend the waygenerate_shaders.dartdoes;tool/source_package.dartis the package resolver both now share.golden_web.shwants the example's own bundle built first, since the example's pubspec declares it. The packer reads the container throughflutter3d_hardware/shader_bundle.dart, the Flutter-free entry point, and says so on stderr when it stamps the SDK token from adartthat is not a Flutter SDK's beside an impeller section — the one way the header goes wrong silently, and said only then, because a warning that fires on every correct run too is read on none of them. An--includeroot with a trailing slash is normalised like the package root, rather than losing the first character of every key under it.- A refresh is held to the header's stage list as well as the section.
A bundle whose header dropped a stage in use while its
webglsection still carried the source was accepted; the conformance suite now asks, and the refusal names the stage as it did for a source that went missing. - A pixel test draws a wall through a loaded look, refreshes the bundle and reads the new colour back through the same handle.
readback, through a pixel-pack buffer behind a fence.readPixelswith a buffer bound toPIXEL_PACK_BUFFERis a command in the stream like any draw — it reads the texture as the commands before it left it — and returns at once where the client-memory form stalls until the GPU has drained everything ahead of it. AfenceSyncsays when the copy is done, polled on a timer rather than blocked on, since the whole engine runs on the threadclientWaitSyncwould block. The region's own y is measured from the bottom for a rendered texture, the way the rows already were, and the rows inside it are turned over the same way; the conformance check that holds a region of a drawn picture to its rows from the top is what found both edges.LuminanceandObjectId, generated with the rest fromflutter3d_shaders;auto-exposurejoins the golden set, its web reference recorded at merge.ObjectIdsamples the material's texture against its cutoff, so a pick through a masked material's hole answers with what is behind it.- A readback of anything but an eight-bit RGBA texture is refused before it
reaches
readPixels, by the rule every backend shares. Asked for a half-float target, this backend'sreadPixels(RGBA, UNSIGNED_BYTE)was anINVALID_OPERATIONthat left the pack buffer at zeros and the future completing successfully with a black picture. - The stencil test, as context state kept honest. Enabled whenever the
attachment carries a stencil and reset to the disabled configuration at
every pass, so nothing carries over; the reference re-issued with the
compare, because GL keeps the two on one
stencilFunc; a stencil clear through a write mask of every bit, for the reason the depth clear setsdepthMaskfirst. The reference is narrowed to eight bits before it reachesstencilFunc, which would otherwise clamp it and make this the one backend where a wider value means something else.stencil-xrayjoins the golden set with a provisional budget, recorded at merge. Xrayis generated with the rest fromflutter3d_shaders, and linked against all three mesh vertex stages in the parity grid. It is the entry point that makes this backend'ssetBlendlimitation moot: the index it ignores would otherwise have been the only way to keep a silhouette out of the surface buffer here.- A pass renders into a cube face and a mip level. A cube attachment goes
through
framebufferTexture2Dwith the face's own target and the level, a pass starts with a viewport the size of that level, and a multisample resolve lands on the same face and level;createCubeRenderTargetis onetexStorage2Don the cube target, so every face of every level is attachable and the texture is complete for a mipmap filter with nothing uploaded.supportsRenderToMipis true. The resolve blits the level's extent on both sides rather than the base texture's, which nothing in the engine needs yet — every pass that names a level is single-sampled — and which is where to look when one does. - A sampler asking for
MipFilter.lineargets a mipmap minification filter. GL keeps the mip filter on the minification filter, and a plainLINEARreads the base level whatever leveltextureLodnames — so a prefiltered environment was a mirror at every roughness here. The nearest mip filter stays the plain filter, so every picture drawn from single-level textures stays where it is; the ones whose textures carry a chain now minify through it, which is the filtering the asset asked for and this backend was quietly not giving.particles-texturedis that case in the golden set — its sprite is a checkerboard with a hand-built chain andSamplerOptions.trilinearRepeatunder it — so that reference is to be re-recorded and its cross-backend budget re-measured in the same pass that recordsprobe-car.ProbePrefilteris generated with the rest;probe-carjoins the golden set, recorded at merge. setBlendColorisglBlendColor, and a pass now starts with the constant back at transparent black — context state that would otherwise carry into the next pass, the same reason the stencil's setters are reset.supportsBlendColoranswers true.
0.4.2 #
- The lightmapped vertex stage, generated with the rest from
flutter3d_shaders;lightmapped-roomjoins the golden set. - Compressed textures, from the extensions the context actually has.
CompressedTextureSupportasks for the six extensions once atcreate()(ETC2 is WebGL2 core and still has to be asked for), a compressed upload goes throughcompressedTexSubImage2Dwith block-rounded sizes, andsupportsTextureFormatanswers from the same table the upload reads, so a format it says yes to is one it takes. Verified in a real Chrome: ETC2 uploads and samples, a chain uploads block by block, a short buffer is refused before any GL call, and every LDR format either loads clean or throws naming the missing extension.
0.4.1 #
- Phones render. The MSAA sample count is now proven at
create()rather than assumed: desktop GL happily multisamples a half-float renderbuffer and mobile GLES very often refuses, and the refusal was not an answer at create time but aGL_INVALID_OPERATIONout ofrenderbufferStorageMultisampleon every frame — a white screen on every phone. Proven by a real one-pixel allocation checked withgetError, not by asking: the Android emulator's GL translator advertises the capability and then errors on the allocation anyway. Where the driver refuses, the renderer takes its ordinary single-sample path and the picture arrives, aliased and alive.
0.4.0 #
- Shaders and programs are deleted at last. The library gained
dispose— every cached stage and every linked program — wired into the device's own, and counted bydebugTrackedResourceCount; a failed compile or link deletes its object before throwing instead of leaking one per retry. - Disposing the device loses the GL context and removes the canvas from the
DOM (the platform-view registry still pins the element; it has no
unregister). The encoder cleans up its framebuffer and every transient and
uniform buffer on any failure path, and a second
submitis aStateErrorrather than resolve blits against a deleted framebuffer._blitToCanvasno longer leaks a framebuffer per frame when the frame is unreadable.
0.3.0 #
- Regenerated against the current sources, including the environment sampling and the composite look.
0.2.0 #
- The GLSL is generated from
flutter3d_shadersand CI fails on the diff, after a stale table turned out to be drawing last month's sky in the browser while nothing could see it. - A pass sets its viewport and scissor to the attachment it draws into rather than to the size of the canvas.
0.1.0 #
- A WebGL2 backend: the second implementation of
flutter3d_hardware, and the one that says whether the HAL is a seam or a description of Impeller.