[Fix, Test] (clientsp, MG_Pipe, Espryt): produce kMGPipeBindSampler and kMGPipeBindShaderImage where D-A4 places them - nothing set either bit, so ImageBindableHint was always 0, the metadata respecify had no live trigger and the remint pull the hint prevents was neither prevented nor counted (final review M-A); the sampler-view resolution notes SAMPLER, glBindImageTexture's state setter notes SHADER_IMAGE at the bind (so the hint precedes the first sync) and the image walk notes it too, both through a contract door since neither may include TextureEmit.h, and Espryt counts every re-mint of storage it already held as tex-remint-pulls (trp= on the stats line, ROADMAP open question 2's number)

This commit is contained in:
2026-09-09 00:09:30 -04:00
parent a7d56a2fe5
commit 03082b8367
14 changed files with 366 additions and 5 deletions
+8
View File
@@ -38,6 +38,7 @@
#include <MG_Impl/Pipe/SlotAllocator.h>
#include <MG_Pipe/MGPipe.h>
#include <MG_Pipe/PipeApply.h>
#include <MG_Pipe/PipeMutation.h>
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/TextureState/TextureState.h>
#include <MG_Util/Metrics/PipeStats.h>
@@ -97,6 +98,13 @@ namespace MobileGL::MG_Pipe {
entry.Res = binding.Texture ? MGPipeSlots().Acquire(MGPipeKind::Texture,
binding.Texture->GetLifetimeId())
: kMGPipeNullHandle;
// D-A4: a texture named in an emitted MGPImageView is SHADER-IMAGE-bound from
// then on - the bit ImageBindableHint is derived from. The bind itself noted it
// first (TextureState.h, so the hint precedes the first sync); this is the
// letter of the rule and a one-compare early-out once the bit is set.
if (!MGPipeHandleIsNull(entry.Res)) {
MGPipeNoteTextureBoundAs(entry.Res, static_cast<Uint32>(kMGPipeBindShaderImage));
}
// THE APPLICATION's format and access, verbatim. The bind-format recast and the
// buffer-texture split view are server-side and stay there; so does
// SupportsLayeredImageBinding's rule, which asks the BACKEND target after
+15
View File
@@ -1290,6 +1290,21 @@ namespace MobileGL::MG_Pipe {
[&](auto& emitter) { emitter.EmitRenderbufferRespecify(renderbuffer); });
}
void MGPipeNoteTextureBoundAs(MGPipeHandle texture, Uint32 bindBit) {
// Not gated on FamilyIsLive: the mask is client state (see the declaration), and the
// emitter gates the emission it causes.
ForwardWhenWired<kMGPipeWiredTextureSubsystem>(
MGPipeTextureEmitterInstance(),
[&](auto& emitter) { emitter.NoteTextureBoundAs(texture, static_cast<Uint16>(bindBit)); });
}
void MGPipeNoteTextureImageBound(ITextureObject& texture) {
ForwardWhenWired<kMGPipeWiredTextureSubsystem>(MGPipeTextureEmitterInstance(), [&](auto& emitter) {
emitter.NoteTextureBoundAs(emitter.AcquireTexture(texture.GetLifetimeId(), &texture),
static_cast<Uint16>(kMGPipeBindShaderImage));
});
}
void MGPipeEmitSamplerCsoCreate(SamplerObject& sampler) {
if (!FamilyIsLive(kMGPipeSubsystemSamplers, kMGPipeWiredSamplerSubsystem)) return;
ForwardWhenWired<kMGPipeWiredSamplerSubsystem>(
+5
View File
@@ -767,6 +767,11 @@ namespace MobileGL::MG_Pipe {
if (MG_State::GLState::SamplesAsIncompleteTexture(texture.get(), effective)) continue;
entry.Texture = MGPipeSlots().Acquire(MGPipeKind::Texture, texture->GetLifetimeId());
// D-A4: a texture the sampler-view resolution names in an emitted MGPBoundView
// is SAMPLER-bound from then on (sticky; the texture emitter's contract door,
// since this header is included BY TextureEmit.h). One early-out per unit per
// pass once the bit is set.
MGPipeNoteTextureBoundAs(entry.Texture, static_cast<Uint32>(kMGPipeBindSampler));
entry.View = AcquireSamplerView(*texture, entry.Texture, bytes);
}
+5 -2
View File
@@ -519,8 +519,11 @@ namespace MobileGL::MG_Pipe {
// ORed, never cleared, and emitted on BOTH resource_create and every
// resource_respecify, exactly as P3a's buffer mask is. The four bits nothing set before
// P4a get their producers here and in the framebuffer emitter: RENDER_TARGET and
// DEPTH_STENCIL from an attachment point, SAMPLER from a resolved sampler view and
// SHADER_IMAGE from a resolved image unit (the sampler package's two).
// DEPTH_STENCIL from an attachment point (FramebufferEmit.h), SAMPLER from a resolved
// sampler view (SamplerEmit.h) and SHADER_IMAGE from glBindImageTexture's state setter
// and the resolved image unit (TextureState.h, ImageEmit.h) - the last two through the
// contract's MGPipeNoteTextureBoundAs door, since neither may include this header
// (final review M-A: before the fix round nothing produced them and the hint was dead).
// A MASK CHANGE AFTER THE ALLOCATION IS A METADATA RESPECIFY (ID-18 M4), and without it
// the sticky half of D-A4 is a no-op for exactly the textures it was written for. The
// mask rides resource_create and every resource_respecify - and an IMMUTABLE texture has