From 93a0bbaed805f8daaefd302d67e737cd3ee04d89 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sun, 19 Oct 2025 11:42:41 +0800 Subject: [PATCH] [Feat] (MG_Backend/DirectGLES): Implement basic stuff for DirectGLES backend. --- CMakeLists.txt | 4 + MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 294 +++++++++++ MobileGL/MG_Backend/DirectGLES/DirectGLES.h | 17 + MobileGL/MG_Backend/DirectGLES/Managers.cpp | 479 ++++++++++++++++++ MobileGL/MG_Backend/DirectGLES/Managers.h | 124 +++++ MobileGL/MG_Backend/DirectGLES/Utils.cpp | 472 +++++++++++++++++ MobileGL/MG_Backend/DirectGLES/Utils.h | 73 +++ .../MG_Impl/GLImpl/Drawing/GL_Drawing.cpp | 37 +- MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h | 2 + .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 4 +- .../GLState/BufferState/BufferObject.cpp | 28 +- .../GLState/BufferState/BufferObject.h | 6 +- .../FramebufferState/FramebufferObject.cpp | 6 + .../FramebufferState/FramebufferObject.h | 3 + .../GLState/TextureState/TextureObject.cpp | 6 + .../GLState/TextureState/TextureObject.h | 2 + .../VertexArrayState/VertexArrayObject.cpp | 31 +- .../VertexArrayState/VertexArrayObject.h | 7 + MobileGL/MG_Util/Types.h | 3 + 19 files changed, 1574 insertions(+), 24 deletions(-) create mode 100644 MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp create mode 100644 MobileGL/MG_Backend/DirectGLES/DirectGLES.h create mode 100644 MobileGL/MG_Backend/DirectGLES/Managers.cpp create mode 100644 MobileGL/MG_Backend/DirectGLES/Managers.h create mode 100644 MobileGL/MG_Backend/DirectGLES/Utils.cpp create mode 100644 MobileGL/MG_Backend/DirectGLES/Utils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7fcbb5..ee9a75a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,10 @@ set(SOURCE_FILES MobileGL/MG_Backend/Init.cpp + MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp + MobileGL/MG_Backend/DirectGLES/Utils.cpp + MobileGL/MG_Backend/DirectGLES/Managers.cpp + MobileGL/MG_State/GLState/Core.cpp MobileGL/MG_State/GLState/ErrorState/Error.cpp MobileGL/MG_State/GLState/BufferState/BufferState.cpp diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp new file mode 100644 index 00000000..6956cf1b --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -0,0 +1,294 @@ +#include "DirectGLES.h" +#include "Utils.h" +#include "Managers.h" +#include +#include +#include +#include +#include + +namespace MobileGL::MG_Backend::DirectGLES { + // TODO: deletion of deleted objects + + namespace BufferImpl { + void SyncNeccessaryBuffers() { + // All buffers we need are: + // 1.VBOs 2.IBO 3.UBOs (TODO) 4.SSBOs (TODO) + Vector> buffersToSync; + const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); + if (!currentVAOObject) { + MGLOG_E("No VAO is currently bound, cannot sync necessary buffers."); + return; + } + + for (const auto& attrib : currentVAOObject->GetAllAttributes()) { + const auto& bufferObject = attrib.Buffer; + if (bufferObject) { + buffersToSync.push_back(bufferObject); + } + } + + const auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); + if (possibleIBO) { + buffersToSync.push_back(possibleIBO); + } + + // Do real sync + for (auto& bufferObject : buffersToSync) { + const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject); + SharedPtr backendBufferObject; + if (backendBufferIt != g_backendBufferObjects.end()) { + backendBufferObject = MakeShared(); + g_backendBufferObjects[bufferObject] = backendBufferObject; + } else { + backendBufferObject = backendBufferIt->second; + } + backendBufferObject->SyncToBackend(bufferObject); + } + } + } // namespace BufferImpl + + namespace VertexArrayImpl { + void SyncCurrentVAO() { + auto currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); + if (!currentVAOObject) { + MGLOG_E("No VAO is currently bound, cannot sync current VAO."); + return; + } + + const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject); + SharedPtr backendVAOObject; + if (backendVAOIt == g_backendVertexArrayObjects.end()) { + backendVAOObject = MakeShared(); + g_backendVertexArrayObjects[currentVAOObject] = backendVAOObject; + } else { + backendVAOObject = backendVAOIt->second; + } + backendVAOObject->SyncToBackend(currentVAOObject); + } + } // namespace VertexArrayImpl + + namespace TextureImpl { + void SyncNeccessaryTextures() { + // All textures we need are: + // 1. textures bound to current 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) + + Vector> texturesToSync; + + auto& currentUnit = + MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); + for (auto& bindingSlot : currentUnit.GetAllBindingSlots()) { + const auto& textureObject = bindingSlot.GetBoundObject(); + if (textureObject) { + texturesToSync.push_back(textureObject); + } + } + + const auto& currentFBO = + MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); + if (currentFBO) { + for (auto& attachment : currentFBO->GetAllAttachments()) { + if (!attachment.IsTexture()) continue; + const auto& textureObject = attachment.GetTexture(); + if (textureObject) { + texturesToSync.push_back(textureObject); + } + } + } + + // Do real sync + for (auto& textureObject : texturesToSync) { + const auto& backendTextureIt = g_backendTextureObjects.find(textureObject); + SharedPtr backendTextureObject; + if (backendTextureIt == g_backendTextureObjects.end()) { + backendTextureObject = MakeShared(); + g_backendTextureObjects[textureObject] = backendTextureObject; + } else { + backendTextureObject = backendTextureIt->second; + } + backendTextureObject->SyncToBackend(textureObject); + } + } + } // namespace TextureImpl + + namespace FramebufferImpl { + void SyncCurrentFBO() { + auto currentFBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); + if (!currentFBO) { + MGLOG_E("No FBO is currently bound, cannot sync current FBO."); + return; + } + + const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO); + SharedPtr backendFBOObject; + if (backendFBOIt == g_backendFramebufferObjects.end()) { + backendFBOObject = MakeShared(); + g_backendFramebufferObjects[currentFBO] = backendFBOObject; + } else { + backendFBOObject = backendFBOIt->second; + } + backendFBOObject->SyncToBackend(currentFBO); + } + } // namespace FramebufferImpl + + namespace RenderStateImpl { + void SyncRenderState() { + /* + void SetViewport(IntVec4 viewport); // x, y, width, height + const IntVec4& GetViewport() const; // x, y, width, height + void SetCapability(CapabilityInput cap, Bool enabled); + Bool IsCapabilityEnabled(CapabilityInput cap) const; + void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha); + void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, + BlendFactor& dstAlpha) const; + void SetDepthFunc(DepthTestFunc func); + DepthTestFunc GetDepthFunc() const; + void SetDepthMask(Bool flag); + Bool GetDepthMask() const; + void SetColorMask(BoolVec4 mask); + const BoolVec4 GetColorMask() const; + void SetClearColor(FloatVec4 color); + const FloatVec4& GetClearColor() const; + void SetClearDepth(Float depth); + Float GetClearDepth() const; + void SetPixelStoreParam(PixelStoreParam param, Int value); + Int GetPixelStoreParam(PixelStoreParam param) const; + void SetCullFaceMode(CullFaceMode mode); + CullFaceMode GetCullFaceMode() const;*/ + + MG_External::GLES::glViewport( + MG_State::pGLContext->GetViewport().x(), MG_State::pGLContext->GetViewport().y(), + MG_State::pGLContext->GetViewport().z(), MG_State::pGLContext->GetViewport().w()); + if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest)) { + MG_External::GLES::glEnable(GL_DEPTH_TEST); + } else { + MG_External::GLES::glDisable(GL_DEPTH_TEST); + } + if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::Blend)) { + MG_External::GLES::glEnable(GL_BLEND); + } else { + MG_External::GLES::glDisable(GL_BLEND); + } + + auto ToGLBoolean = [](Bool b) -> GLboolean { return b ? GL_TRUE : GL_FALSE; }; + + { + BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; + MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); + + MG_External::GLES::glBlendFuncSeparate( + MG_Util::ConvertBlendFactorToGLEnum(srcRGB), MG_Util::ConvertBlendFactorToGLEnum(dstRGB), + MG_Util::ConvertBlendFactorToGLEnum(srcAlpha), MG_Util::ConvertBlendFactorToGLEnum(dstAlpha)); + } + + { + DepthTestFunc df = MG_State::pGLContext->GetDepthFunc(); + MG_External::GLES::glDepthFunc(MG_Util::ConvertDepthTestFuncToGLEnum(df)); + + MG_External::GLES::glDepthMask(MG_State::pGLContext->GetDepthMask() ? GL_TRUE : GL_FALSE); + } + + { + BoolVec4 colorMask = MG_State::pGLContext->GetColorMask(); + MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()), + ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w())); + } + + { + const FloatVec4& clearCol = MG_State::pGLContext->GetClearColor(); + MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w()); + MG_External::GLES::glClearDepthf(MG_State::pGLContext->GetClearDepth()); + } + + { + { + PixelStoreParam p = PixelStoreParam::UnpackAlignment; + GLint v = MG_State::pGLContext->GetPixelStoreParam(p); + MG_External::GLES::glPixelStorei(MG_Util::ConvertPixelStoreParamToGLEnum(p), v); + } + { + PixelStoreParam p = PixelStoreParam::PackAlignment; + GLint v = MG_State::pGLContext->GetPixelStoreParam(p); + MG_External::GLES::glPixelStorei(MG_Util::ConvertPixelStoreParamToGLEnum(p), v); + } + } + + if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace)) { + MG_External::GLES::glEnable(GL_CULL_FACE); + } else { + MG_External::GLES::glDisable(GL_CULL_FACE); + } + + { + CullFaceMode cfm = MG_State::pGLContext->GetCullFaceMode(); + MG_External::GLES::glCullFace(MG_Util::ConvertCullFaceModeToGLEnum(cfm)); + } + } + } // namespace RenderStateImpl + + namespace PrgramImpl { + void SyncCurrentProgram() { + auto currentProgram = MG_State::pGLContext->GetCurrentProgram(); + if (!currentProgram) { + MG_External::GLES::glUseProgram(0); + return; + } + auto backendProgramIt = g_backendProgramObjects.find(currentProgram); + SharedPtr backendProgram; + if (backendProgramIt == g_backendProgramObjects.end()) { + backendProgram = MakeShared(); + g_backendProgramObjects[currentProgram] = backendProgram; + backendProgram->SyncToBackend(currentProgram); + } else { + backendProgram = backendProgramIt->second; + if (!backendProgram->GetBackendProgramId()) { + backendProgram->SyncToBackend(currentProgram); + } + } + backendProgram->Use(); + } + } // namespace PrgramImpl + + void PrepareForDraw() { + BufferImpl::SyncNeccessaryBuffers(); + VertexArrayImpl::SyncCurrentVAO(); + TextureImpl::SyncNeccessaryTextures(); + FramebufferImpl::SyncCurrentFBO(); + PrgramImpl::SyncCurrentProgram(); + RenderStateImpl::SyncRenderState(); + } + + void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { + PrepareForDraw(); + MG_External::GLES::glDrawElements(mode, count, type, indices); + } + + void Clear(GLbitfield mask) { + FramebufferImpl::SyncCurrentFBO(); + RenderStateImpl::SyncRenderState(); + MG_External::GLES::glClear(mask); + } + + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint baseVertex) { + PrepareForDraw(); + MG_External::GLES::glDrawElementsBaseVertex(mode, count, type, indices, baseVertex); + } + + void MultiDrawElements(GLenum mode, const GLsizei* counts, GLenum type, const void* const* indices, + GLsizei drawcount) { + PrepareForDraw(); + for (GLsizei i = 0; i < drawcount; ++i) { + MG_External::GLES::glDrawElements(mode, counts[i], type, indices[i]); + } + } + + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* counts, GLenum type, const void* const* indices, + GLsizei drawcount, const GLint* baseVertices) { + PrepareForDraw(); + for (GLsizei i = 0; i < drawcount; ++i) { + MG_External::GLES::glDrawElementsBaseVertex(mode, counts[i], type, indices[i], baseVertices[i]); + } + } +} // namespace MobileGL::MG_Backend::DirectGLES diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h new file mode 100644 index 00000000..e70ab38d --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h @@ -0,0 +1,17 @@ +#pragma once +#include + +#define CallAndCheck(operation) \ + MGLOG_D("Call GLES func: %s", #operation); \ + operation Utils::CheckGLESError(); + +namespace MobileGL::MG_Backend::DirectGLES { + void Clear(GLbitfield mask); + void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); + void DrawArrays(GLenum mode, GLint first, GLsizei count); + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex); + void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, + GLsizei drawcount); + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, + GLsizei drawcount, const GLint* basevertex); +} // namespace MobileGL::MG_Backend::DirectGLES \ No newline at end of file diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp new file mode 100644 index 00000000..08d3b13e --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -0,0 +1,479 @@ +#include "Managers.h" +#include "Utils.h" +#include "DirectGLES.h" +#include +#include +#include +#include +#include +#include +#include + +namespace MobileGL::MG_Backend::DirectGLES { + namespace BufferImpl { + BackendBufferObject::BackendBufferObject() { + MG_External::GLES::glGenBuffers(1, &m_backendBufferId); + if (m_backendBufferId == 0) { + MGLOG_E("Failed to generate buffer object."); + } else { + MGLOG_D("Generated buffer object with ID: %u.", m_backendBufferId); + } + } + + const GLenum TempBufferTarget = GL_ARRAY_BUFFER; + void BackendBufferObject::SyncToBackend(SharedPtr& stateBufferObject) { + if (!stateBufferObject) { + MGLOG_E("State buffer object is null, cannot sync to backend."); + return; + } + + SizeT bufferSize = stateBufferObject->GetSize(); + if (bufferSize == 0) { + MGLOG_W("Buffer size is zero, skipping sync for object with ID: %u", m_backendBufferId); + return; + } + + MGLOG_D("Syncing buffer object with ID: %u to backend for state: %s", m_backendBufferId, + stateBufferObject.get()); + + Bool needsRegeneration = + !m_isInitialized || bufferSize > m_prevBufferSize || bufferSize > m_prevBufferSize * 2; + + if (needsRegeneration) { + MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u", + m_backendBufferId); + SyncToBackend_glBufferData(stateBufferObject); + m_isInitialized = true; + return; + } + + switch (stateBufferObject->GetUsage()) { + case BufferUsage::StaticDraw: + SyncToBackend_glBufferSubData(stateBufferObject); + break; + case BufferUsage::DynamicDraw: + case BufferUsage::StreamDraw: + SyncToBackend_glMapBufferRange(stateBufferObject); + break; + default: + SyncToBackend_glBufferSubData(stateBufferObject); + break; + } + + m_prevBufferSize = bufferSize; + } + + void BackendBufferObject::SyncToBackend_glBufferData( + SharedPtr& stateBufferObject) { + BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget); + + MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId); + + const void* data = stateBufferObject->GetDataReadOnly().get(); + SizeT size = stateBufferObject->GetSize(); + GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage()); + + MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); + MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage); + + stateBufferObject->ClearDirty(); + } + + void BackendBufferObject::SyncToBackend_glBufferSubData( + SharedPtr& stateBufferObject) { + BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget); + + MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId); + + const void* data = stateBufferObject->GetDataReadOnly().get(); + auto range = stateBufferObject->GetDirtyRange(); + // dirty range: [range.start, range.end) + + MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); + MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start, + reinterpret_cast(data) + range.start); + } + + void BackendBufferObject::SyncToBackend_glMapBufferRange( + SharedPtr& stateBufferObject, Bool invalidate) { + BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget); + + MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId); + MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId); + MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); + auto range = stateBufferObject->GetDirtyRange(); + void* mappedData = MG_External::GLES::glMapBufferRange( + TempBufferTarget, range.start, range.end - range.start, + (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : 0) | GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + const void* data = stateBufferObject->GetDataReadOnly().get(); + if (mappedData) { + Memcpy(reinterpret_cast(reinterpret_cast(data) + range.start), mappedData, + range.end - range.start); + MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId); + MG_External::GLES::glUnmapBuffer(TempBufferTarget); + } else { + MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId); + } + } + + void BackendBufferObject::Bind() { + MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); + } + + void BackendBufferObject::Bind(GLenum target) { + MG_External::GLES::glBindBuffer(target, m_backendBufferId); + } + + UnorderedMap, SharedPtr> g_backendBufferObjects; + } // namespace BufferImpl + + namespace VertexArrayImpl { + BackendVertexArrayObject::BackendVertexArrayObject() { + MG_External::GLES::glGenVertexArrays(1, &m_backendVAOId); + if (m_backendVAOId == 0) { + MGLOG_E("Failed to generate vertex array object."); + } else { + MGLOG_D("Generated vertex array object with ID: %u.", m_backendVAOId); + } + } + + void BackendVertexArrayObject::Bind() { + MG_External::GLES::glBindVertexArray(m_backendVAOId); + } + + void BackendVertexArrayObject::SyncToBackend(SharedPtr& stateVAOObject) { + if (!stateVAOObject) { + MGLOG_E("State VAO object is null, cannot sync to backend."); + return; + } + + MGLOG_D("Syncing VAO object with ID: %u to backend for state: %s", m_backendVAOId, stateVAOObject.get()); + + BufferImpl::BackendBufferBindingProtector backendBufferBindingProtector(BufferImpl::TempBufferTarget); + BackendVertexArrayBindingProtector backendVAOBindingProtector; + + Bind(); + + for (const auto& attribIndex : stateVAOObject->GetDirtyAttributeIndices()) { + const auto& attrib = stateVAOObject->GetAttribute(attribIndex); + + auto bufferObject = attrib.Buffer; + if (!bufferObject) { + MGLOG_W("Attribute has no bound buffer, skipping."); + continue; + } + + auto backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject); + if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) { + MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute."); + continue; + } + auto backendBufferObject = backendBufferIt->second; + + backendBufferObject->Bind(GL_ARRAY_BUFFER); + MG_External::GLES::glEnableVertexAttribArray(attribIndex); + MG_External::GLES::glVertexAttribPointer( + attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type), + attrib.Normalized ? GL_TRUE : GL_FALSE, attrib.Stride, + reinterpret_cast(static_cast(attrib.Offset))); + + // TODO: divisor + } + + auto indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); + if (indexBufferBinding) { + auto backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding); + if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) { + auto backendBufferObject = backendBufferIt->second; + backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER); + } else { + MGLOG_E("No backend buffer found for index buffer binding, cannot bind index buffer."); + } + } + + stateVAOObject->ClearDirtyAttributes(); + } + + UnorderedMap, SharedPtr> + g_backendVertexArrayObjects; + } // namespace VertexArrayImpl + + namespace TextureImpl { + BackendTextureObject::BackendTextureObject() { + MG_External::GLES::glGenTextures(1, &m_backendTextureId); + if (m_backendTextureId == 0) { + MGLOG_E("Failed to generate texture object."); + } else { + MGLOG_D("Generated texture object with ID: %u.", m_backendTextureId); + } + } + + void BackendTextureObject::Bind(GLenum target) { + MG_External::GLES::glBindTexture(target, m_backendTextureId); + } + + Uint BackendTextureObject::GetBackendTextureId() { + return m_backendTextureId; + } + + void BackendTextureObject::SyncToBackend(SharedPtr& stateTextureObject) { + if (!stateTextureObject) { + MGLOG_E("State texture object is null, cannot sync to backend."); + return; + } + + MGLOG_D("Syncing texture object with ID: %u to backend for state: %s", m_backendTextureId, + stateTextureObject.get()); + + GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget()); + + // The texture needs to be regenerated completely with glTexImage* calls if: + // 1. Not initialized + // 2. InternalFormat changed + // 3. Size changed + // 4. Mipmap levels changed + + if (!stateTextureObject->IsComplete()) { + MGLOG_E("Texture object with ID: %u is not complete, skipping sync.", m_backendTextureId); + return; + } + + BackendTextureBindingProtector backendTextureBindingProtector(target); + Bind(target); + + StateTextureBasicInfo currentTextureInfo = { + stateTextureObject->GetFormat(), static_cast(stateTextureObject->GetBaseSize().x()), + static_cast(stateTextureObject->GetBaseSize().y()), + static_cast(stateTextureObject->GetBaseSize().z()), stateTextureObject->GetMipmaps().size()}; + + Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); + + if (needsRegeneration) { + MGLOG_D("Texture state changed significantly or not initialized, regenerating texture with ID: %u", + m_backendTextureId); + + // Regenerate all mipmap levels + const auto& mipmaps = stateTextureObject->GetMipmaps(); + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType, + &glFormat); + for (SizeT level = 0; level < mipmaps.size(); ++level) { + const auto& mipmap = mipmaps[level]; + + MG_External::GLES::glTexImage2D(GL_TEXTURE_2D, static_cast(level), glInternalFormat, + static_cast(mipmap.size.x()), + static_cast(mipmap.size.y()), 0, glFormat, glType, + mipmap.data.data()); + + MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId); + stateTextureObject->UnmarkMipmapDirty(level); + } + + m_isInitialized = true; + } + + { // Update sampler parameters; TODO: always use sampler objects in backend + + auto samplerObject = stateTextureObject->GetSamplerObject(); + if (samplerObject) { + MG_External::GLES::glTexParameteri( + target, GL_TEXTURE_MIN_FILTER, + MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObject->GetMinFilter())); + MG_External::GLES::glTexParameteri( + target, GL_TEXTURE_MAG_FILTER, + MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObject->GetMagFilter())); + MG_External::GLES::glTexParameteri( + target, GL_TEXTURE_WRAP_S, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapS())); + MG_External::GLES::glTexParameteri( + target, GL_TEXTURE_WRAP_T, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapT())); + MG_External::GLES::glTexParameteri( + target, GL_TEXTURE_WRAP_R, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapR())); + } + } + + { // Update all dirty mipmap levels + const auto& mipmaps = stateTextureObject->GetMipmaps(); + GLenum glInternalFormat, glType, glFormat; + TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType, + &glFormat); + for (const auto& mipmap : stateTextureObject->GetMipmaps()) { + if (!mipmap.dirty) { + continue; + } + + if (mipmap.data.empty()) { + MGLOG_W("Mipmap level %d has no data, skipping update.", mipmap.level); + continue; + } + + MG_External::GLES::glTexSubImage2D( + GL_TEXTURE_2D, static_cast(mipmap.level), 0, 0, static_cast(mipmap.size.x()), + static_cast(mipmap.size.y()), glFormat, glType, mipmap.data.data()); + stateTextureObject->UnmarkMipmapDirty(mipmap.level); + } + } + + m_prevTextureInfo = currentTextureInfo; + } + + UnorderedMap, SharedPtr> + g_backendTextureObjects; + } // namespace TextureImpl + + namespace FramebufferImpl { + BackendFramebufferObject::BackendFramebufferObject() { + MG_External::GLES::glGenFramebuffers(1, &m_backendFBOId); + if (m_backendFBOId == 0) { + MGLOG_E("Failed to generate framebuffer object."); + } else { + MGLOG_D("Generated framebuffer object with ID: %u.", m_backendFBOId); + } + } + + void BackendFramebufferObject::Bind() { + MG_External::GLES::glBindFramebuffer(GL_FRAMEBUFFER, m_backendFBOId); + } + + void BackendFramebufferObject::SyncToBackend(SharedPtr& stateFBOObject) { + if (!stateFBOObject) { + MGLOG_E("State FBO object is null, cannot sync to backend."); + return; + } + + MGLOG_D("Syncing FBO object with ID: %u to backend for state: %s", m_backendFBOId, stateFBOObject.get()); + + BackendFramebufferBindingProtector backendFBOBindingProtector(GL_FRAMEBUFFER); + Bind(); + + // TODO: add dirty check + // Sync all attachments + const auto& attachments = stateFBOObject->GetAllAttachments(); + for (SizeT index = 0; index < attachments.size(); ++index) { + FramebufferAttachmentType attachmentType = static_cast(index); + const auto& attachment = attachments[index]; + if (!attachment.IsComplete()) { + MG_External::GLES::glFramebufferRenderbuffer( + GL_FRAMEBUFFER, MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(attachmentType), + GL_RENDERBUFFER, 0); + continue; + } + + if (attachment.IsTexture()) { + auto textureObject = attachment.GetTexture(); + auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); + if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { + MGLOG_E("No backend texture found for FBO attachment, cannot bind texture."); + continue; + } + auto backendTextureObject = backendTextureIt->second; + backendTextureObject->Bind(MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget())); + MG_External::GLES::glFramebufferTexture2D( + GL_FRAMEBUFFER, MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(attachmentType), + MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget()), + backendTextureObject->GetBackendTextureId(), static_cast(attachment.GetTextureLevel())); + } else if (attachment.IsRenderbuffer()) { + // TODO + } + } + } + + UnorderedMap, SharedPtr> + g_backendFramebufferObjects; + } // namespace FramebufferImpl + + namespace PrgramImpl { + UnorderedMap, SharedPtr> + g_backendShaderObjects; + UnorderedMap, SharedPtr> + g_backendProgramObjects; + BackendShaderObjectImpl::BackendShaderObjectImpl() { + m_backendShaderId = MG_External::GLES::glCreateShader(GL_VERTEX_SHADER); + if (m_backendShaderId == 0) { + MGLOG_E("Failed to create shader object in backend."); + } + } + BackendShaderObjectImpl::~BackendShaderObjectImpl() { + if (m_backendShaderId != 0) { + MG_External::GLES::glDeleteShader(m_backendShaderId); + } + } + void BackendShaderObjectImpl::SyncToBackend(SharedPtr& stateShaderObject) { + if (!stateShaderObject || !stateShaderObject->GetCompileStatus()) { + MGLOG_E("Shader object is null or not compiled, skipping backend sync."); + return; + } + String source = stateShaderObject->GetShaderSource(); + source = removeLayoutBinding(source); + source = ProcessOutColorLocations(source); + source = ForceSupporterOutput(source); + GLenum shaderType = ConvertGLShaderTypeByMGLShaderStage(stateShaderObject->GetShaderStage()); + const char* sourceCStr = source.c_str(); + + MG_External::GLES::glShaderSource(m_backendShaderId, 1, &sourceCStr, nullptr); + MG_External::GLES::glCompileShader(m_backendShaderId); + GLint compileStatus; + MG_External::GLES::glGetShaderiv(m_backendShaderId, GL_COMPILE_STATUS, &compileStatus); + if (compileStatus != GL_TRUE) { + GLint logLength; + MG_External::GLES::glGetShaderiv(m_backendShaderId, GL_INFO_LOG_LENGTH, &logLength); + Vector log(logLength); + MG_External::GLES::glGetShaderInfoLog(m_backendShaderId, logLength, nullptr, log.data()); + MGLOG_E("Shader compilation failed: %s", log.data()); + } + m_isInitialized = true; + } + BackendProgramObjectImpl::BackendProgramObjectImpl() { + m_backendProgramId = MG_External::GLES::glCreateProgram(); + if (m_backendProgramId == 0) { + MGLOG_E("Failed to create program object in backend."); + } + } + BackendProgramObjectImpl::~BackendProgramObjectImpl() { + if (m_backendProgramId != 0) { + MG_External::GLES::glDeleteProgram(m_backendProgramId); + } + } + void BackendProgramObjectImpl::SyncToBackend(SharedPtr& stateProgramObject) { + if (!stateProgramObject || !stateProgramObject->GetLinkStatus()) { + MGLOG_E("Program object is null or not linked, skipping backend sync."); + return; + } + // Detach all existing shaders + GLint attachedCount = 0; + MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_ATTACHED_SHADERS, &attachedCount); + if (attachedCount > 0) { + Vector attachedShaders(attachedCount); + GLsizei actualCount; + MG_External::GLES::glGetAttachedShaders(m_backendProgramId, attachedCount, &actualCount, + attachedShaders.data()); + for (GLsizei i = 0; i < actualCount; ++i) { + MG_External::GLES::glDetachShader(m_backendProgramId, attachedShaders[i]); + } + } + // Attach current shaders + for (auto& shader : stateProgramObject->GetAttachedShaders()) { + auto it = g_backendShaderObjects.find(shader); + if (it != g_backendShaderObjects.end() && it->second) { + MG_External::GLES::glAttachShader(m_backendProgramId, it->second->GetBackendShaderId()); + } + } + // Link program + MG_External::GLES::glLinkProgram(m_backendProgramId); + GLint linkStatus; + MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint logLength; + MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_INFO_LOG_LENGTH, &logLength); + Vector log(logLength); + MG_External::GLES::glGetProgramInfoLog(m_backendProgramId, logLength, nullptr, log.data()); + MGLOG_E("Program linking failed: %s", log.data()); + } + m_isInitialized = true; + } + void BackendProgramObjectImpl::Use() { + MG_External::GLES::glUseProgram(m_backendProgramId); + } + } // namespace PrgramImpl + + namespace Utils {} // namespace Utils +} // namespace MobileGL::MG_Backend::DirectGLES \ No newline at end of file diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h new file mode 100644 index 00000000..a41099df --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -0,0 +1,124 @@ +#pragma once +#include +#include "DirectGLES.h" +#include +#include + +namespace MobileGL::MG_Backend::DirectGLES { + namespace BufferImpl { + class BackendBufferObject { + public: + BackendBufferObject(); + void SyncToBackend(SharedPtr& stateBufferObject); + void Bind(); + void Bind(GLenum target); + + private: + void SyncToBackend_glBufferData(SharedPtr& stateBufferObject); + void SyncToBackend_glBufferSubData(SharedPtr& stateBufferObject); + void SyncToBackend_glMapBufferRange(SharedPtr& stateBufferObject, + Bool invalidate = false); + + Uint m_backendBufferId = 0; + SizeT m_prevBufferSize = 0; + Bool m_isInitialized = false; + }; + + extern UnorderedMap, SharedPtr> + g_backendBufferObjects; + } // namespace BufferImpl + + namespace VertexArrayImpl { + class BackendVertexArrayObject { + public: + BackendVertexArrayObject(); + void SyncToBackend(SharedPtr& stateVAOObject); + void Bind(); + + private: + Uint m_backendVAOId = 0; + Bool m_isInitialized = false; + }; + + extern UnorderedMap, SharedPtr> + g_backendVertexArrayObjects; + } // namespace VertexArrayImpl + + namespace TextureImpl { + struct StateTextureBasicInfo { // Used for tracking texture state changes + TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; + SizeT width = 0; + SizeT height = 0; + SizeT depth = 0; + SizeT mipmapLevels = 0; + + bool operator==(const StateTextureBasicInfo& other) const { + return internalFormat == other.internalFormat && width == other.width && height == other.height && + depth == other.depth && mipmapLevels == other.mipmapLevels; + } + + bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); } + }; + + class BackendTextureObject { + public: + BackendTextureObject(); + void SyncToBackend(SharedPtr& stateTextureObject); + void Bind(GLenum target); + Uint GetBackendTextureId(); + + private: + Uint m_backendTextureId = 0; + Bool m_isInitialized = false; + StateTextureBasicInfo m_prevTextureInfo; + }; + + extern UnorderedMap, SharedPtr> + g_backendTextureObjects; + } // namespace TextureImpl + + namespace FramebufferImpl { + class BackendFramebufferObject { + public: + BackendFramebufferObject(); + void SyncToBackend(SharedPtr& stateFBOObject); + void Bind(); + + private: + Uint m_backendFBOId = 0; + }; + + extern UnorderedMap, SharedPtr> + g_backendFramebufferObjects; + } // namespace FramebufferImpl + + namespace PrgramImpl { + class BackendShaderObjectImpl { + public: + BackendShaderObjectImpl(); + ~BackendShaderObjectImpl(); + void SyncToBackend(SharedPtr& stateShaderObject); + Uint GetBackendShaderId() const { return m_backendShaderId; } + + private: + Uint m_backendShaderId = 0; + Bool m_isInitialized = false; + }; + class BackendProgramObjectImpl { + public: + BackendProgramObjectImpl(); + ~BackendProgramObjectImpl(); + void SyncToBackend(SharedPtr& stateProgramObject); + void Use(); + Uint GetBackendProgramId() const { return m_backendProgramId; } + + private: + Uint m_backendProgramId = 0; + Bool m_isInitialized = false; + }; + extern UnorderedMap, SharedPtr> + g_backendShaderObjects; + extern UnorderedMap, SharedPtr> + g_backendProgramObjects; + } // namespace PrgramImpl +} // namespace MobileGL::MG_Backend::DirectGLES \ No newline at end of file diff --git a/MobileGL/MG_Backend/DirectGLES/Utils.cpp b/MobileGL/MG_Backend/DirectGLES/Utils.cpp new file mode 100644 index 00000000..faceb7c2 --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/Utils.cpp @@ -0,0 +1,472 @@ +#include "DirectGLES.h" +#include "Utils.h" +#include "Managers.h" +#include +#include +#include +#include + +namespace MobileGL::MG_Backend::DirectGLES { + namespace BufferImpl { + BackendBufferBindingProtector::BackendBufferBindingProtector(GLenum target) { + m_target = target; + MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding); + } + + BackendBufferBindingProtector::~BackendBufferBindingProtector() { + MG_External::GLES::glBindBuffer(m_target, m_previousBinding); + } + } // namespace BufferImpl + + namespace VertexArrayImpl { + BackendVertexArrayBindingProtector::BackendVertexArrayBindingProtector() { + MG_External::GLES::glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &m_previousBinding); + } + + BackendVertexArrayBindingProtector::~BackendVertexArrayBindingProtector() { + MG_External::GLES::glBindVertexArray(m_previousBinding); + } + } // namespace VertexArrayImpl + + namespace TextureImpl { + BackendTextureBindingProtector::BackendTextureBindingProtector(GLenum target) { + m_target = target; + MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, true), &m_previousBinding); + } + + BackendTextureBindingProtector::~BackendTextureBindingProtector() { + MG_External::GLES::glBindTexture(m_target, m_previousBinding); + } + + void NormalizePixelFormat(GLenum internalFormat, GLenum* outInternalFormat, GLenum* outType, + GLenum* outFormat) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT16: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_SHORT; + if (outFormat) *outFormat = GL_DEPTH_COMPONENT; + break; + + case GL_DEPTH_COMPONENT24: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT; + if (outFormat) *outFormat = GL_DEPTH_COMPONENT; + break; + + case GL_DEPTH_COMPONENT32: + if (outInternalFormat) *outInternalFormat = GL_DEPTH_COMPONENT32F; + if (outType) *outType = GL_FLOAT; + if (outFormat) *outFormat = GL_DEPTH_COMPONENT; + break; + + case GL_DEPTH_COMPONENT32F: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_FLOAT; + if (outFormat) *outFormat = GL_DEPTH_COMPONENT; + break; + + case GL_DEPTH_COMPONENT: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT; + if (outFormat) *outFormat = GL_DEPTH_COMPONENT; + break; + + case GL_DEPTH_STENCIL: + if (outInternalFormat) *outInternalFormat = GL_DEPTH32F_STENCIL8; + if (outType) *outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + if (outFormat) *outFormat = GL_DEPTH_STENCIL; + break; + + case GL_RGB10_A2: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT_2_10_10_10_REV; + if (outFormat) *outFormat = GL_RGBA; + break; + + case GL_RGB5_A1: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_SHORT_5_5_5_1; + if (outFormat) *outFormat = GL_RGBA; + break; + + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_RG_RGTC2: + break; + + case GL_SRGB8: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RGB; + break; + + case GL_RGBA32F: + case GL_RGB32F: + case GL_RG32F: + case GL_R32F: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_FLOAT; + if (outFormat) switch (internalFormat) { + case GL_RGBA32F: + if (outFormat) *outFormat = GL_RGBA; + break; + case GL_RGB32F: + if (outFormat) *outFormat = GL_RGB; + break; + case GL_RG32F: + if (outFormat) *outFormat = GL_RG; + break; + case GL_R32F: + if (outFormat) *outFormat = GL_RED; + break; + } + break; + + case GL_RGB9_E5: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT_5_9_9_9_REV; + if (outFormat) *outFormat = GL_RGB; + break; + + case GL_R11F_G11F_B10F: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT_10F_11F_11F_REV; + if (outFormat) *outFormat = GL_RGB; + break; + + case GL_RGBA32UI: + case GL_RGB32UI: + case GL_RG32UI: + case GL_R32UI: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT; + if (outFormat) switch (internalFormat) { + case GL_RGBA32UI: + if (outFormat) *outFormat = GL_RGBA; + break; + case GL_RGB32UI: + if (outFormat) *outFormat = GL_RGB; + break; + case GL_RG32UI: + if (outFormat) *outFormat = GL_RG; + break; + case GL_R32UI: + if (outFormat) *outFormat = GL_RED; + break; + } + break; + break; + + case GL_RGBA32I: + case GL_RGB32I: + case GL_RG32I: + case GL_R32I: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_INT; + if (outFormat) switch (internalFormat) { + case GL_RGBA32I: + if (outFormat) *outFormat = GL_RGBA; + break; + case GL_RGB32I: + if (outFormat) *outFormat = GL_RGB; + break; + case GL_RG32I: + if (outFormat) *outFormat = GL_RG; + break; + case GL_R32I: + if (outFormat) *outFormat = GL_RED; + break; + } + break; + + case GL_RGBA16: { + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_FLOAT; + if (outFormat) *outFormat = GL_RGBA; + break; + } + case GL_RGBA8: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RGBA; + break; + + case GL_RGBA: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RGBA; + break; + + case GL_RGBA16F: + case GL_R16F: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_HALF_FLOAT; + if (outFormat) { + if (internalFormat == GL_RGBA16F) { + *outFormat = GL_RGBA; + } else { + *outFormat = GL_RED; + } + } + break; + + case GL_R16: + if (outInternalFormat) *outInternalFormat = GL_R16F; + if (outType) *outType = GL_FLOAT; + if (outFormat) *outFormat = GL_RED; + break; + + case GL_RGB16: + if (outInternalFormat) *outInternalFormat = GL_RGB16F; + if (outType) *outType = GL_HALF_FLOAT; + if (outFormat) *outFormat = GL_RGB; + break; + + case GL_RGB16F: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_HALF_FLOAT; + if (outFormat) *outFormat = GL_RGB; + break; + + case GL_RG16: + case GL_RG16F: + if (outInternalFormat) *outInternalFormat = GL_RG16F; + if (outType) *outType = GL_HALF_FLOAT; + if (outFormat) *outFormat = GL_RG; + break; + + case GL_R8: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RED; + break; + case GL_R8UI: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RED_INTEGER; + break; + + case GL_RGB8_SNORM: + case GL_RGBA8_SNORM: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_BYTE; + if (outFormat) { + if (internalFormat == GL_RGB8_SNORM) { + *outFormat = GL_RGB; + } else { + *outFormat = GL_RGBA; + } + } + break; + case GL_RGB8: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_BYTE; + if (outFormat) *outFormat = GL_RGB; + break; + case GL_RGBA16_SNORM: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_SHORT; + if (outFormat) *outFormat = GL_RGBA; + break; + default: + if (outInternalFormat) *outInternalFormat = internalFormat; + if (outType) *outType = GL_UNSIGNED_INT; + if (outFormat) *outFormat = GL_RGBA; + break; + } + } + + void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, GLenum* outType, + GLenum* outFormat) { + NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), outInternalFormat, + outType, outFormat); + } + } // namespace TextureImpl + + namespace FramebufferImpl { + BackendFramebufferBindingProtector::BackendFramebufferBindingProtector(GLenum target) { + m_target = target; + MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding); + } + + BackendFramebufferBindingProtector::~BackendFramebufferBindingProtector() { + MG_External::GLES::glBindFramebuffer(m_target, m_previousBinding); + } + } // namespace FramebufferImpl + + namespace PrgramImpl { + String ProcessOutColorLocations(const String& glslCode) { + const static std::regex pattern(R"(\n(out highp vec4 outColor)(\d+);)"); + const String replacement = "\nlayout(location=$2) $1$2;"; + return std::regex_replace(glslCode, pattern, replacement); + } + + String ForceSupporterOutput(const String& glslCode) { + Bool hasPrecisionFloat = + glslCode.find("precision ") != String::npos && glslCode.find("float;") != String::npos; + Bool hasPrecisionInt = glslCode.find("precision ") != String::npos && glslCode.find("int;") != String::npos; + + String result = glslCode; + String precisionFloat; + String precisionInt; + + if (hasPrecisionFloat && hasPrecisionInt) { + std::istringstream iss(result); + std::vector lines; + String line; + while (std::getline(iss, line)) { + Bool isPrecisionLine = (line.find("precision ") != String::npos) && + (line.find("float;") != String::npos || line.find("int;") != String::npos); + if (!isPrecisionLine) { + lines.push_back(line); + } + } + result.clear(); + for (SizeT i = 0; i < lines.size(); ++i) { + if (i != 0) result += '\n'; + result += lines[i]; + } + precisionFloat = "precision highp float;\n"; + precisionInt = "precision highp int;\n"; + } else { + precisionFloat = hasPrecisionFloat ? "" : "precision highp float;\n"; + precisionInt = hasPrecisionInt ? "" : "precision highp int;\n"; + } + + SizeT lastExtensionPos = result.rfind("#extension"); + SizeT insertionPos = 0; + + if (lastExtensionPos != String::npos) { + SizeT nextNewline = result.find('\n', lastExtensionPos); + if (nextNewline != String::npos) { + insertionPos = nextNewline + 1; + } else { + insertionPos = result.length(); + } + } else { + SizeT firstNewline = result.find('\n'); + if (firstNewline != String::npos) { + insertionPos = firstNewline + 1; + } else { + result = precisionFloat + precisionInt + result; + return result; + } + } + + result.insert(insertionPos, precisionFloat + precisionInt); + return result; + } + + String removeLayoutBinding(const String& glslCode) { + static std::regex bindingRegex(R"(layout\s*\(\s*binding\s*=\s*\d+\s*\)\s*)"); + String result = std::regex_replace(glslCode, bindingRegex, ""); + static std::regex bindingRegex2(R"(layout\s*\(\s*binding\s*=\s*\d+\s*,)"); + result = std::regex_replace(result, bindingRegex2, "layout("); + return result; + } + } // namespace PrgramImpl + + namespace Utils { + void CheckGLESError() { + while (GLenum err = MG_External::GLES::glGetError() != GL_NO_ERROR) { + MGLOG_E("-> GLES Error: %s", MG_Util::ConvertGLEnumToString(err).c_str()); + } + } + + GLenum GetBindingQuery(GLenum target, bool isTexture) { + switch (target) { + case GL_TEXTURE_BUFFER: + return isTexture ? GL_TEXTURE_BINDING_BUFFER : GL_TEXTURE_BUFFER_BINDING; + + case GL_ARRAY_BUFFER: + return GL_ARRAY_BUFFER_BINDING; + case GL_ATOMIC_COUNTER_BUFFER: + return GL_ATOMIC_COUNTER_BUFFER_BINDING; + case GL_COPY_READ_BUFFER: + return GL_COPY_READ_BUFFER_BINDING; + case GL_COPY_WRITE_BUFFER: + return GL_COPY_WRITE_BUFFER_BINDING; + case GL_DISPATCH_INDIRECT_BUFFER: + return GL_DISPATCH_INDIRECT_BUFFER_BINDING; + case GL_DRAW_INDIRECT_BUFFER: + return GL_DRAW_INDIRECT_BUFFER_BINDING; + case GL_ELEMENT_ARRAY_BUFFER: + return GL_ELEMENT_ARRAY_BUFFER_BINDING; + case GL_PIXEL_PACK_BUFFER: + return GL_PIXEL_PACK_BUFFER_BINDING; + case GL_PIXEL_UNPACK_BUFFER: + return GL_PIXEL_UNPACK_BUFFER_BINDING; + case GL_QUERY_BUFFER: + return GL_QUERY_BUFFER_BINDING; + case GL_SHADER_STORAGE_BUFFER: + return GL_SHADER_STORAGE_BUFFER_BINDING; + case GL_TRANSFORM_FEEDBACK_BUFFER: + return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; + case GL_UNIFORM_BUFFER: + return GL_UNIFORM_BUFFER_BINDING; + + case GL_FRAMEBUFFER: + return GL_FRAMEBUFFER_BINDING; + case GL_DRAW_FRAMEBUFFER: + return GL_DRAW_FRAMEBUFFER_BINDING; + case GL_READ_FRAMEBUFFER: + return GL_READ_FRAMEBUFFER_BINDING; + + case GL_RENDERBUFFER: + return GL_RENDERBUFFER_BINDING; + + case GL_VERTEX_ARRAY: + return GL_VERTEX_ARRAY_BINDING; + case GL_VERTEX_ARRAY_BINDING: + return GL_VERTEX_ARRAY_BINDING; + + case GL_PROGRAM_PIPELINE: + return GL_PROGRAM_PIPELINE_BINDING; + + case GL_PROGRAM: + return GL_CURRENT_PROGRAM; + + case GL_SAMPLER: + return GL_SAMPLER_BINDING; + + case GL_TEXTURE: + return GL_TEXTURE_BINDING_2D; + case GL_TEXTURE_1D: + return GL_TEXTURE_BINDING_1D; + case GL_TEXTURE_1D_ARRAY: + return GL_TEXTURE_BINDING_1D_ARRAY; + case GL_TEXTURE_2D: + return GL_TEXTURE_BINDING_2D; + case GL_TEXTURE_2D_ARRAY: + return GL_TEXTURE_BINDING_2D_ARRAY; + case GL_TEXTURE_2D_MULTISAMPLE: + return GL_TEXTURE_BINDING_2D_MULTISAMPLE; + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; + case GL_TEXTURE_3D: + return GL_TEXTURE_BINDING_3D; + case GL_TEXTURE_CUBE_MAP: + return GL_TEXTURE_BINDING_CUBE_MAP; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY; + case GL_TEXTURE_RECTANGLE: + return GL_TEXTURE_BINDING_RECTANGLE; + + case GL_TRANSFORM_FEEDBACK: + return GL_TRANSFORM_FEEDBACK_BINDING; + + case GL_SAMPLES_PASSED: + return GL_SAMPLES_PASSED; + case GL_PRIMITIVES_GENERATED: + return GL_PRIMITIVES_GENERATED; + + case GL_DEBUG_OUTPUT: + return GL_DEBUG_OUTPUT; + case GL_DEBUG_OUTPUT_SYNCHRONOUS: + return GL_DEBUG_OUTPUT_SYNCHRONOUS; + + default: + return 0; + } + } + } // namespace Utils +} // namespace MobileGL::MG_Backend::DirectGLES \ No newline at end of file diff --git a/MobileGL/MG_Backend/DirectGLES/Utils.h b/MobileGL/MG_Backend/DirectGLES/Utils.h new file mode 100644 index 00000000..c086c4a0 --- /dev/null +++ b/MobileGL/MG_Backend/DirectGLES/Utils.h @@ -0,0 +1,73 @@ +#pragma once +#include +#include + +namespace MobileGL::MG_Backend::DirectGLES { + namespace BufferImpl { + class BackendBufferBindingProtector { + public: + BackendBufferBindingProtector(GLenum target); + + ~BackendBufferBindingProtector(); + + private: + GLenum m_target; + GLint m_previousBinding = 0; + }; + } // namespace BufferImpl + + namespace VertexArrayImpl { + GLenum GetBindingQuery(GLenum target, bool isTexture); + + class BackendVertexArrayBindingProtector { + public: + BackendVertexArrayBindingProtector(); + + ~BackendVertexArrayBindingProtector(); + + private: + GLint m_previousBinding = 0; + }; + } // namespace VertexArrayImpl + + namespace TextureImpl { + class BackendTextureBindingProtector { + public: + BackendTextureBindingProtector(GLenum target); + + ~BackendTextureBindingProtector(); + + private: + GLenum m_target; + GLint m_previousBinding = 0; + }; + + void NormalizePixelFormat(GLenum internalFormat, GLenum* outInternalFormat, GLenum* outType, GLenum* outFormat); + void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, GLenum* outType, + GLenum* outFormat); + } // namespace TextureImpl + + namespace FramebufferImpl { + class BackendFramebufferBindingProtector { + public: + BackendFramebufferBindingProtector(GLenum target); + + ~BackendFramebufferBindingProtector(); + + private: + GLenum m_target; + GLint m_previousBinding = 0; + }; + } // namespace FramebufferImpl + + namespace PrgramImpl { + String ProcessOutColorLocations(const String& glslCode); + String ForceSupporterOutput(const String& glslCode); + String removeLayoutBinding(const String& glslCode); + } // namespace PrgramImpl + + namespace Utils { + void CheckGLESError(); + GLenum GetBindingQuery(GLenum target, bool isTexture); + } // namespace Utils +} // namespace MobileGL::MG_Backend::DirectGLES \ No newline at end of file diff --git a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp index aa00db64..7add7aa2 100644 --- a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp +++ b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp @@ -2,25 +2,48 @@ #include #include #include +#include namespace MobileGL { namespace MG_Impl::GLImpl { void Clear_Backend(GLbitfield mask) { - #if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES - auto clearColor = MG_State::pGLContext->GetClearColor(); - MG_External::GLES::glClearColor(clearColor.r(), clearColor.g(), clearColor.b(), clearColor.a()); - auto clearDepth = MG_State::pGLContext->GetClearDepth(); - MG_External::GLES::glClearDepthf(clearDepth); - MG_External::GLES::glClear(mask); + MG_Backend::DirectGLES::Clear(mask); #endif } void DrawElements_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices) { - // TODO +#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES + MG_Backend::DirectGLES::DrawElements(mode, count, type, indices); +#endif + } + + void MultiDrawElements_Backend(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, + GLsizei drawcount) { +#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES + MG_Backend::DirectGLES::MultiDrawElements(mode, count, type, indices, drawcount); +#endif + } + + void MultiDrawElementsBaseVertex_Backend(GLenum mode, const GLsizei* count, GLenum type, + const void* const* indices, GLsizei drawcount, + const GLint* basevertex) { +#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES + MG_Backend::DirectGLES::MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex); +#endif } /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ + void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, + GLsizei drawcount) { + MultiDrawElements_Backend(mode, count, type, indices, drawcount); + } + + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, + GLsizei drawcount, const GLint* basevertex) { + MultiDrawElementsBaseVertex_Backend(mode, count, type, indices, drawcount, basevertex); + } + void Clear(GLbitfield mask) { Clear_Backend(mask); } diff --git a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h index 04e6cd70..20fbbeff 100644 --- a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h +++ b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h @@ -4,6 +4,8 @@ namespace MobileGL { namespace MG_Impl::GLImpl { /* @INSERTION_POINT:FUNCTION_DECLARATION@ */ + void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount); + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex); void Clear(GLbitfield mask); void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); } // namespace MG_Impl::GLImpl diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 2d7d3175..986f3131 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -743,7 +743,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, LoadTransposeMatrixd, const GLdouble* m) DEC DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixf, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixf, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixd, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixd, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArrays, GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArrays, mode, first, count, drawcount) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElements, mode, count, type, indices, drawcount) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElements, mode, count, type, indices, drawcount) DECLARE_GL_FUNCTION_HEAD(void, PointParameterf, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PointParameterf, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfv, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfv, pname, params) DECLARE_GL_FUNCTION_HEAD(void, PointParameteri, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PointParameteri, pname, param) @@ -819,7 +819,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4uiv, GLuint index, const GLuint DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4usv, index, v) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode) DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations) diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp b/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp index ffb9d1e2..63652396 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp @@ -9,15 +9,15 @@ namespace MobileGL { void BufferObject::Resize(SizeT size) { m_size = size; - m_data.reserve(std::bit_ceil(size)); // power-of-2 reserve - m_data.resize(size); + m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve + m_dataPtr->resize(size); m_dirtyRange = {0, 0}; } void BufferObject::UploadData(DataPtr data, SizeT atOffset) { assert(atOffset + data.size <= m_size); assert(!m_isMapped); - memcpy(m_data.data() + atOffset, data.data, data.size); + memcpy(m_dataPtr->data() + atOffset, data.data, data.size); m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); } @@ -30,7 +30,7 @@ namespace MobileGL { if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly - memcpy(m_data.data() + m_mappedRange.start, m_stagingData.data(), + memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), m_mappedRange.end - m_mappedRange.start); m_dirtyRange.UnionUpdate(m_mappedRange.start, m_mappedRange.end); } @@ -53,7 +53,7 @@ namespace MobileGL { SizeT end = start + length; assert(end <= m_mappedRange.end); - memcpy(m_data.data() + start, m_stagingData.data() + offset, length); + memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); m_dirtyRange.UnionUpdate(start, end); } @@ -61,7 +61,7 @@ namespace MobileGL { assert(!m_isMapped); assert(atOffset + data.size <= m_size); - memcpy(m_data.data() + atOffset, data.data, data.size); + memcpy(m_dataPtr->data() + atOffset, data.data, data.size); m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); } @@ -72,8 +72,8 @@ namespace MobileGL { assert(srcOffset + size <= src->GetSize()); assert(dstOffset + size <= m_size); - const Uint8* srcData = src->m_data.data() + srcOffset; - memcpy(m_data.data() + dstOffset, srcData, size); + const Uint8* srcData = src->m_dataPtr->data() + srcOffset; + memcpy(m_dataPtr->data() + dstOffset, srcData, size); m_dirtyRange.UnionUpdate(dstOffset, dstOffset + size); } @@ -91,14 +91,14 @@ namespace MobileGL { if (!(m_mappingAccess & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) { - memcpy(m_stagingData.data(), m_data.data(), m_size); + memcpy(m_stagingData.data(), m_dataPtr->data(), m_size); } return m_stagingData.data(); } } - return m_data.data(); + return m_dataPtr->data(); } void* BufferObject::AcquireMemoryRange(Range1D range, Flags access) { @@ -113,16 +113,20 @@ namespace MobileGL { if (!(access & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) { - memcpy(m_stagingData.data(), m_data.data() + range.start, m_stagingData.size()); + memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size()); } return m_stagingData.data(); } else { m_ownsStagingData = false; - return m_data.data() + range.start; + return m_dataPtr->data() + range.start; } } + SharedPtr BufferObject::GetDataReadOnly() const { + return m_dataPtr; + } + void BufferObject::ClearDirty() { m_dirtyRange = {0, 0}; } diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.h b/MobileGL/MG_State/GLState/BufferState/BufferObject.h index b6dfcb4c..ab00a280 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.h @@ -1,4 +1,5 @@ #pragma once +#include "MG_Util/Types.h" #include namespace MobileGL { @@ -70,18 +71,19 @@ namespace MobileGL { BufferUsage GetUsage() const; Range1D GetDirtyRange() const; Range1D GetMappedRange() const; + SharedPtr GetDataReadOnly() const; Flags GetMappingAccess() const; private: Int m_id = 0; SizeT m_size = 0; BufferUsage m_usage = BufferUsage::StaticDraw; - Data m_data; + SharedPtr m_dataPtr; Bool m_isMapped; Flags m_mappingAccess; Range1D m_dirtyRange; Range1D m_mappedRange; - std::vector m_stagingData; + Vector m_stagingData; Bool m_ownsStagingData; }; } // namespace GLState diff --git a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp index c206f6c4..0b055d18 100644 --- a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp +++ b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp @@ -88,6 +88,12 @@ namespace MobileGL { return m_attachments[static_cast(type)]; } + const Array(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>& + FramebufferObject::GetAllAttachments() const { + return m_attachments; + } + Bool FramebufferObject::CheckCompleteness() const { if (m_attachments.empty()) { return false; diff --git a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h index 1e7879bd..b1ea3af9 100644 --- a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h +++ b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.h @@ -89,6 +89,9 @@ namespace MobileGL { std::shared_ptr renderbuffer); void Detach(FramebufferAttachmentType type); const FramebufferAttachment& GetAttachment(FramebufferAttachmentType type) const; + const Array(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>& + GetAllAttachments() const; Bool CheckCompleteness() const; void SetDrawBuffers(const std::vector& buffers); const Vector& GetDrawBuffers() const; diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp index a241dc66..c60629ea 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -68,6 +68,12 @@ namespace MobileGL { m_internalFormat = format; } + void TextureObjectBase::UnmarkMipmapDirty(Int index) { + if (index >= 0 && index < static_cast(m_mipmaps.size())) { + m_mipmaps[index].dirty = false; + } + } + // TextureObject1D TextureObject1D::TextureObject1D() : TextureObjectBase(TextureTarget::Texture1D) {} diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.h b/MobileGL/MG_State/GLState/TextureState/TextureObject.h index 5e19ccb6..83c13bc2 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.h @@ -211,6 +211,7 @@ namespace MobileGL { virtual MipmapLevelInternal& GetMipmap(Int index) = 0; virtual void SetInternalFormat(TextureInternalFormat format) = 0; virtual Bool IsComplete() const = 0; + virtual void UnmarkMipmapDirty(Int index) = 0; }; class TextureObjectBase : public ITextureObject { @@ -227,6 +228,7 @@ namespace MobileGL { MipmapLevelInternal& GetMipmap(Int index) override; void SetInternalFormat(TextureInternalFormat format) override; Bool IsComplete() const override; + void UnmarkMipmapDirty(Int index) override; protected: virtual void SetMipmapImpl(const MipmapLevelInput& level) = 0; diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp index df7472cf..84f53235 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp @@ -4,7 +4,8 @@ namespace MobileGL { namespace MG_State { namespace GLState { VertexArrayObject::VertexArrayObject() { - for (auto& attr : m_attributes) { + for (int index = 0; index < MAX_VERTEX_ATTRIBS; ++index) { + auto& attr = m_attributes[index]; attr.Enabled = false; attr.Size = 4; attr.Type = DataType::Float32; @@ -12,17 +13,21 @@ namespace MobileGL { attr.Stride = 0; attr.Offset = 0; attr.Buffer = nullptr; + + MarkAttributeDirty(index); } } void VertexArrayObject::EnableAttribute(Uint index) { if (index >= MAX_VERTEX_ATTRIBS) return; m_attributes[index].Enabled = true; + MarkAttributeDirty(index); } void VertexArrayObject::DisableAttribute(Uint index) { if (index >= MAX_VERTEX_ATTRIBS) return; m_attributes[index].Enabled = false; + MarkAttributeDirty(index); } Bool VertexArrayObject::IsAttributeEnabled(Uint index) const { @@ -45,11 +50,14 @@ namespace MobileGL { attr.Stride = stride; attr.Offset = offset; attr.IsInteger = isInteger; + + MarkAttributeDirty(index); } void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr& buffer) { if (index >= MAX_VERTEX_ATTRIBS) return; m_attributes[index].Buffer = buffer; + MarkAttributeDirty(index); } BindingSlot& VertexArrayObject::GetIndexBufferBindingSlot() { @@ -61,6 +69,27 @@ namespace MobileGL { if (index >= MAX_VERTEX_ATTRIBS) return emptyAttr; return m_attributes[index]; } + + const Array& VertexArrayObject::GetAllAttributes() + const { + return m_attributes; + } + + void VertexArrayObject::MarkAttributeDirty(Uint index) { + if (index >= MAX_VERTEX_ATTRIBS) return; + if (std::find(m_dirtyAttributes.begin(), m_dirtyAttributes.end(), index) != m_dirtyAttributes.end()) { + return; + } + m_dirtyAttributes.push_back(index); + } + + const Vector& VertexArrayObject::GetDirtyAttributeIndices() const { + return m_dirtyAttributes; + } + + void VertexArrayObject::ClearDirtyAttributes() { + m_dirtyAttributes.clear(); + } } // namespace GLState } // namespace MG_State } // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h index 95b0b089..2c1ab1e3 100644 --- a/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h +++ b/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.h @@ -34,9 +34,16 @@ namespace MobileGL { BindingSlot& GetIndexBufferBindingSlot(); const VertexAttribute& GetAttribute(Uint index) const; + const Array& GetAllAttributes() const; + + const Vector& GetDirtyAttributeIndices() const; + void ClearDirtyAttributes(); private: + void MarkAttributeDirty(Uint index); + Array m_attributes; + Vector m_dirtyAttributes; BindingSlot m_indexBufferBindingSlot; }; } // namespace GLState diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index 26744f40..4b520792 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -56,6 +56,9 @@ namespace MobileGL { inline constexpr void Copy(const T* src, T* dest, SizeT count) { std::copy(src, src + count, dest); } + inline constexpr void Memcpy(const void* src, void* dest, SizeT size) { + std::memcpy(dest, src, size); + } template constexpr auto ToArray(Ts&&... elems) { using E = std::common_type_t;