Commit Graph
33 Commits
Author SHA1 Message Date
swung0x48 2b46a3db96 [Fix, Test] (MG_Util, MG_Backend/DirectGLES, MG_Backend/DirectVulkan): the two image target kinds a compute dispatch could not read - 1D-array on ES, imageBuffer on Vulkan 2026-08-12 16:11:10 -04:00
swung0x48 7311251f30 [Fix] (MG_Util, MG_Backend/DirectVulkan): GL reads gl_BaseVertex as zero on a non-indexed draw where Vulkan's builtin hands over firstVertex 2026-08-12 04:18:07 -04:00
swung0x48 97facf777b [Fix] (MG_Backend/DirectVulkan): act on a failed binding remap, bound the storage-block array count, and correct the decline rationale review found describing the reverted mechanism 2026-08-12 01:09:56 -04:00
swung0x48 5cfbb716c0 Merge remote-tracking branch 'origin/dev' into feat/sampler-array-descriptors 2026-08-12 00:58:20 -04:00
swung0x48 068786e812 [Fix, Test] (MG_Backend/DirectVulkan, MG_IntegrationTest): a declined descriptor must refuse the draw, not just leave the layout - a multi-dimensional sampler array otherwise faulted in the shader 2026-08-12 00:45:36 -04:00
swung0x48 e71d715e1a [Fix, Test] (MG_Backend/DirectVulkan, MG_Util, MG_Test): VkProgramObject move dropped stageSpirvDigests - a robin-hood swap would pair one program's modules with another's digests; sanity tests assert key identity, not iteration counts 2026-08-12 00:11:56 -04:00
swung0x48 21a43bf6a4 [Fix, Test] (MG_Backend/DirectVulkan): re-land the gl_FragCoord default-framebuffer origin fix - the suspected slowdown was a mismeasurement, paired timings are within 1% 2026-08-11 07:54:24 -04:00
swung0x48 5b6dec2d81 [Revert] (MG_Backend/DirectVulkan): back out the gl_FragCoord default-framebuffer origin fix - correct, but it costs DirectVulkan a large order-dependent slowdown that is not yet root-caused 2026-08-11 06:30:30 -04:00
swung0x48 543c29bf86 [Fix, Test] (MG_Backend/DirectVulkan): gl_FragCoord on the default framebuffer reports GL's window origin - the stored row is not the window row once the viewport rect is converted 2026-08-11 05:25:32 -04:00
swung0x48 7c5fc03b26 [Fix, Test] (MG_Backend/DirectVulkan): never bind or cache a null pipeline, and name the modules a failed vkCreateGraphicsPipelines rejected 2026-08-11 02:33:32 -04:00
BZLZHH 8f2b766b56 [Perf] (MG_Backend): let DirectVulkan trust across frames what it proved once
The draw fast path still paid for its own proofs: the hottest single
load (20% of TrySetupDrawFastPath) was chasing the cold
VertexInputStateFactory heap entry just to answer "same vertex-input
layout?". That answer now comes from the frontend VAO's config-guarded
aux memo (layout hash + attribute masks), and a VAO-cycling stream with
a stable layout skips the pre-flight AND pipeline re-resolution
entirely. The VkProgramObject* is memoized on the snapshot behind a new
ProgramFactory cache-structure epoch (bumped on every insert/erase; use
is re-stamped so the idle sweep can never evict a live entry). A
render-state version move no longer forces the full path: the pipeline
value hash is refreshed in place and the 8-entry memo probed directly
(the GL_BLEND-toggle case).

The resolved-vertex-bindings memo now revalidates all-resident unmapped
entries ACROSS frames via per-binding slice epochs - minted from a
process-lifetime counter so a recycled address can never revalidate,
with every mutation path funnelled through BumpSliceEpoch - while
stamping each resource's GPU-use serial exactly as the skipped acquire
would, preserving the busy-tracking that glBufferSubData's
host-write-vs-staged-copy choice depends on. Resident index buffers get
the same treatment through an EBO slice memo.

The six-part dynamic-state tail (viewport/scissor/blend constants/depth
bias/line width/stencil) is gated behind one render-state-parameters
version + pass-geometry compare per command buffer. GetSlice is inlined;
SampledBindingsUnchanged walks only the program's declared bindings.

