From 8f5517949360fa1ac21a88c80d67f6493b09c699 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 2 Feb 2026 15:37:55 +0800 Subject: [PATCH] [Optimize] (MG_Backend/DirectGLES): Texture object mipmap dirty bit --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 28 +- MobileGL/MG_Backend/DirectGLES/Managers.cpp | 301 +++++++++--------- MobileGL/MG_Backend/DirectGLES/Managers.h | 1 + .../MG_Impl/GLImpl/Texture/GL_Texture.cpp | 1 + .../GLState/TextureState/TextureObject.cpp | 18 ++ .../GLState/TextureState/TextureObject.h | 16 +- .../TextureState/TextureObject2DCube.cpp | 14 + .../TextureState/TextureObject2DCube.h | 1 + .../TextureState/TextureObjectBuffer.cpp | 8 + .../TextureState/TextureObjectBuffer.h | 2 + MobileGL/MG_Util/Types.h | 10 + 11 files changed, 238 insertions(+), 162 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 89aeb380..c0a4752c 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -205,8 +205,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // 1. textures bound to texture units (TODO: only sync ones that are used in current program) // 2. textures used in current FBO // 3. textures bound to image units (TODO) - constexpr SizeT TextureTargetCount = static_cast(TextureTarget::TextureTargetCount); - std::bitset dirtyTextureTargetBits; +// constexpr SizeT TextureTargetCount = static_cast(TextureTarget::TextureTargetCount); +// std::bitset dirtyTextureTargetBits; Vector> texturesToSync; @@ -218,7 +218,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& end = texturesToSync.end(); if (std::find(texturesToSync.begin(), end, textureObject) == end) { texturesToSync.push_back(textureObject); - dirtyTextureTargetBits.set(static_cast(textureObject->GetTarget())); +// dirtyTextureTargetBits.set(static_cast(textureObject->GetTarget())); } } } @@ -234,22 +234,22 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& end = texturesToSync.end(); if (std::find(texturesToSync.begin(), end, textureObject) == end) { texturesToSync.push_back(textureObject); - dirtyTextureTargetBits.set(static_cast(textureObject->GetTarget())); +// dirtyTextureTargetBits.set(static_cast(textureObject->GetTarget())); } } } } - BufferImpl::BackendBufferBindingProtector pixelUnpackProtector = - BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); - - Vector textureBindingProtectors; - for (SizeT target = 0; target < TextureTargetCount; ++target) { - if (dirtyTextureTargetBits[target]) { - textureBindingProtectors.emplace_back( - MG_Util::ConvertTextureTargetToGLEnum(static_cast(target))); - } - } +// BufferImpl::BackendBufferBindingProtector pixelUnpackProtector = +// BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); +// +// Vector textureBindingProtectors; +// for (SizeT target = 0; target < TextureTargetCount; ++target) { +// if (dirtyTextureTargetBits[target]) { +// textureBindingProtectors.emplace_back( +// MG_Util::ConvertTextureTargetToGLEnum(static_cast(target))); +// } +// } // Do real sync for (auto& textureObject : texturesToSync) { diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 8acecd7e..492ae6f0 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -366,166 +366,173 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(baseSize.z()), 0, 0}; - switch (stateTextureObject->GetStorageType()) { - case TextureStorageType::Mipmap: { - auto* textureMipmapObject = - static_cast(stateTextureObject.get()); - const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); - currentTextureInfo.mipmapLevels = mipmapCount; - Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); + if (stateTextureObject->CheckDirtyBit(MG_State::GLState::TextureDirtyBit::StorageDirtyBit)) { + switch (stateTextureObject->GetStorageType()) { + case TextureStorageType::Mipmap: { + auto* textureMipmapObject = + static_cast(stateTextureObject.get()); + const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); + currentTextureInfo.mipmapLevels = mipmapCount; - MGLOG_D("%s: Got texture info: %dx%dx%d, mips %d, format %s", __func__, baseSize.x(), baseSize.y(), - baseSize.z(), mipmapCount, - MG_Util::ConvertTextureInternalFormatToString(textureMipmapObject->GetFormat()).c_str()); + Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); - if (needsRegeneration) { - MGLOG_D("Texture state changed significantly or not initialized, regenerating texture with ID: %u", + MGLOG_D("%s: Got texture info: %dx%dx%d, mips %d, format %s", __func__, baseSize.x(), baseSize.y(), + baseSize.z(), mipmapCount, + MG_Util::ConvertTextureInternalFormatToString(textureMipmapObject->GetFormat()).c_str()); + + if (needsRegeneration) { + MGLOG_D("Texture state changed significantly or not initialized, regenerating texture with ID: %u", + m_backendTextureId); + + // Regenerate all mipmap levels + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, + &glFormat, &glType); + + const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); + for (auto uploadTarget : uploadTargets) { + for (SizeT level = 0; level < mipmapCount; ++level) { + auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); + auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); + bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level); + auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); + auto* pData = (levelDirty && levelByteSize != 0) + ? textureMipmapObject->MapMipmapData(uploadTarget, level) + : nullptr; + MGLOG_D( + "%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s", + __func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, + levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData, + levelDirty ? "true" : "false"); + + errorLopper.Clear(); + MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + auto textureTarget = stateTextureObject->GetTarget(); + // TODO: handle more texture types + switch (textureTarget) { + case TextureTarget::Texture2D: + case TextureTarget::TextureCubeMap: { + MG_External::GLES::glTexImage2D( + glUploadTarget, static_cast(level), glInternalFormat, + static_cast(levelTexelSize.x()), static_cast(levelTexelSize.y()), + 0, glFormat, glType, pData); + break; + } + case TextureTarget::Texture3D: { + MG_External::GLES::glTexImage3D( + glUploadTarget, static_cast(level), glInternalFormat, + static_cast(levelTexelSize.x()), static_cast(levelTexelSize.y()), + static_cast(levelTexelSize.z()), 0, glFormat, glType, pData); + break; + } + default: { + MGLOG_E("Unhandled texture target %s", + MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); + } + } + errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget, + glInternalFormat, glFormat, glType, pData](GLenum err) { + MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, " + "type=%s, pixels=%p", + func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), + MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(), + MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(), + MG_Util::ConvertGLEnumToString(glFormat).c_str(), + MG_Util::ConvertGLEnumToString(glType).c_str(), pData); + }); + MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId); + textureMipmapObject->MarkStorageDirty(uploadTarget, level, false); + } + } + + m_isInitialized = true; + } + + { // Update all dirty mipmap levels + const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, + &glFormat, &glType); + const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); + for (auto uploadTarget : uploadTargets) { + for (SizeT level = 0; level < mipmapCount; ++level) { + if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) { + continue; + } + + auto byteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); + if (byteSize == 0) { + MGLOG_W("Mipmap level %d has no data, skipping update.", level); + continue; + } + + if (level > 0) + MGLOG_D("%s: Updating dirty mip %d for texture ID %u, size: %dx%d, " + "byteSize: %d", + __func__, level, m_backendTextureId, + textureMipmapObject->GetMipmapTexelSize(uploadTarget, level).x(), + textureMipmapObject->GetMipmapTexelSize(uploadTarget, level).y(), byteSize); + + auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); + MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { + MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, + MG_Util::ConvertGLEnumToString(err).c_str()); + }); + auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); + MG_External::GLES::glTexSubImage2D(glUploadTarget, static_cast(level), 0, 0, + static_cast(texelSize.x()), + static_cast(texelSize.y()), glFormat, glType, + textureMipmapObject->MapMipmapData(uploadTarget, level)); + textureMipmapObject->MarkStorageDirty(uploadTarget, level, false); + } + } + } + + textureMipmapObject->ClearAllStorageDirtyBit(); + break; + } + case TextureStorageType::Buffer: { + auto* textureBufferObject = + static_cast(stateTextureObject.get()); + auto& slot = textureBufferObject->GetBufferBindingSlot(); + auto buffer = slot.GetBoundObject(); + auto bufferIndex = buffer->GetExternalIndex(); + currentTextureInfo.bufferExternalIndex = bufferIndex; + + Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); + MGLOG_D("Texture state changed significantly or not initialized, regenerating texture (tex buffer) " + "with ID: %u", m_backendTextureId); - // Regenerate all mipmap levels - GLenum glInternalFormat, glType, glFormat; - TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, - &glFormat, &glType); - - const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); - for (auto uploadTarget : uploadTargets) { - for (SizeT level = 0; level < mipmapCount; ++level) { - auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); - auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); - bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level); - auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); - auto* pData = (levelDirty && levelByteSize != 0) - ? textureMipmapObject->MapMipmapData(uploadTarget, level) - : nullptr; - MGLOG_D( - "%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s", - __func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, - levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData, - levelDirty ? "true" : "false"); - - errorLopper.Clear(); - MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - auto textureTarget = stateTextureObject->GetTarget(); - // TODO: handle more texture types - switch (textureTarget) { - case TextureTarget::Texture2D: - case TextureTarget::TextureCubeMap: { - MG_External::GLES::glTexImage2D( - glUploadTarget, static_cast(level), glInternalFormat, - static_cast(levelTexelSize.x()), static_cast(levelTexelSize.y()), - 0, glFormat, glType, pData); - break; - } - case TextureTarget::Texture3D: { - MG_External::GLES::glTexImage3D( - glUploadTarget, static_cast(level), glInternalFormat, - static_cast(levelTexelSize.x()), static_cast(levelTexelSize.y()), - static_cast(levelTexelSize.z()), 0, glFormat, glType, pData); - break; - } - default: { - MGLOG_E("Unhandled texture target %s", - MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); - } - } - errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget, - glInternalFormat, glFormat, glType, pData](GLenum err) { - MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, " - "type=%s, pixels=%p", - func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), - MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(), - MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(), - MG_Util::ConvertGLEnumToString(glFormat).c_str(), - MG_Util::ConvertGLEnumToString(glType).c_str(), pData); - }); - MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId); - textureMipmapObject->MarkStorageDirty(uploadTarget, level, false); - } + // Need to sync texture buffer if not synced yet + auto& backendBuffers = BufferImpl::g_backendBufferObjects; + SharedPtr backendBufferObject; + const auto& backendBufferIt = backendBuffers.find(buffer); + if (backendBufferIt == backendBuffers.end()) { + backendBufferObject = MakeShared(); + backendBuffers[buffer] = backendBufferObject; + } else { + backendBufferObject = backendBufferIt->second; } + backendBufferObject->SyncToBackend(buffer); - m_isInitialized = true; - } + // Bind buffer to texture + auto backendId = backendBufferObject->GetBackendBufferId(); - { // Update all dirty mipmap levels - const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); GLenum glInternalFormat, glType, glFormat; - TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, - &glFormat, &glType); - const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); - for (auto uploadTarget : uploadTargets) { - for (SizeT level = 0; level < mipmapCount; ++level) { - if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) { - continue; - } + TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat, + &glType); - auto byteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); - if (byteSize == 0) { - MGLOG_W("Mipmap level %d has no data, skipping update.", level); - continue; - } + MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); - if (level > 0) - MGLOG_D("%s: Updating dirty mip %d for texture ID %u, size: %dx%d, " - "byteSize: %d", - __func__, level, m_backendTextureId, - textureMipmapObject->GetMipmapTexelSize(uploadTarget, level).x(), - textureMipmapObject->GetMipmapTexelSize(uploadTarget, level).y(), byteSize); - - auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); - MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { - MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, - MG_Util::ConvertGLEnumToString(err).c_str()); - }); - auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); - MG_External::GLES::glTexSubImage2D(glUploadTarget, static_cast(level), 0, 0, - static_cast(texelSize.x()), - static_cast(texelSize.y()), glFormat, glType, - textureMipmapObject->MapMipmapData(uploadTarget, level)); - textureMipmapObject->MarkStorageDirty(uploadTarget, level, false); - } - } + textureBufferObject->ClearAllStorageDirtyBit(); + break; } - break; - } - case TextureStorageType::Buffer: { - auto* textureBufferObject = - static_cast(stateTextureObject.get()); - auto& slot = textureBufferObject->GetBufferBindingSlot(); - auto buffer = slot.GetBoundObject(); - auto bufferIndex = buffer->GetExternalIndex(); - currentTextureInfo.bufferExternalIndex = bufferIndex; - - Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); - MGLOG_D("Texture state changed significantly or not initialized, regenerating texture (tex buffer) " - "with ID: %u", - m_backendTextureId); - - // Need to sync texture buffer if not synced yet - auto& backendBuffers = BufferImpl::g_backendBufferObjects; - SharedPtr backendBufferObject; - const auto& backendBufferIt = backendBuffers.find(buffer); - if (backendBufferIt == backendBuffers.end()) { - backendBufferObject = MakeShared(); - backendBuffers[buffer] = backendBufferObject; - } else { - backendBufferObject = backendBufferIt->second; + default: + THROW_UNIMPL_EXCEPTION; } - backendBufferObject->SyncToBackend(buffer); - - // Bind buffer to texture - auto backendId = backendBufferObject->GetBackendBufferId(); - - GLenum glInternalFormat, glType, glFormat; - TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat, - &glType); - - MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); - break; - } - default: - THROW_UNIMPL_EXCEPTION; } { // Update built-in sampler parameters diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 506e0cb8..3c884958 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -9,6 +9,7 @@ #pragma once #include #include "DirectGLES.h" +#include "Utils.h" #include "MG_State/GLState/SamplerState/SamplerObject.h" #include "MG_State/GLState/TextureState/TextureEnum.h" #include diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 911fca93..61a9d9f3 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -788,6 +788,7 @@ namespace MobileGL { auto* texBufferObject = static_cast(textureObject.get()); auto& bufferSlot = texBufferObject->GetBufferBindingSlot(); bufferSlot.Bind(bufferObject); + texBufferObject->SetStorageDirtyBit(); texBufferObject->SetInternalFormat(textureInternalFormat); } diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp index 2fbf712f..7f011c1d 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -115,6 +115,13 @@ namespace MobileGL { m_levelRange.y() = maxLevel; } + bool TextureObjectBase::IsDirty() const { + return m_dirtyBit; + } + bool TextureObjectBase::CheckDirtyBit(TextureDirtyBit bit) const { + return m_dirtyBit & bit; + } + Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const { return m_textureStorage.GetLevelCount(); } @@ -146,6 +153,9 @@ namespace MobileGL { void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) { m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); + if (dirty) { + m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit); + } } bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { @@ -189,6 +199,14 @@ namespace MobileGL { return true; } + void TextureObjectWithOneMipmap::ClearAllStorageDirtyBit() { + auto levelCount = GetMipmapLevelCount(); + for (Uint i = 0; i < levelCount; ++i) { + m_textureStorage.MarkDirty(0, i, false); + } + m_dirtyBit.Clear(TextureDirtyBit::StorageDirtyBit); + } + // TODO: add other texture types as needed } // namespace GLState diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.h b/MobileGL/MG_State/GLState/TextureState/TextureObject.h index dab1b41c..78d285be 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.h @@ -17,6 +17,12 @@ namespace MobileGL { namespace MG_State { namespace GLState { + enum class TextureDirtyBit: Uint8 { + None = 0, + StorageDirtyBit = 1 << 0, // refers to mipmap or TexBuffer according to tex type + ParamDirtyBit = 1 << 1 + }; + class ITextureObject { public: using TargetEnum = TextureTarget; @@ -41,6 +47,8 @@ namespace MobileGL { virtual const UintVec2& GetLevelRange() const = 0; virtual void SetBaseLevel(Uint baseLevel) = 0; virtual void SetMaxLevel(Uint maxLevel) = 0; + virtual bool IsDirty() const = 0; + virtual bool CheckDirtyBit(TextureDirtyBit bit) const = 0; protected: virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0; @@ -67,6 +75,9 @@ namespace MobileGL { const UintVec2& GetLevelRange() const override; void SetBaseLevel(Uint baseLevel) override; void SetMaxLevel(Uint maxLevel) override; + bool IsDirty() const override; + bool CheckDirtyBit(TextureDirtyBit bit) const override; + virtual void ClearAllStorageDirtyBit() = 0; protected: const Uint m_externalIndex; @@ -77,6 +88,8 @@ namespace MobileGL { Vec4 m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; UintVec2 m_levelRange = {0, 1000}; + + Flags m_dirtyBit = TextureDirtyBit::None; }; class TextureObjectMipmap : public TextureObjectBase { @@ -92,7 +105,7 @@ namespace MobileGL { virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0; - virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) = 0; + virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty = true) = 0; virtual bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0; }; @@ -110,6 +123,7 @@ namespace MobileGL { void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; + void ClearAllStorageDirtyBit() override; IntVec3 GetBaseSize() const override; Bool IsComplete() const override; diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.cpp index 8ed9113b..e7eea174 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.cpp @@ -42,6 +42,9 @@ namespace MobileGL { void TextureObject2DCube::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) { m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); + if (dirty) { + m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit); + } } bool TextureObject2DCube::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { @@ -82,6 +85,17 @@ namespace MobileGL { // TODO: add more completeness checks based on texture type and mipmap levels return true; } + + void TextureObject2DCube::ClearAllStorageDirtyBit() { + auto uploadTargetCount = GetUploadTargets().size(); + auto levelCount = GetMipmapLevelCount(); + for (SizeT target = 0; target < uploadTargetCount; ++target) { + for (Uint level = 0; level < levelCount; ++level) { + m_textureStorage.MarkDirty(target, level, false); + } + } + m_dirtyBit.Clear(TextureDirtyBit::StorageDirtyBit); + } } // namespace GLState } // namespace MG_State } // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.h b/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.h index 2d97a8b2..a7f8abe9 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject2DCube.h @@ -26,6 +26,7 @@ namespace MobileGL { void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; + void ClearAllStorageDirtyBit() override; IntVec3 GetBaseSize() const override; Bool IsComplete() const override; diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.cpp index 4cb4f712..481e9760 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.cpp @@ -23,6 +23,14 @@ namespace MobileGL { MOBILEGL_ASSERT(target == TextureUploadTarget::TextureBuffer, "Invalid TextureUploadTarget!"); return m_bufferBindingSlot; } + + void TextureObjectBuffer::ClearAllStorageDirtyBit() { + m_dirtyBit.Clear(TextureDirtyBit::StorageDirtyBit); + } + + void TextureObjectBuffer::SetStorageDirtyBit() { + m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit); + } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h index f5d7928e..c2b4badf 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h @@ -20,6 +20,8 @@ namespace MobileGL { const Vector& GetUploadTargets() const override { return m_uploadTargets; } BindingSlot& GetBufferBindingSlot( TextureUploadTarget target = TextureUploadTarget::TextureBuffer); + void ClearAllStorageDirtyBit() override; + void SetStorageDirtyBit(); protected: Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override; diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index c4748b5c..94085dc6 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -278,6 +278,16 @@ namespace MobileGL { Flags(typename Underlying::type b) : flags(b) {} + Flags Set(const Bit b) { + flags |= static_cast(b); + return flags; + } + + Flags Clear(const Bit b) { + flags &= ~static_cast(b); + return flags; + } + // Flags - Bit Flags operator|(const Bit b) const { return Flags(flags | static_cast(b)); }