From de028204a23a8ca35c065aadb130c3bf2b5eb93e Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sun, 14 Dec 2025 12:06:48 +0800 Subject: [PATCH] [Feat] (MG_Backend/DirectGLES): Implement ClearBuffer* in backend. --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 196 +++++++++++++- MobileGL/MG_Backend/DirectGLES/DirectGLES.h | 4 + MobileGL/MG_Backend/DirectGLES/Managers.cpp | 246 +++++++++--------- MobileGL/MG_Backend/DirectGLES/Managers.h | 4 +- 4 files changed, 319 insertions(+), 131 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 59b468cd..a2cbb822 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -227,7 +227,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } BufferImpl::BackendBufferBindingProtector pixelUnpackProtector = - BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); + BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); Vector textureBindingProtectors; for (SizeT target = 0; target < TextureTargetCount; ++target) { @@ -411,7 +411,7 @@ namespace MobileGL::MG_Backend::DirectGLES { { #ifdef TRACY_ENABLE - ZoneScopedNC("BindCurrentVAO", TRACY_ZONECOLOR_BACKEND); + ZoneScopedNC("BindCurrentVAO", TRACY_ZONECOLOR_BACKEND); #endif const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray(); if (currentVAO) { @@ -440,14 +440,14 @@ namespace MobileGL::MG_Backend::DirectGLES { // Bind texture object auto target = textureObject->GetTarget(); - if (target == TextureTarget::Texture1D || - target == TextureTarget::TextureRectangle || target == TextureTarget::Texture2DMultisampleArray || - target == TextureTarget::Texture1DArray || target == TextureTarget::Texture3D || - target == TextureTarget::Texture2DMultisample || target == TextureTarget::Texture2DArray) { + if (target == TextureTarget::Texture1D || target == TextureTarget::TextureRectangle || + target == TextureTarget::Texture2DMultisampleArray || target == TextureTarget::Texture1DArray || + target == TextureTarget::Texture3D || target == TextureTarget::Texture2DMultisample || + target == TextureTarget::Texture2DArray) { MGLOG_D(" Texture target %s is not supported, skipping.", MG_Util::ConvertTextureTargetToString(target).c_str()); continue; - } + } const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue; @@ -480,7 +480,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // Global UBO if (currentProgram->GetUBOSize() > 0) { #ifdef TRACY_ENABLE - ZoneScopedNC("UpdateGlobalUBO", TRACY_ZONECOLOR_BACKEND); + ZoneScopedNC("UpdateGlobalUBO", TRACY_ZONECOLOR_BACKEND); #endif MG_External::GLES::glBindBuffer(GL_UNIFORM_BUFFER, backendProgramIt->second->GetBackendGlobalUBOId()); @@ -499,7 +499,7 @@ namespace MobileGL::MG_Backend::DirectGLES { { #ifdef TRACY_ENABLE - ZoneScopedNC("UpdateUBO", TRACY_ZONECOLOR_BACKEND); + ZoneScopedNC("UpdateUBO", TRACY_ZONECOLOR_BACKEND); #endif // Normal UBO auto uboCount = currentProgram->GetActiveUniformBlocksCount(); @@ -511,7 +511,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // Connect program ubo index to backend binding point auto binding = currentProgram->GetUniformBlockBinding(i); auto& name = currentProgram->GetUniformBlockName(i); - GLuint backendBlkIdx = MG_External::GLES::glGetUniformBlockIndex(backendProgramId, name.c_str()); + GLuint backendBlkIdx = + MG_External::GLES::glGetUniformBlockIndex(backendProgramId, name.c_str()); MG_External::GLES::glUniformBlockBinding(backendProgramId, backendBlkIdx, lastUBOBinding); // Connect buffer to backend binding point @@ -541,7 +542,7 @@ namespace MobileGL::MG_Backend::DirectGLES { { #ifdef TRACY_ENABLE - ZoneScopedNC("BindSamplerUnit", TRACY_ZONECOLOR_BACKEND); + ZoneScopedNC("BindSamplerUnit", TRACY_ZONECOLOR_BACKEND); #endif // Sampler unit binding auto maxUniformLoc = currentProgram->GetMaxUniformLocation(); @@ -823,7 +824,7 @@ namespace MobileGL::MG_Backend::DirectGLES { textureObject->SetInternalFormat(mglInternalFormat); MOBILEGL_ASSERT(nullptr != dynamic_cast(textureObject.get()), - "Texture object here should always be an object with mipmap"); + "Texture object here should always be an object with mipmap"); auto textureMipmapObject = static_cast(textureObject.get()); textureMipmapObject->AllocateStorage(TextureUploadTarget::Texture2D, level, {{width, height, 1}, 0}); } @@ -932,4 +933,175 @@ namespace MobileGL::MG_Backend::DirectGLES { const GLubyte* GetString(GLenum name) { return MG_External::GLES::glGetString(name); } + + void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { + TextureImpl::SyncNeccessaryTextures(); + FramebufferImpl::SyncCurrentFBO(); + RenderStateImpl::SyncRenderState(); + + BindCurrentFBO(FramebufferTarget::Draw); + + MG_External::GLES::glClearBufferfi(buffer, drawbuffer, depth, stencil); + } + + void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { + TextureImpl::SyncNeccessaryTextures(); + FramebufferImpl::SyncCurrentFBO(); + RenderStateImpl::SyncRenderState(); + + BindCurrentFBO(FramebufferTarget::Draw); + auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( + MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); + if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { + MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); + return; + } + auto backendFBO = backendFBOIt->second; + + GLint realDrawbuffer = drawbuffer; + + if (buffer == GL_COLOR) { + auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); + + if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { + MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); + return; + } + + FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; + + if (attachmentType == FramebufferAttachmentType::None) { + MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer); + return; + } + + bool found = false; + for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) { + if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) { + realDrawbuffer = i; + found = true; + break; + } + } + + if (!found) { + MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast(attachmentType)); + return; + } + } else if (buffer == GL_DEPTH || buffer == GL_STENCIL) { + if (drawbuffer != 0) { + MGLOG_W("Depth/stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer); + } + realDrawbuffer = 0; + } + + MG_External::GLES::glClearBufferfv(buffer, realDrawbuffer, value); + } + void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { + TextureImpl::SyncNeccessaryTextures(); + FramebufferImpl::SyncCurrentFBO(); + RenderStateImpl::SyncRenderState(); + + BindCurrentFBO(FramebufferTarget::Draw); + auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( + MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); + if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { + MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); + return; + } + auto backendFBO = backendFBOIt->second; + + GLint realDrawbuffer = drawbuffer; + + if (buffer == GL_COLOR) { + auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); + + if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { + MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); + return; + } + + FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; + + if (attachmentType == FramebufferAttachmentType::None) { + MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer); + return; + } + + bool found = false; + for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) { + if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) { + realDrawbuffer = i; + found = true; + break; + } + } + + if (!found) { + MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast(attachmentType)); + return; + } + } else if (buffer == GL_STENCIL) { + if (drawbuffer != 0) { + MGLOG_W("Stencil clear buffer index must be 0, got %d. Using 0.", drawbuffer); + } + realDrawbuffer = 0; + } + + MG_External::GLES::glClearBufferiv(buffer, realDrawbuffer, value); + } + + void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { + TextureImpl::SyncNeccessaryTextures(); + FramebufferImpl::SyncCurrentFBO(); + RenderStateImpl::SyncRenderState(); + + BindCurrentFBO(FramebufferTarget::Draw); + auto backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find( + MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject()); + if (backendFBOIt == FramebufferImpl::g_backendFramebufferObjects.end()) { + MGLOG_E("No backend FBO found for current draw FBO, cannot clear buffer."); + return; + } + auto backendFBO = backendFBOIt->second; + + GLint realDrawbuffer = drawbuffer; + + if (buffer == GL_COLOR) { + auto& stateDrawBuffers = backendFBOIt->first->GetDrawBuffers(); + + if (drawbuffer < 0 || drawbuffer >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { + MGLOG_E("Invalid drawbuffer index: %d", drawbuffer); + return; + } + + FramebufferAttachmentType attachmentType = stateDrawBuffers[drawbuffer]; + + if (attachmentType == FramebufferAttachmentType::None) { + MGLOG_D("Drawbuffer %d has no attachment, skipping clear", drawbuffer); + return; + } + + bool found = false; + for (int i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; i++) { + if (backendFBO->GetCompactedAttachmentTypeAtDrawBufferIndex(i) == attachmentType) { + realDrawbuffer = i; + found = true; + break; + } + } + + if (!found) { + MGLOG_E("Failed to find backend drawbuffer for attachment type: %d", static_cast(attachmentType)); + return; + } + } else { + MGLOG_E("ClearBufferuiv can only be used with GL_COLOR buffer, got %s", + MG_Util::ConvertGLEnumToString(buffer).c_str()); + return; + } + + MG_External::GLES::glClearBufferuiv(buffer, realDrawbuffer, value); + } + } // namespace MobileGL::MG_Backend::DirectGLES diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h index 06caf70f..11ad4f0b 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h @@ -6,6 +6,10 @@ operation Utils::CheckGLESError(); namespace MobileGL::MG_Backend::DirectGLES { + void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); + void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); + void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); + void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void Clear(GLbitfield mask); void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); void DrawArrays(GLenum mode, GLint first, GLsizei count); diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 2e0e5770..27269cf9 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -306,8 +306,7 @@ namespace MobileGL::MG_Backend::DirectGLES { auto targetInternal = stateTextureObject->GetTarget(); MGLOG_D(" Texture target for syncing is %s", MG_Util::ConvertTextureTargetToString(targetInternal).c_str()); - if (targetInternal == TextureTarget::Texture1D || - targetInternal == TextureTarget::TextureRectangle || + if (targetInternal == TextureTarget::Texture1D || targetInternal == TextureTarget::TextureRectangle || targetInternal == TextureTarget::Texture2DMultisampleArray || targetInternal == TextureTarget::Texture1DArray || targetInternal == TextureTarget::Texture3D || targetInternal == TextureTarget::Texture2DMultisample || @@ -334,131 +333,138 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); }); const auto baseSize = stateTextureObject->GetBaseSize(); - StateTextureBasicInfo currentTextureInfo = { - stateTextureObject->GetFormat(), static_cast(baseSize.x()), static_cast(baseSize.y()), - static_cast(baseSize.z()), 0, 0}; + StateTextureBasicInfo currentTextureInfo = {stateTextureObject->GetFormat(), + static_cast(baseSize.x()), + static_cast(baseSize.y()), + 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; + case TextureStorageType::Mipmap: { + auto* textureMipmapObject = + static_cast(stateTextureObject.get()); + const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); + currentTextureInfo.mipmapLevels = mipmapCount; - Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); + Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); - 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()); + 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, &glType, - &glFormat); - - 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, 0); - 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", __func__, - MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, - levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData); - - errorLopper.Clear(); - MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - MG_External::GLES::glTexImage2D(glUploadTarget, static_cast(level), glInternalFormat, - static_cast(levelTexelSize.x()), - static_cast(levelTexelSize.y()), 0, glFormat, glType, - pData); - - // TODO: handle more texture types - - 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, &glType, - &glFormat); - 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; - } - - 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); - } - } - } - 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; - } - backendBufferObject->SyncToBackend(buffer); - - // Bind buffer to texture - auto backendId = backendBufferObject->GetBackendBufferId(); + 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(textureBufferObject->GetFormat(), &glInternalFormat, &glType, + TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, &glType, &glFormat); - MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); - break; + 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, 0); + 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", __func__, + MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, + levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData); + + errorLopper.Clear(); + MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + MG_External::GLES::glTexImage2D(glUploadTarget, static_cast(level), glInternalFormat, + static_cast(levelTexelSize.x()), + static_cast(levelTexelSize.y()), 0, glFormat, + glType, pData); + + // TODO: handle more texture types + + MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId); + textureMipmapObject->MarkStorageDirty(uploadTarget, level, false); + } + } + + m_isInitialized = true; } - default: THROW_UNIMPL_EXCEPTION; + + { // Update all dirty mipmap levels + const auto mipmapCount = textureMipmapObject->GetMipmapLevelCount(); + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, &glType, + &glFormat); + 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; + } + + 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); + } + } + } + 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; + } + backendBufferObject->SyncToBackend(buffer); + + // Bind buffer to texture + auto backendId = backendBufferObject->GetBackendBufferId(); + + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glType, + &glFormat); + + MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); + break; + } + default: + THROW_UNIMPL_EXCEPTION; } { // Update built-in sampler parameters @@ -702,6 +708,10 @@ namespace MobileGL::MG_Backend::DirectGLES { } } + FramebufferAttachmentType BackendFramebufferObject::GetCompactedAttachmentTypeAtDrawBufferIndex(Int index) { + return m_compactedFrontendDrawBuffers[index]; + } + UnorderedMap, SharedPtr> g_backendFramebufferObjects; } // namespace FramebufferImpl diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 3c193a8b..7269a859 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -58,7 +58,8 @@ namespace MobileGL::MG_Backend::DirectGLES { bool operator==(const StateTextureBasicInfo& other) const { return internalFormat == other.internalFormat && width == other.width && height == other.height && - depth == other.depth && mipmapLevels == other.mipmapLevels && bufferExternalIndex == other.bufferExternalIndex; + depth == other.depth && mipmapLevels == other.mipmapLevels && + bufferExternalIndex == other.bufferExternalIndex; } bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); } @@ -94,6 +95,7 @@ namespace MobileGL::MG_Backend::DirectGLES { FramebufferTarget asTarget); Uint GetBackendFramebufferId() { return m_backendFBOId; } void Bind(FramebufferTarget target); + FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); private: Uint m_backendFBOId = 0;