Quiet-box 6-round order-alternating A/B (on top of the frontend
VAO-bind commit): vanilla_draw -20.8% (790 -> 626 ns/op, 3.4x native to
2.5x), sampler_churn -28.2%, ubo_range -8.4%, state_toggle -3.8%;
tex_param's matrix flag (+10%) was adjudicated by an isolated
alternating re-run at +1.0% - position bias, not regression. Unit tests
421/421.
2026-08-06 13:18:38 -04:00
BZLZHH d39a706d57 [Perf] (MG_Backend): stop paying for descriptor slots and mip barriers nobody asked for
Five independent bits of per-draw and per-operation waste in the DirectVulkan
backend, all removing work whose answer was already known.

The per-draw descriptor walk iterated all 256 slots of bindingKinds to find the
one to eight bindings a real GL program declares, because that vector is sized to
the binding cap rather than to the program. Reflection now records the bindings it
actually assigned, and the draw path iterates that. It is built at the end of
ReflectLayout, not where bindingKinds is sized - at that point the vector is only
zero-initialised and the kinds are assigned further down, so a list built there
would be empty. It has to stay ascending: Vulkan consumes pDynamicOffsets in
binding order and the writer pushes them in iteration order, so an unordered list
would silently mis-pair dynamic offsets with their uniform blocks.

Descriptor pools were sized maxSets * the 256-binding cap, declaring 81,920
descriptors per pool and 245,760 across the frames in flight, for sets that hold
what shader reflection found. Sized from eight now; an outlier program is absorbed
by the VK_ERROR_OUT_OF_POOL_MEMORY path that already exists, which works because
pool sizes are aggregate budgets rather than per-set limits.

TrackLiveResource swept the whole live-buffer vector on every insert once it
passed 256 entries, and when the buffers are all live the sweep removes nothing
and the vector grows by one - so creating N live buffers cost about N^2/2
expired() checks. It sweeps on a doubling watermark now, with the same
reclamation semantics.

GenerateMipmap transitioned each destination level individually inside its loop,
but every generated level starts in the same layout and the loop only moves a
level out of TRANSFER_DST after writing it, so the whole range can be prepared in
one barrier - 3(N-1)+1 barrier commands become 2(N-1)+2. Each level is still
transitioned to TRANSFER_SRC before it is read, so the dependency between
consecutive levels is unchanged.

WaitForFrameSerial drained the entire graphics queue, as its own comment admitted.
Every submission records the frame serial it was made under, so it now waits on
the first fence at or past the requested serial. The narrow path deliberately does
not call NotifyDeviceIdle(): that claims every submission has retired, which is
only true after a real drain, so it stays on the fallback.

Verified with an 8213-case A/B (textures, buffers, queries, mipmaps, uniforms and
the whole direct_state_access suite): the Espryt failure list is identical, the
Magma failure list differs by one case, and both crash sets are unchanged on
Magma. That one case, buffer_storage.map_persistent_draw, does not reproduce in
isolation - running the buffer_storage group alone gives byte-identical results on
both builds (the same three failures, not including it), and it reports
NotSupported when run on its own. It is the same ordering-dependent behaviour this
suite shows elsewhere, and the three Espryt crash-set differences are the known
copy_image cluster moving chunk position. Flagging rather than hiding it.

direct_state_access stays at Espryt 370/371 and Magma 371/371; unit tests 421/421.
2026-08-05 15:19:37 -04:00
BZLZHH c069890ac7 [Feat] (DirectVulkan): GPU transform feedback capture via VK_EXT_transform_feedback
Second stage of GL 3.0 transform feedback: captured draws now write real
data.

- Device setup enables the VK_EXT_transform_feedback feature when present
  and loads the bind/begin/end entry points.
- Captured draws compile an XfbCapture program variant whose last
  vertex-processing stage gets XfbBuffer/XfbStride/Offset decorations from
  the program's resolved varyings (a new spirv-opt pass). A captured
  gl_Position is mirrored into a dedicated output written before every
  OpReturn - or before every OpEmitVertex in a geometry stage - ahead of
  the position fixup, so the captured value is the shader's own pre-remap
  position.
- DrawArrays/DrawElements wrap the draw in Begin/EndTransformFeedbackEXT;
  a small counter buffer resumes the append position across draws within
  one glBeginTransformFeedback (fresh Begin starts at the bound offsets).
- Capture targets are promoted to persistently-mapped host-coherent GPU
  storage (persistent-map storage now also carries the transform feedback
  usage), so MapBuffer/GetBufferSubData read the captured bytes after the
  fence wait glEndTransformFeedback now performs.
- Draw-mode/feedback-mode validation defers to the geometry shader's
  output primitive when one is present, and glGetBooleanv reports
  GL_TRANSFORM_FEEDBACK_ACTIVE/PAUSED so dEQP's per-case state reset can
  unwind an active capture.

