mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Perf] (MG_Backend/DirectVulkan): re-land content-version texture early-out; bump content version on glGenerateMipmap so cached sampled views re-sync (fixes Iris shader retrace)
This commit is contained in:
@@ -1065,6 +1065,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
||||||
TextureResource &outResource) {
|
TextureResource &outResource) {
|
||||||
|
// Cross-draw fast path: if the resource is already built and neither the texture's
|
||||||
|
// pixel content (bumped in MarkStorageDirty) nor its params changed since the last
|
||||||
|
// sync, there is nothing to re-check or re-upload - skip CheckMipmapCompleteness,
|
||||||
|
// SyncTextureResource, SyncTextureViews and the per-level dirty scan. Layout is
|
||||||
|
// maintained separately by the transition path, so the resource still reflects truth.
|
||||||
|
const Uint64 syncingContentVersion = texture.GetContentVersion();
|
||||||
|
const auto* syncingMipTexture = MG_State::GLState::AsMipmapTexture(&texture);
|
||||||
|
const Uint32 syncingMipLevelCount =
|
||||||
|
syncingMipTexture != nullptr ? syncingMipTexture->GetMipmapLevelCount() : 0u;
|
||||||
|
if (outResource.image != VK_NULL_HANDLE &&
|
||||||
|
outResource.syncedContentVersion == syncingContentVersion &&
|
||||||
|
outResource.syncedTextureParamsVersion == texture.GetTextureParamsVersion() &&
|
||||||
|
outResource.syncedMipLevelCount == syncingMipLevelCount) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown;
|
TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown;
|
||||||
IntVec3 texelSize{0, 0, 0};
|
IntVec3 texelSize{0, 0, 0};
|
||||||
SizeT byteSize = 0;
|
SizeT byteSize = 0;
|
||||||
@@ -1111,6 +1127,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
DumpTextureSyncStats(texture.GetExternalIndex(), texture.GetFormat(), uploadTarget, mipLevelCount,
|
DumpTextureSyncStats(texture.GetExternalIndex(), texture.GetFormat(), uploadTarget, mipLevelCount,
|
||||||
texelSize, byteSize, hasDirtyMipLevel);
|
texelSize, byteSize, hasDirtyMipLevel);
|
||||||
if (!hasDirtyMipLevel) {
|
if (!hasDirtyMipLevel) {
|
||||||
|
outResource.syncedContentVersion = syncingContentVersion;
|
||||||
|
outResource.syncedMipLevelCount = syncingMipLevelCount;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,6 +1136,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MGLOG_D("%s: UploadDirtyMipLevels failed", __func__);
|
MGLOG_D("%s: UploadDirtyMipLevels failed", __func__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
outResource.syncedContentVersion = syncingContentVersion;
|
||||||
|
outResource.syncedMipLevelCount = syncingMipLevelCount;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,13 @@ public:
|
|||||||
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
|
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||||
Uint16 syncedTextureParamsVersion = 0;
|
Uint16 syncedTextureParamsVersion = 0;
|
||||||
|
// Snapshot of ITextureObject::GetContentVersion() at the last successful sync;
|
||||||
|
// lets SyncTexture skip the whole re-check/re-upload when content is unchanged.
|
||||||
|
Uint64 syncedContentVersion = 0;
|
||||||
|
// Snapshot of the defined mip-level count at the last sync. Folded into the early-out key
|
||||||
|
// as defense-in-depth: any path that grows the level set (which resizes the sampled view)
|
||||||
|
// busts the skip even if it failed to bump the content version.
|
||||||
|
Uint32 syncedMipLevelCount = 0;
|
||||||
|
|
||||||
TextureResource() = default;
|
TextureResource() = default;
|
||||||
TextureResource(const TextureResource&) = delete;
|
TextureResource(const TextureResource&) = delete;
|
||||||
@@ -120,6 +127,8 @@ public:
|
|||||||
std::swap(this->viewType, that.viewType);
|
std::swap(this->viewType, that.viewType);
|
||||||
std::swap(this->sampleCount, that.sampleCount);
|
std::swap(this->sampleCount, that.sampleCount);
|
||||||
std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion);
|
std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion);
|
||||||
|
std::swap(this->syncedContentVersion, that.syncedContentVersion);
|
||||||
|
std::swap(this->syncedMipLevelCount, that.syncedMipLevelCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
@@ -166,6 +175,8 @@ public:
|
|||||||
viewType = VK_IMAGE_VIEW_TYPE_2D;
|
viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||||
syncedTextureParamsVersion = 0;
|
syncedTextureParamsVersion = 0;
|
||||||
|
syncedContentVersion = 0;
|
||||||
|
syncedMipLevelCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~TextureResource() {
|
~TextureResource() {
|
||||||
|
|||||||
@@ -332,6 +332,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
texture.AllocateStorage(uploadTarget, level, {levelTexelSize, levelByteSize});
|
texture.AllocateStorage(uploadTarget, level, {levelTexelSize, levelByteSize});
|
||||||
texture.MarkStorageDirty(uploadTarget, level, false);
|
texture.MarkStorageDirty(uploadTarget, level, false);
|
||||||
}
|
}
|
||||||
|
// Mip generation grows/regenerates the level set on the GPU without marking any CPU
|
||||||
|
// level dirty (MarkStorageDirty(...,false) above). Bump the content version so the
|
||||||
|
// backend re-syncs: a cached sampled VkImageView built for the pre-generate level
|
||||||
|
// range would otherwise stay stale and clamp LOD>0 sampling to mip 0.
|
||||||
|
texture.BumpContentVersion();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,12 +207,21 @@ namespace MobileGL {
|
|||||||
return m_textureParamsVersion;
|
return m_textureParamsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint64 TextureObjectBase::GetContentVersion() const {
|
||||||
|
return m_contentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureObjectBase::BumpContentVersion() {
|
||||||
|
++m_contentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
Int TextureObjectBase::GetSamples() const {
|
Int TextureObjectBase::GetSamples() const {
|
||||||
return m_samples;
|
return m_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureObjectBase::SetSamples(Int samples) {
|
void TextureObjectBase::SetSamples(Int samples) {
|
||||||
m_samples = samples;
|
m_samples = samples;
|
||||||
|
++m_textureParamsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool TextureObjectBase::HasFixedSampleLocations() const {
|
Bool TextureObjectBase::HasFixedSampleLocations() const {
|
||||||
@@ -221,6 +230,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
void TextureObjectBase::SetFixedSampleLocations(Bool fixedSampleLocations) {
|
void TextureObjectBase::SetFixedSampleLocations(Bool fixedSampleLocations) {
|
||||||
m_fixedSampleLocations = fixedSampleLocations;
|
m_fixedSampleLocations = fixedSampleLocations;
|
||||||
|
++m_textureParamsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint64 TextureObjectBase::GetLifetimeId() const {
|
Uint64 TextureObjectBase::GetLifetimeId() const {
|
||||||
@@ -257,6 +267,9 @@ namespace MobileGL {
|
|||||||
|
|
||||||
void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
|
void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
|
||||||
Bool dirty) {
|
Bool dirty) {
|
||||||
|
if (dirty) {
|
||||||
|
++m_contentVersion;
|
||||||
|
}
|
||||||
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
|
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
virtual Uint GetImmutableLevels() const = 0;
|
virtual Uint GetImmutableLevels() const = 0;
|
||||||
virtual void SetImmutableLevels(Uint levels) = 0;
|
virtual void SetImmutableLevels(Uint levels) = 0;
|
||||||
virtual Uint16 GetTextureParamsVersion() const = 0;
|
virtual Uint16 GetTextureParamsVersion() const = 0;
|
||||||
|
// Monotonic counter bumped on every CPU-side pixel mutation (see MarkStorageDirty).
|
||||||
|
// Backends compare it against a per-resource snapshot to skip re-syncing unchanged
|
||||||
|
// textures across draws (e.g. the block atlas bound across a whole terrain batch).
|
||||||
|
virtual Uint64 GetContentVersion() const = 0;
|
||||||
virtual Int GetSamples() const = 0;
|
virtual Int GetSamples() const = 0;
|
||||||
virtual void SetSamples(Int samples) = 0;
|
virtual void SetSamples(Int samples) = 0;
|
||||||
virtual Bool HasFixedSampleLocations() const = 0;
|
virtual Bool HasFixedSampleLocations() const = 0;
|
||||||
@@ -86,6 +90,11 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
Uint GetImmutableLevels() const override;
|
Uint GetImmutableLevels() const override;
|
||||||
void SetImmutableLevels(Uint levels) override;
|
void SetImmutableLevels(Uint levels) override;
|
||||||
Uint16 GetTextureParamsVersion() const override;
|
Uint16 GetTextureParamsVersion() const override;
|
||||||
|
Uint64 GetContentVersion() const override;
|
||||||
|
// Bumps the content version without touching per-level storage-dirty flags. Used when the
|
||||||
|
// set of defined mip levels grows via GPU-side mip generation (glGenerateMipmap): the level
|
||||||
|
// set changed (so a cached sampled view's level range is stale) but no CPU data is dirty.
|
||||||
|
void BumpContentVersion();
|
||||||
Int GetSamples() const override;
|
Int GetSamples() const override;
|
||||||
void SetSamples(Int samples) override;
|
void SetSamples(Int samples) override;
|
||||||
Bool HasFixedSampleLocations() const override;
|
Bool HasFixedSampleLocations() const override;
|
||||||
@@ -108,6 +117,9 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
UintVec2 m_levelRange = {0, 1000};
|
UintVec2 m_levelRange = {0, 1000};
|
||||||
Uint m_immutableLevels = 0;
|
Uint m_immutableLevels = 0;
|
||||||
Uint16 m_textureParamsVersion = 0;
|
Uint16 m_textureParamsVersion = 0;
|
||||||
|
// Starts at 1 so a freshly-created backend resource (snapshot 0) never spuriously
|
||||||
|
// matches before its first sync. Bumped only on dirty=true in MarkStorageDirty.
|
||||||
|
Uint64 m_contentVersion = 1;
|
||||||
Int m_samples = 0;
|
Int m_samples = 0;
|
||||||
Bool m_fixedSampleLocations = true;
|
Bool m_fixedSampleLocations = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureObject2DCube::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) {
|
void TextureObject2DCube::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) {
|
||||||
|
if (dirty) {
|
||||||
|
++m_contentVersion;
|
||||||
|
}
|
||||||
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
|
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user