mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Fix] (MG_Backend/DirectVulkan): key the sampled-set walk-skip on a program lifetime id, not the recyclable GL name, so a deleted+recreated program can't false-hit the cache
This commit is contained in:
@@ -3406,11 +3406,11 @@ void main() {
|
|||||||
// elides re-resolving *which* textures are sampled, never their layout handling.
|
// elides re-resolving *which* textures are sampled, never their layout handling.
|
||||||
auto& sampledTextures = m_sampledTexturesScratch;
|
auto& sampledTextures = m_sampledTexturesScratch;
|
||||||
{
|
{
|
||||||
const Uint programIndex = program.GetExternalIndex();
|
const Uint64 programLifetimeId = program.GetLifetimeId();
|
||||||
const Uint32 programVersion = program.GetBackendStateVersion();
|
const Uint32 programVersion = program.GetBackendStateVersion();
|
||||||
const Uint64 bindGeneration = MG_State::pGLContext->GetTextureBindGeneration();
|
const Uint64 bindGeneration = MG_State::pGLContext->GetTextureBindGeneration();
|
||||||
const Bool sampledSetUnchanged =
|
const Bool sampledSetUnchanged =
|
||||||
m_lastSampledSetValid && m_lastSampledSetProgramIndex == programIndex &&
|
m_lastSampledSetValid && m_lastSampledSetProgramLifetimeId == programLifetimeId &&
|
||||||
m_lastSampledSetProgramVersion == programVersion &&
|
m_lastSampledSetProgramVersion == programVersion &&
|
||||||
m_lastSampledSetTransformFlags == transformFlags &&
|
m_lastSampledSetTransformFlags == transformFlags &&
|
||||||
m_lastSampledSetBindGeneration == bindGeneration;
|
m_lastSampledSetBindGeneration == bindGeneration;
|
||||||
@@ -3419,7 +3419,7 @@ void main() {
|
|||||||
m_uniformManager->CollectSampledTextures(program, programObj, sampledTextures);
|
m_uniformManager->CollectSampledTextures(program, programObj, sampledTextures);
|
||||||
MOBILEGL_ASSERT(hasSampledTextures, "%s: CollectSampledTextures failed", __func__);
|
MOBILEGL_ASSERT(hasSampledTextures, "%s: CollectSampledTextures failed", __func__);
|
||||||
m_lastSampledSetValid = true;
|
m_lastSampledSetValid = true;
|
||||||
m_lastSampledSetProgramIndex = programIndex;
|
m_lastSampledSetProgramLifetimeId = programLifetimeId;
|
||||||
m_lastSampledSetProgramVersion = programVersion;
|
m_lastSampledSetProgramVersion = programVersion;
|
||||||
m_lastSampledSetTransformFlags = transformFlags;
|
m_lastSampledSetTransformFlags = transformFlags;
|
||||||
m_lastSampledSetBindGeneration = bindGeneration;
|
m_lastSampledSetBindGeneration = bindGeneration;
|
||||||
|
|||||||
@@ -404,15 +404,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
|
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
|
||||||
|
|
||||||
// Skip the per-draw CollectSampledTextures walk (~5% of the render thread) when the sampled
|
// Skip the per-draw CollectSampledTextures walk (~5% of the render thread) when the sampled
|
||||||
// texture SET is provably unchanged from the previous draw: same program (external index +
|
// texture SET is provably unchanged from the previous draw: same program (lifetime id +
|
||||||
// backend-state version, which covers sampler-uniform reassignment / relink) and transform
|
// backend-state version, which covers sampler-uniform reassignment / relink) and transform
|
||||||
// flags, and no texture bind/unbind/delete since (GetTextureBindGeneration). On a hit,
|
// flags, and no texture bind/unbind/delete since (GetTextureBindGeneration). On a hit,
|
||||||
// m_sampledTexturesScratch still holds the previous draw's list and steps 2-4 (feedback /
|
// m_sampledTexturesScratch still holds the previous draw's list and steps 2-4 (feedback /
|
||||||
// layout probe / transition) re-run on it, so layout correctness is unaffected - only the GL
|
// layout probe / transition) re-run on it, so layout correctness is unaffected - only the GL
|
||||||
// walk is skipped. Reset per command-buffer recording so a reused program/FBO address can't
|
// walk is skipped. The program lifetime id (never reused, unlike the GL name) and the
|
||||||
// outlive a frame.
|
// monotonic bind generation make the key ABA-proof; the per-command-buffer reset is a cheap
|
||||||
|
// belt-and-suspenders.
|
||||||
Bool m_lastSampledSetValid = false;
|
Bool m_lastSampledSetValid = false;
|
||||||
Uint m_lastSampledSetProgramIndex = 0;
|
Uint64 m_lastSampledSetProgramLifetimeId = 0;
|
||||||
Uint32 m_lastSampledSetProgramVersion = 0;
|
Uint32 m_lastSampledSetProgramVersion = 0;
|
||||||
ProgramFactory::CompileOptionFlags m_lastSampledSetTransformFlags = {};
|
ProgramFactory::CompileOptionFlags m_lastSampledSetTransformFlags = {};
|
||||||
Uint64 m_lastSampledSetBindGeneration = 0;
|
Uint64 m_lastSampledSetBindGeneration = 0;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
|
#include <atomic>
|
||||||
#include <MG_Backend/BackendObjects.h>
|
#include <MG_Backend/BackendObjects.h>
|
||||||
#include <MG_State/GLState/VertexArrayState/VertexArrayObject.h>
|
#include <MG_State/GLState/VertexArrayState/VertexArrayObject.h>
|
||||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||||
@@ -122,6 +123,12 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace MobileGL::MG_State::GLState {
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
static std::atomic<Uint64> s_nextProgramLifetimeId = 1;
|
||||||
|
|
||||||
|
Uint64 ProgramObject::AllocateLifetimeId() {
|
||||||
|
return s_nextProgramLifetimeId.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
void ProgramObject::ResetLinkArtifacts() {
|
void ProgramObject::ResetLinkArtifacts() {
|
||||||
// Relinking regenerates the SPIR-V, so any backend-cached state keyed on
|
// Relinking regenerates the SPIR-V, so any backend-cached state keyed on
|
||||||
// m_backendStateVersion (e.g. the content-hash memo) must be invalidated,
|
// m_backendStateVersion (e.g. the content-hash memo) must be invalidated,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
namespace MobileGL::MG_State::GLState {
|
namespace MobileGL::MG_State::GLState {
|
||||||
class ProgramObject {
|
class ProgramObject {
|
||||||
public:
|
public:
|
||||||
ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
|
ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex), m_lifetimeId(AllocateLifetimeId()) {}
|
||||||
bool ShaderIsAttached(const SharedPtr<ShaderObject>& shader);
|
bool ShaderIsAttached(const SharedPtr<ShaderObject>& shader);
|
||||||
bool AttachShader(const SharedPtr<ShaderObject>& shader);
|
bool AttachShader(const SharedPtr<ShaderObject>& shader);
|
||||||
SizeT DetachShader(const SharedPtr<ShaderObject>& shader);
|
SizeT DetachShader(const SharedPtr<ShaderObject>& shader);
|
||||||
@@ -340,6 +340,11 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Uint GetExternalIndex() const { return m_externalIndex; }
|
Uint GetExternalIndex() const { return m_externalIndex; }
|
||||||
|
// Globally-unique, never-reused id for this program object's lifetime. Unlike the GL
|
||||||
|
// name (external index), which is freed to a LIFO list and immediately handed back by
|
||||||
|
// the next glCreateProgram, this distinguishes a deleted-and-recreated program from the
|
||||||
|
// original, so an identity cache can't false-hit on name recycling.
|
||||||
|
Uint64 GetLifetimeId() const { return m_lifetimeId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetLinkArtifacts();
|
void ResetLinkArtifacts();
|
||||||
@@ -349,7 +354,10 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
void AddDefaultFragmentShaderIfMissing();
|
void AddDefaultFragmentShaderIfMissing();
|
||||||
Bool ValidateFragmentOutputLocations();
|
Bool ValidateFragmentOutputLocations();
|
||||||
|
|
||||||
|
static Uint64 AllocateLifetimeId();
|
||||||
|
|
||||||
const Uint m_externalIndex = 0;
|
const Uint m_externalIndex = 0;
|
||||||
|
const Uint64 m_lifetimeId = 0;
|
||||||
Vector<SharedPtr<ShaderObject>> m_shaders;
|
Vector<SharedPtr<ShaderObject>> m_shaders;
|
||||||
Vector<SharedPtr<ShaderObject>> m_detachedShaders; // Store detached shaders and remove on next link
|
Vector<SharedPtr<ShaderObject>> m_detachedShaders; // Store detached shaders and remove on next link
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user