KHR-GL33: transform_feedback capture_vertex_*/capture_geometry_*/
discard_*/draw_xfb and clip_distance.coverage now pass; queries
(PRIMITIVES_WRITTEN) and gl_ClipDistance capture remain.
2026-07-31 17:31:41 -04:00
swung0x48 992d16267c [Fix] (DirectVulkan): rewrite implicit-LOD fragment samples to explicit LOD 0 when every bound sampler is pinned to a single mip level - Adreno 650 (driver 512.502) reads outside a full-screen colour render target's allocation on its implicit-LOD sampling path and faults the GPU, which killed MC 26.2 on its own blit shader (texture(InSampler, texCoord)) between frames 344-421 on every run; this is the same driver defect the default-framebuffer blit shader already works around with textureLod, but an application's shader cannot be edited, so ForceExplicitLod0SamplePass converts OpImageSample*ImplicitLod to the explicit form at the SPIR-V level under a new CompileOptionBit that is only requested when the rewrite provably cannot move a texel (every sampler binding on a single-level view, no anisotropy, and either a LOD clamp that already pins lambda at 0 or min and mag filters that agree - an explicit LOD 0 always takes the magnification side of the min/mag decision); a single-level view now also clamps its sampler to mipmapMode NEAREST with maxLod min(maxLod, 0.25) rather than 0, since collapsing the clamp would make every fragment magnify and quietly retire the min filter; and the program's backend hash memo grows from one slot to four so a program resolved under two compile-flag sets in the same frame stops re-hashing every stage's SPIR-V once per draw 2026-07-29 03:26:57 -04:00
swung0x48 34685b4bb0 [Fix] (DirectVulkan): age-based eviction for the content-addressed cache family - ProgramFactory entries (shader modules/layouts), PipelineFactory graphics pipelines, compute pipelines and per-layout descriptor-set tracking now retire after ~1024 idle frame boundaries (render-pass-manager sweep precedent), render-pass eviction purges pipelines hashed on the dying handle (closes a handle-recycling stale-pipeline hazard), and the program reflection cache is lifetime-id-keyed and cleared at EGL teardown - shader/program churn no longer grows Vulkan objects without bound 2026-07-27 22:05:25 -04:00
swung0x48 63f0756644 [Fix] (DirectVulkan): support UBO instance arrays as arrayed descriptors - uniform Block{...}b[N] reflected as one binding with descriptorCount=N, per-element GL block mapping, per-element buffer infos and dynamic offsets; non-UBO descriptor arrays now fail program creation cleanly instead of continuing corrupt 2026-07-26 18:30:41 -04:00
swung0x48 65ea54da9e [Refactor] (ShaderTranspiler, DirectVulkan): replace the hand-rolled SPIR-V word walkers with a DecoratePositionInvariantPass and SPIRV-Reflect-based InstanceIndex detection 2026-07-20 08:35:00 -04:00
swung0x48 c158bfa584 [Fix] (DirectVulkan): narrow the blended depth-write quirk to order-independent accumulation blends, exempting sorted-transparency, gl_FragDepth writers and fully masked attachments 2026-07-20 07:39:25 -04:00
swung0x48 4658536652 [Perf] (DirectVulkan): keep the render pass alive for steady-state storage-image draws and skip storage-image collection for programs without them 2026-07-20 02:36:24 -04:00
swung0x48 e5388c0e7e [Fix] (MG_Backend, MG_Impl, ShaderTranspiler, MG_Test): support iterationRP custom images and storage format reinterpretation 2026-07-20 02:35:30 -04:00
swung0x48andClaude Fable 5 139de76347 [Fix] (MG_State/MG_Impl/MG_Backend): render Flywheel instanced+indirect on both backends
Create 6 / Flywheel 1.0.6 now renders correctly with both flywheel:instancing
and flywheel:indirect on DirectGLES and DirectVulkan (verified in-game on
Adreno 830: waterwheels and cogwheels solid, animated, correct pairing, no
crashes across all four combinations).

- MG_State/MG_Impl: sync explicitly-ranged SSBO bindings of FLUSH_EXPLICIT
  persistent maps to the backend before compute dispatches. Flywheel writes
  its scatter-copy descriptors into the staging ring's persistent map and
  never flushes that span (UB per spec, works on drivers whose maps alias
  GPU-visible memory); our maps alias the CPU shadow, so the descriptors
  never reached the GPU: the scatter compute copied nothing (GLES: empty
  draw commands) or stale garbage (Vulkan: wild indirect commands ending in
  VK_ERROR_DEVICE_LOST).
