Merge branch 'Feat/Backend-Direct-GLES' into dev

This commit is contained in:
BZLZHH
2026-02-05 22:00:49 +08:00
68 changed files with 2283 additions and 1731 deletions
+27 -4
View File
@@ -13,11 +13,33 @@ if (ANDROID)
endif() endif()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR MOBILEGL_FORCE_RELEASE_OPT) if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR MOBILEGL_FORCE_RELEASE_OPT)
# Check if ThinLTO or LTO is suppported
include(CheckIPOSupported) include(CheckIPOSupported)
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
check_ipo_supported(RESULT LTOSupported OUTPUT LTOError) check_ipo_supported(RESULT LTOSupported OUTPUT LTOError)
if (LTOSupported)
check_c_compiler_flag("-flto" HAS_LTO_C)
check_cxx_compiler_flag("-flto" HAS_LTO_CXX)
if (LTOSupported OR (HAS_LTO_C AND HAS_LTO_CXX))
# Check ThinLTO
check_c_compiler_flag("-flto=thin" HAS_THINLTO_C)
check_cxx_compiler_flag("-flto=thin" HAS_THINLTO_CXX)
if (HAS_THINLTO_C AND HAS_THINLTO_CXX)
message(STATUS "ThinLTO supported, using -flto=thin")
add_compile_options(-flto=thin)
add_link_options(-flto=thin)
else()
# ThinLTO is not supported
message(STATUS "ThinLTO not available, fallback to CMAKE IPO")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif() endif()
else()
message(STATUS "IPO not supported: ${LTOError}")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MATCHES "AppleClang") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MATCHES "AppleClang")
add_compile_options(-O3 -ffunction-sections -fdata-sections) add_compile_options(-O3 -ffunction-sections -fdata-sections)
@@ -103,7 +125,9 @@ set(SOURCE_FILES
MobileGL/MG_Util/Debug/Log.cpp MobileGL/MG_Util/Debug/Log.cpp
MobileGL/MG_Util/Math/VectorTypes.cpp
MobileGL/MG_Util/Metrics/TextureMetrics.cpp MobileGL/MG_Util/Metrics/TextureMetrics.cpp
MobileGL/MG_Util/Metrics/BufferMetrics.cpp MobileGL/MG_Util/Metrics/BufferMetrics.cpp
MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp
@@ -248,6 +272,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
if(NOT ANDROID)
add_library(${CMAKE_PROJECT_NAME}_s STATIC add_library(${CMAKE_PROJECT_NAME}_s STATIC
${SOURCE_FILES} ${SOURCE_FILES}
) )
@@ -274,6 +299,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME}_s
PRIVATE PRIVATE
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
endif()
if (TRACY_ENABLE) if (TRACY_ENABLE)
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient) target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient)
@@ -287,9 +313,6 @@ if (ANDROID)
android android
log log
) )
target_link_libraries(${CMAKE_PROJECT_NAME}_s PUBLIC
android
log)
endif() endif()
if (MOBILEGL_BUILD_TEST) if (MOBILEGL_BUILD_TEST)
+205 -325
View File
@@ -7,6 +7,9 @@
// End of Source File Header // End of Source File Header
#include "DirectGLES.h" #include "DirectGLES.h"
#include "GLES3/gl32.h"
#include "MG_State/GLState/SamplerState/SamplerObject.h"
#include "MG_Util/Debug/Log.h"
#include "Utils.h" #include "Utils.h"
#include "Managers.h" #include "Managers.h"
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
@@ -86,71 +89,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
// TODO: deletion for deleted objects // TODO: deletion for deleted objects
namespace BufferImpl { namespace BufferImpl {
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) { void CreateAndSyncBufferObject(SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
#ifdef TRACY_ENABLE if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
// All buffers we need are:
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
// PBO is not needed since it should be handled in frontend
Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
return;
}
// VBO
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
if (!attrib.Enabled) continue;
const auto& bufferObject = attrib.Buffer;
if (bufferObject) {
const auto& end = buffersToSync.end();
if (std::find(buffersToSync.begin(), end, bufferObject) == end) {
buffersToSync.push_back(bufferObject);
}
}
}
// IBO
if (includeIBO) {
const auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (possibleIBO) {
const auto& end = buffersToSync.end();
if (std::find(buffersToSync.begin(), end, possibleIBO) == end) {
buffersToSync.push_back(possibleIBO);
}
}
}
// Indirect Buffer Object
if (includeIndirectBuffer) {
const auto& possibleIndirectBuffer =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (possibleIndirectBuffer) {
const auto& end = buffersToSync.end();
if (std::find(buffersToSync.begin(), end, possibleIndirectBuffer) == end) {
buffersToSync.push_back(possibleIndirectBuffer);
}
}
}
// UBO
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
auto obj = point.GetBoundObject();
if (obj) {
const auto& end = buffersToSync.end();
if (std::find(buffersToSync.begin(), end, obj) == end) {
buffersToSync.push_back(obj);
}
}
}
// Do real sync
for (auto& bufferObject : buffersToSync) {
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject); const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject);
SharedPtr<BackendBufferObject> backendBufferObject; SharedPtr<BackendBufferObject> backendBufferObject;
if (backendBufferIt == g_backendBufferObjects.end()) { if (backendBufferIt == g_backendBufferObjects.end()) {
@@ -161,11 +102,64 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
backendBufferObject->SyncToBackend(bufferObject); backendBufferObject->SyncToBackend(bufferObject);
} }
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
// All buffers we need are:
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
// PBO is not needed since it should be handled in frontend
// static Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
// buffersToSync.clear();
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
return;
}
// VBO
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
if (!attrib.Enabled) continue;
auto bufferObject = attrib.Buffer;
if (bufferObject) {
CreateAndSyncBufferObject(bufferObject);
}
}
// IBO
if (includeIBO) {
auto possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (possibleIBO) {
CreateAndSyncBufferObject(possibleIBO);
}
}
// Indirect Buffer Object
if (includeIndirectBuffer) {
auto possibleIndirectBuffer =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (possibleIndirectBuffer) {
CreateAndSyncBufferObject(possibleIndirectBuffer);
}
}
// UBO
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
auto obj = point.GetBoundObject();
if (obj) {
CreateAndSyncBufferObject(obj);
}
}
} }
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
void SyncCurrentVAO(Bool needDivisor) { void SyncCurrentVAO() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -183,7 +177,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else { } else {
backendVAOObject = backendVAOIt->second; backendVAOObject = backendVAOIt->second;
} }
backendVAOObject->SyncToBackend(currentVAOObject, needDivisor); backendVAOObject->SyncToBackend(currentVAOObject);
} }
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
@@ -201,7 +195,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else { } else {
backendTextureObject = backendTextureIt->second; backendTextureObject = backendTextureIt->second;
} }
backendTextureObject->SyncToBackend(textureObject); backendTextureObject->SyncTextureParamsToBackend(textureObject);
backendTextureObject->SyncBuiltinSamplerToBackend(textureObject);
backendTextureObject->SyncMipmapsToBackend(textureObject);
return backendTextureObject; return backendTextureObject;
} }
@@ -213,21 +209,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
// 1. textures bound to texture units (TODO: only sync ones that are used in current program) // 1. textures bound to texture units (TODO: only sync ones that are used in current program)
// 2. textures used in current FBO // 2. textures used in current FBO
// 3. textures bound to image units (TODO) // 3. textures bound to image units (TODO)
constexpr SizeT TextureTargetCount = static_cast<SizeT>(TextureTarget::TextureTargetCount);
std::bitset<TextureTargetCount> dirtyTextureTargetBits;
Vector<SharedPtr<MG_State::GLState::ITextureObject>> texturesToSync;
for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) { for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) {
auto& unit = MG_State::pGLContext->GetTextureUnitObject(index); auto& unit = MG_State::pGLContext->GetTextureUnitObject(index);
for (const auto& bindingSlot : unit.GetAllBindingSlots()) { for (const auto& bindingSlot : unit.GetAllBindingSlots()) {
const auto& textureObject = bindingSlot.GetBoundObject(); auto textureObject = bindingSlot.GetBoundObject();
if (textureObject) { if (textureObject) {
const auto& end = texturesToSync.end(); SyncTextureObjectToBackend(textureObject);
if (std::find(texturesToSync.begin(), end, textureObject) == end) {
texturesToSync.push_back(textureObject);
dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget()));
}
} }
} }
} }
@@ -235,35 +223,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& currentFBO = const auto& currentFBO =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (currentFBO) { if (currentFBO) {
for (const auto& attachment : currentFBO->GetAllAttachments()) { for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
if (!attachment.IsTexture()) continue; if (!attachment.IsTexture()) continue;
const auto& textureObject = attachment.GetTexture(); auto textureObject = attachment.GetTexture();
if (textureObject) { if (textureObject) {
const auto& end = texturesToSync.end();
if (std::find(texturesToSync.begin(), end, textureObject) == end) {
texturesToSync.push_back(textureObject);
dirtyTextureTargetBits.set(static_cast<SizeT>(textureObject->GetTarget()));
}
}
}
}
BufferImpl::BackendBufferBindingProtector pixelUnpackProtector =
BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER);
Vector<BackendTextureBindingProtector> textureBindingProtectors;
for (SizeT target = 0; target < TextureTargetCount; ++target) {
if (dirtyTextureTargetBits[target]) {
textureBindingProtectors.emplace_back(
MG_Util::ConvertTextureTargetToGLEnum(static_cast<TextureTarget>(target)));
}
}
// Do real sync
for (auto& textureObject : texturesToSync) {
SyncTextureObjectToBackend(textureObject); SyncTextureObjectToBackend(textureObject);
} }
} }
}
}
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {
@@ -276,7 +244,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr; MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr;
for (auto target : fboTargets) { for (auto target : fboTargets) {
auto currentFBO = MG_State::pGLContext->GetFramebufferBindingSlot(target).GetBoundObject(); auto slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
auto version = slot.GetVersion();
if (version == g_fboBindVersions[SizeT(target)]) continue;
auto currentFBO = slot.GetBoundObject();
if (!currentFBO) { if (!currentFBO) {
MGLOG_E("No FBO is currently bound, cannot sync current FBO."); MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
@@ -303,39 +275,51 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendFBOObject->SyncToBackend(currentFBO, target); backendFBOObject->SyncToBackend(currentFBO, target);
} }
backendFBOObject->Bind(target);
lastUpdatedFBO = currentFBO.get(); lastUpdatedFBO = currentFBO.get();
} }
} }
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace RenderStateImpl { namespace RenderStateImpl {
static Uint16 g_syncedRenderStateVersion = 0;
static RenderStateParameters g_syncedRenderStateParameters;
void SyncRenderState() { void SyncRenderState() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
MG_External::GLES::glViewport( Uint16 currentRenderStateVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
MG_State::pGLContext->GetViewport().x(), MG_State::pGLContext->GetViewport().y(), if (currentRenderStateVersion == g_syncedRenderStateVersion) return;
MG_State::pGLContext->GetViewport().z(), MG_State::pGLContext->GetViewport().w());
const auto& parameters = MG_State::pGLContext->GetRenderStateParameters();
if (parameters.Viewport != g_syncedRenderStateParameters.Viewport) {
MG_External::GLES::glViewport(parameters.Viewport.x(), parameters.Viewport.y(), parameters.Viewport.z(),
parameters.Viewport.w());
}
#define SYNC_CAPABILITY(cap_mg, cap_gl) \ #define SYNC_CAPABILITY(cap_mg, cap_gl) \
if (MG_State::pGLContext->IsCapabilityEnabled(cap_mg)) { \ if (parameters.cap_mg##Enabled != g_syncedRenderStateParameters.cap_mg##Enabled) { \
if (parameters.cap_mg##Enabled) { \
MG_External::GLES::glEnable(cap_gl); \ MG_External::GLES::glEnable(cap_gl); \
} else { \ } else { \
MG_External::GLES::glDisable(cap_gl); \ MG_External::GLES::glDisable(cap_gl); \
} \
} }
SYNC_CAPABILITY(CapabilityInput::Blend, GL_BLEND); SYNC_CAPABILITY(Blend, GL_BLEND);
SYNC_CAPABILITY(CapabilityInput::DepthTest, GL_DEPTH_TEST); SYNC_CAPABILITY(DepthTest, GL_DEPTH_TEST);
SYNC_CAPABILITY(CapabilityInput::ScissorTest, GL_SCISSOR_TEST); SYNC_CAPABILITY(ScissorTest, GL_SCISSOR_TEST);
SYNC_CAPABILITY(CapabilityInput::CullFace, GL_CULL_FACE); SYNC_CAPABILITY(CullFace, GL_CULL_FACE);
#undef SYNC_CAPABILITY #undef SYNC_CAPABILITY
const auto& ToGLBoolean = [](Bool b) -> GLboolean { return b ? GL_TRUE : GL_FALSE; }; const auto& ToGLBoolean = [](Bool b) -> GLboolean { return b ? GL_TRUE : GL_FALSE; };
{ // Blend func if (parameters.SrcFactorRGB != g_syncedRenderStateParameters.SrcFactorRGB ||
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; parameters.DstFactorRGB != g_syncedRenderStateParameters.DstFactorRGB ||
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); parameters.SrcFactorAlpha != g_syncedRenderStateParameters.SrcFactorAlpha ||
parameters.DstFactorAlpha != g_syncedRenderStateParameters.DstFactorAlpha) { // Blend func
const BlendFactor &srcRGB = parameters.SrcFactorRGB, &dstRGB = parameters.DstFactorRGB,
&srcAlpha = parameters.SrcFactorAlpha, &dstAlpha = parameters.DstFactorAlpha;
MG_External::GLES::glBlendFuncSeparate( MG_External::GLES::glBlendFuncSeparate(
MG_Util::ConvertBlendFactorToGLEnum(srcRGB), MG_Util::ConvertBlendFactorToGLEnum(dstRGB), MG_Util::ConvertBlendFactorToGLEnum(srcRGB), MG_Util::ConvertBlendFactorToGLEnum(dstRGB),
@@ -343,34 +327,49 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
{ // Blend equation { // Blend equation
DepthTestFunc df = MG_State::pGLContext->GetDepthFunc(); if (parameters.DepthFunc != g_syncedRenderStateParameters.DepthFunc) {
MG_External::GLES::glDepthFunc(MG_Util::ConvertDepthTestFuncToGLEnum(df)); MG_External::GLES::glDepthFunc(MG_Util::ConvertDepthTestFuncToGLEnum(parameters.DepthFunc));
}
MG_External::GLES::glDepthMask(MG_State::pGLContext->GetDepthMask() ? GL_TRUE : GL_FALSE); if (parameters.DepthMask != g_syncedRenderStateParameters.DepthMask) {
MG_External::GLES::glDepthMask(parameters.DepthMask ? GL_TRUE : GL_FALSE);
}
} }
{ // Color mask { // Color mask
BoolVec4 colorMask = MG_State::pGLContext->GetColorMask(); if (parameters.ColorMask != g_syncedRenderStateParameters.ColorMask) {
const BoolVec4& colorMask = parameters.ColorMask;
MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()), MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()),
ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w())); ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w()));
} }
}
{ // Clear values { // Clear values
const FloatVec4& clearCol = MG_State::pGLContext->GetClearColor(); if (parameters.ClearColor != g_syncedRenderStateParameters.ClearColor) {
const FloatVec4& clearCol = parameters.ClearColor;
MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w()); MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w());
MG_External::GLES::glClearDepthf(MG_State::pGLContext->GetClearDepth()); }
if (parameters.ClearDepth != g_syncedRenderStateParameters.ClearDepth) {
MG_External::GLES::glClearDepthf(parameters.ClearDepth);
}
} }
{ // Cull face mode { // Cull face mode
CullFaceMode cfm = MG_State::pGLContext->GetCullFaceMode(); if (parameters.CullFaceModeSetting != g_syncedRenderStateParameters.CullFaceModeSetting) {
const CullFaceMode& cfm = parameters.CullFaceModeSetting;
MG_External::GLES::glCullFace(MG_Util::ConvertCullFaceModeToGLEnum(cfm)); MG_External::GLES::glCullFace(MG_Util::ConvertCullFaceModeToGLEnum(cfm));
} }
}
{ // Scissor box { // Scissor box
const IntVec4& scissorBox = MG_State::pGLContext->GetScissorBox(); if (parameters.ScissorBox != g_syncedRenderStateParameters.ScissorBox) {
const IntVec4& scissorBox = parameters.ScissorBox;
MG_External::GLES::glScissor(scissorBox.x(), scissorBox.y(), scissorBox.z(), scissorBox.w()); MG_External::GLES::glScissor(scissorBox.x(), scissorBox.y(), scissorBox.z(), scissorBox.w());
} }
} }
g_syncedRenderStateVersion = currentRenderStateVersion;
g_syncedRenderStateParameters = parameters;
}
} // namespace RenderStateImpl } // namespace RenderStateImpl
namespace PrgramImpl { namespace PrgramImpl {
@@ -402,7 +401,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
const auto& currentFBO = MG_State::pGLContext->GetFramebufferBindingSlot(target).GetBoundObject(); auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
if (slot.GetVersion() == FramebufferImpl::g_fboBindVersions[(SizeT)target]) return;
const auto& currentFBO = slot.GetBoundObject();
if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) { if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO); const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO);
if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) { if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) {
@@ -423,7 +425,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BufferImpl::SyncNeccessaryBuffers(syncBit & DrawSyncBit::IndexBuffer, syncBit & DrawSyncBit::IndirectBuffer); BufferImpl::SyncNeccessaryBuffers(syncBit & DrawSyncBit::IndexBuffer, syncBit & DrawSyncBit::IndirectBuffer);
VertexArrayImpl::SyncCurrentVAO(syncBit & DrawSyncBit::Instancing); VertexArrayImpl::SyncCurrentVAO();
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
PrgramImpl::SyncCurrentProgram(); PrgramImpl::SyncCurrentProgram();
@@ -454,8 +456,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
for (Int unit = 0; unit < maxTextureUnits; ++unit) { for (Int unit = 0; unit < maxTextureUnits; ++unit) {
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
MG_External::GLES::glActiveTexture(GL_TEXTURE0 + unit);
for (const auto& bindingSlot : textureUnit.GetAllBindingSlots()) { for (const auto& bindingSlot : textureUnit.GetAllBindingSlots()) {
const auto& textureObject = bindingSlot.GetBoundObject(); const auto& textureObject = bindingSlot.GetBoundObject();
if (!textureObject) continue; if (!textureObject) continue;
@@ -471,18 +471,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue; if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue;
GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target); GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target);
backendTextureIt->second->Bind(targetGL); backendTextureIt->second->Bind(targetGL, unit);
} }
// Bind sampler object // Bind sampler object if necessary
const auto& samplerObject = textureUnit.GetSamplerObject(); const auto& samplerObject = textureUnit.GetSamplerObject();
if (samplerObject) { if (samplerObject) {
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject); const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject);
if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) { if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) {
backendSamplerIt->second->Bind(unit); backendSamplerIt->second->Bind(unit);
} }
} else { } else {
MG_External::GLES::glBindSampler(unit, 0);
} }
} }
} }
@@ -586,7 +586,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
backendSamplerObject->SyncToBackend(samplerObject); backendSamplerObject->SyncToBackend(samplerObject);
} else { } else {
MG_External::GLES::glBindSampler(unit, 0); SamplerImpl::UnbindSampler(unit);
} }
} }
} }
@@ -778,22 +778,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
MG_Util::ConvertGLEnumToString(filter).c_str()); dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
MG_External::GLES::glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); MG_External::GLES::glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
bool UpdateTextureBindingAtTarget(GLenum target) { Bool UpdateTextureBindingAtTarget(GLenum target) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND); ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND);
#endif #endif
auto unit = MG_State::pGLContext->GetActiveTextureUnit(); auto unit = MG_State::pGLContext->GetActiveTextureUnit();
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
MG_External::GLES::glActiveTexture(GL_TEXTURE0 + unit);
auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
if (!TextureImpl::IsSupportedTextureTarget(textureTarget)) { if (!TextureImpl::IsSupportedTextureTarget(textureTarget)) {
MOBILEGL_ASSERT(false, " Texture target %s is not supported, skipping.", MOBILEGL_ASSERT(false, " Texture target %s is not supported, skipping.",
@@ -817,11 +816,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else { } else {
backendTextureObject = backendTextureIt->second; backendTextureObject = backendTextureIt->second;
} }
backendTextureObject->Bind(target); backendTextureObject->Bind(target, unit);
} }
return true; return true;
} }
static GLuint s_prevDrawFBO = 0;
void BindTempDrawFBO() {
MGLOG_D("%s: Binding temporary FBO for operations like CopyTexImage2D that require framebuffer binding, "
"previous draw FBO=%u",
__func__, s_prevDrawFBO);
static GLuint tempFBO = 0;
if (!tempFBO) {
MG_External::GLES::glGenFramebuffers(1, &tempFBO);
}
MG_External::GLES::glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&s_prevDrawFBO);
MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tempFBO);
}
void RestoreDrawFBOFromTemp() {
MGLOG_D("%s: Restoring previous draw FBO=%u", __func__, s_prevDrawFBO);
MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_prevDrawFBO);
}
class TempFBOBinder {
public:
TempFBOBinder() { BindTempDrawFBO(); }
~TempFBOBinder() { RestoreDrawFBOFromTemp(); }
};
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) { GLsizei height, GLint border) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
@@ -841,31 +863,36 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (!UpdateTextureBindingAtTarget(target)) return;
if (!UpdateTextureBindingAtTarget(target)) // Bind necessary FBO and texture
BindCurrentFBO(FramebufferTarget::Read);
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
.GetBoundObject();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
textureObject ? textureObject->GetExternalIndex() : 0);
return; return;
}
backendTextureIt->second->Bind(target, activeTextureUnit);
// GLint realInternalFormat; auto mgInternalFormat = textureObject->GetFormat();
// MG_External::GLES::glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &realInternalFormat);
// errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
// MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
// });
// internalformat = (GLenum)realInternalFormat;
auto mglInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
GLenum format = GL_DEPTH_COMPONENT; GLenum format = GL_DEPTH_COMPONENT;
GLenum type = GL_UNSIGNED_INT; GLenum type = GL_UNSIGNED_INT;
TextureImpl::GenerateTextureFormatInfo(mglInternalFormat, &internalformat, &format, &type); TextureImpl::GenerateTextureFormatInfo(mgInternalFormat, &internalformat, &format, &type);
MOBILEGL_ASSERT(format != GL_NONE && type != GL_NONE, "%s: cannot GenerateTextureFormatInfo(%s): out internalformat=%s, format=%s, type=%s", MOBILEGL_ASSERT(format != GL_NONE && type != GL_NONE,
MG_Util::ConvertTextureInternalFormatToString(mglInternalFormat).c_str(), "%s: cannot GenerateTextureFormatInfo(%s): out internalformat=%s, format=%s, type=%s",
MG_Util::ConvertTextureInternalFormatToString(mgInternalFormat).c_str(),
MG_Util::ConvertGLEnumToString(internalformat).c_str(), MG_Util::ConvertGLEnumToString(internalformat).c_str(),
MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(type).c_str());
MG_Util::ConvertGLEnumToString(type).c_str());
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type); TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
bool isDepthFormat = Bool isDepthFormat =
MG_Util::IsDepthFormatInternalFormat(MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat)); MG_Util::IsDepthFormatInternalFormat(MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat));
bool isStencilFormat = Bool isStencilFormat =
MG_Util::IsStencilFormatInternalFormat(MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat)); MG_Util::IsStencilFormatInternalFormat(MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat));
if (!isDepthFormat) { if (!isDepthFormat) {
@@ -880,30 +907,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
FramebufferImpl::BackendFramebufferBindingProtector drawFboProtector(GL_DRAW_FRAMEBUFFER);
FramebufferImpl::BackendFramebufferBindingProtector readFboProtector(GL_READ_FRAMEBUFFER);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
FramebufferImpl::BackendFramebufferBindingProtector::BindTempFBO(FramebufferTarget::Draw); GLint currentTex = backendTextureIt->second->GetBackendTextureId();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
GLint currentTex;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &currentTex);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
TempFBOBinder tempFBOBinder;
MG_External::GLES::glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level); MG_External::GLES::glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
if (MG_External::GLES::glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if (MG_External::GLES::glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
MGLOG_E("ES glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE"); MGLOG_E("ES glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE");
// Protector will automatically revert to previous fbo states
return; return;
} }
@@ -913,7 +928,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
// Protector will automatically revert to previous fbo states
} }
} }
@@ -938,10 +952,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (!UpdateTextureBindingAtTarget(target)) if (!UpdateTextureBindingAtTarget(target)) return;
return;
// Bind necessary FBO and texture
BindCurrentFBO(FramebufferTarget::Read); BindCurrentFBO(FramebufferTarget::Read);
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
.GetBoundObject();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
textureObject ? textureObject->GetExternalIndex() : 0);
return;
}
backendTextureIt->second->Bind(target, activeTextureUnit);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -950,10 +976,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
auto mglInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat); auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat);
bool isDepthFormat = MG_Util::IsDepthFormatInternalFormat(mglInternalFormat); Bool isDepthFormat = MG_Util::IsDepthFormatInternalFormat(mgInternalFormat);
bool isStencilFormat = MG_Util::IsStencilFormatInternalFormat(mglInternalFormat); Bool isStencilFormat = MG_Util::IsStencilFormatInternalFormat(mgInternalFormat);
if (!isDepthFormat) { if (!isDepthFormat) {
MG_External::GLES::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); MG_External::GLES::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
@@ -962,29 +988,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
}); });
} else { } else {
MGLOG_D("%s: Backend depth", __func__); MGLOG_D("%s: Backend depth", __func__);
FramebufferImpl::BackendFramebufferBindingProtector drawFboProtector(GL_DRAW_FRAMEBUFFER); GLint currentTex = backendTextureIt->second->GetBackendTextureId();
FramebufferImpl::BackendFramebufferBindingProtector readFboProtector(GL_READ_FRAMEBUFFER);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
FramebufferImpl::BackendFramebufferBindingProtector::BindTempFBO(FramebufferTarget::Draw);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
GLint currentTex;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &currentTex);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
TempFBOBinder tempFBOBinder;
MG_External::GLES::glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level); MG_External::GLES::glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (MG_External::GLES::glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if (MG_External::GLES::glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
MGLOG_E("ES glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE"); MGLOG_E("ES glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE");
// Protector will automatically revert to previous fbo states
return; return;
} }
@@ -994,7 +1009,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
// Protector will automatically revert to previous fbo states
} }
} }
@@ -1008,8 +1022,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto texture = slot.GetBoundObject(); auto texture = slot.GetBoundObject();
auto backendTexture = TextureImpl::SyncTextureObjectToBackend(texture); auto backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
TextureImpl::BackendTextureBindingProtector protector(target); backendTexture->Bind(target, unitIndex);
backendTexture->Bind(target);
MG_External::GLES::glGenerateMipmap(target); MG_External::GLES::glGenerateMipmap(target);
} }
@@ -1033,105 +1046,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); 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; MG_External::GLES::glClearBufferfv(buffer, drawbuffer, value);
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<int>(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) { void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); MG_External::GLES::glClearBufferiv(buffer, drawbuffer, value);
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<int>(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) { void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
@@ -1140,51 +1063,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
BindCurrentFBO(FramebufferTarget::Draw); 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; MG_External::GLES::glClearBufferuiv(buffer, drawbuffer, value);
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<int>(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 } // namespace MobileGL::MG_Backend::DirectGLES
@@ -8,6 +8,8 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureState.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h>
#define CallAndCheck(operation) \ #define CallAndCheck(operation) \
MGLOG_D("Call GLES func: %s", #operation); \ MGLOG_D("Call GLES func: %s", #operation); \
+436 -243
View File
@@ -7,24 +7,29 @@
// End of Source File Header // End of Source File Header
#include "Managers.h" #include "Managers.h"
#include "MG_Backend/Backends.h" #include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_Util/Debug/Log.h" #include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_State/GLState/TextureState/TextureState.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
#include "Utils.h" #include "Utils.h"
#include "DirectGLES.h" #include "DirectGLES.h"
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
#include <MG_Util/BackendLoaders/OpenGL/Loader.h> #include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h> #include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h> #include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h> #include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h> #include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
namespace BufferImpl { namespace BufferImpl {
BackendBufferObject::BackendBufferObject() { BackendBufferObject::BackendBufferObject() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -39,7 +44,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -58,8 +62,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing buffer object with backend ID %u to backend for state ID %u", m_backendBufferId, MGLOG_D("Syncing buffer object with backend ID %u to backend for state ID %u", m_backendBufferId,
stateBufferObject->GetExternalIndex()); stateBufferObject->GetExternalIndex());
// Decide sync method
// glBufferData
Bool needsRegeneration = Bool needsRegeneration =
!m_isInitialized || bufferSize > m_prevBufferSize || bufferSize < m_prevBufferSize / 2; !m_isInitialized || (stateBufferObject->GetChangeBits() & BufferChangeBits::PreferReallocationBit);
if (needsRegeneration) { if (needsRegeneration) {
MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u", MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u",
@@ -67,22 +73,33 @@ namespace MobileGL::MG_Backend::DirectGLES {
SyncToBackend_glBufferData(stateBufferObject); SyncToBackend_glBufferData(stateBufferObject);
m_isInitialized = true; m_isInitialized = true;
m_prevBufferSize = bufferSize; m_prevBufferSize = bufferSize;
stateBufferObject->ClearDirty();
return; return;
} }
switch (stateBufferObject->GetUsage()) { // glMapBufferRange or glBufferSubData
case BufferUsage::StaticDraw: Bool useInvalidationMap = !(stateBufferObject->GetChangeBits() & BufferChangeBits::ForbidInvalidationBit);
SyncToBackend_glBufferSubData(stateBufferObject); Bool useUnsynchronizedMap =
break; !(stateBufferObject->GetChangeBits() & BufferChangeBits::ForbidUnsynchronizationBit);
case BufferUsage::DynamicDraw: Bool useMapBufferRange = useInvalidationMap || useUnsynchronizedMap;
case BufferUsage::StreamDraw:
SyncToBackend_glMapBufferRange(stateBufferObject); if (!useMapBufferRange && PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC) {
break; auto usage = stateBufferObject->GetUsage();
default: if (usage == BufferUsage::DynamicDraw || usage == BufferUsage::StreamDraw ||
SyncToBackend_glBufferSubData(stateBufferObject); usage == BufferUsage::StreamCopy || usage == BufferUsage::DynamicCopy) {
break; useMapBufferRange = true;
}
} }
if (useMapBufferRange) {
MGLOG_D("Using glMapBufferRange to sync buffer with ID: %u", m_backendBufferId);
SyncToBackend_glMapBufferRange(stateBufferObject, useInvalidationMap, useUnsynchronizedMap);
} else {
MGLOG_D("Using glBufferSubData to sync buffer with ID: %u", m_backendBufferId);
SyncToBackend_glBufferSubData(stateBufferObject);
}
// Clear dirty state
stateBufferObject->ClearDirty(); stateBufferObject->ClearDirty();
m_prevBufferSize = bufferSize; m_prevBufferSize = bufferSize;
} }
@@ -92,7 +109,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId);
@@ -100,10 +116,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
SizeT size = stateBufferObject->GetSize(); SizeT size = stateBufferObject->GetSize();
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage()); GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); Bind();
MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage); MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage);
stateBufferObject->ClearDirty();
} }
void BackendBufferObject::SyncToBackend_glBufferSubData( void BackendBufferObject::SyncToBackend_glBufferSubData(
@@ -111,66 +125,74 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId);
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
// dirty range: [range.start, range.end) // dirty range: [range.start, range.end)
const auto& range = stateBufferObject->GetDirtyRange(); auto ranges = stateBufferObject->GetDirtyRanges();
if (range.end == 0) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
} }
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); for (const auto& range : ranges) {
Bind();
MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start, MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start,
reinterpret_cast<const char*>(data) + range.start); reinterpret_cast<const char*>(data) + range.start);
} }
}
void BackendBufferObject::SyncToBackend_glMapBufferRange( void BackendBufferObject::SyncToBackend_glMapBufferRange(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate) { SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId); MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
const auto& range = stateBufferObject->GetDirtyRange(); auto ranges = stateBufferObject->GetDirtyRanges();
if (range.end == 0) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
} }
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); SizeT minStart = ranges.GetOverallMinStart();
void* mappedData = SizeT maxEnd = ranges.GetOverallMaxEnd();
MG_External::GLES::glMapBufferRange(TempBufferTarget, range.start, range.end - range.start, Bind();
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : 0) | GL_MAP_WRITE_BIT); void* mappedData = MG_External::GLES::glMapBufferRange(
TempBufferTarget, minStart, maxEnd - minStart,
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
if (mappedData) { if (mappedData) {
Memcpy(mappedData, ((const char*)(data) + range.start), range.end - range.start);
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId); MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
Memcpy(mappedData, reinterpret_cast<const char*>(data) + minStart, maxEnd - minStart);
// Explicitly flush the dirty ranges
for (const auto& range : ranges) {
MG_External::GLES::glFlushMappedBufferRange(TempBufferTarget, range.start - minStart,
range.end - range.start);
}
MG_External::GLES::glUnmapBuffer(TempBufferTarget); MG_External::GLES::glUnmapBuffer(TempBufferTarget);
} else { } else {
MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId); MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId);
} }
} }
void BackendBufferObject::Bind() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
}
void BackendBufferObject::Bind(GLenum target) { void BackendBufferObject::Bind(GLenum target) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (target == GL_ARRAY_BUFFER) {
if (g_boundVertexBufferObject == this) {
return;
}
g_boundVertexBufferObject = this;
}
MG_External::GLES::glBindBuffer(target, m_backendBufferId); MG_External::GLES::glBindBuffer(target, m_backendBufferId);
} }
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects; UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
BackendBufferObject* g_boundVertexBufferObject = nullptr;
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
@@ -194,8 +216,25 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_External::GLES::glBindVertexArray(m_backendVAOId); MG_External::GLES::glBindVertexArray(m_backendVAOId);
} }
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, void BackendVertexArrayObject::BindAttributeBuffer(Uint index,
Bool needDivisor) { const MG_State::GLState::VertexAttribute& attrib) {
const auto& bufferObject = attrib.Buffer;
if (!bufferObject) {
MGLOG_W("Attribute has no bound buffer, skipping.");
return;
}
const 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.");
return;
}
const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER);
}
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -207,36 +246,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing VAO with backend ID %u to backend for state ID %u", m_backendVAOId, MGLOG_D("Syncing VAO with backend ID %u to backend for state ID %u", m_backendVAOId,
stateVAOObject->GetExternalIndex()); stateVAOObject->GetExternalIndex());
BufferImpl::BackendBufferBindingProtector backendBufferBindingProtector(BufferImpl::TempBufferTarget);
BackendVertexArrayBindingProtector backendVAOBindingProtector;
Bind(); Bind();
for (const auto& attribIndex : stateVAOObject->GetDirtyAttributeIndices()) { const auto& allAttributeVersions = stateVAOObject->GetAllAttributeVersions();
const auto& attrib = stateVAOObject->GetAttribute(attribIndex); const auto& allAttributes = stateVAOObject->GetAllAttributes();
for (Uint attribIndex = 0; attribIndex < allAttributes.size(); ++attribIndex) {
const auto& attrib = allAttributes[attribIndex];
Bool needsSyncSwitch = allAttributeVersions[attribIndex].SwitchVersion !=
m_syncedAttributeVersions[attribIndex].SwitchVersion;
if (needsSyncSwitch) {
if (attrib.Enabled) { if (attrib.Enabled) {
MGLOG_D("Binding attribute index %u for VAO ID: %u", attribIndex, m_backendVAOId);
MG_External::GLES::glEnableVertexAttribArray(attribIndex); MG_External::GLES::glEnableVertexAttribArray(attribIndex);
} else { } else {
MGLOG_D("Disabling attribute index %u for VAO ID: %u", attribIndex, m_backendVAOId);
MG_External::GLES::glDisableVertexAttribArray(attribIndex); MG_External::GLES::glDisableVertexAttribArray(attribIndex);
continue; }
} }
const auto& bufferObject = attrib.Buffer; Bool needsSyncFormat = allAttributeVersions[attribIndex].FormatVersion !=
if (!bufferObject) { m_syncedAttributeVersions[attribIndex].FormatVersion;
MGLOG_W("Attribute has no bound buffer, skipping."); Bool needsSyncBuffer = allAttributeVersions[attribIndex].BufferVersion !=
continue; m_syncedAttributeVersions[attribIndex].BufferVersion;
} if (!needsSyncFormat && !needsSyncBuffer) continue;
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject); BindAttributeBuffer(attribIndex, attrib);
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
continue;
}
const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER);
if (!attrib.IsInteger) { if (!attrib.IsInteger) {
MG_External::GLES::glVertexAttribPointer( MG_External::GLES::glVertexAttribPointer(
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type), attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
@@ -247,11 +280,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
attrib.Stride, (const void*)attrib.Offset); attrib.Stride, (const void*)attrib.Offset);
} }
if (needDivisor) { if (needsSyncFormat) {
MG_External::GLES::glVertexAttribDivisor(attribIndex, attrib.Divisor); MG_External::GLES::glVertexAttribDivisor(attribIndex, attrib.Divisor);
} }
} }
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (indexBufferBinding) { if (indexBufferBinding) {
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
@@ -262,8 +297,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer."); MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer.");
} }
} }
m_syncedIndexBufferVersion = currentIndexBufferVersion;
}
stateVAOObject->ClearDirtyAttributes(); m_syncedAttributeVersions = allAttributeVersions;
} }
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
@@ -284,11 +321,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendTextureObject::Bind(GLenum target) { void BackendTextureObject::Bind(GLenum target, Uint unit) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (g_activeTextureUnit != unit) {
ActivateTextureUnit(unit);
}
auto targetN = static_cast<SizeT>(MG_Util::ConvertGLEnumToTextureTarget(target));
if (this == g_boundTexturesCache[unit][targetN]) return;
MG_External::GLES::glBindTexture(target, m_backendTextureId); MG_External::GLES::glBindTexture(target, m_backendTextureId);
g_boundTexturesCache[unit][targetN] = this;
} }
Uint BackendTextureObject::GetBackendTextureId() { Uint BackendTextureObject::GetBackendTextureId() {
@@ -298,17 +343,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
return m_backendTextureId; return m_backendTextureId;
} }
void BackendTextureObject::SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { void BackendTextureObject::SyncMipmapsToBackend(
#ifdef TRACY_ENABLE SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) { if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend."); MGLOG_E("State texture object is null, cannot sync to backend.");
return; return;
} }
MGLOG_D("Syncing texture with backend ID %u to backend for state ID %u", m_backendTextureId, #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
stateTextureObject->GetExternalIndex()); stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget()); GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
@@ -328,11 +375,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
// 4. Mipmap levels changed // 4. Mipmap levels changed
if (!stateTextureObject->IsComplete()) { if (!stateTextureObject->IsComplete()) {
MGLOG_D("Texture object with ID: %u is not complete, skipping sync.", stateTextureObject->GetExternalIndex()); MGLOG_D("Texture object with ID: %u is not complete, skipping sync.",
stateTextureObject->GetExternalIndex());
return; return;
} }
// BackendTextureBindingProtector backendTextureBindingProtector(target);
Bind(target); Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
@@ -376,9 +423,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto* pData = (levelDirty && levelByteSize != 0) auto* pData = (levelDirty && levelByteSize != 0)
? textureMipmapObject->MapMipmapData(uploadTarget, level) ? textureMipmapObject->MapMipmapData(uploadTarget, level)
: nullptr; : nullptr;
MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s", __func__, MGLOG_D(
MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, "%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s",
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData, levelDirty ? "true" : "false"); __func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level,
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
levelDirty ? "true" : "false");
errorLopper.Clear(); errorLopper.Clear();
MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -386,29 +435,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
// TODO: handle more texture types // TODO: handle more texture types
switch (textureTarget) { switch (textureTarget) {
case TextureTarget::Texture2D: case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap: case TextureTarget::TextureCubeMap: {
{ MG_External::GLES::glTexImage2D(
MG_External::GLES::glTexImage2D(glUploadTarget, static_cast<GLint>(level), glInternalFormat, glUploadTarget, static_cast<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, 0, glFormat, glType, pData);
glType, pData);
break; break;
} }
case TextureTarget::Texture3D: { case TextureTarget::Texture3D: {
MG_External::GLES::glTexImage3D(glUploadTarget, static_cast<GLint>(level), glInternalFormat, MG_External::GLES::glTexImage3D(
static_cast<GLsizei>(levelTexelSize.x()), glUploadTarget, static_cast<GLint>(level), glInternalFormat,
static_cast<GLsizei>(levelTexelSize.y()), static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.z()), static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
0, glFormat,
glType, pData);
break; break;
} }
default: { default: {
MGLOG_E("Unhandled texture target %s", MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); MGLOG_E("Unhandled texture target %s",
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
} }
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget, glInternalFormat, glFormat, glType, pData](GLenum err) { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, type=%s, pixels=%p", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), glInternalFormat, glFormat, glType, pData](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
"type=%s, pixels=%p",
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(), MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(),
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(), MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
MG_Util::ConvertGLEnumToString(glFormat).c_str(), MG_Util::ConvertGLEnumToString(glFormat).c_str(),
@@ -493,8 +543,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto backendId = backendBufferObject->GetBackendBufferId(); auto backendId = backendBufferObject->GetBackendBufferId();
GLenum glInternalFormat, glType, glFormat; GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
&glFormat, &glType); &glType);
MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); MG_External::GLES::glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
break; break;
@@ -503,9 +553,54 @@ namespace MobileGL::MG_Backend::DirectGLES {
THROW_UNIMPL_EXCEPTION; THROW_UNIMPL_EXCEPTION;
} }
{ // Update built-in sampler parameters 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());
});
m_prevTextureInfo = currentTextureInfo;
}
void BackendTextureObject::SyncBuiltinSamplerToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend.");
return;
}
auto* samplerObject = stateTextureObject->GetSamplerObject().get();
Uint currentSamplerVersion = samplerObject->GetVersion();
if (m_syncedSamplerVersion == currentSamplerVersion) {
MGLOG_D("Sampler parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId);
return;
}
m_syncedSamplerVersion = currentSamplerVersion;
MGLOG_D("Syncing texture built-in sampler with backend ID %u to backend for state ID %u",
m_backendTextureId, stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
auto targetInternal = stateTextureObject->GetTarget();
MGLOG_D(" Texture target for syncing is %s",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
if (!IsSupportedTextureTarget(targetInternal)) {
MGLOG_E(" Texture target %s is not supported, skipping.",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
return;
}
Bind(target);
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());
});
// Update built-in sampler parameters
MGLOG_D("Updating sampler parameters for texture with ID: %u", m_backendTextureId); MGLOG_D("Updating sampler parameters for texture with ID: %u", m_backendTextureId);
const auto& samplerParams = stateTextureObject->GetSamplerObject()->GetAllSamplerParameters(); const auto& samplerParams = samplerObject->GetAllSamplerParameters();
#define SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \ #define SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \ if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
@@ -556,22 +651,56 @@ namespace MobileGL::MG_Backend::DirectGLES {
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED #undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
} }
{ // Update texture parameters void BackendTextureObject::SyncTextureParamsToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend.");
return;
}
Uint16 currentTextureParamsVersion = stateTextureObject->GetTextureParamsVersion();
if (m_syncedTextureParamsVersion == currentTextureParamsVersion) {
MGLOG_D("Texture parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId);
return;
}
m_syncedTextureParamsVersion = currentTextureParamsVersion;
MGLOG_D("Syncing texture params with backend ID %u to backend for state ID %u", m_backendTextureId,
stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
auto targetInternal = stateTextureObject->GetTarget();
MGLOG_D(" Texture target for syncing is %s",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
if (!IsSupportedTextureTarget(targetInternal)) {
MGLOG_E(" Texture target %s is not supported, skipping.",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
return;
}
Bind(target);
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());
});
// Update texture parameters
MGLOG_D("Updating texture parameters for texture with ID: %u", m_backendTextureId); MGLOG_D("Updating texture parameters for texture with ID: %u", m_backendTextureId);
const auto& levelRange = stateTextureObject->GetLevelRange(); const auto& levelRange = stateTextureObject->GetLevelRange();
if (m_cacheLodRange.x() != levelRange.x()) { if (m_cacheLodRange.x() != levelRange.x()) {
MG_External::GLES::glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, MG_External::GLES::glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
static_cast<GLint>(levelRange.x()));
m_cacheLodRange.x() = levelRange.x(); m_cacheLodRange.x() = levelRange.x();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (m_cacheLodRange.y() != levelRange.y()) { if (m_cacheLodRange.y() != levelRange.y()) {
MG_External::GLES::glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, MG_External::GLES::glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
static_cast<GLint>(levelRange.y()));
m_cacheLodRange.y() = levelRange.y(); m_cacheLodRange.y() = levelRange.y();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
@@ -608,13 +737,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { void ActivateTextureUnit(Uint unit) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); if (unit == g_activeTextureUnit) {
}); return;
}
m_prevTextureInfo = currentTextureInfo; MG_External::GLES::glActiveTexture(GL_TEXTURE0 + unit);
g_activeTextureUnit = unit;
} }
void UnbindTexture(Uint unit, GLenum target) { // Active unit will be modified
if (unit != g_activeTextureUnit) {
ActivateTextureUnit(unit);
}
auto targetN = static_cast<SizeT>(MG_Util::ConvertGLEnumToTextureTarget(target));
if (g_boundTexturesCache[unit][targetN] == nullptr) return;
MG_External::GLES::glBindTexture(target, 0);
g_boundTexturesCache[unit][targetN] = nullptr;
}
Uint g_activeTextureUnit = 0;
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundTexturesCache;
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects; g_backendTextureObjects;
} // namespace TextureImpl } // namespace TextureImpl
@@ -643,6 +789,42 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
Bool BackendFramebufferObject::SyncAttachmentObject(
GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment) {
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
return false;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glBackendAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
return true;
}
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget) { FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -655,129 +837,148 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing FBO with backend ID %u to backend for state ID %u, as %s FBO", m_backendFBOId, MGLOG_D("Syncing FBO with backend ID %u to backend for state ID %u, as %s FBO", m_backendFBOId,
stateFBOObject->GetExternalIndex(), (asTarget == FramebufferTarget::Draw ? "DRAW" : "READ")); stateFBOObject->GetExternalIndex(), (asTarget == FramebufferTarget::Draw ? "DRAW" : "READ"));
GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget);
BackendFramebufferBindingProtector backendFBOBindingProtector(glFBOTarget);
Bind(asTarget); Bind(asTarget);
// Handle all attachments // -------------------- Connect attachments (set buffers) -----------------------
const auto& attachments = stateFBOObject->GetAllAttachments(); // 1. Remap draw buffers
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachment = attachments[i];
if (!attachment.IsValid() || attachment.IsEmpty()) {
continue;
}
FramebufferAttachmentType type = static_cast<FramebufferAttachmentType>(i);
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(type);
if (attachment.IsTexture()) {
const auto& textureObject = attachment.GetTexture();
const 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;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachment.GetTextureLevel()));
} else if (attachment.IsRenderbuffer()) {
const auto& renderbufferObject = attachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
}
// Handle draw buffers for DRAW_FRAMEBUFFER
if (asTarget == FramebufferTarget::Draw) {
// Create mappings for draw buffers
int nBuffers = 0;
std::fill(m_frontendDrawBuffers,
m_frontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None);
std::fill(m_compactedFrontendDrawBuffers,
m_compactedFrontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None);
std::fill(m_backendDrawBuffers,
m_backendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers();
for (GLint i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; ++i) { Bool drawBufferClean = false;
if (stateDrawBuffers[i] == FramebufferAttachmentType::None) { if (memcmp(m_frontendDrawBuffers, stateDrawBuffers.data(),
m_frontendDrawBuffers[i] = FramebufferAttachmentType::None; FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) {
continue; drawBufferClean = true;
} }
m_frontendDrawBuffers[i] = stateDrawBuffers[i]; if (!drawBufferClean) {
memcpy(m_frontendDrawBuffers, stateDrawBuffers.data(),
FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType));
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
int nEffectiveBuffers = 0;
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
auto frontendBuf = stateDrawBuffers[i];
if (frontendBuf == FramebufferAttachmentType::None) {
m_backendDrawBuffers[i] = GL_NONE;
continue;
}
// Create compacted mapping // Create compacted mapping
m_backendDrawBuffers[nBuffers] = GL_COLOR_ATTACHMENT0 + nBuffers; if (frontendBuf == FramebufferAttachmentType::FrontLeft ||
m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i]; frontendBuf == FramebufferAttachmentType::FrontRight ||
nBuffers++; frontendBuf == FramebufferAttachmentType::BackLeft ||
} frontendBuf == FramebufferAttachmentType::BackRight) {
MGLOG_D("%s: frontend buf token found for default fbo, shouldn't remap", __func__);
MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers); m_backendDrawBuffers[i] = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendBuf);
stateFBOObject->ClearDrawBuffersDirtyState();
}
// Handle read buffer for READ_FRAMEBUFFER
else if (asTarget == FramebufferTarget::Read) {
m_frontendReadBuffer = stateFBOObject->GetReadBuffer();
GLenum frontendAtt = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer);
GLenum backendAtt = GL_NONE;
const auto& readAttachment = attachments[(SizeT)m_frontendReadBuffer];
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer);
if (!readAttachment.IsValid() || readAttachment.IsEmpty()) {
return;
}
if (readAttachment.IsTexture()) {
const auto& textureObject = readAttachment.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("ReadBuffer: No backend texture found for FBO attachment, cannot bind texture.");
return;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(readAttachment.GetTextureLevel()));
} else if (readAttachment.IsRenderbuffer()) {
const auto& renderbufferObject = readAttachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else { } else {
backendRenderbufferObject = backendRenderbufferIt->second; m_backendDrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
}
nEffectiveBuffers = i + 1;
}
MG_External::GLES::glDrawBuffers(nEffectiveBuffers, m_backendDrawBuffers);
} }
backendRenderbufferObject->SyncToBackend(renderbufferObject); // 2. Remap read buffer
backendRenderbufferObject->Bind(); auto frontendReadBuf = stateFBOObject->GetReadBuffer();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER, if (frontendReadBuf != m_frontendReadBuffer) {
backendRenderbufferObject->GetBackendRenderbufferId()); m_frontendReadBuffer = frontendReadBuf;
}
MG_External::GLES::glReadBuffer(glAttachment); GLenum glBackendReadBuffer = GetBackendAttachmentType(frontendReadBuf);
if (m_backendReadBuffer != glBackendReadBuffer) {
m_backendReadBuffer = glBackendReadBuffer;
MG_External::GLES::glReadBuffer(glBackendReadBuffer);
} }
} }
FramebufferAttachmentType BackendFramebufferObject::GetCompactedAttachmentTypeAtDrawBufferIndex(Int index) { // -------------------- Attach texture to backend FBO -----------------------
return m_compactedFrontendDrawBuffers[index]; const auto& attachments = stateFBOObject->GetAllAttachmentObjects();
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachmentObject = attachments[i];
FramebufferAttachmentType frontendType = static_cast<FramebufferAttachmentType>(i);
GLenum glBackendAttachment = GL_NONE;
if (frontendType >= FramebufferAttachmentType::Color0 &&
frontendType <= FramebufferAttachmentType::Color31)
glBackendAttachment = GetBackendAttachmentType(frontendType);
else
glBackendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendType);
// relevant FRONTEND!!! version should be checked and updated
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
}
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
else {
MGLOG_D("%s: Skipped SyncAttachmentObject(target=%s, frontendObj=(%dx%dx%d, %s), backendAtt=%s), "
"version = %u",
__func__, MG_Util::ConvertGLEnumToString(glFBOTarget).c_str(),
attachmentObject.GetSize().x(), attachmentObject.GetSize().y(),
attachmentObject.GetSize().z(),
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
m_syncedFrontendAttachmentVersions[i]);
GLint objectType = GL_NONE;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
MOBILEGL_ASSERT((objectType == GL_NONE) ||
(attachmentObject.IsTexture() && objectType == GL_TEXTURE) ||
(attachmentObject.IsRenderbuffer() && objectType == GL_RENDERBUFFER),
"Attachment type not match!");
GLint objectName = 0;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &objectName);
// Verify that the backend object's name and parameters match the frontend attachment state
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
"No backend texture found while framebuffer reports texture attachment.");
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
MOBILEGL_ASSERT(static_cast<GLint>(backendTexId) == objectName,
"Attachment texture name mismatch between GLES (%d) and backend texture object "
"(%d), frontend texture object ID=%d.",
objectName, backendTexId, textureObject->GetExternalIndex());
GLint texLevel = 0;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &texLevel);
MOBILEGL_ASSERT(texLevel == static_cast<GLint>(attachmentObject.GetTextureLevel()),
"Attachment texture level mismatch between GLES and state object.");
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
MOBILEGL_ASSERT(
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
"No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
GLuint backendRboId = backendRboIt->second->GetBackendRenderbufferId();
MOBILEGL_ASSERT(static_cast<GLint>(backendRboId) == objectName,
"Attachment renderbuffer name mismatch between GLES and state object.");
}
}
#endif
}
}
GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const {
GLenum glBackendReadBuffer = GL_NONE;
auto it = std::find(m_frontendDrawBuffers, m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS,
frontendAtt);
Bool notFound = (it == m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS);
if (notFound) {
MGLOG_D(
"%s: frontendAtt not found in draw buffer (probably not remapped), just use the same as frontend",
__func__);
glBackendReadBuffer = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendAtt);
} else {
MGLOG_D("%s: frontendAtt found in draw buffer, keep it consistent as in read buffers", __func__);
auto index = std::distance(m_frontendDrawBuffers, it);
glBackendReadBuffer = m_backendDrawBuffers[index];
}
return glBackendReadBuffer;
} }
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects; g_backendFramebufferObjects;
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
@@ -898,16 +1099,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = ProcessOutColorLocations(source); source = ProcessOutColorLocations(source);
source = ForceSupporterOutput(source); source = ForceSupporterOutput(source);
// TODO: probably a patch system? // Patch for Photon compiler precision issue
// String findStr = "if (distance_weight_sum == 0.0)";
// String replaceStr = "if (distance_weight_sum <= 0.0001)";
// auto pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #1 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
String findStr = "1000000.0"; String findStr = "1000000.0";
String replaceStr = "65500.0"; String replaceStr = "65500.0";
auto pos = source.find(findStr); auto pos = source.find(findStr);
@@ -917,24 +1109,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
pos = source.find(findStr, pos); pos = source.find(findStr, pos);
} }
// findStr = "if (gtao.w == 0.0)";
// replaceStr = "if (abs(gtao.w) <= 0.00001)";
// pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #3 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
// findStr = "== 0.0";
// replaceStr = "<= 0.00001";
// pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #4 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
const char* sourceCStr = source.c_str(); const char* sourceCStr = source.c_str();
MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr); MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr);
MG_External::GLES::glShaderSource(backendShaderId, 1, &sourceCStr, nullptr); MG_External::GLES::glShaderSource(backendShaderId, 1, &sourceCStr, nullptr);
@@ -1021,6 +1195,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
return; return;
} }
Uint currentSamplerVersion = stateSamplerObject->GetVersion();
if (m_isInitialized && m_syncedSamplerVersion == currentSamplerVersion) {
MGLOG_D("Sampler parameters have not changed for sampler ID: %u, skipping sync.",
stateSamplerObject->GetExternalIndex());
return;
}
m_syncedSamplerVersion = currentSamplerVersion;
MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId, MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId,
stateSamplerObject->GetExternalIndex()); stateSamplerObject->GetExternalIndex());
@@ -1069,7 +1252,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (g_boundSamplersCache[unit] == this) return;
MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), m_backendSamplerId); MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), m_backendSamplerId);
g_boundSamplersCache[unit] = this;
} }
Uint BackendSamplerObject::GetBackendSamplerId() { Uint BackendSamplerObject::GetBackendSamplerId() {
@@ -1079,6 +1265,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return m_backendSamplerId; return m_backendSamplerId;
} }
void UnbindSampler(Uint unit) {
if (g_boundSamplersCache[unit] == nullptr) return;
MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), 0);
g_boundSamplersCache[unit] = nullptr;
}
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
@@ -1129,8 +1323,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Int width = static_cast<Int>(stateRBOObject->GetWidth()); Int width = static_cast<Int>(stateRBOObject->GetWidth());
Int height = static_cast<Int>(stateRBOObject->GetHeight()); Int height = static_cast<Int>(stateRBOObject->GetHeight());
GLenum glInternalFormat, glType, glFormat; GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(internalFormat, &glInternalFormat, TextureImpl::GenerateTextureFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType);
&glFormat, &glType);
MG_External::GLES::glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, static_cast<GLsizei>(width), MG_External::GLES::glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, static_cast<GLsizei>(width),
static_cast<GLsizei>(height)); static_cast<GLsizei>(height));
+42 -22
View File
@@ -16,25 +16,26 @@
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl { namespace BufferImpl {
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
class BackendBufferObject { class BackendBufferObject {
public: public:
BackendBufferObject(); BackendBufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
Uint GetBackendBufferId() { return m_backendBufferId; } Uint GetBackendBufferId() { return m_backendBufferId; }
void Bind(); void Bind(GLenum target = TempBufferTarget);
void Bind(GLenum target);
private: private:
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
Bool invalidate = true); Bool invalidate = true, Bool unsynchronized = true);
Uint m_backendBufferId = 0; Uint m_backendBufferId = 0;
SizeT m_prevBufferSize = 0; SizeT m_prevBufferSize = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
extern BackendBufferObject* g_boundVertexBufferObject;
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
g_backendBufferObjects; g_backendBufferObjects;
} // namespace BufferImpl } // namespace BufferImpl
@@ -43,13 +44,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendVertexArrayObject { class BackendVertexArrayObject {
public: public:
BackendVertexArrayObject(); BackendVertexArrayObject();
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, Bool needDivisor); void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
Uint GetBackendVertexArrayId() { return m_backendVAOId; } Uint GetBackendVertexArrayId() { return m_backendVAOId; }
void Bind(); void Bind();
private: private:
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
Uint m_backendVAOId = 0; Uint m_backendVAOId = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
Uint16 m_syncedIndexBufferVersion = 0;
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
m_syncedAttributeVersions;
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
@@ -58,12 +64,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace TextureImpl { namespace TextureImpl {
inline Bool IsSupportedTextureTarget(TextureTarget target) { inline Bool IsSupportedTextureTarget(TextureTarget target) {
if (target == TextureTarget::Texture1D || if (target == TextureTarget::Texture1D || target == TextureTarget::TextureRectangle ||
target == TextureTarget::TextureRectangle || target == TextureTarget::Texture2DMultisampleArray || target == TextureTarget::Texture1DArray ||
target == TextureTarget::Texture2DMultisampleArray || target == TextureTarget::Texture2DMultisample || target == TextureTarget::Texture2DArray)
target == TextureTarget::Texture1DArray ||
target == TextureTarget::Texture2DMultisample ||
target == TextureTarget::Texture2DArray)
return false; return false;
return true; return true;
} }
@@ -85,11 +88,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); } bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); }
}; };
inline const Uint TempTextureUnit = 0;
class BackendTextureObject { class BackendTextureObject {
public: public:
BackendTextureObject(); BackendTextureObject();
void SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target); void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target, Uint unit = TempTextureUnit);
Uint GetBackendTextureId(); Uint GetBackendTextureId();
private: private:
@@ -101,10 +107,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f}; FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
Uint16 m_syncedSamplerVersion = 0;
Uint16 m_syncedTextureParamsVersion = 0;
}; };
void ActivateTextureUnit(Uint unit);
void UnbindTexture(Uint unit, GLenum target);
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects; g_backendTextureObjects;
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundTexturesCache;
extern Uint g_activeTextureUnit;
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {
@@ -115,7 +129,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
FramebufferTarget asTarget); FramebufferTarget asTarget);
Uint GetBackendFramebufferId() { return m_backendFBOId; } Uint GetBackendFramebufferId() { return m_backendFBOId; }
void Bind(FramebufferTarget target); void Bind(FramebufferTarget target);
FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment);
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
private: private:
Uint m_backendFBOId = 0; Uint m_backendFBOId = 0;
@@ -128,25 +146,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
*/ */
FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = { FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None}; FramebufferAttachmentType::None};
/* this will save buffers in its compacted GL form,
not consecutive is not allowed
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT5, COLOR_ATTACHMENT4]
(no GL_NONE among those)
*/
FramebufferAttachmentType
m_compactedFrontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None};
/* this will save buffers in stricter ES rules /* this will save buffers in stricter ES rules
reversion, absence or not consecutive are not allowed, according to ES spec reversion, absence or not consecutive are not allowed, according to ES spec
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, NONE, ...] i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, COLOR_ATTACHMENT3, ...]
this array could be provided as data directly to ES `glDrawBuffers` function this array could be provided as data directly to ES `glDrawBuffers` function
*/ */
GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE}; GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE};
FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0; FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0;
GLenum m_backendReadBuffer = GL_COLOR_ATTACHMENT0;
using FramebufferObject = MG_State::GLState::FramebufferObject;
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects; g_backendFramebufferObjects;
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
@@ -181,8 +196,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint m_backendSamplerId = 0; Uint m_backendSamplerId = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
SamplerParameters m_cacheSamplerParameters; SamplerParameters m_cacheSamplerParameters;
Uint16 m_syncedSamplerVersion = 0;
}; };
void UnbindSampler(Uint unit);
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundSamplersCache;
extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
+7 -90
View File
@@ -19,108 +19,25 @@
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl { namespace BufferImpl {} // namespace BufferImpl
BackendBufferBindingProtector::BackendBufferBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendBufferBindingProtector::~BackendBufferBindingProtector() { namespace VertexArrayImpl {} // namespace VertexArrayImpl
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindBuffer(m_target, m_previousBinding);
}
} // namespace BufferImpl
namespace VertexArrayImpl {
BackendVertexArrayBindingProtector::BackendVertexArrayBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &m_previousBinding);
}
BackendVertexArrayBindingProtector::~BackendVertexArrayBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindVertexArray(m_previousBinding);
}
} // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
BackendTextureBindingProtector::BackendTextureBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, true), &m_previousBinding);
}
BackendTextureBindingProtector::~BackendTextureBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindTexture(m_target, m_previousBinding);
}
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
GLenum* outFormat, GLenum* outType) { GLenum* outFormat, GLenum* outType) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
using namespace MobileGL::MG_Util::TextureFormatProcessor; using namespace MobileGL::MG_Util::TextureFormatProcessor;
auto options = auto options = (MG_External::GLES::g_glesCaps.hasNorm16Texture) ? PixelFormatNormalizeOptionBit::None
(MG_External::GLES::g_glesCaps.hasNorm16Texture) ? PixelFormatNormalizeOptionBit::None : PixelFormatNormalizeOptionBit::NoNorm16; : PixelFormatNormalizeOptionBit::NoNorm16;
NormalizePixelFormat( NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), options,
MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), outInternalFormat, outFormat, outType);
options,
outInternalFormat,
outFormat, outType);
} }
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {} // namespace FramebufferImpl
BackendFramebufferBindingProtector::BackendFramebufferBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendFramebufferBindingProtector::~BackendFramebufferBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindFramebuffer(m_target, m_previousBinding);
}
GLuint BackendFramebufferBindingProtector::GetTempFBO(FramebufferTarget target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
GLenum glTarget = MG_Util::ConvertFramebufferTargetToGLEnum(target);
GLuint& fbo = (glTarget == GL_DRAW_FRAMEBUFFER) ? s_tempDrawFBO : s_tempReadFBO;
if (fbo == 0) {
MG_External::GLES::glGenFramebuffers(1, &fbo);
}
return fbo;
}
void BackendFramebufferBindingProtector::BindTempFBO(MobileGL::FramebufferTarget target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
GLuint fbo = GetTempFBO(target);
GLenum glTarget = MG_Util::ConvertFramebufferTargetToGLEnum(target);
MG_External::GLES::glBindFramebuffer(glTarget, fbo);
}
} // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode) { String ProcessOutColorLocations(const String& glslCode) {
+2 -50
View File
@@ -27,66 +27,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
}; };
} // namespace DebugImpl } // namespace DebugImpl
namespace BufferImpl { namespace BufferImpl {} // namespace BufferImpl
class BackendBufferBindingProtector {
public:
BackendBufferBindingProtector(GLenum target);
~BackendBufferBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
} // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
GLenum GetBindingQuery(GLenum target, bool isTexture); GLenum GetBindingQuery(GLenum target, bool isTexture);
class BackendVertexArrayBindingProtector {
public:
BackendVertexArrayBindingProtector();
~BackendVertexArrayBindingProtector();
private:
GLint m_previousBinding = 0;
};
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
class BackendTextureBindingProtector {
public:
BackendTextureBindingProtector(GLenum target);
~BackendTextureBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
GLenum* outFormat, GLenum* outType); GLenum* outFormat, GLenum* outType);
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {} // namespace FramebufferImpl
class BackendFramebufferBindingProtector {
public:
BackendFramebufferBindingProtector(GLenum target);
~BackendFramebufferBindingProtector();
static GLuint GetTempFBO(FramebufferTarget target);
static void BindTempFBO(FramebufferTarget target);
private:
GLenum m_target;
GLint m_previousBinding = 0;
inline static GLuint s_tempReadFBO = 0;
inline static GLuint s_tempDrawFBO = 0;
};
} // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode); String ProcessOutColorLocations(const String& glslCode);
@@ -174,47 +174,41 @@ namespace MobileGL {
return MG_External::EGL::eglCreateSync(dpy, type, attrib_list); return MG_External::EGL::eglCreateSync(dpy, type, attrib_list);
} }
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync) { EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync) {
return MG_External::EGL::eglDestroySync(dpy, sync); return MG_External::EGL::eglDestroySync(dpy, sync);
} }
EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) {
return MG_External::EGL::eglClientWaitSync(dpy, sync, flags, timeout); return MG_External::EGL::eglClientWaitSync(dpy, sync, flags, timeout);
} }
EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) { EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) {
return MG_External::EGL::eglGetSyncAttrib(dpy, sync, attribute, value); return MG_External::EGL::eglGetSyncAttrib(dpy, sync, attribute, value);
} }
EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list) { const EGLAttrib* attrib_list) {
return MG_External::EGL::eglCreateImage(dpy, ctx, target, buffer, attrib_list); return MG_External::EGL::eglCreateImage(dpy, ctx, target, buffer, attrib_list);
} }
EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image) { EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image) {
return MG_External::EGL::eglDestroyImage(dpy, image); return MG_External::EGL::eglDestroyImage(dpy, image);
} }
EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list) { EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list) {
return MG_External::EGL::eglGetPlatformDisplay(platform, native_display, attrib_list); return MG_External::EGL::eglGetPlatformDisplay(platform, native_display, attrib_list);
} }
EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window,
EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list) { const EGLAttrib* attrib_list) {
return MG_External::EGL::eglCreatePlatformWindowSurface(dpy, config, native_window, attrib_list); return MG_External::EGL::eglCreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
} }
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list) { const EGLAttrib* attrib_list) {
return MG_External::EGL::eglCreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list); return MG_External::EGL::eglCreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list);
} }
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) { EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) {
return MG_External::EGL::eglWaitSync(dpy, sync, flags); return MG_External::EGL::eglWaitSync(dpy, sync, flags);
} }
@@ -53,11 +53,14 @@ namespace MobileGL {
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync); EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync);
EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value); EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value);
EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list); EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
const EGLAttrib* attrib_list);
EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image); EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image);
EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list); EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list);
EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list); EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window,
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list); const EGLAttrib* attrib_list);
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
const EGLAttrib* attrib_list);
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags); EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);
} // namespace MG_Impl::EGLImpl } // namespace MG_Impl::EGLImpl
} // namespace MobileGL } // namespace MobileGL
+2 -2
View File
@@ -525,8 +525,7 @@ namespace MobileGL {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex); auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex);
point.Bind(bufferObject); point.Bind(bufferObject);
point.SetRange(Range1D(0, bufferObject->GetSize())); point.SetRange(Range1D(0, bufferObject->GetSize()));
MGLOG_D("%s: set range (0, %d)", __func__, MGLOG_D("%s: set range (0, %d)", __func__, bufferObject->GetSize());
bufferObject->GetSize());
} }
void BindBufferRange_State(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { void BindBufferRange_State(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) {
@@ -575,6 +574,7 @@ namespace MobileGL {
return MapBuffer_State(target, access); return MapBuffer_State(target, access);
} }
// FIXME: this should be a "backend" function
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size) { GLsizeiptr size) {
CopyBufferSubData_State(readTarget, writeTarget, readOffset, writeOffset, size); CopyBufferSubData_State(readTarget, writeTarget, readOffset, writeOffset, size);
+12 -6
View File
@@ -12,16 +12,22 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
GLsizei stride);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, GLint basevertex); void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex); GLsizei instancecount, GLint basevertex, GLuint baseinstance);
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLuint baseinstance); void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex);
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLuint baseinstance);
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount); void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect); void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
void DrawArraysIndirect(GLenum mode, const void* indirect); void DrawArraysIndirect(GLenum mode, const void* indirect);
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex); void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
@@ -304,6 +304,25 @@ namespace MobileGL {
} }
} }
void ReadBuffer_State(GLenum mode) {
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(mode);
// ------------------- Check validity begin ------------------------
if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("`mode` = {} is not an accepted value.",
MG_Util::ConvertGLEnumToString(mode))));
return;
}
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto fbo = bindingSlot.GetBoundObject();
fbo->SetReadBuffer(attType);
}
void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -575,6 +594,10 @@ namespace MobileGL {
DrawBuffers_State(n, bufs); DrawBuffers_State(n, bufs);
} }
void ReadBuffer(GLenum src) {
ReadBuffer_State(src);
}
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
DeleteRenderbuffers_State(n, renderbuffers); DeleteRenderbuffers_State(n, renderbuffers);
} }
@@ -46,6 +46,7 @@ namespace MobileGL {
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void DrawBuffer(GLenum buf); void DrawBuffer(GLenum buf);
void DrawBuffers(GLsizei n, const GLenum* bufs); void DrawBuffers(GLsizei n, const GLenum* bufs);
void ReadBuffer(GLenum src);
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers); void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
GLenum CheckFramebufferStatus(GLenum target); GLenum CheckFramebufferStatus(GLenum target);
+2 -2
View File
@@ -567,7 +567,7 @@ namespace MobileGL {
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackImageHeight); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackImageHeight);
break; break;
case GL_PACK_LSB_FIRST: case GL_PACK_LSB_FIRST:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackLsbFirst); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackLSBFirst);
break; break;
case GL_PACK_ROW_LENGTH: case GL_PACK_ROW_LENGTH:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackRowLength); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackRowLength);
@@ -839,7 +839,7 @@ namespace MobileGL {
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackImageHeight); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackImageHeight);
break; break;
case GL_UNPACK_LSB_FIRST: case GL_UNPACK_LSB_FIRST:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackLsbFirst); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackLSBFirst);
break; break;
case GL_UNPACK_ROW_LENGTH: case GL_UNPACK_ROW_LENGTH:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackRowLength); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackRowLength);
@@ -516,15 +516,15 @@ namespace MobileGL {
void Uniform_State(MG_State::GLState::ProgramObject& programObject, GLuint location, T* value, void Uniform_State(MG_State::GLState::ProgramObject& programObject, GLuint location, T* value,
SizeT byteOffsetInsideUniform = 0) { SizeT byteOffsetInsideUniform = 0) {
if (!programObject.IsUniformOpaqueAtLocation(location)) { if (!programObject.IsUniformOpaqueAtLocation(location)) {
MGLOG_D("%s: program = %d, location = %d, maxLocation = %d", __func__, MGLOG_D("%s: program = %d, location = %d, maxLocation = %d", __func__, programObject.GetExternalIndex(),
programObject.GetExternalIndex(), location, programObject.GetMaxUniformLocation()); location, programObject.GetMaxUniformLocation());
auto size = programObject.GetUniformSizesInBytes(location); auto size = programObject.GetUniformSizesInBytes(location);
auto offset = programObject.GetUniformOffset(location); auto offset = programObject.GetUniformOffset(location);
MOBILEGL_ASSERT(size >= ItemCount * sizeof(T), MOBILEGL_ASSERT(size >= ItemCount * sizeof(T),
"Uniform size mismatch, expected at least %zu bytes, got %zu bytes.", "Uniform size mismatch, expected at least %zu bytes, got %zu bytes.",
ItemCount * sizeof(T), size); ItemCount * sizeof(T), size);
MGLOG_D("%s: program = %d, location = %d, byteOffset = %d", __func__, MGLOG_D("%s: program = %d, location = %d, byteOffset = %d", __func__, programObject.GetExternalIndex(),
programObject.GetExternalIndex(), location, offset + byteOffsetInsideUniform); location, offset + byteOffsetInsideUniform);
Memcpy((char*)programObject.MapUBO() + offset + byteOffsetInsideUniform, value, ItemCount * sizeof(T)); Memcpy((char*)programObject.MapUBO() + offset + byteOffsetInsideUniform, value, ItemCount * sizeof(T));
} else { } else {
auto* ttype = programObject.GetUniformTType(location); auto* ttype = programObject.GetUniformTType(location);
@@ -241,10 +241,6 @@ namespace MobileGL {
// TODO: implement // TODO: implement
} }
void ReadBuffer_State(GLenum src) {
// TODO: implement
}
void ClearStencil_State(GLint s) { void ClearStencil_State(GLint s) {
// TODO: implement // TODO: implement
} }
@@ -390,10 +386,6 @@ namespace MobileGL {
BlendColor_State(red, green, blue, alpha); BlendColor_State(red, green, blue, alpha);
} }
void ReadBuffer(GLenum src) {
ReadBuffer_State(src);
}
void ClearStencil(GLint s) { void ClearStencil(GLint s) {
ClearStencil_State(s); ClearStencil_State(s);
} }
@@ -45,7 +45,6 @@ namespace MobileGL {
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
void BlendEquation(GLenum mode); void BlendEquation(GLenum mode);
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void ReadBuffer(GLenum src);
void ClearStencil(GLint s); void ClearStencil(GLint s);
void ClearDepth(GLclampd depth); void ClearDepth(GLclampd depth);
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+81 -34
View File
@@ -7,26 +7,27 @@
// End of Source File Header // End of Source File Header
#include "GL_Texture.h" #include "GL_Texture.h"
#include "GL/gl.h"
#include "Config.h" #include "Config.h"
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
#include <MG_Backend/DirectGLES/DirectGLES.h>
#endif
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include "Validators.h" #include "Validators.h"
#include "ProxyTexture.h" #include "ProxyTexture.h"
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
#include "MG_Util/Texture/TextureFormatProcessor.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_Util/Metrics/TextureMetrics.h> #include <MG_Util/Metrics/TextureMetrics.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Texture/PixelStoreProcessor.h> #include <MG_Util/Texture/PixelStoreProcessor.h>
#include <MG_Util/Texture/TextureFormatProcessor.h>
#include <MG_Util/Classifiers/TextureEnumClassifier.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h> #include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
#include <MG_Backend/DirectGLES/DirectGLES.h>
#endif
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
@@ -63,8 +64,7 @@ namespace MobileGL {
// TextureInternalFormat textureInternalFormat = // TextureInternalFormat textureInternalFormat =
// MG_Util::ConvertGLEnumToTextureInternalFormat(format); // MG_Util::ConvertGLEnumToTextureInternalFormat(format);
MGLOG_D("TexSubImage2D_State: target = %s, level = %d, (%d, %d), format = %s, pixels = %p", MGLOG_D("TexSubImage2D_State: target = %s, level = %d, (%d, %d), format = %s, pixels = %p",
MG_Util::ConvertGLEnumToString(target).c_str(), level, MG_Util::ConvertGLEnumToString(target).c_str(), level, width, height,
width, height,
MG_Util::ConvertTextureInputFormatToString(textureInputFormat).c_str(), pixels); MG_Util::ConvertTextureInputFormatToString(textureInputFormat).c_str(), pixels);
// ===================== Error Checking ============================== // ===================== Error Checking ==============================
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return; if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
@@ -502,14 +502,18 @@ namespace MobileGL {
GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) { GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) {
MGLOG_D( MGLOG_D(
"%s called with target: %s, level: %d, internalformat: %s, width: %d, height: %d, depth: %d, " "%s called with target: %s, level: %d, internalformat: %s, width: %d, height: %d, depth: %d, "
"border: %d, format: %s, type: %s (%u), pixels: %p", __func__, "border: %d, format: %s, type: %s (%u), pixels: %p",
MG_Util::ConvertTextureUploadTargetToString(MG_Util::ConvertGLEnumToTextureUploadTarget(target)).c_str(), __func__,
MG_Util::ConvertTextureUploadTargetToString(MG_Util::ConvertGLEnumToTextureUploadTarget(target))
.c_str(),
level, level,
MG_Util::ConvertTextureInternalFormatToString( MG_Util::ConvertTextureInternalFormatToString(
MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat)).c_str(), MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat))
.c_str(),
width, height, depth, border, width, height, depth, border,
MG_Util::ConvertTextureInputFormatToString(MG_Util::ConvertGLEnumToTextureInputFormat(format)).c_str(), MG_Util::ConvertTextureInputFormatToString(MG_Util::ConvertGLEnumToTextureInputFormat(format)).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(MG_Util::ConvertGLEnumToTexturePixelDataType(type)).c_str(), MG_Util::ConvertTexturePixelDataTypeToString(MG_Util::ConvertGLEnumToTexturePixelDataType(type))
.c_str(),
type, pixels); type, pixels);
// ======================= Converting ================================ // ======================= Converting ================================
TextureUploadTarget textureUploadingTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target); TextureUploadTarget textureUploadingTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
@@ -580,13 +584,13 @@ namespace MobileGL {
reinterpret_cast<SizeT>(pixels); reinterpret_cast<SizeT>(pixels);
} }
MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get()), MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(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<MG_State::GLState::TextureObjectMipmap*>(textureObject.get()); auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
// Allocate in TextureObject // Allocate in TextureObject
textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, depth}, internalBytes}); textureMipmapObject->AllocateStorage(textureUploadingTarget, level,
{{width, height, depth}, internalBytes});
if (!originalPixels) { if (!originalPixels) {
MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__); MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__);
@@ -601,8 +605,8 @@ namespace MobileGL {
if (processedPixels && imageSize > 0) { if (processedPixels && imageSize > 0) {
if (imageSize != internalBytes) { if (imageSize != internalBytes) {
MGLOG_W("%s: Processed pixel data size (%zu) does not match expected size (%zu). " MGLOG_W("%s: Processed pixel data size (%zu) does not match expected size (%zu). "
"This may indicate an alignment or processing issue.", __func__, "This may indicate an alignment or processing issue.",
imageSize, internalBytes); __func__, imageSize, internalBytes);
} }
const SizeT copySize = std::min(imageSize, internalBytes); const SizeT copySize = std::min(imageSize, internalBytes);
@@ -623,20 +627,16 @@ namespace MobileGL {
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format); TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type); TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat); TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
MGLOG_D( MGLOG_D("%s called with target: %s (%s), level: %d, internalformat: %s (%s), width: %d, height: %d, "
"%s called with target: %s (%s), level: %d, internalformat: %s (%s), width: %d, height: %d, " "border: %d, format: %s (%s), type: %s (%s), pixels: %p",
"border: %d, format: %s (%s), type: %s (%s), pixels: %p", __func__, __func__, MG_Util::ConvertTextureUploadTargetToString(textureUploadingTarget).c_str(),
MG_Util::ConvertTextureUploadTargetToString(textureUploadingTarget).c_str(), MG_Util::ConvertGLEnumToString(target).c_str(), level,
MG_Util::ConvertGLEnumToString(target).c_str(),
level,
MG_Util::ConvertTextureInternalFormatToString(textureInternalFormat).c_str(), MG_Util::ConvertTextureInternalFormatToString(textureInternalFormat).c_str(),
MG_Util::ConvertGLEnumToString(internalformat).c_str(), MG_Util::ConvertGLEnumToString(internalformat).c_str(), width, height, border,
width, height, border,
MG_Util::ConvertTextureInputFormatToString(textureInputFormat).c_str(), MG_Util::ConvertTextureInputFormatToString(textureInputFormat).c_str(),
MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(texturePixelDataType).c_str(), MG_Util::ConvertTexturePixelDataTypeToString(texturePixelDataType).c_str(),
MG_Util::ConvertGLEnumToString(type).c_str(), MG_Util::ConvertGLEnumToString(type).c_str(), pixels);
pixels);
// ===================== Error Checking ============================== // ===================== Error Checking ==============================
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return; if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return; if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
@@ -661,7 +661,8 @@ namespace MobileGL {
// indicated by type. // indicated by type.
// ======================= Processing ================================ // ======================= Processing ================================
textureInternalFormat = MG_Util::ConvertInternalFormatToSized(textureInternalFormat, textureInputFormat, texturePixelDataType); textureInternalFormat =
MG_Util::ConvertInternalFormatToSized(textureInternalFormat, textureInputFormat, texturePixelDataType);
SharedPtr<MG_State::GLState::ITextureObject> textureObject = nullptr; SharedPtr<MG_State::GLState::ITextureObject> textureObject = nullptr;
Bool isProxy = TextureImpl::IsProxyTextureTarget(textureUploadingTarget); Bool isProxy = TextureImpl::IsProxyTextureTarget(textureUploadingTarget);
if (isProxy) { if (isProxy) {
@@ -714,9 +715,6 @@ namespace MobileGL {
MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level); MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level);
textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, internalBytes}); textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, internalBytes});
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
if (!originalPixels) { if (!originalPixels) {
MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__); MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__);
return; return;
@@ -740,6 +738,9 @@ namespace MobileGL {
} }
free(processedPixels); free(processedPixels);
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
} }
void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border,
@@ -1228,11 +1229,57 @@ namespace MobileGL {
void CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) { GLsizei height, GLint border) {
GLenum outInternalFormat, format, type; auto internalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
MG_Util::TextureFormatProcessor::NormalizePixelFormat(internalformat, 0, &outInternalFormat, &format, &type); const auto& currentReadFBO =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (!currentReadFBO) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", "CopyTexImage2D_State",
"No framebuffer is currently bound to the GL_READ_FRAMEBUFFER target."));
return;
}
Bool isDepth = MG_Util::IsDepthFormatInternalFormat(internalFormat);
Bool isStencil = MG_Util::IsStencilFormatInternalFormat(internalFormat);
TextureInternalFormat srcInternalFormat = TextureInternalFormat::Unknown;
#define GET_SRC_INTERNAL_FORMAT(AttachmentType) \
const auto& srcAttachment = currentReadFBO->GetAttachment(AttachmentType); \
if (srcAttachment.IsTexture()) { \
const auto& texObj = srcAttachment.GetTexture(); \
srcInternalFormat = texObj->GetFormat(); \
} else if (srcAttachment.IsRenderbuffer()) { \
const auto& rboObj = srcAttachment.GetRenderbuffer(); \
srcInternalFormat = rboObj->GetInternalFormat(); \
} else { \
MG_State::pGLContext->RecordError( \
ErrorCode::InvalidOperation, \
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyTexImage2D_State", \
"The attachment specified by the read buffer is incomplete.")); \
return; \
}
if (isDepth) {
GET_SRC_INTERNAL_FORMAT(FramebufferAttachmentType::Depth);
} else if (isStencil) {
GET_SRC_INTERNAL_FORMAT(FramebufferAttachmentType::Stencil);
} else {
const auto& readBufferType = currentReadFBO->GetReadBuffer();
GET_SRC_INTERNAL_FORMAT(readBufferType);
}
if (!TextureImpl::ValidateBaseInternalFormatMatch(internalFormat, srcInternalFormat))
THROW_UNIMPL_EXCEPTION;
GLenum outInternalFormat = MG_Util::ConvertTextureInternalFormatToGLEnum(srcInternalFormat);
GLenum realInternalFormat = GL_RGBA8;
GLenum format = GL_DEPTH_COMPONENT;
GLenum type = GL_UNSIGNED_INT;
MG_Util::TextureFormatProcessor::NormalizePixelFormat(
outInternalFormat, PixelFormatNormalizeOptionBit::None, &realInternalFormat, &format, &type);
const auto pixelUnpackBufferObject = const auto pixelUnpackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject();
TexImage2D_State(target, level, outInternalFormat, width, height, border, format, type, nullptr); TexImage2D_State(target, level, realInternalFormat, width, height, border, format, type, nullptr);
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).Bind(pixelUnpackBufferObject); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).Bind(pixelUnpackBufferObject);
} }
+26 -6
View File
@@ -7,13 +7,12 @@
// End of Source File Header // End of Source File Header
#include "Validators.h" #include "Validators.h"
#include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_Util/Types.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl {
@@ -170,7 +169,9 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
return true; return true;
} }
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, TextureInternalFormat internalFormat,
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
TextureInternalFormat internalFormat,
TexturePixelDataType type) { TexturePixelDataType type) {
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev || if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev || type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
@@ -178,7 +179,8 @@ namespace MobileGL::MG_Impl::GLImpl {
if (format != TextureInputFormat::RGB) { if (format != TextureInputFormat::RGB) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type")); "Invalid format for the given type"));
return false; return false;
} }
@@ -193,7 +195,8 @@ namespace MobileGL::MG_Impl::GLImpl {
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) { if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type")); "Invalid format for the given type"));
return false; return false;
} }
@@ -206,7 +209,8 @@ namespace MobileGL::MG_Impl::GLImpl {
if (format != TextureInputFormat::DepthComponent) { if (format != TextureInputFormat::DepthComponent) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for depth component internal format")); "Invalid format for depth component internal format"));
return false; return false;
} }
@@ -299,5 +303,21 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
return true; return true;
} }
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
if (unsizedFormat1 != unsizedFormat2) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>(
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
"The base internal format of the two formats do not match ({} vs. {})",
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
return false;
}
return true;
} // namespace TextureImpl
} // namespace TextureImpl } // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
+4 -1
View File
@@ -7,6 +7,7 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h> #include <MG_State/GLState/TextureState/TextureObject.h>
@@ -23,7 +24,8 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth); Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth);
Bool ValidateTextureInternalFormat(TextureInternalFormat format); Bool ValidateTextureInternalFormat(TextureInternalFormat format);
Bool ValidateTextureBorderNumber(Int border); Bool ValidateTextureBorderNumber(Int border);
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, TextureInternalFormat internalFormat, Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
TextureInternalFormat internalFormat,
TexturePixelDataType type); TexturePixelDataType type);
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level); Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject); Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
@@ -31,5 +33,6 @@ namespace MobileGL::MG_Impl::GLImpl {
TextureTarget target); TextureTarget target);
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset, Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0); Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
} // namespace TextureImpl } // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
@@ -14,14 +14,18 @@ namespace MobileGL {
namespace GLState { namespace GLState {
BufferObject::BufferObject(Uint externalIndex) BufferObject::BufferObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false), : m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
m_mappingAccess(BufferMappingAccessBit::Null), m_dirtyRange({0, 0}), m_mappedRange({0, 0}), m_mappingAccess(BufferMappingAccessBit::Null),
m_dataPtr(MakeShared<Data>()) {} m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
m_dataPtr(MakeShared<Data>()) {
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
}
void BufferObject::Resize(SizeT size) { void BufferObject::Resize(SizeT size) {
m_size = size; m_size = size;
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
m_dataPtr->resize(size); m_dataPtr->resize(size);
m_dirtyRange = {0, 0}; m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
} }
void BufferObject::UploadData(DataPtr data, SizeT atOffset) { void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
@@ -30,7 +34,14 @@ namespace MobileGL {
data.size, m_size); data.size, m_size);
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped.");
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
// This function may be called by `glBufferData`, but we still set the forbid bits above,
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
// The bits can fit the `glBufferSubData` semantics
// (though `glBufferSubData` calls `UploadSubData` instead).
} }
void BufferObject::SetUsage(BufferUsage usage) { void BufferObject::SetUsage(BufferUsage usage) {
@@ -44,7 +55,8 @@ namespace MobileGL {
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
m_mappedRange.end - m_mappedRange.start); m_mappedRange.end - m_mappedRange.start);
m_dirtyRange.UnionUpdate(m_mappedRange.start, m_mappedRange.end); m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
m_stagingData.clear(); m_stagingData.clear();
@@ -69,7 +81,8 @@ namespace MobileGL {
"Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end); "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end);
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
m_dirtyRange.UnionUpdate(start, end); m_change.DirtyRanges.Add({start, end});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) { void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
@@ -79,7 +92,10 @@ namespace MobileGL {
atOffset, data.size, m_size); atOffset, data.size, m_size);
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
} }
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset,
@@ -95,7 +111,8 @@ namespace MobileGL {
const Uint8* srcData = src->m_dataPtr->data() + srcOffset; const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
Memcpy(m_dataPtr->data() + dstOffset, srcData, size); Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
m_dirtyRange.UnionUpdate(dstOffset, dstOffset + size); m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) { void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
@@ -144,6 +161,14 @@ namespace MobileGL {
m_ownsStagingData = false; m_ownsStagingData = false;
return m_dataPtr->data() + range.start; return m_dataPtr->data() + range.start;
} }
m_change.Bits |= !(access & BufferMappingAccessBit::InvalidateBuffer ||
access & BufferMappingAccessBit::InvalidateRange)
? BufferChangeBits::ForbidInvalidationBit
: BufferChangeBits::None;
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
? BufferChangeBits::ForbidUnsynchronizationBit
: BufferChangeBits::None;
} }
const SharedPtr<Data> BufferObject::GetDataReadOnly() const { const SharedPtr<Data> BufferObject::GetDataReadOnly() const {
@@ -151,7 +176,8 @@ namespace MobileGL {
} }
void BufferObject::ClearDirty() { void BufferObject::ClearDirty() {
m_dirtyRange = {0, 0}; m_change.DirtyRanges.clear();
m_change.Bits = BufferChangeBits::None;
} }
SizeT BufferObject::GetSize() const { SizeT BufferObject::GetSize() const {
@@ -162,8 +188,12 @@ namespace MobileGL {
return m_usage; return m_usage;
} }
Range1D BufferObject::GetDirtyRange() const { const VecRange1D& BufferObject::GetDirtyRanges() const {
return m_dirtyRange; return m_change.DirtyRanges;
}
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
return m_change.Bits;
} }
Bool BufferObject::IsMapped() const { Bool BufferObject::IsMapped() const {
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h>
namespace MobileGL { namespace MobileGL {
enum class BufferTarget { enum class BufferTarget {
@@ -55,6 +56,23 @@ namespace MobileGL {
Coherent = 0x80 Coherent = 0x80
}; };
enum class BufferChangeBits : Uint8 {
None = 0,
DirtyBit = 1 << 0, // When not set, bits below are ignored and nothing should be synced to backend
PreferReallocationBit =
1 << 1, // <=> `glBufferData`; When set, ForbidInvalidationBit and ForbidUnsynchronizationBit are ignored
ForbidInvalidationBit = 1 << 2, // Indidate that invalidation flags were not used during mapping, else we're
// allowed to act as `GL_MAP_INVALIDATE_*` in backend
ForbidUnsynchronizationBit = 1 << 3, // (the same description as above, but for unsynchronization)
};
struct BufferChange {
static constexpr int DEFAULT_RESERVED_DIRTY_RANGES_COUNT = 50;
Flags<BufferChangeBits> Bits = BufferChangeBits::None;
VecRange1D DirtyRanges;
};
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class BufferObject { class BufferObject {
@@ -77,11 +95,12 @@ namespace MobileGL {
Bool IsMapped() const; Bool IsMapped() const;
SizeT GetSize() const; SizeT GetSize() const;
BufferUsage GetUsage() const; BufferUsage GetUsage() const;
Range1D GetDirtyRange() const;
Range1D GetMappedRange() const; Range1D GetMappedRange() const;
const SharedPtr<Data> GetDataReadOnly() const; const SharedPtr<Data> GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const; Flags<BufferMappingAccessBit> GetMappingAccess() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
const VecRange1D& GetDirtyRanges() const;
Flags<BufferChangeBits> GetChangeBits() const;
private: private:
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
@@ -90,7 +109,7 @@ namespace MobileGL {
SharedPtr<Data> m_dataPtr; SharedPtr<Data> m_dataPtr;
Bool m_isMapped; Bool m_isMapped;
Flags<BufferMappingAccessBit> m_mappingAccess; Flags<BufferMappingAccessBit> m_mappingAccess;
Range1D m_dirtyRange; BufferChange m_change;
Range1D m_mappedRange; Range1D m_mappedRange;
Vector<Uint8> m_stagingData; Vector<Uint8> m_stagingData;
Bool m_ownsStagingData; Bool m_ownsStagingData;
+8
View File
@@ -220,6 +220,14 @@ namespace MobileGL {
} }
// RenderState // RenderState
Uint GLContext::GetRenderStateParametersVersion() const {
return m_renderState.GetVersion();
}
const RenderStateParameters& GLContext::GetRenderStateParameters() const {
return m_renderState.GetAllParameters();
}
void GLContext::SetViewport(IntVec4 viewport) { void GLContext::SetViewport(IntVec4 viewport) {
m_renderState.SetViewport(viewport); m_renderState.SetViewport(viewport);
} }
+2
View File
@@ -86,6 +86,8 @@ namespace MobileGL {
SharedPtr<ProgramObject> GetCurrentProgram(); SharedPtr<ProgramObject> GetCurrentProgram();
// RenderState // RenderState
Uint GetRenderStateParametersVersion() const;
const RenderStateParameters& GetRenderStateParameters() const;
void SetViewport(IntVec4 viewport); // x, y, width, height void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height const IntVec4& GetViewport() const; // x, y, width, height
void SetCapability(CapabilityInput cap, Bool enabled); void SetCapability(CapabilityInput cap, Bool enabled);
@@ -12,41 +12,41 @@
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
// FramebufferAttachment // FramebufferAttachmentObject
FramebufferAttachment::FramebufferAttachment(SharedPtr<MG_State::GLState::ITextureObject> texture, FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture,
Int level) Int level)
: m_texture(texture), m_textureLevel(level) {} : m_texture(texture), m_textureLevel(level) {}
FramebufferAttachment::FramebufferAttachment(SharedPtr<RenderbufferObject> renderbuffer) FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer)
: m_renderbuffer(renderbuffer) {} : m_renderbuffer(renderbuffer) {}
FramebufferAttachment::FramebufferAttachment(Bool IsValid) : m_texture(nullptr), m_renderbuffer(nullptr) { FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid) : m_texture(nullptr), m_renderbuffer(nullptr) {
m_isValid = IsValid; m_isValid = IsValid;
} }
Bool FramebufferAttachment::IsTexture() const { Bool FramebufferAttachmentObject::IsTexture() const {
return m_texture != nullptr; return m_texture != nullptr;
} }
Bool FramebufferAttachment::IsRenderbuffer() const { Bool FramebufferAttachmentObject::IsRenderbuffer() const {
return m_renderbuffer != nullptr; return m_renderbuffer != nullptr;
} }
Bool FramebufferAttachment::IsEmpty() const { Bool FramebufferAttachmentObject::IsEmpty() const {
return m_texture == nullptr && m_renderbuffer == nullptr; return m_texture == nullptr && m_renderbuffer == nullptr;
} }
SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachment::GetTexture() const { SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachmentObject::GetTexture() const {
return m_texture; return m_texture;
} }
SharedPtr<RenderbufferObject> FramebufferAttachment::GetRenderbuffer() const { SharedPtr<RenderbufferObject> FramebufferAttachmentObject::GetRenderbuffer() const {
return m_renderbuffer; return m_renderbuffer;
} }
Int FramebufferAttachment::GetTextureLevel() const { Int FramebufferAttachmentObject::GetTextureLevel() const {
return m_textureLevel; return m_textureLevel;
} }
Bool FramebufferAttachment::IsComplete() const { Bool FramebufferAttachmentObject::IsComplete() const {
if (IsTexture()) { if (IsTexture()) {
Bool complete = m_texture->IsComplete(); Bool complete = m_texture->IsComplete();
return complete; return complete;
@@ -58,7 +58,7 @@ namespace MobileGL {
return false; return false;
} }
IntVec3 FramebufferAttachment::GetSize() const { IntVec3 FramebufferAttachmentObject::GetSize() const {
if (IsTexture()) { if (IsTexture()) {
// TODO: get correct upload target // TODO: get correct upload target
MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()), MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()),
@@ -71,56 +71,55 @@ namespace MobileGL {
return {0, 0, 0}; return {0, 0, 0};
} }
Bool FramebufferAttachment::IsValid() const { Bool FramebufferAttachmentObject::IsValid() const {
return m_isValid; return m_isValid;
} }
// FramebufferObject // FramebufferObject
FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) { FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {
m_attachments.fill(FramebufferAttachment(false)); m_attachmentObjects.fill(FramebufferAttachmentObject(false));
m_drawBuffers.fill(FramebufferAttachmentType::None); m_drawBuffers.fill(FramebufferAttachmentType::None);
m_drawBuffers[0] = FramebufferAttachmentType::Color0; m_drawBuffers[0] = FramebufferAttachmentType::Color0;
m_attachmentVersions.fill(0);
} }
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture,
int level) { int level) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(std::move(texture), level); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type, void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer) { std::shared_ptr<RenderbufferObject> renderbuffer) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(renderbuffer); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::Detach(FramebufferAttachmentType type) { void FramebufferObject::Detach(FramebufferAttachmentType type) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(false); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
const FramebufferAttachment& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const { const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const {
return m_attachments[static_cast<SizeT>(type)]; return m_attachmentObjects[static_cast<SizeT>(type)];
} }
const Array<FramebufferAttachment, const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const {
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>& return m_attachmentObjects;
FramebufferObject::GetAllAttachments() const {
return m_attachments;
} }
Bool FramebufferObject::CheckCompleteness() const { Bool FramebufferObject::CheckCompleteness() const {
if (m_attachments.empty()) { if (m_attachmentObjects.empty()) {
return false; return false;
} }
Int width = -1, height = -1; Int width = -1, height = -1;
Int validAttachmentCount = 0; Int validAttachmentCount = 0;
for (SizeT i = 0; i < m_attachments.size(); ++i) { for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) {
if (!m_attachments[i].IsValid()) continue; if (!m_attachmentObjects[i].IsValid()) continue;
++validAttachmentCount; ++validAttachmentCount;
const auto& attachment = m_attachments[i]; const auto& attachment = m_attachmentObjects[i];
auto attachmentSize = attachment.GetSize(); auto attachmentSize = attachment.GetSize();
Int w = attachmentSize.x(); Int w = attachmentSize.x();
Int h = attachmentSize.y(); Int h = attachmentSize.y();
@@ -143,26 +142,22 @@ namespace MobileGL {
void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) { void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
if (m_drawBuffers[index] == buffer) return; if (m_drawBuffers[index] == buffer) return;
m_drawBuffersDirty = true;
m_drawBuffers[index] = buffer; m_drawBuffers[index] = buffer;
BumpAttachmentVersion(buffer);
} }
// void FramebufferObject::SetDrawBuffers(const Vector<FramebufferAttachmentType>& buffers) { const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const {
// m_drawBuffers = buffers;
// m_drawBuffersDirty = true;
// }
// void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
//
// }
const Array<FramebufferAttachmentType, FramebufferObject::MAX_DRAW_BUFFERS>& FramebufferObject::
GetDrawBuffers() const {
return m_drawBuffers; return m_drawBuffers;
} }
Uint FramebufferObject::GetExternalIndex() const { Uint FramebufferObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -69,11 +69,12 @@ namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class FramebufferAttachment { class FramebufferAttachmentObject {
public: public:
explicit FramebufferAttachment(SharedPtr<MG_State::GLState::ITextureObject> texture, Int level = 0); explicit FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture,
explicit FramebufferAttachment(SharedPtr<RenderbufferObject> renderbuffer); Int level = 0);
explicit FramebufferAttachment(Bool IsValid = true); explicit FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer);
explicit FramebufferAttachmentObject(Bool IsValid = true);
Bool IsTexture() const; Bool IsTexture() const;
Bool IsRenderbuffer() const; Bool IsRenderbuffer() const;
@@ -94,36 +95,51 @@ namespace MobileGL {
class FramebufferObject { class FramebufferObject {
public: public:
using TargetEnum = FramebufferTarget;
static constexpr Uint MAX_DRAW_BUFFERS = 8; static constexpr Uint MAX_DRAW_BUFFERS = 8;
using TargetEnum = FramebufferTarget;
using FramebufferAttachmentObjectArray =
Array<FramebufferAttachmentObject,
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>;
using FramebufferAttachmentVersionArray =
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
FramebufferObject(Uint externalIndex); FramebufferObject(Uint externalIndex);
void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0); void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0);
void AttachRenderbuffer(FramebufferAttachmentType type, void AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer); std::shared_ptr<RenderbufferObject> renderbuffer);
void Detach(FramebufferAttachmentType type); void Detach(FramebufferAttachmentType type);
const FramebufferAttachment& GetAttachment(FramebufferAttachmentType type) const; const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
const Array<FramebufferAttachment, const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>&
GetAllAttachments() const;
Bool CheckCompleteness() const; Bool CheckCompleteness() const;
// aka. `buffer` as in glDrawBuffers/glReadBuffers // aka. `buffer` as in glDrawBuffers/glReadBuffers
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer); void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
bool DrawBuffersIsDirty() const { return m_drawBuffersDirty; } const FramebufferAttachmentArray& GetDrawBuffers() const;
void ClearDrawBuffersDirtyState() { m_drawBuffersDirty = false; } void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
const Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>& GetDrawBuffers() const;
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
return m_attachmentVersions;
}
Uint16 GetObjectVersion() const { return m_objectVersion; }
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
private: private:
void BumpAttachmentVersion(FramebufferAttachmentType type);
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
Array<FramebufferAttachment, FramebufferAttachmentObjectArray m_attachmentObjects;
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)> FramebufferAttachmentVersionArray m_attachmentVersions;
m_attachments;
Bool m_drawBuffersDirty = false; FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS> m_drawBuffers; FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0;
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
Uint16 m_objectVersion = 0;
}; };
} // namespace GLState } // namespace GLState
@@ -42,7 +42,8 @@ namespace MobileGL {
} else { } else {
m_compileStatus = false; m_compileStatus = false;
m_infoLog = result.error().log; m_infoLog = result.error().log;
MGLOG_D("ShaderObject::Compile: Shader %d compilation failed.\nSource:\n%s\nInfoLog:\n%s\nSetting m_compileStatus = false as a result.", MGLOG_D("ShaderObject::Compile: Shader %d compilation failed.\nSource:\n%s\nInfoLog:\n%s\nSetting "
"m_compileStatus = false as a result.",
m_externalIndex, m_source.c_str(), m_infoLog.c_str()); m_externalIndex, m_source.c_str(), m_infoLog.c_str());
} }
} }
@@ -13,45 +13,55 @@ namespace MobileGL {
namespace GLState { namespace GLState {
RenderState::RenderState() {} RenderState::RenderState() {}
Uint RenderState::GetVersion() const {
return m_version;
}
const RenderStateParameters& RenderState::GetAllParameters() const {
return m_parameters;
}
// -------------------- Rasterization -------------------- // -------------------- Rasterization --------------------
void RenderState::SetViewport(IntVec4 viewport) { void RenderState::SetViewport(IntVec4 viewport) {
m_viewport = viewport; if (m_parameters.Viewport == viewport) return;
m_parameters.Viewport = viewport;
++m_version;
} }
const IntVec4& RenderState::GetViewport() const { const IntVec4& RenderState::GetViewport() const {
return m_viewport; return m_parameters.Viewport;
} }
// -------------------- Capabilities -------------------- // -------------------- Capabilities --------------------
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) { void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
#define SET_CAPABILITY(capability, flag) \
case CapabilityInput::capability: \
if (m_parameters.capability##Enabled == flag) break; \
m_parameters.capability##Enabled = flag; \
++m_version; \
break;
switch (cap) { switch (cap) {
case CapabilityInput::Blend: SET_CAPABILITY(Blend, enabled);
m_blendEnabled = enabled; SET_CAPABILITY(DepthTest, enabled);
break; SET_CAPABILITY(CullFace, enabled);
case CapabilityInput::DepthTest: SET_CAPABILITY(ScissorTest, enabled);
m_depthTestEnabled = enabled;
break;
case CapabilityInput::CullFace:
m_cullFaceEnabled = enabled;
break;
case CapabilityInput::ScissorTest:
m_scissorTestEnabled = enabled;
break;
default: // not supported currently default: // not supported currently
break; break;
} }
#undef SET_CAPABILITY
} }
Bool RenderState::IsCapabilityEnabled(CapabilityInput cap) const { Bool RenderState::IsCapabilityEnabled(CapabilityInput cap) const {
#define RETURN_CAPABILITY(capability) \
case CapabilityInput::capability: \
return m_parameters.capability##Enabled;
switch (cap) { switch (cap) {
case CapabilityInput::Blend: RETURN_CAPABILITY(Blend);
return m_blendEnabled; RETURN_CAPABILITY(DepthTest);
case CapabilityInput::DepthTest: RETURN_CAPABILITY(CullFace);
return m_depthTestEnabled; RETURN_CAPABILITY(ScissorTest);
case CapabilityInput::CullFace:
return m_cullFaceEnabled;
case CapabilityInput::ScissorTest:
return m_scissorTestEnabled;
default: default:
return false; return false;
} }
@@ -60,115 +70,108 @@ namespace MobileGL {
// -------------------- Blending -------------------- // -------------------- Blending --------------------
void RenderState::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, void RenderState::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor dstAlpha) { BlendFactor dstAlpha) {
m_srcFactorRGB = srcRGB; if (m_parameters.SrcFactorRGB == srcRGB && m_parameters.DstFactorRGB == dstRGB &&
m_dstFactorRGB = dstRGB; m_parameters.SrcFactorAlpha == srcAlpha && m_parameters.DstFactorAlpha == dstAlpha)
m_srcFactorAlpha = srcAlpha; return;
m_dstFactorAlpha = dstAlpha;
m_parameters.SrcFactorRGB = srcRGB;
m_parameters.DstFactorRGB = dstRGB;
m_parameters.SrcFactorAlpha = srcAlpha;
m_parameters.DstFactorAlpha = dstAlpha;
++m_version;
} }
void RenderState::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, void RenderState::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const { BlendFactor& dstAlpha) const {
srcRGB = m_srcFactorRGB; srcRGB = m_parameters.SrcFactorRGB;
dstRGB = m_dstFactorRGB; dstRGB = m_parameters.DstFactorRGB;
srcAlpha = m_srcFactorAlpha; srcAlpha = m_parameters.SrcFactorAlpha;
dstAlpha = m_dstFactorAlpha; dstAlpha = m_parameters.DstFactorAlpha;
} }
// -------------------- Depth -------------------- // -------------------- Depth --------------------
void RenderState::SetDepthFunc(DepthTestFunc func) { void RenderState::SetDepthFunc(DepthTestFunc func) {
m_depthFunc = func; if (m_parameters.DepthFunc == func) return;
m_parameters.DepthFunc = func;
++m_version;
} }
DepthTestFunc RenderState::GetDepthFunc() const { DepthTestFunc RenderState::GetDepthFunc() const {
return m_depthFunc; return m_parameters.DepthFunc;
} }
void RenderState::SetDepthMask(Bool flag) { void RenderState::SetDepthMask(Bool flag) {
m_depthMask = flag; if (m_parameters.DepthMask == flag) return;
m_parameters.DepthMask = flag;
++m_version;
} }
Bool RenderState::GetDepthMask() const { Bool RenderState::GetDepthMask() const {
return m_depthMask; return m_parameters.DepthMask;
} }
// -------------------- Color Mask -------------------- // -------------------- Color Mask --------------------
void RenderState::SetColorMask(BoolVec4 mask) { void RenderState::SetColorMask(BoolVec4 mask) {
m_colorMask = mask; if (m_parameters.ColorMask == mask) return;
m_parameters.ColorMask = mask;
++m_version;
} }
const BoolVec4 RenderState::GetColorMask() const { const BoolVec4 RenderState::GetColorMask() const {
return m_colorMask; return m_parameters.ColorMask;
} }
// -------------------- Clear State -------------------- // -------------------- Clear State --------------------
void RenderState::SetClearColor(FloatVec4 color) { void RenderState::SetClearColor(FloatVec4 color) {
m_clearColor = color; if (m_parameters.ClearColor == color) return;
m_parameters.ClearColor = color;
++m_version;
} }
const FloatVec4& RenderState::GetClearColor() const { const FloatVec4& RenderState::GetClearColor() const {
return m_clearColor; return m_parameters.ClearColor;
} }
void RenderState::SetClearDepth(Float depth) { void RenderState::SetClearDepth(Float depth) {
m_clearDepth = depth; if (m_parameters.ClearDepth == depth) return;
m_parameters.ClearDepth = depth;
++m_version;
} }
Float RenderState::GetClearDepth() const { Float RenderState::GetClearDepth() const {
return m_clearDepth; return m_parameters.ClearDepth;
} }
// -------------------- Pixel Store -------------------- // -------------------- Pixel Store --------------------
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) { void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
case PixelStoreParam::paramNameHead##paramNameTail: \
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == val) break; \
m_pixelStore##paramNameHead##Parameters.paramNameTail = val; \
break;
switch (param) { switch (param) {
case PixelStoreParam::PackAlignment: SET_PIXEL_STORE_PARAM(Pack, Alignment, value);
m_packParameters.Alignment = value; SET_PIXEL_STORE_PARAM(Pack, RowLength, value);
break; SET_PIXEL_STORE_PARAM(Pack, ImageHeight, value);
case PixelStoreParam::PackRowLength: SET_PIXEL_STORE_PARAM(Pack, SkipPixels, value);
m_packParameters.RowLength = value; SET_PIXEL_STORE_PARAM(Pack, SkipRows, value);
break; SET_PIXEL_STORE_PARAM(Pack, SkipImages, value);
case PixelStoreParam::PackImageHeight: SET_PIXEL_STORE_PARAM(Pack, SwapBytes, value != 0);
m_packParameters.ImageHeight = value; SET_PIXEL_STORE_PARAM(Pack, LSBFirst, value != 0);
break; SET_PIXEL_STORE_PARAM(Unpack, Alignment, value);
case PixelStoreParam::PackSkipPixels: SET_PIXEL_STORE_PARAM(Unpack, RowLength, value);
m_packParameters.SkipPixels = value; SET_PIXEL_STORE_PARAM(Unpack, ImageHeight, value);
break; SET_PIXEL_STORE_PARAM(Unpack, SkipPixels, value);
case PixelStoreParam::PackSkipRows: SET_PIXEL_STORE_PARAM(Unpack, SkipRows, value);
m_packParameters.SkipRows = value; SET_PIXEL_STORE_PARAM(Unpack, SkipImages, value);
break; SET_PIXEL_STORE_PARAM(Unpack, SwapBytes, value != 0);
case PixelStoreParam::PackSkipImages: SET_PIXEL_STORE_PARAM(Unpack, LSBFirst, value != 0);
m_packParameters.SkipImages = value;
break;
case PixelStoreParam::PackSwapBytes:
m_packParameters.SwapBytes = value != 0;
break;
case PixelStoreParam::PackLsbFirst:
m_packParameters.LSBFirst = value != 0;
break;
case PixelStoreParam::UnpackAlignment:
m_unpackParameters.Alignment = value;
break;
case PixelStoreParam::UnpackRowLength:
m_unpackParameters.RowLength = value;
break;
case PixelStoreParam::UnpackImageHeight:
m_unpackParameters.ImageHeight = value;
break;
case PixelStoreParam::UnpackSkipPixels:
m_unpackParameters.SkipPixels = value;
break;
case PixelStoreParam::UnpackSkipRows:
m_unpackParameters.SkipRows = value;
break;
case PixelStoreParam::UnpackSkipImages:
m_unpackParameters.SkipImages = value;
break;
case PixelStoreParam::UnpackSwapBytes:
m_unpackParameters.SwapBytes = value != 0;
MGLOG_D("%s: SwapBytes = %s", __func__, value ? "true" : "false");
break;
case PixelStoreParam::UnpackLsbFirst:
m_unpackParameters.LSBFirst = value != 0;
break;
default: default:
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param)); MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
return; return;
@@ -176,39 +179,26 @@ namespace MobileGL {
} }
Int RenderState::GetPixelStoreParam(PixelStoreParam param) const { Int RenderState::GetPixelStoreParam(PixelStoreParam param) const {
#define RETURN_PIXEL_STORE_PARAM(paramNameHead, paramNameTail) \
case PixelStoreParam::paramNameHead##paramNameTail: \
return m_pixelStore##paramNameHead##Parameters.paramNameTail;
switch (param) { switch (param) {
case PixelStoreParam::PackAlignment: RETURN_PIXEL_STORE_PARAM(Pack, Alignment);
return m_packParameters.Alignment; RETURN_PIXEL_STORE_PARAM(Pack, RowLength);
case PixelStoreParam::PackRowLength: RETURN_PIXEL_STORE_PARAM(Pack, ImageHeight);
return m_packParameters.RowLength; RETURN_PIXEL_STORE_PARAM(Pack, SkipPixels);
case PixelStoreParam::PackImageHeight: RETURN_PIXEL_STORE_PARAM(Pack, SkipRows);
return m_packParameters.ImageHeight; RETURN_PIXEL_STORE_PARAM(Pack, SkipImages);
case PixelStoreParam::PackSkipPixels: RETURN_PIXEL_STORE_PARAM(Pack, SwapBytes);
return m_packParameters.SkipPixels; RETURN_PIXEL_STORE_PARAM(Pack, LSBFirst);
case PixelStoreParam::PackSkipRows: RETURN_PIXEL_STORE_PARAM(Unpack, Alignment);
return m_packParameters.SkipRows; RETURN_PIXEL_STORE_PARAM(Unpack, RowLength);
case PixelStoreParam::PackSkipImages: RETURN_PIXEL_STORE_PARAM(Unpack, ImageHeight);
return m_packParameters.SkipImages; RETURN_PIXEL_STORE_PARAM(Unpack, SkipPixels);
case PixelStoreParam::PackSwapBytes: RETURN_PIXEL_STORE_PARAM(Unpack, SkipRows);
return m_packParameters.SwapBytes ? 1 : 0; RETURN_PIXEL_STORE_PARAM(Unpack, SkipImages);
case PixelStoreParam::PackLsbFirst: RETURN_PIXEL_STORE_PARAM(Unpack, SwapBytes);
return m_packParameters.LSBFirst ? 1 : 0; RETURN_PIXEL_STORE_PARAM(Unpack, LSBFirst);
case PixelStoreParam::UnpackAlignment:
return m_unpackParameters.Alignment;
case PixelStoreParam::UnpackRowLength:
return m_unpackParameters.RowLength;
case PixelStoreParam::UnpackImageHeight:
return m_unpackParameters.ImageHeight;
case PixelStoreParam::UnpackSkipPixels:
return m_unpackParameters.SkipPixels;
case PixelStoreParam::UnpackSkipRows:
return m_unpackParameters.SkipRows;
case PixelStoreParam::UnpackSkipImages:
return m_unpackParameters.SkipImages;
case PixelStoreParam::UnpackSwapBytes:
return m_unpackParameters.SwapBytes ? 1 : 0;
case PixelStoreParam::UnpackLsbFirst:
return m_unpackParameters.LSBFirst ? 1 : 0;
default: default:
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param)); MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
return 0; return 0;
@@ -216,25 +206,31 @@ namespace MobileGL {
} }
PixelStoreParameters RenderState::GetPixelStoreParameters(Bool isUnpack) const { PixelStoreParameters RenderState::GetPixelStoreParameters(Bool isUnpack) const {
return isUnpack ? m_unpackParameters : m_packParameters; return isUnpack ? m_pixelStoreUnpackParameters : m_pixelStorePackParameters;
} }
// -------------------- Cull Face -------------------- // -------------------- Cull Face --------------------
void RenderState::SetCullFaceMode(CullFaceMode mode) { void RenderState::SetCullFaceMode(CullFaceMode mode) {
m_cullFaceMode = mode; if (m_parameters.CullFaceModeSetting == mode) return;
m_parameters.CullFaceModeSetting = mode;
++m_version;
} }
CullFaceMode RenderState::GetCullFaceMode() const { CullFaceMode RenderState::GetCullFaceMode() const {
return m_cullFaceMode; return m_parameters.CullFaceModeSetting;
} }
// --------------------- Scissor --------------------- // --------------------- Scissor ---------------------
void RenderState::SetScissorBox(IntVec4 box) { void RenderState::SetScissorBox(IntVec4 box) {
m_scissorBox = box; if (m_parameters.ScissorBox == box) return;
m_parameters.ScissorBox = box;
++m_version;
} }
const IntVec4& RenderState::GetScissorBox() const { const IntVec4& RenderState::GetScissorBox() const {
return m_scissorBox; return m_parameters.ScissorBox;
} }
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
@@ -7,9 +7,8 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_Util/Math/VectorTypes.h"
#include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h>
namespace MobileGL { namespace MobileGL {
enum class BlendFactor { enum class BlendFactor {
@@ -53,7 +52,7 @@ namespace MobileGL {
PackSkipPixels, PackSkipPixels,
PackSkipImages, PackSkipImages,
PackSwapBytes, PackSwapBytes,
PackLsbFirst, PackLSBFirst,
// Unpack Parameters // Unpack Parameters
UnpackAlignment, UnpackAlignment,
@@ -63,7 +62,7 @@ namespace MobileGL {
UnpackSkipPixels, UnpackSkipPixels,
UnpackSkipImages, UnpackSkipImages,
UnpackSwapBytes, UnpackSwapBytes,
UnpackLsbFirst, UnpackLSBFirst,
PixelStoreParamCount, PixelStoreParamCount,
Unknown = -1 Unknown = -1
@@ -128,12 +127,47 @@ namespace MobileGL {
Int Alignment = 4; Int Alignment = 4;
}; };
struct RenderStateParameters {
// Rasterization
IntVec4 Viewport = IntVec4(0, 0, 0, 0); // x, y, width, height
// Blending
Bool BlendEnabled = false;
BlendFactor SrcFactorRGB = BlendFactor::One;
BlendFactor DstFactorRGB = BlendFactor::Zero;
BlendFactor SrcFactorAlpha = BlendFactor::One;
BlendFactor DstFactorAlpha = BlendFactor::Zero;
// Depth
Bool DepthTestEnabled = false;
DepthTestFunc DepthFunc = DepthTestFunc::Less;
Bool DepthMask = true;
// Color Mask
BoolVec4 ColorMask = BoolVec4(true, true, true, true);
// Clear State
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float ClearDepth = 1.0f;
// Cull Face
Bool CullFaceEnabled = false;
CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
// Scissor
Bool ScissorTestEnabled = false;
IntVec4 ScissorBox = IntVec4(0, 0, 0, 0); // x, y, width, height
};
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class RenderState { class RenderState {
public: public:
RenderState(); RenderState();
Uint GetVersion() const;
const RenderStateParameters& GetAllParameters() const;
// Rasterization // Rasterization
void SetViewport(IntVec4 viewport); // x, y, width, height void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height const IntVec4& GetViewport() const; // x, y, width, height
@@ -177,39 +211,12 @@ namespace MobileGL {
const IntVec4& GetScissorBox() const; // x, y, width, height const IntVec4& GetScissorBox() const; // x, y, width, height
private: private:
// Rasterization Uint16 m_version = 0;
IntVec4 m_viewport = IntVec4(0, 0, 0, 0); // x, y, width, height RenderStateParameters m_parameters;
// Blending
Bool m_blendEnabled = false;
BlendFactor m_srcFactorRGB = BlendFactor::One;
BlendFactor m_dstFactorRGB = BlendFactor::Zero;
BlendFactor m_srcFactorAlpha = BlendFactor::One;
BlendFactor m_dstFactorAlpha = BlendFactor::Zero;
// Depth
Bool m_depthTestEnabled = false;
DepthTestFunc m_depthFunc = DepthTestFunc::Less;
Bool m_depthMask = true;
// Color Mask
BoolVec4 m_colorMask = BoolVec4(true, true, true, true);
// Clear State
FloatVec4 m_clearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float m_clearDepth = 1.0f;
// Pixel Store // Pixel Store
PixelStoreParameters m_packParameters; PixelStoreParameters m_pixelStorePackParameters;
PixelStoreParameters m_unpackParameters; PixelStoreParameters m_pixelStoreUnpackParameters;
// Cull Face
Bool m_cullFaceEnabled = false;
CullFaceMode m_cullFaceMode = CullFaceMode::Back;
// Scissor
Bool m_scissorTestEnabled = false;
IntVec4 m_scissorBox = IntVec4(0, 0, 0, 0); // x, y, width, height
}; };
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
@@ -14,47 +14,77 @@ namespace MobileGL {
SamplerObject::SamplerObject(Uint externalIndex) : m_externalIndex(externalIndex) {} SamplerObject::SamplerObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
void SamplerObject::SetWrapS(SamplerWrapMode mode) { void SamplerObject::SetWrapS(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapS) return;
m_samplerParameters.wrapS = mode; m_samplerParameters.wrapS = mode;
++m_version;
} }
void SamplerObject::SetWrapT(SamplerWrapMode mode) { void SamplerObject::SetWrapT(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapT) return;
m_samplerParameters.wrapT = mode; m_samplerParameters.wrapT = mode;
++m_version;
} }
void SamplerObject::SetWrapR(SamplerWrapMode mode) { void SamplerObject::SetWrapR(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapR) return;
m_samplerParameters.wrapR = mode; m_samplerParameters.wrapR = mode;
++m_version;
} }
void SamplerObject::SetMinFilter(SamplerFilterMode mode) { void SamplerObject::SetMinFilter(SamplerFilterMode mode) {
if (mode == m_samplerParameters.minFilter) return;
m_samplerParameters.minFilter = mode; m_samplerParameters.minFilter = mode;
++m_version;
} }
void SamplerObject::SetMagFilter(SamplerFilterMode mode) { void SamplerObject::SetMagFilter(SamplerFilterMode mode) {
if (mode == m_samplerParameters.magFilter) return;
m_samplerParameters.magFilter = mode; m_samplerParameters.magFilter = mode;
++m_version;
} }
void SamplerObject::SetMipmapMode(SamplerMipmapMode mode) { void SamplerObject::SetMipmapMode(SamplerMipmapMode mode) {
if (mode == m_samplerParameters.mipmapMode) return;
m_samplerParameters.mipmapMode = mode; m_samplerParameters.mipmapMode = mode;
++m_version;
} }
void SamplerObject::SetLodRange(Float minLod, Float maxLod) { void SamplerObject::SetLodRange(Float minLod, Float maxLod) {
if (minLod == m_samplerParameters.minLod && maxLod == m_samplerParameters.maxLod) return;
if (minLod > maxLod) { if (minLod > maxLod) {
THROW_EXCEPTION("minLod cannot be greater than maxLod"); THROW_EXCEPTION("minLod cannot be greater than maxLod");
} }
m_samplerParameters.minLod = minLod; m_samplerParameters.minLod = minLod;
m_samplerParameters.maxLod = maxLod; m_samplerParameters.maxLod = maxLod;
++m_version;
} }
void SamplerObject::SetLodBias(Float bias) { void SamplerObject::SetLodBias(Float bias) {
if (bias == m_samplerParameters.lodBias) return;
m_samplerParameters.lodBias = bias; m_samplerParameters.lodBias = bias;
++m_version;
} }
void SamplerObject::SetSamplerCompareFunc(SamplerCompareFunc func) { void SamplerObject::SetSamplerCompareFunc(SamplerCompareFunc func) {
if (func == m_samplerParameters.compareFunc) return;
m_samplerParameters.compareFunc = func; m_samplerParameters.compareFunc = func;
++m_version;
} }
void SamplerObject::SetCompareMode(SamplerCompareMode mode) { void SamplerObject::SetCompareMode(SamplerCompareMode mode) {
if (mode == m_samplerParameters.compareMode) return;
m_samplerParameters.compareMode = mode; m_samplerParameters.compareMode = mode;
++m_version;
} }
SamplerWrapMode SamplerObject::GetWrapS() const { SamplerWrapMode SamplerObject::GetWrapS() const {
@@ -108,6 +138,10 @@ namespace MobileGL {
const SamplerParameters& SamplerObject::GetAllSamplerParameters() const { const SamplerParameters& SamplerObject::GetAllSamplerParameters() const {
return m_samplerParameters; return m_samplerParameters;
} }
Uint16 SamplerObject::GetVersion() const {
return m_version;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -98,10 +98,12 @@ namespace MobileGL {
SamplerCompareMode GetCompareMode() const; SamplerCompareMode GetCompareMode() const;
SamplerCompareFunc GetSamplerCompareFunc() const; SamplerCompareFunc GetSamplerCompareFunc() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
Uint16 GetVersion() const;
const SamplerParameters& GetAllSamplerParameters() const; const SamplerParameters& GetAllSamplerParameters() const;
private: private:
const Uint m_externalIndex; const Uint m_externalIndex;
Uint16 m_version = 0;
SamplerParameters m_samplerParameters; SamplerParameters m_samplerParameters;
}; };
} // namespace GLState } // namespace GLState
@@ -25,6 +25,7 @@ namespace MobileGL {
SizeT GetByteSize(Uint level) const; SizeT GetByteSize(Uint level) const;
void MarkDirty(Uint level, bool dirty); void MarkDirty(Uint level, bool dirty);
bool IsDirty(Uint level) const; bool IsDirty(Uint level) const;
protected: protected:
Vector<IntVec3> m_texelSizes; Vector<IntVec3> m_texelSizes;
Vector<Vector<Uint8>> m_data; Vector<Vector<Uint8>> m_data;
@@ -19,7 +19,9 @@ namespace MobileGL {
template <SizeT TargetCount> template <SizeT TargetCount>
class MipmapUploadTargetArray { class MipmapUploadTargetArray {
public: public:
MipmapUploadTargetArray() { static_assert(TargetCount > 0, "Upload target count must be greater than zero"); } MipmapUploadTargetArray() {
static_assert(TargetCount > 0, "Upload target count must be greater than zero");
}
void AllocateLevel(Uint targetIndex, Uint level, MipmapInput input) { void AllocateLevel(Uint targetIndex, Uint level, MipmapInput input) {
MOBILEGL_ASSERT(targetIndex < TargetCount, "AllocateLevel: target invalid"); MOBILEGL_ASSERT(targetIndex < TargetCount, "AllocateLevel: target invalid");
@@ -7,6 +7,7 @@
// End of Source File Header // End of Source File Header
#include "TextureObject.h" #include "TextureObject.h"
#include "MG_Util/Types.h"
#include <MG_Util/Metrics/TextureMetrics.h> #include <MG_Util/Metrics/TextureMetrics.h>
namespace MobileGL { namespace MobileGL {
@@ -43,7 +44,10 @@ namespace MobileGL {
} }
void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) { void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) {
if (format == m_internalFormat) return;
m_internalFormat = format; m_internalFormat = format;
++m_textureParamsVersion;
} }
Uint TextureObjectBase::GetExternalIndex() const { Uint TextureObjectBase::GetExternalIndex() const {
@@ -55,7 +59,10 @@ namespace MobileGL {
} }
void TextureObjectBase::SetBorderColor(const FloatVec4& color) { void TextureObjectBase::SetBorderColor(const FloatVec4& color) {
if (color == m_borderColor) return;
m_borderColor = color; m_borderColor = color;
++m_textureParamsVersion;
} }
TextureSwizzleParam TextureObjectBase::GetSwizzleParam(TextureSwizzleParam param) const { TextureSwizzleParam TextureObjectBase::GetSwizzleParam(TextureSwizzleParam param) const {
@@ -80,6 +87,8 @@ namespace MobileGL {
} }
void TextureObjectBase::SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) { void TextureObjectBase::SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) {
if (GetSwizzleParam(param) == value) return;
switch (param) { switch (param) {
case TextureSwizzleParam::Red: case TextureSwizzleParam::Red:
m_swizzleParams.r() = value; m_swizzleParams.r() = value;
@@ -98,9 +107,14 @@ namespace MobileGL {
static_cast<Int>(param)); static_cast<Int>(param));
break; break;
} }
++m_textureParamsVersion;
} }
void TextureObjectBase::SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) { void TextureObjectBase::SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) {
if (values == m_swizzleParams) return;
m_swizzleParams = values; m_swizzleParams = values;
++m_textureParamsVersion;
} }
const UintVec2& TextureObjectBase::GetLevelRange() const { const UintVec2& TextureObjectBase::GetLevelRange() const {
@@ -108,11 +122,21 @@ namespace MobileGL {
} }
void TextureObjectBase::SetBaseLevel(Uint baseLevel) { void TextureObjectBase::SetBaseLevel(Uint baseLevel) {
if (baseLevel == m_levelRange.x()) return;
m_levelRange.x() = baseLevel; m_levelRange.x() = baseLevel;
++m_textureParamsVersion;
} }
void TextureObjectBase::SetMaxLevel(Uint maxLevel) { void TextureObjectBase::SetMaxLevel(Uint maxLevel) {
if (maxLevel == m_levelRange.y()) return;
m_levelRange.y() = maxLevel; m_levelRange.y() = maxLevel;
++m_textureParamsVersion;
}
Uint16 TextureObjectBase::GetTextureParamsVersion() const {
return m_textureParamsVersion;
} }
Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const { Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const {
@@ -144,11 +168,11 @@ namespace MobileGL {
} }
void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
bool dirty) { Bool dirty) {
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
} }
bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { Bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const {
return m_textureStorage.IsDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel); return m_textureStorage.IsDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel);
} }
@@ -170,7 +194,7 @@ namespace MobileGL {
// For some reason mojang decided to have 0x0 in last level mipmap // For some reason mojang decided to have 0x0 in last level mipmap
// Relaxing checks for that // Relaxing checks for that
bool hadZero = false; Bool hadZero = false;
for (SizeT i = 0; i < levelCount; ++i) { for (SizeT i = 0; i < levelCount; ++i) {
const auto& levelSize = m_textureStorage.GetTexelSize(0, i); const auto& levelSize = m_textureStorage.GetTexelSize(0, i);
if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) { if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) {
@@ -41,6 +41,7 @@ namespace MobileGL {
virtual const UintVec2& GetLevelRange() const = 0; virtual const UintVec2& GetLevelRange() const = 0;
virtual void SetBaseLevel(Uint baseLevel) = 0; virtual void SetBaseLevel(Uint baseLevel) = 0;
virtual void SetMaxLevel(Uint maxLevel) = 0; virtual void SetMaxLevel(Uint maxLevel) = 0;
virtual Uint16 GetTextureParamsVersion() const = 0;
protected: protected:
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0; virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
@@ -67,7 +68,7 @@ namespace MobileGL {
const UintVec2& GetLevelRange() const override; const UintVec2& GetLevelRange() const override;
void SetBaseLevel(Uint baseLevel) override; void SetBaseLevel(Uint baseLevel) override;
void SetMaxLevel(Uint maxLevel) override; void SetMaxLevel(Uint maxLevel) override;
Uint16 GetTextureParamsVersion() const override;
protected: protected:
const Uint m_externalIndex; const Uint m_externalIndex;
const TextureTarget m_target = TextureTarget::Unknown; const TextureTarget m_target = TextureTarget::Unknown;
@@ -77,11 +78,13 @@ namespace MobileGL {
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
UintVec2 m_levelRange = {0, 1000}; UintVec2 m_levelRange = {0, 1000};
Uint16 m_textureParamsVersion = 0;
}; };
class TextureObjectMipmap : public TextureObjectBase { class TextureObjectMipmap : public TextureObjectBase {
public: public:
TextureObjectMipmap(TextureTarget target, Uint externalIndex): TextureObjectBase(target, externalIndex) {} TextureObjectMipmap(TextureTarget target, Uint externalIndex)
: TextureObjectBase(target, externalIndex) {}
TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; } TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; }
@@ -91,8 +94,9 @@ namespace MobileGL {
virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0;
virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0;
virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0; virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0;
virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) = 0; virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
virtual bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0; Bool dirty = true) = 0;
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
}; };
class TextureObjectWithOneMipmap : public TextureObjectMipmap { class TextureObjectWithOneMipmap : public TextureObjectMipmap {
@@ -107,7 +111,7 @@ namespace MobileGL {
void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) override; void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) override;
void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) override; void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) override;
void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override;
void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, Bool dirty) override;
bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override;
IntVec3 GetBaseSize() const override; IntVec3 GetBaseSize() const override;
@@ -18,7 +18,8 @@ namespace MobileGL {
TextureStorageType GetStorageType() const override { return TextureStorageType::Buffer; } TextureStorageType GetStorageType() const override { return TextureStorageType::Buffer; }
explicit TextureObjectBuffer(Uint externalIndex); explicit TextureObjectBuffer(Uint externalIndex);
const Vector<TextureUploadTarget>& GetUploadTargets() const override { return m_uploadTargets; } const Vector<TextureUploadTarget>& GetUploadTargets() const override { return m_uploadTargets; }
BindingSlot<BufferObject>& GetBufferBindingSlot(TextureUploadTarget target = TextureUploadTarget::TextureBuffer); BindingSlot<BufferObject>& GetBufferBindingSlot(
TextureUploadTarget target = TextureUploadTarget::TextureBuffer);
protected: protected:
Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override; Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override;
@@ -22,20 +22,26 @@ namespace MobileGL {
attr.Offset = 0; attr.Offset = 0;
attr.Buffer = nullptr; attr.Buffer = nullptr;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
} }
void VertexArrayObject::EnableAttribute(Uint index) { void VertexArrayObject::EnableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Enabled) return;
m_attributes[index].Enabled = true; m_attributes[index].Enabled = true;
MarkAttributeDirty(index); BumpAttributeSwitchVersion(index);
} }
void VertexArrayObject::DisableAttribute(Uint index) { void VertexArrayObject::DisableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (!m_attributes[index].Enabled) return;
m_attributes[index].Enabled = false; m_attributes[index].Enabled = false;
MarkAttributeDirty(index); BumpAttributeSwitchVersion(index);
} }
Bool VertexArrayObject::IsAttributeEnabled(Uint index) const { Bool VertexArrayObject::IsAttributeEnabled(Uint index) const {
@@ -47,6 +53,12 @@ namespace MobileGL {
SizeT offset, Bool isInteger) { SizeT offset, Bool isInteger) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Size == size && m_attributes[index].Type == type &&
m_attributes[index].Normalized == normalized && m_attributes[index].Stride == stride &&
m_attributes[index].Offset == offset && m_attributes[index].IsInteger == isInteger) {
return;
}
if (size < 1 || size > 4) { if (size < 1 || size > 4) {
return; return;
} }
@@ -59,13 +71,16 @@ namespace MobileGL {
attr.Offset = offset; attr.Offset = offset;
attr.IsInteger = isInteger; attr.IsInteger = isInteger;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr<BufferObject>& buffer) { void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr<BufferObject>& buffer) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Buffer == buffer) return;
m_attributes[index].Buffer = buffer; m_attributes[index].Buffer = buffer;
MarkAttributeDirty(index); BumpAttributeBufferVersion(index);
} }
BindingSlot<BufferObject>& VertexArrayObject::GetIndexBufferBindingSlot() { BindingSlot<BufferObject>& VertexArrayObject::GetIndexBufferBindingSlot() {
@@ -83,22 +98,6 @@ namespace MobileGL {
return m_attributes; 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<Uint>& VertexArrayObject::GetDirtyAttributeIndices() const {
return m_dirtyAttributes;
}
void VertexArrayObject::ClearDirtyAttributes() {
m_dirtyAttributes.clear();
}
Uint VertexArrayObject::GetExternalIndex() const { Uint VertexArrayObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
@@ -107,13 +106,39 @@ namespace MobileGL {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Divisor == divisor) return; if (m_attributes[index].Divisor == divisor) return;
m_attributes[index].Divisor = divisor; m_attributes[index].Divisor = divisor;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
Uint VertexArrayObject::GetAttributeDivisor(Uint index) const { Uint VertexArrayObject::GetAttributeDivisor(Uint index) const {
if (index >= MAX_VERTEX_ATTRIBS) return 0; if (index >= MAX_VERTEX_ATTRIBS) return 0;
return m_attributes[index].Divisor; return m_attributes[index].Divisor;
} }
void VertexArrayObject::BumpAttributeFormatVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].FormatVersion;
}
void VertexArrayObject::BumpAttributeBufferVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].BufferVersion;
}
void VertexArrayObject::BumpAttributeSwitchVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].SwitchVersion;
}
const VertexAttributeVersion& VertexArrayObject::GetAttributeVersion(Uint index) const {
static VertexAttributeVersion emptyVersion;
if (index >= MAX_VERTEX_ATTRIBS) return emptyVersion;
return m_attributeVersions[index];
}
const Array<VertexAttributeVersion, VertexArrayObject::MAX_VERTEX_ATTRIBS>& VertexArrayObject::
GetAllAttributeVersions() const {
return m_attributeVersions;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "../BufferState/BufferObject.h" #include "../BufferState/BufferObject.h"
#include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
@@ -25,6 +26,12 @@ namespace MobileGL {
SharedPtr<BufferObject> Buffer; SharedPtr<BufferObject> Buffer;
}; };
struct VertexAttributeVersion {
Uint16 FormatVersion = 0;
Uint16 BufferVersion = 0;
Uint16 SwitchVersion = 0;
};
class VertexArrayObject { class VertexArrayObject {
public: public:
static constexpr int MAX_VERTEX_ATTRIBS = 16; static constexpr int MAX_VERTEX_ATTRIBS = 16;
@@ -45,19 +52,22 @@ namespace MobileGL {
const VertexAttribute& GetAttribute(Uint index) const; const VertexAttribute& GetAttribute(Uint index) const;
const Array<VertexAttribute, MAX_VERTEX_ATTRIBS>& GetAllAttributes() const; const Array<VertexAttribute, MAX_VERTEX_ATTRIBS>& GetAllAttributes() const;
const Vector<Uint>& GetDirtyAttributeIndices() const;
void ClearDirtyAttributes();
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
void SetAttributeDivisor(Uint index, Uint divisor); void SetAttributeDivisor(Uint index, Uint divisor);
Uint GetAttributeDivisor(Uint index) const; Uint GetAttributeDivisor(Uint index) const;
const VertexAttributeVersion& GetAttributeVersion(Uint index) const;
const Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS>& GetAllAttributeVersions() const;
private: private:
void MarkAttributeDirty(Uint index); void BumpAttributeFormatVersion(Uint index);
void BumpAttributeBufferVersion(Uint index);
void BumpAttributeSwitchVersion(Uint index);
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes; Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes;
Vector<Uint> m_dirtyAttributes; Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS> m_attributeVersions;
BindingSlot<BufferObject> m_indexBufferBindingSlot; BindingSlot<BufferObject> m_indexBufferBindingSlot;
}; };
} // namespace GLState } // namespace GLState
+18 -9
View File
@@ -72,7 +72,8 @@ TEST_F(BufferTest, PingPong) {
Vector<Int> bufdata(data.size()); Vector<Int> bufdata(data.size());
memcpy(bufdata.data(), p, byteSize); memcpy(bufdata.data(), p, byteSize);
ASSERT_EQ(data, bufdata); ASSERT_EQ(data, bufdata);
auto range = bufRead->GetDirtyRange(); ASSERT_EQ(bufRead->GetDirtyRanges().size() >= 1, true);
auto range = bufRead->GetDirtyRanges()[0];
ASSERT_EQ(range.start, 0); ASSERT_EQ(range.start, 0);
ASSERT_EQ(range.end, byteSize); ASSERT_EQ(range.end, byteSize);
} }
@@ -122,7 +123,8 @@ TEST_F(BufferTest, AcquireMemory) {
void* p = bufObj->AcquireMemory(false, true, false); void* p = bufObj->AcquireMemory(false, true, false);
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 0); ASSERT_EQ(dirty.start, 0);
ASSERT_EQ(dirty.end, sizeof(Int) * 5); ASSERT_EQ(dirty.end, sizeof(Int) * 5);
@@ -150,7 +152,8 @@ TEST_F(BufferTest, AcquireMemoryRangeWithoutExplicit) {
void* p = bufObj->AcquireMemory(false, true, false); void* p = bufObj->AcquireMemory(false, true, false);
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 4); ASSERT_EQ(dirty.end, sizeof(Int) * 4);
} }
@@ -177,13 +180,15 @@ TEST_F(BufferTest, AcquireMemoryRangeWithExplicit) {
mappedPtr[1] = 300; mappedPtr[1] = 300;
bufObj->FlushMemoryRange(0, sizeof(Int)); bufObj->FlushMemoryRange(0, sizeof(Int));
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
bufObj->ReleaseMemory(); bufObj->ReleaseMemory();
dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
@@ -193,7 +198,8 @@ TEST_F(BufferTest, AcquireMemoryRangeWithExplicit) {
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
} }
@@ -235,7 +241,8 @@ TEST_F(BufferTest, CopyBufferSubData) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = dstObj->GetDirtyRange(); ASSERT_EQ(dstObj->GetDirtyRanges().size() >= 1, true);
auto dirty = dstObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 5 * sizeof(Int)); ASSERT_EQ(dirty.start, 5 * sizeof(Int));
ASSERT_EQ(dirty.end, 9 * sizeof(Int)); ASSERT_EQ(dirty.end, 9 * sizeof(Int));
} }
@@ -265,7 +272,8 @@ TEST_F(BufferTest, WriteWhileMapped) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 0); ASSERT_EQ(dirty.start, 0);
ASSERT_EQ(dirty.end, byteSize); ASSERT_EQ(dirty.end, byteSize);
} }
@@ -293,7 +301,8 @@ TEST_F(BufferTest, PartialUpdate) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, 3 * sizeof(Int)); ASSERT_EQ(dirty.end, 3 * sizeof(Int));
} }
@@ -457,7 +457,10 @@ namespace MobileGL {
void *libGLES = nullptr, *libEGL = nullptr; void *libGLES = nullptr, *libEGL = nullptr;
static const char* LibPathPrefixes[] = { static const char* LibPathPrefixes[] = {
"/opt/vc/lib/", "/usr/local/lib/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/", "/opt/vc/lib/",
"/usr/local/lib/",
"/usr/lib/",
"/usr/lib/x86_64-linux-gnu/",
"", // We should put this to the end of the list to avoid breaking `LD_LIBRARY_PATH` usage "", // We should put this to the end of the list to avoid breaking `LD_LIBRARY_PATH` usage
nullptr}; nullptr};
static const char* LibExts[] = {"so", "so.1", "so.2", "dylib", "dll", nullptr}; static const char* LibExts[] = {"so", "so.1", "so.2", "dylib", "dll", nullptr};
@@ -531,8 +534,10 @@ namespace MobileGL {
} }
MGLOG_I("OpenGL ES capabilities:"); MGLOG_I("OpenGL ES capabilities:");
MG_External::GLES::glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment); MG_External::GLES::glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
MGLOG_I(" GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: %d", MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment); &MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment);
MGLOG_I(" GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: %d",
MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment);
} }
void InitGLES() { void InitGLES() {
@@ -514,13 +514,15 @@ namespace MobileGL {
typedef EGLSync (*eglCreateSync_PTR)(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list); typedef EGLSync (*eglCreateSync_PTR)(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list);
typedef EGLBoolean (*eglDestroySync_PTR)(EGLDisplay dpy, EGLSync sync); typedef EGLBoolean (*eglDestroySync_PTR)(EGLDisplay dpy, EGLSync sync);
typedef EGLint (*eglClientWaitSync_PTR)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); typedef EGLint (*eglClientWaitSync_PTR)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
typedef EGLBoolean (*eglGetSyncAttrib_PTR)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value); typedef EGLBoolean (*eglGetSyncAttrib_PTR)(EGLDisplay dpy, EGLSync sync, EGLint attribute,
typedef EGLImage (*eglCreateImage_PTR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list); EGLAttrib* value);
typedef EGLImage (*eglCreateImage_PTR)(EGLDisplay dpy, EGLContext ctx, EGLenum target,
EGLClientBuffer buffer, const EGLAttrib* attrib_list);
typedef EGLBoolean (*eglDestroyImage_PTR)(EGLDisplay dpy, EGLImage image); typedef EGLBoolean (*eglDestroyImage_PTR)(EGLDisplay dpy, EGLImage image);
typedef EGLSurface (*eglCreatePlatformPixmapSurface_PTR)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list); typedef EGLSurface (*eglCreatePlatformPixmapSurface_PTR)(EGLDisplay dpy, EGLConfig config,
void* native_pixmap, const EGLAttrib* attrib_list);
typedef EGLBoolean (*eglWaitSync_PTR)(EGLDisplay dpy, EGLSync sync, EGLint flags); typedef EGLBoolean (*eglWaitSync_PTR)(EGLDisplay dpy, EGLSync sync, EGLint flags);
EGL_FUNC_DECL(eglBindAPI) EGL_FUNC_DECL(eglBindAPI)
EGL_FUNC_DECL(eglBindTexImage) EGL_FUNC_DECL(eglBindTexImage)
EGL_FUNC_DECL(eglChooseConfig) EGL_FUNC_DECL(eglChooseConfig)
@@ -30,11 +30,20 @@ namespace MobileGL {
} }
switch (attachment) { switch (attachment) {
case GL_NONE:
return FramebufferAttachmentType::None;
case GL_DEPTH_ATTACHMENT: case GL_DEPTH_ATTACHMENT:
return FramebufferAttachmentType::Depth; return FramebufferAttachmentType::Depth;
case GL_STENCIL_ATTACHMENT: case GL_STENCIL_ATTACHMENT:
return FramebufferAttachmentType::Stencil; return FramebufferAttachmentType::Stencil;
case GL_UNKNOWN_MGL: case GL_FRONT_LEFT:
return FramebufferAttachmentType::FrontLeft;
case GL_FRONT_RIGHT:
return FramebufferAttachmentType::FrontRight;
case GL_BACK_LEFT:
return FramebufferAttachmentType::BackLeft;
case GL_BACK_RIGHT:
return FramebufferAttachmentType::BackRight;
default: default:
return FramebufferAttachmentType::Unknown; return FramebufferAttachmentType::Unknown;
} }
@@ -85,7 +85,7 @@ namespace MobileGL {
case GL_PACK_SWAP_BYTES: case GL_PACK_SWAP_BYTES:
return PixelStoreParam::PackSwapBytes; return PixelStoreParam::PackSwapBytes;
case GL_PACK_LSB_FIRST: case GL_PACK_LSB_FIRST:
return PixelStoreParam::PackLsbFirst; return PixelStoreParam::PackLSBFirst;
case GL_UNPACK_ALIGNMENT: case GL_UNPACK_ALIGNMENT:
return PixelStoreParam::UnpackAlignment; return PixelStoreParam::UnpackAlignment;
case GL_UNPACK_ROW_LENGTH: case GL_UNPACK_ROW_LENGTH:
@@ -101,7 +101,7 @@ namespace MobileGL {
case GL_UNPACK_SWAP_BYTES: case GL_UNPACK_SWAP_BYTES:
return PixelStoreParam::UnpackSwapBytes; return PixelStoreParam::UnpackSwapBytes;
case GL_UNPACK_LSB_FIRST: case GL_UNPACK_LSB_FIRST:
return PixelStoreParam::UnpackLsbFirst; return PixelStoreParam::UnpackLSBFirst;
default: default:
return PixelStoreParam::Unknown; return PixelStoreParam::Unknown;
} }
@@ -234,7 +234,8 @@ namespace MobileGL {
case GL_RGBA: case GL_RGBA:
return TextureInternalFormat::RGBA; return TextureInternalFormat::RGBA;
default: default:
MGLOG_D("%s: unknown internal format %s", __func__, MG_Util::ConvertGLEnumToString(internalformat).c_str()); MGLOG_D("%s: unknown internal format %s", __func__,
MG_Util::ConvertGLEnumToString(internalformat).c_str());
return TextureInternalFormat::Unknown; return TextureInternalFormat::Unknown;
} }
} }
@@ -33,6 +33,14 @@ namespace MobileGL {
return GL_DEPTH_ATTACHMENT; return GL_DEPTH_ATTACHMENT;
case FramebufferAttachmentType::Stencil: case FramebufferAttachmentType::Stencil:
return GL_STENCIL_ATTACHMENT; return GL_STENCIL_ATTACHMENT;
case FramebufferAttachmentType::FrontLeft:
return GL_FRONT_LEFT;
case FramebufferAttachmentType::FrontRight:
return GL_FRONT_RIGHT;
case FramebufferAttachmentType::BackLeft:
return GL_BACK_LEFT;
case FramebufferAttachmentType::BackRight:
return GL_BACK_RIGHT;
default: default:
return GL_NONE; return GL_NONE;
} }
@@ -85,7 +85,7 @@ namespace MobileGL {
return GL_PACK_SKIP_IMAGES; return GL_PACK_SKIP_IMAGES;
case PixelStoreParam::PackSwapBytes: case PixelStoreParam::PackSwapBytes:
return GL_PACK_SWAP_BYTES; return GL_PACK_SWAP_BYTES;
case PixelStoreParam::PackLsbFirst: case PixelStoreParam::PackLSBFirst:
return GL_PACK_LSB_FIRST; return GL_PACK_LSB_FIRST;
case PixelStoreParam::UnpackAlignment: case PixelStoreParam::UnpackAlignment:
return GL_UNPACK_ALIGNMENT; return GL_UNPACK_ALIGNMENT;
@@ -101,7 +101,7 @@ namespace MobileGL {
return GL_UNPACK_SKIP_IMAGES; return GL_UNPACK_SKIP_IMAGES;
case PixelStoreParam::UnpackSwapBytes: case PixelStoreParam::UnpackSwapBytes:
return GL_UNPACK_SWAP_BYTES; return GL_UNPACK_SWAP_BYTES;
case PixelStoreParam::UnpackLsbFirst: case PixelStoreParam::UnpackLSBFirst:
return GL_UNPACK_LSB_FIRST; return GL_UNPACK_LSB_FIRST;
default: default:
return GL_UNKNOWN_MGL; return GL_UNKNOWN_MGL;
@@ -53,7 +53,8 @@ namespace MobileGL {
} }
} }
TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat, TextureInputFormat format, TexturePixelDataType type) { TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat,
TextureInputFormat format, TexturePixelDataType type) {
switch (internalformat) { switch (internalformat) {
case TextureInternalFormat::R8: case TextureInternalFormat::R8:
case TextureInternalFormat::R8Snorm: case TextureInternalFormat::R8Snorm:
@@ -131,9 +132,9 @@ namespace MobileGL {
case TexturePixelDataType::UnsignedShort: case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::RGBA16; return TextureInternalFormat::RGBA16;
default: default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning original.", MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
__func__, "returning original.",
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(), __func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(), MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str()); MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat; return internalformat;
@@ -144,9 +145,9 @@ namespace MobileGL {
case TexturePixelDataType::UnsignedByte: case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RGB8; return TextureInternalFormat::RGB8;
default: default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning original.", MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
__func__, "returning original.",
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(), __func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(), MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str()); MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat; return internalformat;
@@ -159,9 +160,9 @@ namespace MobileGL {
case TexturePixelDataType::UnsignedShort: case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::RG16; return TextureInternalFormat::RG16;
default: default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning original.", MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
__func__, "returning original.",
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(), __func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(), MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str()); MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat; return internalformat;
@@ -174,23 +175,141 @@ namespace MobileGL {
case TexturePixelDataType::UnsignedShort: case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::R16; return TextureInternalFormat::R16;
default: default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning original.", MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
__func__, "returning original.",
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(), __func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
case TextureInternalFormat::DepthComponent: {
switch (type) {
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::DepthComponent16;
case TexturePixelDataType::UnsignedInt:
return TextureInternalFormat::DepthComponent32;
case TexturePixelDataType::Float:
return TextureInternalFormat::DepthComponent32F;
default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
"returning original.",
__func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
case TextureInternalFormat::DepthStencil: {
switch (type) {
case TexturePixelDataType::UnsignedInt248:
return TextureInternalFormat::Depth24Stencil8;
default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
"returning original.",
__func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(), MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str()); MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat; return internalformat;
} }
} }
default: { default: {
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning original.", MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning "
__func__, "original.",
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(), __func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(), MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str()); MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat; return internalformat;
} }
} }
} }
TextureInternalFormat ConvertInternalFormatToUnsized(TextureInternalFormat internalformat) {
switch (internalformat) {
case TextureInternalFormat::R8:
case TextureInternalFormat::R8Snorm:
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::R16F:
case TextureInternalFormat::R32F:
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
case TextureInternalFormat::Red:
return TextureInternalFormat::Red;
case TextureInternalFormat::RG8:
case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RG16F:
case TextureInternalFormat::RG32F:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
case TextureInternalFormat::RG:
return TextureInternalFormat::RG;
case TextureInternalFormat::R3G3B2:
case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGB32F:
case TextureInternalFormat::R11FG11FB10F:
case TextureInternalFormat::RGB9E5:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
case TextureInternalFormat::RGB:
return TextureInternalFormat::RGB;
case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGB5A1:
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
case TextureInternalFormat::RGBA12:
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGBA16F:
case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
case TextureInternalFormat::RGBA:
return TextureInternalFormat::RGBA;
case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::DepthComponent:
return TextureInternalFormat::DepthComponent;
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return TextureInternalFormat::DepthStencil;
default:
MGLOG_W("%s: Unknown or unhandled internal format %s, returning original.", __func__,
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str());
return internalformat;
}
}
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -13,6 +13,8 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Util { namespace MG_Util {
TextureTarget ConvertTextureUploadTargetToTextureTarget(TextureUploadTarget target); TextureTarget ConvertTextureUploadTargetToTextureTarget(TextureUploadTarget target);
TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat, TextureInputFormat format, TexturePixelDataType type); TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat,
TextureInputFormat format, TexturePixelDataType type);
TextureInternalFormat ConvertInternalFormatToUnsized(TextureInternalFormat internalformat);
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -84,8 +84,8 @@ namespace MobileGL {
return "PackSkipImages"; return "PackSkipImages";
case PixelStoreParam::PackSwapBytes: case PixelStoreParam::PackSwapBytes:
return "PackSwapBytes"; return "PackSwapBytes";
case PixelStoreParam::PackLsbFirst: case PixelStoreParam::PackLSBFirst:
return "PackLsbFirst"; return "PackLSBFirst";
case PixelStoreParam::UnpackAlignment: case PixelStoreParam::UnpackAlignment:
return "UnpackAlignment"; return "UnpackAlignment";
case PixelStoreParam::UnpackRowLength: case PixelStoreParam::UnpackRowLength:
@@ -100,8 +100,8 @@ namespace MobileGL {
return "UnpackSkipImages"; return "UnpackSkipImages";
case PixelStoreParam::UnpackSwapBytes: case PixelStoreParam::UnpackSwapBytes:
return "UnpackSwapBytes"; return "UnpackSwapBytes";
case PixelStoreParam::UnpackLsbFirst: case PixelStoreParam::UnpackLSBFirst:
return "UnpackLsbFirst"; return "UnpackLSBFirst";
default: default:
return "Unknown"; return "Unknown";
} }
+134
View File
@@ -0,0 +1,134 @@
// MobileGL - MobileGL/MG_Util/Math/VectorTypes.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include "VectorTypes.h"
namespace MobileGL {
void VecRange1D::Add(const Range1D& newRange, Double ratio, SizeT* outMinStart, SizeT* outMaxEnd) {
if (this->empty()) {
this->push_back(newRange);
m_overallMaxEnd = newRange.end;
if (outMinStart) *outMinStart = this->front().start;
if (outMaxEnd) *outMaxEnd = m_overallMaxEnd;
return;
}
auto it = std::lower_bound(this->begin(), this->end(), newRange.start,
[](const Range1D& a, SizeT valueStart) { return a.start < valueStart; });
size_t pos = static_cast<size_t>(std::distance(this->begin(), it));
auto calc_gap = [](const Range1D& a, const Range1D& b) -> SizeT {
return (b.start > a.end) ? (b.start - a.end) : 0;
};
auto calc_threshold = [ratio](const Range1D& a, const Range1D& b) -> SizeT {
SizeT minStart = (a.start < b.start) ? a.start : b.start;
SizeT maxEnd = (a.end > b.end) ? a.end : b.end;
SizeT span = (maxEnd > minStart) ? (maxEnd - minStart) : 0;
return static_cast<SizeT>(static_cast<Double>(span) * ratio);
};
if (pos >= this->size()) {
Range1D& last = this->back();
SizeT gap = calc_gap(last, newRange);
SizeT threshold = calc_threshold(last, newRange);
if (gap <= threshold) {
last.end = std::max(last.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, last.end);
} else {
this->push_back(newRange);
m_overallMaxEnd = std::max(m_overallMaxEnd, newRange.end);
}
if (outMinStart) *outMinStart = this->front().start;
if (outMaxEnd) *outMaxEnd = m_overallMaxEnd;
return;
}
bool merged = false;
if (pos > 0) {
Range1D& prev = (*this)[pos - 1];
SizeT gapPrev = calc_gap(prev, newRange);
SizeT thresholdPrev = calc_threshold(prev, newRange);
if (gapPrev <= thresholdPrev) {
prev.end = std::max(prev.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, prev.end);
size_t writeIdx = pos - 1;
while (writeIdx + 1 < this->size()) {
Range1D& cur = (*this)[writeIdx];
Range1D& nxt = (*this)[writeIdx + 1];
SizeT gap = calc_gap(cur, nxt);
SizeT threshold = calc_threshold(cur, nxt);
if (gap <= threshold) {
// merge nxt into cur
cur.end = std::max(cur.end, nxt.end);
this->erase(this->begin() + (writeIdx + 1));
m_overallMaxEnd = std::max(m_overallMaxEnd, cur.end);
} else {
break;
}
}
merged = true;
}
}
if (!merged) {
// Try to merge with the current pos interval or insert
Range1D& cur = (*this)[pos];
SizeT gapCur = calc_gap(newRange, cur); // gap between new and cur
SizeT thresholdCur = calc_threshold(newRange, cur);
if (gapCur <= thresholdCur) {
cur.start = std::min(cur.start, newRange.start);
cur.end = std::max(cur.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, cur.end);
size_t writeIdx = pos;
while (writeIdx + 1 < this->size()) {
Range1D& cur2 = (*this)[writeIdx];
Range1D& nxt = (*this)[writeIdx + 1];
SizeT gap = calc_gap(cur2, nxt);
SizeT threshold = calc_threshold(cur2, nxt);
if (gap <= threshold) {
cur2.end = std::max(cur2.end, nxt.end);
this->erase(this->begin() + (writeIdx + 1));
m_overallMaxEnd = std::max(m_overallMaxEnd, cur2.end);
} else {
break;
}
}
merged = true;
} else {
this->insert(this->begin() + pos, newRange);
m_overallMaxEnd = std::max(m_overallMaxEnd, newRange.end);
merged = true;
}
}
if (outMinStart) {
*outMinStart = this->front().start;
}
if (outMaxEnd) {
*outMaxEnd = m_overallMaxEnd;
}
}
SizeT VecRange1D::GetOverallMaxEnd() const {
return m_overallMaxEnd;
}
SizeT VecRange1D::GetOverallMinStart() const {
if (this->empty()) return 0;
return this->front().start;
}
} // namespace MobileGL
+11 -1
View File
@@ -11,7 +11,6 @@
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL {
template <typename Derived, typename T, SizeT N> template <typename Derived, typename T, SizeT N>
struct VecBase { struct VecBase {
Array<T, N> data; Array<T, N> data;
@@ -247,4 +246,15 @@ namespace MobileGL {
return incident - normal * (2.0f * incident.Dot(normal)); return incident - normal * (2.0f * incident.Dot(normal));
} }
} // namespace MG_Util } // namespace MG_Util
class VecRange1D : public Vector<Range1D> {
public:
void Add(const Range1D& newRange, Double ratio = 0.07, SizeT* outMinStart = nullptr,
SizeT* outMaxEnd = nullptr);
SizeT GetOverallMaxEnd() const;
SizeT GetOverallMinStart() const;
private:
SizeT m_overallMaxEnd;
};
} // namespace MobileGL } // namespace MobileGL
@@ -227,15 +227,17 @@ namespace MobileGL {
return allSpirv; return allSpirv;
} }
bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary, Vector<uint32_t>& outputBinary) { bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary,
Vector<uint32_t>& outputBinary) {
using namespace spvtools; using namespace spvtools;
OptimizerOptions options;
options.set_run_validator(false);
Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5); Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5);
optimizer optimizer.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass());
.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass())
;
return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary); return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options);
} }
Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) { Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) {
@@ -20,7 +20,8 @@ namespace MobileGL {
static Result<SharedPtr<glslang::TShader>> CompileShader(const ShaderAttrib& attrib); static Result<SharedPtr<glslang::TShader>> CompileShader(const ShaderAttrib& attrib);
static Result<SharedPtr<glslang::TProgram>> LinkProgram(const ProgramAttrib& attrib); static Result<SharedPtr<glslang::TProgram>> LinkProgram(const ProgramAttrib& attrib);
static Result<Vector<Vector<unsigned>>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib); static Result<Vector<Vector<unsigned>>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib);
static bool SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary, Vector<uint32_t>& outputBinary); static bool SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary,
Vector<uint32_t>& outputBinary);
static Result<String> DecompileShader(SpvcSession& session); static Result<String> DecompileShader(SpvcSession& session);
}; };
} // namespace ShaderTranspiler } // namespace ShaderTranspiler
@@ -1,4 +1,4 @@
// MobileGL - MobileGL/MG_Util/ShaderTranspiler/FloatEqualsZeroEliminationPass.cpp // MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
// Copyright (c) 2025-2026 MobileGL-Dev // Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0: // Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/gpl-3.0.txt
@@ -96,18 +96,13 @@ namespace MobileGL {
// 2. Create constant ID for `Epsilon` // 2. Create constant ID for `Epsilon`
const analysis::Constant* eps_const = const_mgr->GetConstant( const analysis::Constant* eps_const = const_mgr->GetConstant(
type_mgr->GetType(float_type_id), type_mgr->GetType(float_type_id), {*(reinterpret_cast<const uint32_t*>(&K_EPSILON))});
{*(reinterpret_cast<const uint32_t*>(&K_EPSILON))}
);
uint32_t eps_id = const_mgr->GetDefiningInstruction(eps_const)->result_id(); uint32_t eps_id = const_mgr->GetDefiningInstruction(eps_const)->result_id();
// 3. Build Abs(x) inst // 3. Build Abs(x) inst
// OpExtInst %float_type %glsl_import Abs %x // OpExtInst %float_type %glsl_import Abs %x
InstructionBuilder builder( InstructionBuilder builder(
context(), context(), &inst, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
&inst,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping
);
std::vector<Operand> abs_operands; std::vector<Operand> abs_operands;
abs_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl_std_450_id}}); abs_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl_std_450_id}});
@@ -117,12 +112,7 @@ namespace MobileGL {
// In GLSL.std.450, `FAbs`'s OpCode == 4 // In GLSL.std.450, `FAbs`'s OpCode == 4
// Ref: https://registry.khronos.org/SPIR-V/specs/1.0/GLSL.std.450.html // Ref: https://registry.khronos.org/SPIR-V/specs/1.0/GLSL.std.450.html
Instruction* abs_inst = builder.AddInstruction(MakeUnique<Instruction>( Instruction* abs_inst = builder.AddInstruction(MakeUnique<Instruction>(
context(), context(), spv::Op::OpExtInst, float_type_id, context()->TakeNextId(), abs_operands));
spv::Op::OpExtInst,
float_type_id,
context()->TakeNextId(),
abs_operands
));
// 4. build Abs(x) < Epsilon // 4. build Abs(x) < Epsilon
// OpFOrdLessThan %bool_type %abs_val %eps // OpFOrdLessThan %bool_type %abs_val %eps
@@ -130,14 +120,11 @@ namespace MobileGL {
less_operands.push_back({SPV_OPERAND_TYPE_ID, {abs_inst->result_id()}}); less_operands.push_back({SPV_OPERAND_TYPE_ID, {abs_inst->result_id()}});
less_operands.push_back({SPV_OPERAND_TYPE_ID, {eps_id}}); less_operands.push_back({SPV_OPERAND_TYPE_ID, {eps_id}});
bool isEqualOp = (inst.opcode() == spv::Op::OpFOrdEqual || inst.opcode() == spv::Op::OpFUnordEqual); bool isEqualOp =
(inst.opcode() == spv::Op::OpFOrdEqual || inst.opcode() == spv::Op::OpFUnordEqual);
Instruction* less_than_inst = builder.AddInstruction(MakeUnique<Instruction>( Instruction* less_than_inst = builder.AddInstruction(MakeUnique<Instruction>(
context(), context(), isEqualOp ? spv::Op::OpFOrdLessThan : spv::Op::OpFOrdGreaterThanEqual,
isEqualOp ? spv::Op::OpFOrdLessThan : spv::Op::OpFOrdGreaterThanEqual, bool_type_id, context()->TakeNextId(), less_operands));
bool_type_id,
context()->TakeNextId(),
less_operands
));
// 5. Replaces all uses of old insn with new one // 5. Replaces all uses of old insn with new one
context()->ReplaceAllUsesWith(inst.result_id(), less_than_inst->result_id()); context()->ReplaceAllUsesWith(inst.result_id(), less_than_inst->result_id());
@@ -161,5 +148,5 @@ namespace MobileGL {
return spvtools::Optimizer::PassToken(MakeUnique<EliminateFloatEqualsZeroPass>()); return spvtools::Optimizer::PassToken(MakeUnique<EliminateFloatEqualsZeroPass>());
} }
} // namespace ShaderTranspiler } // namespace ShaderTranspiler
} } // namespace MG_Util
} } // namespace MobileGL
@@ -1,4 +1,4 @@
// MobileGL - MobileGL/MG_Util/ShaderTranspiler/FloatEqualsZeroEliminationPass.h // MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.h
// Copyright (c) 2025-2026 MobileGL-Dev // Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0: // Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/gpl-3.0.txt
@@ -21,10 +21,10 @@ namespace MobileGL {
Status Process() override; Status Process() override;
static spvtools::Optimizer::PassToken CreateEliminateFloatEqualsZeroPass(); static spvtools::Optimizer::PassToken CreateEliminateFloatEqualsZeroPass();
private: private:
const float K_EPSILON = 0.0001f; const float K_EPSILON = 0.0001f;
}; };
} // namespace ShaderTranspiler } // namespace ShaderTranspiler
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -108,8 +108,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
const Int copyHeight = height; const Int copyHeight = height;
const Int copyDepth = depth; const Int copyDepth = depth;
MGLOG_D("%s: start at: (%d, %d, %d), copy size: (%d, %d, %d), i/o row stride: (%d, %dx%d)", __func__, MGLOG_D("%s: start at: (%d, %d, %d), copy size: (%d, %d, %d), i/o row stride: (%d, %dx%d)", __func__, startX,
startX, startY, startZ, copyWidth, copyHeight, copyDepth, inputRowStride, width, pixelSize); startY, startZ, copyWidth, copyHeight, copyDepth, inputRowStride, width, pixelSize);
if (copyWidth <= 0 || copyHeight <= 0 || copyDepth <= 0) { if (copyWidth <= 0 || copyHeight <= 0 || copyDepth <= 0) {
outSize = 0; outSize = 0;
@@ -14,7 +14,8 @@
namespace MobileGL::MG_Util::PixelStoreProcessor { namespace MobileGL::MG_Util::PixelStoreProcessor {
void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params, void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params,
TextureInternalFormat targetInternalFormat, TextureInputFormat textureInputFormat, TexturePixelDataType inputDataType, TextureInternalFormat targetInternalFormat,
TextureInputFormat textureInputFormat, TexturePixelDataType inputDataType,
IntVec3 dimension, Bool isBitmap, SizeT& outSize); IntVec3 dimension, Bool isBitmap, SizeT& outSize);
void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize,
IntVec3 dimension, Bool isBitmap, SizeT& outSize); IntVec3 dimension, Bool isBitmap, SizeT& outSize);
@@ -10,7 +10,8 @@
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h" #include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
namespace MobileGL::MG_Util::TextureFormatProcessor { namespace MobileGL::MG_Util::TextureFormatProcessor {
void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options, GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType) { void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options,
GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -183,7 +184,8 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
break; break;
default: default:
MGLOG_E("NormalizePixelFormat: outFormat: unhandled internalFormat: %s", MG_Util::ConvertGLEnumToString(internalFormat).c_str()); MGLOG_E("NormalizePixelFormat: outFormat: unhandled internalFormat: %s",
MG_Util::ConvertGLEnumToString(internalFormat).c_str());
// Fallback handling for other formats // Fallback handling for other formats
// Try to infer format from internal format name // Try to infer format from internal format name
if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGBA") != nullptr) { if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGBA") != nullptr) {
@@ -335,7 +337,8 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
break; break;
default: default:
MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s", MG_Util::ConvertGLEnumToString(internalFormat).c_str()); MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s",
MG_Util::ConvertGLEnumToString(internalFormat).c_str());
// Fallback handling for other formats // Fallback handling for other formats
*outType = GL_UNSIGNED_BYTE; *outType = GL_UNSIGNED_BYTE;
break; break;
@@ -9,10 +9,14 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Util::TextureFormatProcessor { namespace MobileGL {
enum class PixelFormatNormalizeOptionBit : Uint { enum class PixelFormatNormalizeOptionBit : Uint {
NoNorm16 = 1 << 0, NoNorm16 = 1 << 0,
None = 0, None = 0,
}; };
void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options, GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType);
} // namespace MobileGL::MG_Util::TextureFormatProcessor namespace MG_Util::TextureFormatProcessor {
void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options,
GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType);
}
} // namespace MobileGL
+7 -4
View File
@@ -145,17 +145,20 @@ namespace MobileGL {
using TargetEnum = typename ObjectType::TargetEnum; using TargetEnum = typename ObjectType::TargetEnum;
BindingSlot() : m_target((TargetEnum)0), m_boundObject(nullptr) {} BindingSlot() : m_target((TargetEnum)0), m_boundObject(nullptr) {}
explicit BindingSlot(TargetEnum target) : m_target(target), m_boundObject(nullptr) {} explicit BindingSlot(TargetEnum target) : m_target(target), m_boundObject(nullptr) {}
void Bind(SharedPtr<ObjectType> object) {
if (m_boundObject == object) return;
void Bind(SharedPtr<ObjectType> object) { m_boundObject = object; } m_boundObject = object;
++m_version;
}
SharedPtr<ObjectType> GetBoundObject() const { return m_boundObject; } SharedPtr<ObjectType> GetBoundObject() const { return m_boundObject; }
TargetEnum GetTarget() const { return m_target; } TargetEnum GetTarget() const { return m_target; }
Uint16 GetVersion() const { return m_version; }
private: private:
TargetEnum m_target; TargetEnum m_target;
Uint16 m_version = 0;
SharedPtr<ObjectType> m_boundObject; SharedPtr<ObjectType> m_boundObject;
}; };
+1 -1
View File
@@ -91,7 +91,7 @@ If you want to try the project right now, youll need to build it yourself:
## Build Options ## Build Options
| Option | Description | Default | | Option | Description | Default |
| ---------------------------- | ----------------------------------------------------- | ------- | |------------------------------| ----------------------------------------------------- | ------- |
| `MOBILEGL_BUILD_TEST` | Build MobileGL tests (requires Clang) | ON | | `MOBILEGL_BUILD_TEST` | Build MobileGL tests (requires Clang) | ON |
| `MOBILEGL_BUILD_BENCHMARK` | Build MobileGL benchmarks (requires Clang) | ON | | `MOBILEGL_BUILD_BENCHMARK` | Build MobileGL benchmarks (requires Clang) | ON |
| `MOBILEGL_FORCE_RELEASE_OPT` | Enable O3 and LTO in Debug build | ON | | `MOBILEGL_FORCE_RELEASE_OPT` | Enable O3 and LTO in Debug build | ON |
+1 -1
View File
@@ -11,7 +11,7 @@ android {
// externalNativeBuild { // externalNativeBuild {
// cmake { // cmake {
// arguments "-DTRACY_ENABLE=ON" // arguments "-DMOBILEGL_ENABLE_TRACY=ON"
// } // }
// } // }
} }