flutter3d_webgl 0.5.1
flutter3d_webgl: ^0.5.1 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.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.