- MG_Impl/MG_Backend: real glFenceSync objects backed by backend fences
  (GLES: native ES syncs guarded by context generation and owner thread;
  Vulkan: buffer-manager frame serials), replacing always-signaled stubs
  that let Flywheel reclaim staging memory the GPU still reads.
- MG_Backend/DirectGLES: compute dispatches now run the same per-program
  resource sync as draws (uniform-block bindings and sampler units must be
  re-established through the API because layout(binding) is stripped from
  transpiled ESSL) and rebind texture units afterwards; the cull shader
  used to read a stale _FlwFrameUniforms binding and the depth-pyramid
  downsample sampled a stale unit-0 texture, zeroing the Hi-Z pyramid and
  occlusion-culling all Flywheel geometry. Image uniforms are excluded from
  glUniform1i (ES bakes their unit via layout(binding)); image-unit sync is
  clamped to the device limit; eliminated/SSBO-classified uniform blocks
  are skipped.
- MG_Backend/DirectGLES: gl_BaseInstance in native indirect draws reads the
  GPU-written command buffer through an injected mg_IndirectParams SSBO
  view addressed per draw instead of the zero CPU shadow; layout(binding)
  is preserved for SSBO/image declarations (ES has no API rebinding for
  them); the ES context ownership claim moved to a global atomic owner
  thread with an EGL ground-truth check, and deferred buffer op state is
  mutex-guarded, so ops cannot silently no-op after context migration.
- MG_Backend/DirectVulkan: new RebaseInstanceIndexPass rewrites vertex
  InstanceIndex loads to (InstanceIndex - BaseInstance). glslang's relaxed
  Vulkan mode aliases gl_InstanceID to InstanceIndex, which includes
  firstInstance, but GL's gl_InstanceID is zero-based - draws with nonzero
  baseInstance paired meshes with wrong instance data (cogwheel drawn as a
  waterwheel, another wheel collapsed invisible). Gated on the
  shaderDrawParameters device feature. Sampled-read barriers additionally
  cover the compute stage (the Hi-Z downsample samples the depth
  attachment from compute), and short uniform-buffer ranges keep the
  existing zero-padding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 06:30:10 +00:00
swung0x48 5cfe9c8998 [Feat] (MG_Backend/DirectVulkan): support compute shaders 2026-06-05 11:52:10 +08:00
swung0x48 9e0e03d4c0 [Optimaization] (MG_Backend/DirectVulkan): optimize perf
- Properly reuse descriptor sets rather than always allocating
- Add program lookup cache
2026-05-11 23:20:55 +08:00
swung0x48 d7e768096e [Fix] (MG_Backend/DirectVulkan): fix Minecraft 26.2 startup crashes
- Support cube map face uploads with cube-compatible images and per-face array layers
- Add uniform texel buffer descriptor support for samplerBuffer bindings
- Cache transient vertex/index buffer uploads per frame to avoid VMA allocation failures
2026-05-10 08:50:55 +08:00
swung0x48 39c5b28dfb [Fix] (MG_Backend/DirectVulkan): fixing Photon v1.1
- Flatten DailyWeatherVariation interface varyings
- Correct internal-format component counts
- Preserve GL draw-buffer slot semantics in render pass creation
- relax GL_NONE / vec4-to-RGB pipeline checks
2026-05-09 09:56:45 +08:00
swung0x48 f61a7bb9c0 [Fix] (MG_Backend/DirectVulkan): fix some uniform/sampler binding 2026-05-04 22:48:50 +08:00
swung0x48 4a3a44924a [Refactor] (MG_Backend/DirectVulkan/ProgramFactory): refactor uniform reflection 2026-04-03 16:45:11 +08:00
swung0x48 35658eb998 [Refactor] (MG_Backend/DirectVulkan): move uniform reflection from UniformDescriptorBinder to ProgramFactory 2026-03-23 16:36:17 +08:00
swung0x48 09f96e5ba5 [Fix] (MG_Backend/DirectVulkan): Properly handle front face state. save VkDevice as static member 2026-03-04 15:08:23 +08:00
swung0x48 6540c2eec1 [Feat] (MG_Backend/DirectVulkan): properly handle Vulkan surface transform (pre-rotation) 2026-02-21 20:32:25 +08:00
BZLZHH 7f9953fdee [Fix] (MG_Backend/DirectVulkan): Handle shader position transform. 2026-02-21 15:36:28 +08:00
swung0x48 12d514229c [Fix] (MG_Backend/DirectVulkan): add move ctor for BackendProgramObject 2026-02-17 21:57:29 +08:00
swung0x48 2ad1207a31 [Feat] (MG_Backend/DirectVulkan): ProgramFactory and some refactoring 2026-02-16 22:29:04 +08:00