mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
[Optimize] (MG_Backend/DirectGLES): Texture object mipmap dirty bit
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user