[Optimize] (MG_Backend/DirectGLES): Texture object mipmap dirty bit

This commit is contained in:
2026-02-02 15:37:55 +08:00
parent cb2ce8f2a5
commit 8f55179493
11 changed files with 238 additions and 162 deletions
+14 -14
View File
@@ -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) // 1. textures bound to texture units (TODO: only sync ones that are used in current program)
// 2. textures used in current FBO // 2. textures used in current FBO
// 3. textures bound to image units (TODO) // 3. textures bound to image units (TODO)
constexpr SizeT TextureTargetCount = static_cast<SizeT>(TextureTarget::TextureTargetCount); // constexpr SizeT TextureTargetCount = static_cast<SizeT>(TextureTarget::TextureTargetCount);
std::bitset<TextureTargetCount> dirtyTextureTargetBits; // std::bitset<TextureTargetCount> dirtyTextureTargetBits;
Vector<SharedPtr<MG_State::GLState::ITextureObject>> texturesToSync; Vector<SharedPtr<MG_State::GLState::ITextureObject>> texturesToSync;
@@ -218,7 +218,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& end = texturesToSync.end(); const auto& end = texturesToSync.end();
if (std::find(texturesToSync.begin(), end, textureObject) == end) { if (std::find(texturesToSync.begin(), end, textureObject) == end) {
texturesToSync.push_back(textureObject); texturesToSync.push_back(textureObject);
dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget())); // dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget()));
} }
} }
} }
@@ -234,22 +234,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& end = texturesToSync.end(); const auto& end = texturesToSync.end();
if (std::find(texturesToSync.begin(), end, textureObject) == end) { if (std::find(texturesToSync.begin(), end, textureObject) == end) {
texturesToSync.push_back(textureObject); texturesToSync.push_back(textureObject);
dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget())); // dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget()));
} }
} }
} }
} }
BufferImpl::BackendBufferBindingProtector pixelUnpackProtector = // BufferImpl::BackendBufferBindingProtector pixelUnpackProtector =
BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); // BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER);
//
Vector<BackendTextureBindingProtector> textureBindingProtectors; // Vector<BackendTextureBindingProtector> textureBindingProtectors;
for (SizeT target = 0; target < TextureTargetCount; ++target) { // for (SizeT target = 0; target < TextureTargetCount; ++target) {
if (dirtyTextureTargetBits[target]) { // if (dirtyTextureTargetBits[target]) {
textureBindingProtectors.emplace_back( // textureBindingProtectors.emplace_back(
MG_Util::ConvertTextureTargetToGLEnum(static_cast<TextureTarget>(target))); // MG_Util::ConvertTextureTargetToGLEnum(static_cast<TextureTarget>(target)));
} // }
} // }
// Do real sync // Do real sync
for (auto& textureObject : texturesToSync) { for (auto& textureObject : texturesToSync) {
+154 -147
View File
@@ -366,166 +366,173 @@ namespace MobileGL::MG_Backend::DirectGLES {
static_cast<SizeT>(baseSize.z()), static_cast<SizeT>(baseSize.z()),
0, 0,
0}; 0};
switch (stateTextureObject->GetStorageType()) {
case TextureStorageType::Mipmap: {
auto* textureMipmapObject =
static_cast<MG_State::GLState::TextureObjectMipmap*>(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<MG_State::GLState::TextureObjectMipmap*>(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(), Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
baseSize.z(), mipmapCount,
MG_Util::ConvertTextureInternalFormatToString(textureMipmapObject->GetFormat()).c_str());
if (needsRegeneration) { MGLOG_D("%s: Got texture info: %dx%dx%d, mips %d, format %s", __func__, baseSize.x(), baseSize.y(),
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture with ID: %u", 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<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
0, glFormat, glType, pData);
break;
}
case TextureTarget::Texture3D: {
MG_External::GLES::glTexImage3D(
glUploadTarget, static_cast<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(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<GLint>(level), 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()), glFormat, glType,
textureMipmapObject->MapMipmapData(uploadTarget, level));
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
}
}
}
textureMipmapObject->ClearAllStorageDirtyBit();
break;
}
case TextureStorageType::Buffer: {
auto* textureBufferObject =
static_cast<MG_State::GLState::TextureObjectBuffer*>(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); m_backendTextureId);
// Regenerate all mipmap levels // Need to sync texture buffer if not synced yet
GLenum glInternalFormat, glType, glFormat; auto& backendBuffers = BufferImpl::g_backendBufferObjects;
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
&glFormat, &glType); const auto& backendBufferIt = backendBuffers.find(buffer);
if (backendBufferIt == backendBuffers.end()) {
const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>();
for (auto uploadTarget : uploadTargets) { backendBuffers[buffer] = backendBufferObject;
for (SizeT level = 0; level < mipmapCount; ++level) { } else {
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); backendBufferObject = backendBufferIt->second;
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<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
0, glFormat, glType, pData);
break;
}
case TextureTarget::Texture3D: {
MG_External::GLES::glTexImage3D(
glUploadTarget, static_cast<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(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);
}
} }
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; GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
&glFormat, &glType); &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); MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
if (byteSize == 0) {
MGLOG_W("Mipmap level %d has no data, skipping update.", level);
continue;
}
if (level > 0) textureBufferObject->ClearAllStorageDirtyBit();
MGLOG_D("%s: Updating dirty mip %d for texture ID %u, size: %dx%d, " break;
"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<GLint>(level), 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()), glFormat, glType,
textureMipmapObject->MapMipmapData(uploadTarget, level));
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
}
}
} }
break; default:
} THROW_UNIMPL_EXCEPTION;
case TextureStorageType::Buffer: {
auto* textureBufferObject =
static_cast<MG_State::GLState::TextureObjectBuffer*>(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<BufferImpl::BackendBufferObject> backendBufferObject;
const auto& backendBufferIt = backendBuffers.find(buffer);
if (backendBufferIt == backendBuffers.end()) {
backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>();
backendBuffers[buffer] = backendBufferObject;
} else {
backendBufferObject = backendBufferIt->second;
} }
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 { // Update built-in sampler parameters
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "DirectGLES.h" #include "DirectGLES.h"
#include "Utils.h"
#include "MG_State/GLState/SamplerState/SamplerObject.h" #include "MG_State/GLState/SamplerState/SamplerObject.h"
#include "MG_State/GLState/TextureState/TextureEnum.h" #include "MG_State/GLState/TextureState/TextureEnum.h"
#include <MG_State/GLState/TextureState/TextureObject.h> #include <MG_State/GLState/TextureState/TextureObject.h>
@@ -788,6 +788,7 @@ namespace MobileGL {
auto* texBufferObject = static_cast<MG_State::GLState::TextureObjectBuffer*>(textureObject.get()); auto* texBufferObject = static_cast<MG_State::GLState::TextureObjectBuffer*>(textureObject.get());
auto& bufferSlot = texBufferObject->GetBufferBindingSlot(); auto& bufferSlot = texBufferObject->GetBufferBindingSlot();
bufferSlot.Bind(bufferObject); bufferSlot.Bind(bufferObject);
texBufferObject->SetStorageDirtyBit();
texBufferObject->SetInternalFormat(textureInternalFormat); texBufferObject->SetInternalFormat(textureInternalFormat);
} }
@@ -115,6 +115,13 @@ namespace MobileGL {
m_levelRange.y() = maxLevel; 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 { Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const {
return m_textureStorage.GetLevelCount(); return m_textureStorage.GetLevelCount();
} }
@@ -146,6 +153,9 @@ namespace MobileGL {
void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
bool dirty) { bool dirty) {
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
if (dirty) {
m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit);
}
} }
bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const {
@@ -189,6 +199,14 @@ namespace MobileGL {
return true; 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 // TODO: add other texture types as needed
} // namespace GLState } // namespace GLState
@@ -17,6 +17,12 @@
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { 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 { class ITextureObject {
public: public:
using TargetEnum = TextureTarget; using TargetEnum = TextureTarget;
@@ -41,6 +47,8 @@ namespace MobileGL {
virtual const UintVec2& GetLevelRange() const = 0; virtual const UintVec2& GetLevelRange() const = 0;
virtual void SetBaseLevel(Uint baseLevel) = 0; virtual void SetBaseLevel(Uint baseLevel) = 0;
virtual void SetMaxLevel(Uint maxLevel) = 0; virtual void SetMaxLevel(Uint maxLevel) = 0;
virtual bool IsDirty() const = 0;
virtual bool CheckDirtyBit(TextureDirtyBit bit) const = 0;
protected: protected:
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0; virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
@@ -67,6 +75,9 @@ namespace MobileGL {
const UintVec2& GetLevelRange() const override; const UintVec2& GetLevelRange() const override;
void SetBaseLevel(Uint baseLevel) override; void SetBaseLevel(Uint baseLevel) override;
void SetMaxLevel(Uint maxLevel) override; void SetMaxLevel(Uint maxLevel) override;
bool IsDirty() const override;
bool CheckDirtyBit(TextureDirtyBit bit) const override;
virtual void ClearAllStorageDirtyBit() = 0;
protected: protected:
const Uint m_externalIndex; const Uint m_externalIndex;
@@ -77,6 +88,8 @@ namespace MobileGL {
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
UintVec2 m_levelRange = {0, 1000}; UintVec2 m_levelRange = {0, 1000};
Flags<TextureDirtyBit> m_dirtyBit = TextureDirtyBit::None;
}; };
class TextureObjectMipmap : public TextureObjectBase { class TextureObjectMipmap : public TextureObjectBase {
@@ -92,7 +105,7 @@ namespace MobileGL {
virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0;
virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0;
virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 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; virtual bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
}; };
@@ -110,6 +123,7 @@ namespace MobileGL {
void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override;
void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override;
bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override;
void ClearAllStorageDirtyBit() override;
IntVec3 GetBaseSize() const override; IntVec3 GetBaseSize() const override;
Bool IsComplete() const override; Bool IsComplete() const override;
@@ -42,6 +42,9 @@ namespace MobileGL {
void TextureObject2DCube::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) { void TextureObject2DCube::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) {
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
if (dirty) {
m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit);
}
} }
bool TextureObject2DCube::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { 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 // TODO: add more completeness checks based on texture type and mipmap levels
return true; 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 GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -26,6 +26,7 @@ namespace MobileGL {
void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override;
void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override;
bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override;
void ClearAllStorageDirtyBit() override;
IntVec3 GetBaseSize() const override; IntVec3 GetBaseSize() const override;
Bool IsComplete() const override; Bool IsComplete() const override;
@@ -23,6 +23,14 @@ namespace MobileGL {
MOBILEGL_ASSERT(target == TextureUploadTarget::TextureBuffer, "Invalid TextureUploadTarget!"); MOBILEGL_ASSERT(target == TextureUploadTarget::TextureBuffer, "Invalid TextureUploadTarget!");
return m_bufferBindingSlot; return m_bufferBindingSlot;
} }
void TextureObjectBuffer::ClearAllStorageDirtyBit() {
m_dirtyBit.Clear(TextureDirtyBit::StorageDirtyBit);
}
void TextureObjectBuffer::SetStorageDirtyBit() {
m_dirtyBit.Set(TextureDirtyBit::StorageDirtyBit);
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -20,6 +20,8 @@ namespace MobileGL {
const Vector<TextureUploadTarget>& GetUploadTargets() const override { return m_uploadTargets; } const Vector<TextureUploadTarget>& GetUploadTargets() const override { return m_uploadTargets; }
BindingSlot<BufferObject>& GetBufferBindingSlot( BindingSlot<BufferObject>& GetBufferBindingSlot(
TextureUploadTarget target = TextureUploadTarget::TextureBuffer); TextureUploadTarget target = TextureUploadTarget::TextureBuffer);
void ClearAllStorageDirtyBit() override;
void SetStorageDirtyBit();
protected: protected:
Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override; Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override;
+10
View File
@@ -278,6 +278,16 @@ namespace MobileGL {
Flags(typename Underlying::type b) : flags(b) {} Flags(typename Underlying::type b) : flags(b) {}
Flags Set(const Bit b) {
flags |= static_cast<typename Underlying::type>(b);
return flags;
}
Flags Clear(const Bit b) {
flags &= ~static_cast<typename Underlying::type>(b);
return flags;
}
// Flags - Bit // Flags - Bit
Flags operator|(const Bit b) const { return Flags(flags | static_cast<typename Underlying::type>(b)); } Flags operator|(const Bit b) const { return Flags(flags | static_cast<typename Underlying::type>(b)); }