mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Perf] (MG_Backend/DirectVulkan, MG_State): stop re-deriving per-draw state
- Memoize the program content hash on ProgramObject (keyed by the backend state version + compile flags; relinking and binding changes invalidate it) and the vertex-input hash on VertexArrayObject (keyed by a new aggregate config version bumped by every attribute mutation). Full-SPIRV XXH64 hashing fell from 13.7% to 1.4% of the render thread. - ProgramObject also gains a link version and a global-UBO content version (bumped by uniform writes and on relink, wrap-safe around the backends' "never uploaded" sentinel) for backends to gate uploads and link caches. - Reuse member scratch vectors in SetupDraw, UploadAndBindVertexBuffers, GetOrCreatePipeline and BindProgramUniformBuffers instead of allocating per draw (~12% of render-thread time was in the allocator). - Replace hot-path dynamic_cast with AsMipmapTexture (storage-type tag + static_cast); TextureObjectMipmap is the only Mipmap-tagged branch. - Register/prune texture aliases only when a new (texture, lifetimeId) identity appears instead of scanning the entire alive map on every sampled-texture sync. - Make the fallback VkPresentModeKHR log strings report the actual mode. Vanilla render-thread share of libMobileGL dropped from 48% to 35% on DirectVulkan (simpleperf, Adreno 830). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,14 @@ namespace {
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
void ProgramObject::ResetLinkArtifacts() {
|
||||
// Relinking regenerates the SPIR-V, so any backend-cached state keyed on
|
||||
// m_backendStateVersion (e.g. the content-hash memo) must be invalidated,
|
||||
// along with every link-derived backend cache (m_linkVersion) and the
|
||||
// last-uploaded-UBO gate (a relink resets uniforms to their initial values,
|
||||
// and that reset must reach the GPU).
|
||||
++m_backendStateVersion;
|
||||
++m_linkVersion;
|
||||
MarkUBOContentDirty();
|
||||
m_program.reset();
|
||||
m_generatedSpirv.clear();
|
||||
m_uniformLocations.clear();
|
||||
|
||||
@@ -170,7 +170,33 @@ namespace MobileGL::MG_State::GLState {
|
||||
void* MapUBO() { return m_globalUboScratch.data(); }
|
||||
const void* GetUBOData() const { return m_globalUboScratch.data(); }
|
||||
Uint GetUBOSize() const { return static_cast<Uint>(m_globalUboScratch.size()); }
|
||||
// Content version of the CPU-side global-UBO shadow: writers bump it so backends
|
||||
// can skip re-uploading an unchanged UBO on every draw. ~0u is reserved as the
|
||||
// backends' "never uploaded" sentinel, so skip over it on wrap.
|
||||
Uint32 GetUBOContentVersion() const { return m_uboContentVersion; }
|
||||
void MarkUBOContentDirty() {
|
||||
if (++m_uboContentVersion == ~0u) m_uboContentVersion = 0;
|
||||
}
|
||||
Uint32 GetBackendStateVersion() const { return m_backendStateVersion; }
|
||||
// Bumped only by (re)linking — lets backends detect that every piece of
|
||||
// link-derived reflection (locations, block order, UBO layout) is stale.
|
||||
Uint32 GetLinkVersion() const { return m_linkVersion; }
|
||||
|
||||
// Content-hash memo for backends: avoids re-hashing the generated SPIR-V on every
|
||||
// draw. The memo is keyed by (backendStateVersion, flags); ResetLinkArtifacts and
|
||||
// the binding setters below invalidate it by bumping m_backendStateVersion.
|
||||
Bool GetBackendHashMemo(Uint flags, Uint64& outHash) const {
|
||||
if (m_backendHashMemoVersion != m_backendStateVersion || m_backendHashMemoFlags != flags) {
|
||||
return false;
|
||||
}
|
||||
outHash = m_backendHashMemo;
|
||||
return true;
|
||||
}
|
||||
void SetBackendHashMemo(Uint flags, Uint64 hash) const {
|
||||
m_backendHashMemo = hash;
|
||||
m_backendHashMemoVersion = m_backendStateVersion;
|
||||
m_backendHashMemoFlags = flags;
|
||||
}
|
||||
|
||||
void SetUniformSamplerOrImageUnitIndex(Uint location, Int unit) {
|
||||
if (location >= m_uniformSamplerOrImageUnitIndex.size() ||
|
||||
@@ -308,5 +334,13 @@ namespace MobileGL::MG_State::GLState {
|
||||
Bool m_linkStatus = false;
|
||||
Bool m_validateStatus = true;
|
||||
Uint32 m_backendStateVersion = 0;
|
||||
|
||||
// Backend-owned content-hash memo (see GetBackendHashMemo): valid only while
|
||||
// m_backendStateVersion and the compile flags match the recorded values.
|
||||
mutable Uint64 m_backendHashMemo = 0;
|
||||
mutable Uint32 m_backendHashMemoVersion = ~0u;
|
||||
mutable Uint m_backendHashMemoFlags = 0;
|
||||
Uint32 m_uboContentVersion = 0;
|
||||
Uint32 m_linkVersion = 0;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -128,6 +128,20 @@ namespace MobileGL::MG_State::GLState {
|
||||
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
|
||||
};
|
||||
|
||||
// Cheap replacement for dynamic_cast on the hot path: TextureObjectMipmap is the
|
||||
// only hierarchy branch whose storage type reports Mipmap, so the tag check makes
|
||||
// the static_cast safe.
|
||||
inline TextureObjectMipmap* AsMipmapTexture(ITextureObject* texture) {
|
||||
return (texture && texture->GetStorageType() == TextureStorageType::Mipmap)
|
||||
? static_cast<TextureObjectMipmap*>(texture)
|
||||
: nullptr;
|
||||
}
|
||||
inline const TextureObjectMipmap* AsMipmapTexture(const ITextureObject* texture) {
|
||||
return (texture && texture->GetStorageType() == TextureStorageType::Mipmap)
|
||||
? static_cast<const TextureObjectMipmap*>(texture)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
class TextureObjectWithOneMipmap : public TextureObjectMipmap {
|
||||
public:
|
||||
TextureObjectWithOneMipmap(TextureTarget target, Uint externalIndex)
|
||||
|
||||
@@ -207,16 +207,19 @@ namespace MobileGL::MG_State::GLState {
|
||||
void VertexArrayObject::BumpAttributeFormatVersion(Uint index) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
++m_attributeVersions[index].FormatVersion;
|
||||
++m_configVersion;
|
||||
}
|
||||
|
||||
void VertexArrayObject::BumpAttributeBufferVersion(Uint index) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
++m_attributeVersions[index].BufferVersion;
|
||||
++m_configVersion;
|
||||
}
|
||||
|
||||
void VertexArrayObject::BumpAttributeSwitchVersion(Uint index) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
++m_attributeVersions[index].SwitchVersion;
|
||||
++m_configVersion;
|
||||
}
|
||||
|
||||
const VertexAttributeVersion& VertexArrayObject::GetAttributeVersion(Uint index) const {
|
||||
|
||||
@@ -81,6 +81,23 @@ namespace MobileGL {
|
||||
const VertexAttributeVersion& GetAttributeVersion(Uint index) const;
|
||||
const Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS>& GetAllAttributeVersions() const;
|
||||
|
||||
// Aggregate of every per-attribute version bump; lets backends detect
|
||||
// "any vertex-input state changed" with one compare.
|
||||
Uint32 GetConfigVersion() const { return m_configVersion; }
|
||||
|
||||
// Backend-owned content-hash memo, valid while the config version matches
|
||||
// (same idea as ProgramObject's hash memo — avoids re-hashing all
|
||||
// attributes on every draw).
|
||||
Bool GetBackendHashMemo(Uint64& outHash) const {
|
||||
if (m_backendHashMemoVersion != m_configVersion) return false;
|
||||
outHash = m_backendHashMemo;
|
||||
return true;
|
||||
}
|
||||
void SetBackendHashMemo(Uint64 hash) const {
|
||||
m_backendHashMemo = hash;
|
||||
m_backendHashMemoVersion = m_configVersion;
|
||||
}
|
||||
|
||||
private:
|
||||
void BumpAttributeFormatVersion(Uint index);
|
||||
void BumpAttributeBufferVersion(Uint index);
|
||||
@@ -100,6 +117,10 @@ namespace MobileGL {
|
||||
// ARB_vertex_attrib_binding API; only such attributes are re-resolved, so the
|
||||
// classic glVertexAttribPointer path keeps its exact historical behavior.
|
||||
Array<Bool, MAX_VERTEX_ATTRIBS> m_attributeUsesBindingModel = {};
|
||||
|
||||
Uint32 m_configVersion = 0;
|
||||
mutable Uint64 m_backendHashMemo = 0;
|
||||
mutable Uint32 m_backendHashMemoVersion = ~0u;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
|
||||
Reference in New Issue
Block a user