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
+51 -28
View File
@@ -13,10 +13,32 @@ 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)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 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)
endif()
else()
message(STATUS "IPO not supported: ${LTOError}")
endif() 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")
@@ -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,33 +272,35 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
add_library(${CMAKE_PROJECT_NAME}_s STATIC if(NOT ANDROID)
${SOURCE_FILES} add_library(${CMAKE_PROJECT_NAME}_s STATIC
) ${SOURCE_FILES}
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES
C_VISIBILITY_PRESET default
CXX_VISIBILITY_PRESET default
VISIBILITY_INLINES_HIDDEN OFF
) )
else()
set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES if (CMAKE_BUILD_TYPE STREQUAL "Debug")
C_VISIBILITY_PRESET hidden set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES
CXX_VISIBILITY_PRESET hidden C_VISIBILITY_PRESET default
VISIBILITY_INLINES_HIDDEN ON CXX_VISIBILITY_PRESET default
VISIBILITY_INLINES_HIDDEN OFF
)
else()
set_target_properties(${CMAKE_PROJECT_NAME}_s PROPERTIES
C_VISIBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
)
endif()
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC
${MOBILEGL_INCLUDE_DIR}
)
target_link_libraries(${CMAKE_PROJECT_NAME}_s
PRIVATE
${MOBILEGL_LINK_LIBRARIES}
) )
endif() endif()
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC
${MOBILEGL_INCLUDE_DIR}
)
target_link_libraries(${CMAKE_PROJECT_NAME}_s
PRIVATE
${MOBILEGL_LINK_LIBRARIES}
)
if (TRACY_ENABLE) if (TRACY_ENABLE)
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient) target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient)
target_link_libraries(${CMAKE_PROJECT_NAME}_s PUBLIC Tracy::TracyClient) target_link_libraries(${CMAKE_PROJECT_NAME}_s 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)
+182 -302
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,6 +89,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
// TODO: deletion for deleted objects // TODO: deletion for deleted objects
namespace BufferImpl { namespace BufferImpl {
void CreateAndSyncBufferObject(SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject);
SharedPtr<BackendBufferObject> backendBufferObject;
if (backendBufferIt == g_backendBufferObjects.end()) {
backendBufferObject = MakeShared<BackendBufferObject>();
g_backendBufferObjects[bufferObject] = backendBufferObject;
} else {
backendBufferObject = backendBufferIt->second;
}
backendBufferObject->SyncToBackend(bufferObject);
}
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) { void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -94,7 +111,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO) // 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 // PBO is not needed since it should be handled in frontend
Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync; // static Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
// buffersToSync.clear();
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) { if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers."); MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
@@ -104,35 +123,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
// VBO // VBO
for (const auto& attrib : currentVAOObject->GetAllAttributes()) { for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
if (!attrib.Enabled) continue; if (!attrib.Enabled) continue;
const auto& bufferObject = attrib.Buffer; auto bufferObject = attrib.Buffer;
if (bufferObject) { if (bufferObject) {
const auto& end = buffersToSync.end(); CreateAndSyncBufferObject(bufferObject);
if (std::find(buffersToSync.begin(), end, bufferObject) == end) {
buffersToSync.push_back(bufferObject);
}
} }
} }
// IBO // IBO
if (includeIBO) { if (includeIBO) {
const auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); auto possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (possibleIBO) { if (possibleIBO) {
const auto& end = buffersToSync.end(); CreateAndSyncBufferObject(possibleIBO);
if (std::find(buffersToSync.begin(), end, possibleIBO) == end) {
buffersToSync.push_back(possibleIBO);
}
} }
} }
// Indirect Buffer Object // Indirect Buffer Object
if (includeIndirectBuffer) { if (includeIndirectBuffer) {
const auto& possibleIndirectBuffer = auto possibleIndirectBuffer =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (possibleIndirectBuffer) { if (possibleIndirectBuffer) {
const auto& end = buffersToSync.end(); CreateAndSyncBufferObject(possibleIndirectBuffer);
if (std::find(buffersToSync.begin(), end, possibleIndirectBuffer) == end) {
buffersToSync.push_back(possibleIndirectBuffer);
}
} }
} }
@@ -142,30 +152,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i); auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
auto obj = point.GetBoundObject(); auto obj = point.GetBoundObject();
if (obj) { if (obj) {
const auto& end = buffersToSync.end(); CreateAndSyncBufferObject(obj);
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);
SharedPtr<BackendBufferObject> backendBufferObject;
if (backendBufferIt == g_backendBufferObjects.end()) {
backendBufferObject = MakeShared<BackendBufferObject>();
g_backendBufferObjects[bufferObject] = backendBufferObject;
} else {
backendBufferObject = backendBufferIt->second;
}
backendBufferObject->SyncToBackend(bufferObject);
}
} }
} // 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,34 +223,14 @@ 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(); SyncTextureObjectToBackend(textureObject);
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);
}
} }
} // namespace TextureImpl } // namespace TextureImpl
@@ -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) { \
MG_External::GLES::glEnable(cap_gl); \ if (parameters.cap_mg##Enabled) { \
} else { \ MG_External::GLES::glEnable(cap_gl); \
MG_External::GLES::glDisable(cap_gl); \ } else { \
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,33 +327,48 @@ 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) {
MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()), const BoolVec4& colorMask = parameters.ColorMask;
ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w())); MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()),
ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w()));
}
} }
{ // Clear values { // Clear values
const FloatVec4& clearCol = MG_State::pGLContext->GetClearColor(); if (parameters.ClearColor != g_syncedRenderStateParameters.ClearColor) {
MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w()); const FloatVec4& clearCol = parameters.ClearColor;
MG_External::GLES::glClearDepthf(MG_State::pGLContext->GetClearDepth()); MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w());
}
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) {
MG_External::GLES::glCullFace(MG_Util::ConvertCullFaceModeToGLEnum(cfm)); const CullFaceMode& cfm = parameters.CullFaceModeSetting;
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) {
MG_External::GLES::glScissor(scissorBox.x(), scissorBox.y(), scissorBox.z(), scissorBox.w()); const IntVec4& scissorBox = parameters.ScissorBox;
MG_External::GLES::glScissor(scissorBox.x(), scissorBox.y(), scissorBox.z(), scissorBox.w());
}
} }
g_syncedRenderStateVersion = currentRenderStateVersion;
g_syncedRenderStateParameters = parameters;
} }
} // namespace RenderStateImpl } // namespace RenderStateImpl
@@ -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,15 +816,38 @@ 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
DebugImpl::OpenGLScopeMarker marker(__func__); DebugImpl::OpenGLScopeMarker marker(__func__);
#endif #endif
DebugImpl::ErrorLopper errorLopper; DebugImpl::ErrorLopper errorLopper;
MGLOG_D("%s: Backend", __func__); MGLOG_D("%s: Backend", __func__);
@@ -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); \
File diff suppressed because it is too large Load Diff
+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);
@@ -88,7 +88,7 @@ namespace MobileGL {
return MG_External::EGL::eglQuerySurface(display, surface, attribute, value); return MG_External::EGL::eglQuerySurface(display, surface, attribute, value);
} }
char const * QueryString(EGLDisplay display, EGLint name) { char const* QueryString(EGLDisplay display, EGLint name) {
return MG_External::EGL::eglQueryString(display, name); return MG_External::EGL::eglQueryString(display, name);
} }
@@ -122,7 +122,7 @@ namespace MobileGL {
} }
EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap,
const EGLint* attrib_list) { const EGLint* attrib_list) {
return MG_External::EGL::eglCreatePixmapSurface(dpy, config, pixmap, attrib_list); return MG_External::EGL::eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
} }
@@ -170,51 +170,45 @@ namespace MobileGL {
return (__eglMustCastToProperFunctionPointerType)proc; return (__eglMustCastToProperFunctionPointerType)proc;
} }
EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list) { EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) {
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);
} }
@@ -98,7 +98,7 @@ namespace MobileGL {
return EGL_TRUE; return EGL_TRUE;
} }
char const * QueryString(EGLDisplay display, EGLint name) { char const* QueryString(EGLDisplay display, EGLint name) {
return ""; return "";
} }
@@ -132,7 +132,7 @@ namespace MobileGL {
} }
EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap,
const EGLint* attrib_list) { const EGLint* attrib_list) {
return (EGLSurface)1; return (EGLSurface)1;
} }
@@ -29,7 +29,7 @@ namespace MobileGL {
EGLBoolean BindAPI(EGLenum api); EGLBoolean BindAPI(EGLenum api);
EGLSurface GetCurrentSurface(EGLint readdraw); EGLSurface GetCurrentSurface(EGLint readdraw);
EGLBoolean QuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value); EGLBoolean QuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value);
char const * QueryString(EGLDisplay display, EGLint name); char const* QueryString(EGLDisplay display, EGLint name);
EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval); EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval);
EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw); EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw);
EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list); EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list);
@@ -39,7 +39,7 @@ namespace MobileGL {
EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
EGLConfig config, const EGLint* attrib_list); EGLConfig config, const EGLint* attrib_list);
EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap,
const EGLint* attrib_list); const EGLint* attrib_list);
EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config); EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config);
EGLDisplay GetCurrentDisplay(void); EGLDisplay GetCurrentDisplay(void);
EGLenum QueryAPI(void); EGLenum QueryAPI(void);
@@ -49,15 +49,18 @@ namespace MobileGL {
EGLBoolean WaitGL(void); EGLBoolean WaitGL(void);
EGLBoolean WaitNative(EGLint engine); EGLBoolean WaitNative(EGLint engine);
__eglMustCastToProperFunctionPointerType GetProcAddress(const char* name); __eglMustCastToProperFunctionPointerType GetProcAddress(const char* name);
EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list); EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list);
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);
+83 -36
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,
@@ -1227,12 +1228,58 @@ 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);
} }
+4 -4
View File
@@ -20,10 +20,10 @@ namespace MobileGL {
const GLvoid* pixels); const GLvoid* pixels);
void TexParameterf(GLenum target, GLenum pname, GLfloat param); void TexParameterf(GLenum target, GLenum pname, GLfloat param);
void TexParameteri(GLenum target, GLenum pname, GLint param); void TexParameteri(GLenum target, GLenum pname, GLint param);
void TexParameterfv(GLenum target, GLenum pname, const GLfloat * params); void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
void TexParameteriv(GLenum target, GLenum pname, const GLint * params); void TexParameteriv(GLenum target, GLenum pname, const GLint* params);
void TexParameterIiv(GLenum target, GLenum pname, const GLint * params); void TexParameterIiv(GLenum target, GLenum pname, const GLint* params);
void TexParameterIuiv(GLenum target, GLenum pname, const GLuint * params); void TexParameterIuiv(GLenum target, GLenum pname, const GLuint* params);
void TexImage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, void TexImage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth, GLboolean fixedsamplelocations); GLsizei depth, GLboolean fixedsamplelocations);
+27 -7
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
+3 -3
View File
@@ -7,9 +7,9 @@
// End of Source File Header // End of Source File Header
#include "GetProcAddress.h" #include "GetProcAddress.h"
#define GETPROC(name, var) \ #define GETPROC(name, var) \
if (strcmp(#name, var) == 0) { \ if (strcmp(#name, var) == 0) { \
return (void*)name; \ return (void*)name; \
} }
namespace MobileGL { namespace MobileGL {
@@ -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
@@ -453,7 +453,7 @@ namespace MobileGL {
MGLOG_D("ProgramObject %u: GenerateBinary - generated %zu SPIR-V modules", m_externalIndex, MGLOG_D("ProgramObject %u: GenerateBinary - generated %zu SPIR-V modules", m_externalIndex,
m_generatedSpirv.size()); m_generatedSpirv.size());
for (auto& spv: m_generatedSpirv) { for (auto& spv : m_generatedSpirv) {
auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv); auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv);
MOBILEGL_ASSERT(success, "SanitizeBinary failed"); MOBILEGL_ASSERT(success, "SanitizeBinary failed");
} }
@@ -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));
} }
+1 -1
View File
@@ -925,7 +925,7 @@ TEST_F(ProgramTest, CompileAndLinkWithExplicitVertexIn) {
// auto& vertexSpirv = spirvs[1]; // 0 - fragment, 1 - vertex // auto& vertexSpirv = spirvs[1]; // 0 - fragment, 1 - vertex
char* pSrcVertIn = nullptr; char* pSrcVertIn = nullptr;
const char* needle = "layout(location = 2) in vec2 UV0;"; const char* needle = "layout(location = 2) in vec2 UV0;";
for (auto spirv: spirvs) { for (auto spirv : spirvs) {
MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirv); MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirv);
spvc_compiler_options options; spvc_compiler_options options;
spvcSession.CreateOptions(&options); spvcSession.CreateOptions(&options);
@@ -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() {
@@ -511,16 +511,18 @@ namespace MobileGL {
typedef EGLBoolean (*eglWaitClient_PTR)(); typedef EGLBoolean (*eglWaitClient_PTR)();
typedef EGLBoolean (*eglWaitGL_PTR)(); typedef EGLBoolean (*eglWaitGL_PTR)();
typedef EGLBoolean (*eglWaitNative_PTR)(EGLint engine); typedef EGLBoolean (*eglWaitNative_PTR)(EGLint engine);
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,13 +30,22 @@ namespace MobileGL {
} }
switch (attachment) { switch (attachment) {
case GL_DEPTH_ATTACHMENT: case GL_NONE:
return FramebufferAttachmentType::Depth; return FramebufferAttachmentType::None;
case GL_STENCIL_ATTACHMENT: case GL_DEPTH_ATTACHMENT:
return FramebufferAttachmentType::Stencil; return FramebufferAttachmentType::Depth;
case GL_UNKNOWN_MGL: case GL_STENCIL_ATTACHMENT:
default: return FramebufferAttachmentType::Stencil;
return FramebufferAttachmentType::Unknown; 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:
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;
} }
} }
@@ -29,12 +29,20 @@ namespace MobileGL {
} }
switch (type) { switch (type) {
case FramebufferAttachmentType::Depth: case FramebufferAttachmentType::Depth:
return GL_DEPTH_ATTACHMENT; return GL_DEPTH_ATTACHMENT;
case FramebufferAttachmentType::Stencil: case FramebufferAttachmentType::Stencil:
return GL_STENCIL_ATTACHMENT; return GL_STENCIL_ATTACHMENT;
default: case FramebufferAttachmentType::FrontLeft:
return GL_NONE; 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:
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,144 +53,263 @@ 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:
case TextureInternalFormat::R16: case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm: case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::RG8: case TextureInternalFormat::RG8:
case TextureInternalFormat::RG8Snorm: case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG16: case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm: case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::R3G3B2: case TextureInternalFormat::R3G3B2:
case TextureInternalFormat::RGB4: case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5: case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB8: case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm: case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::RGB10: case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12: case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16Snorm: case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGBA2: case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4: case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGB5A1: case TextureInternalFormat::RGB5A1:
case TextureInternalFormat::RGBA8: case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm: case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGB10A2: case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI: case TextureInternalFormat::RGB10A2UI:
case TextureInternalFormat::RGBA12: case TextureInternalFormat::RGBA12:
case TextureInternalFormat::RGBA16: case TextureInternalFormat::RGBA16:
case TextureInternalFormat::SRGB8: case TextureInternalFormat::SRGB8:
case TextureInternalFormat::SRGB8Alpha8: case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::R16F: case TextureInternalFormat::R16F:
case TextureInternalFormat::RG16F: case TextureInternalFormat::RG16F:
case TextureInternalFormat::RGB16F: case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGBA16F: case TextureInternalFormat::RGBA16F:
case TextureInternalFormat::R32F: case TextureInternalFormat::R32F:
case TextureInternalFormat::RG32F: case TextureInternalFormat::RG32F:
case TextureInternalFormat::RGB32F: case TextureInternalFormat::RGB32F:
case TextureInternalFormat::RGBA32F: case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::R11FG11FB10F: case TextureInternalFormat::R11FG11FB10F:
case TextureInternalFormat::RGB9E5: case TextureInternalFormat::RGB9E5:
case TextureInternalFormat::R8I: case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI: case TextureInternalFormat::R8UI:
case TextureInternalFormat::R16I: case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI: case TextureInternalFormat::R16UI:
case TextureInternalFormat::R32I: case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI: case TextureInternalFormat::R32UI:
case TextureInternalFormat::RG8I: case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI: case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG16I: case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI: case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG32I: case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI: case TextureInternalFormat::RG32UI:
case TextureInternalFormat::RGB8I: case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI: case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB16I: case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI: case TextureInternalFormat::RGB16UI:
case TextureInternalFormat::RGB32I: case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI: case TextureInternalFormat::RGB32UI:
case TextureInternalFormat::RGBA8I: case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI: case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::RGBA16I: case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI: case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA32I: case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI: case TextureInternalFormat::RGBA32UI:
case TextureInternalFormat::DepthComponent16: case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24: case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32: // not a standard format in OpenGL core profile case TextureInternalFormat::DepthComponent32: // not a standard format in OpenGL core profile
case TextureInternalFormat::DepthComponent32F: case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::Depth24Stencil8: case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8: case TextureInternalFormat::Depth32FStencil8:
return internalformat; return internalformat;
// probably we should assume unorm here? // probably we should assume unorm here?
case TextureInternalFormat::RGBA: { case TextureInternalFormat::RGBA: {
switch (type) { switch (type) {
case TexturePixelDataType::UnsignedByte: case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RGBA8; return TextureInternalFormat::RGBA8;
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::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
case TextureInternalFormat::RGB: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RGB8;
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::RG: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RG8;
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::RG16;
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::Red: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::R8;
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::R16;
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;
}
}
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;
} }
} }
case TextureInternalFormat::RGB: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RGB8;
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::RG: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::RG8;
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::RG16;
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::Red: {
switch (type) {
case TexturePixelDataType::UnsignedByte:
return TextureInternalFormat::R8;
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::R16;
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::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::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
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;
}
}
}
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";
} }
+2 -2
View File
@@ -91,9 +91,9 @@ namespace MobileGL {
int n = std::vsnprintf(buffer, sizeof(buffer), fmt, args); int n = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
std::string out = header + std::string out = header +
#if MOBILEGL_LOG_ENABLE_STACKTRACE #if MOBILEGL_LOG_ENABLE_STACKTRACE
padding + padding +
#endif #endif
std::string(buffer, n) + "\n"; std::string(buffer, n) + "\n";
#if MOBILEGL_LOG_ENABLE_CONSOLE #if MOBILEGL_LOG_ENABLE_CONSOLE
std::fwrite(out.c_str(), 1, out.size(), stdout); std::fwrite(out.c_str(), 1, out.size(), stdout);
+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
@@ -39,7 +39,7 @@ namespace MobileGL {
// 3. iterate all function -> basic block -> insn // 3. iterate all function -> basic block -> insn
for (auto& func : *get_module()) { for (auto& func : *get_module()) {
for (auto& bb : func) { for (auto& bb : func) {
for (auto itInst = bb.begin(); itInst != bb.end(); ) { for (auto itInst = bb.begin(); itInst != bb.end();) {
auto& inst = *itInst; auto& inst = *itInst;
bool shouldSkip = true; bool shouldSkip = true;
@@ -48,14 +48,14 @@ namespace MobileGL {
// `OpFOrdNotEqual` or `OpFUnordNotEqual`, // `OpFOrdNotEqual` or `OpFUnordNotEqual`,
// simply skip if irrelevant // simply skip if irrelevant
switch (inst.opcode()) { switch (inst.opcode()) {
case spv::Op::OpFOrdEqual: case spv::Op::OpFOrdEqual:
case spv::Op::OpFUnordEqual: case spv::Op::OpFUnordEqual:
case spv::Op::OpFOrdNotEqual: case spv::Op::OpFOrdNotEqual:
case spv::Op::OpFUnordNotEqual: case spv::Op::OpFUnordNotEqual:
shouldSkip = false; shouldSkip = false;
break; break;
default: default:
break; break;
} }
if (shouldSkip) { if (shouldSkip) {
@@ -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
@@ -15,16 +15,16 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Util { namespace MG_Util {
namespace ShaderTranspiler { namespace ShaderTranspiler {
class EliminateFloatEqualsZeroPass: public spvtools::opt::Pass { class EliminateFloatEqualsZeroPass : public spvtools::opt::Pass {
public: public:
const char* name() const override { return "float-equals-zero-elimination"; } const char* name() const override { return "float-equals-zero-elimination"; }
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;
@@ -152,14 +152,14 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
if (textureInputFormat == TextureInputFormat::BGRA && if (textureInputFormat == TextureInputFormat::BGRA &&
targetInternalFormat == TextureInternalFormat::RGBA8) { targetInternalFormat == TextureInternalFormat::RGBA8) {
MGLOG_D("%s: Swizzle (BGRA)", __func__); MGLOG_D("%s: Swizzle (BGRA)", __func__);
// MGLOG_D("%s: pixel0 before = %x", __func__, *((Uint32*)layerDst)); // MGLOG_D("%s: pixel0 before = %x", __func__, *((Uint32*)layerDst));
ProcessColorSwizzle(layerDst, static_cast<SizeT>(copyWidth), ProcessColorSwizzle(layerDst, static_cast<SizeT>(copyWidth),
{TextureSwizzleParam::Green, TextureSwizzleParam::Blue, {TextureSwizzleParam::Green, TextureSwizzleParam::Blue,
TextureSwizzleParam::Alpha, TextureSwizzleParam::Red}); TextureSwizzleParam::Alpha, TextureSwizzleParam::Red});
// MGLOG_D("%s: pixel0 after = %x", __func__, *((Uint32*)layerDst)); // MGLOG_D("%s: pixel0 after = %x", __func__, *((Uint32*)layerDst));
} }
// else // else
// MGLOG_D("%s: pixel0 = %x", __func__, *((Uint32*)layerDst)); // MGLOG_D("%s: pixel0 = %x", __func__, *((Uint32*)layerDst));
layerSrc += inputRowStride; layerSrc += inputRowStride;
layerDst += outputRowStride; layerDst += outputRowStride;
@@ -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,335 +10,338 @@
#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
// internal format // internal format
if (outInternalFormat) { if (outInternalFormat) {
switch (internalFormat) { switch (internalFormat) {
case GL_DEPTH_COMPONENT32: case GL_DEPTH_COMPONENT32:
*outInternalFormat = GL_DEPTH_COMPONENT; *outInternalFormat = GL_DEPTH_COMPONENT;
break;
case GL_RGBA16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RGBA32F;
break; break;
case GL_RGBA16: }
if (options & PixelFormatNormalizeOptionBit::NoNorm16) { case GL_RGB16:
*outInternalFormat = GL_RGBA32F; if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
break; *outInternalFormat = GL_RGB32F;
}
case GL_RGB16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RGB32F;
break;
}
case GL_RG16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RG32F;
break;
}
case GL_R16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_R32F;
break;
}
default:
*outInternalFormat = internalFormat;
break; break;
}
case GL_RG16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RG32F;
break;
}
case GL_R16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_R32F;
break;
}
default:
*outInternalFormat = internalFormat;
break;
} }
} }
// format // format
if (outFormat) { if (outFormat) {
switch (internalFormat) { switch (internalFormat) {
// Color Unsigned Normalized // Color Unsigned Normalized
case GL_RGBA: case GL_RGBA:
case GL_RGBA16: case GL_RGBA16:
case GL_RGBA8: case GL_RGBA8:
*outFormat = GL_RGBA;
break;
case GL_RGB:
case GL_RGB16:
case GL_RGB8:
*outFormat = GL_RGB;
break;
case GL_RG:
case GL_RG16:
case GL_RG8:
*outFormat = GL_RG;
break;
case GL_RED:
case GL_R16:
case GL_R8:
*outFormat = GL_RED;
break;
// Color Signed Normalized
case GL_RGBA_SNORM:
case GL_RGBA16_SNORM:
case GL_RGBA8_SNORM:
*outFormat = GL_RGBA;
break;
case GL_RGB_SNORM:
case GL_RGB16_SNORM:
case GL_RGB8_SNORM:
*outFormat = GL_RGB;
break;
case GL_RG_SNORM:
case GL_RG16_SNORM:
case GL_RG8_SNORM:
*outFormat = GL_RG;
break;
case GL_RED_SNORM:
case GL_R16_SNORM:
case GL_R8_SNORM:
*outFormat = GL_RED;
break;
// Color Integer
case GL_RGBA32UI:
case GL_RGBA16UI:
case GL_RGBA8UI:
case GL_RGBA32I:
case GL_RGBA16I:
case GL_RGBA8I:
*outFormat = GL_RGBA_INTEGER;
break;
case GL_RGB32UI:
case GL_RGB16UI:
case GL_RGB8UI:
case GL_RGB32I:
case GL_RGB16I:
case GL_RGB8I:
*outFormat = GL_RGB_INTEGER;
break;
case GL_RG32UI:
case GL_RG16UI:
case GL_RG8UI:
case GL_RG32I:
case GL_RG16I:
case GL_RG8I:
*outFormat = GL_RG_INTEGER;
break;
case GL_R32UI:
case GL_R16UI:
case GL_R8UI:
case GL_R32I:
case GL_R16I:
case GL_R8I:
*outFormat = GL_RED_INTEGER;
break;
// Color Float
case GL_RGBA32F:
case GL_RGBA16F:
*outFormat = GL_RGBA;
break;
case GL_RGB32F:
case GL_RGB16F:
*outFormat = GL_RGB;
break;
case GL_RG32F:
case GL_RG16F:
*outFormat = GL_RG;
break;
case GL_R32F:
case GL_R16F:
*outFormat = GL_RED;
break;
// Color sRGB
case GL_SRGB:
case GL_SRGB8:
*outFormat = GL_RGB;
break;
// Color sized other
case GL_RGB9_E5:
case GL_R11F_G11F_B10F:
*outFormat = GL_RGB;
break;
case GL_RGB10_A2:
case GL_RGB5_A1:
*outFormat = GL_RGBA;
break;
// Depth
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT:
*outFormat = GL_DEPTH_COMPONENT;
break;
// Depth Stencil
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outFormat = GL_DEPTH_STENCIL;
break;
default:
MGLOG_E("NormalizePixelFormat: outFormat: unhandled internalFormat: %s",
MG_Util::ConvertGLEnumToString(internalFormat).c_str());
// Fallback handling for other formats
// Try to infer format from internal format name
if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGBA") != nullptr) {
*outFormat = GL_RGBA; *outFormat = GL_RGBA;
break; } else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGB") != nullptr) {
case GL_RGB:
case GL_RGB16:
case GL_RGB8:
*outFormat = GL_RGB; *outFormat = GL_RGB;
break; } else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RG") != nullptr) {
case GL_RG:
case GL_RG16:
case GL_RG8:
*outFormat = GL_RG; *outFormat = GL_RG;
break; } else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RED") != nullptr) {
case GL_RED:
case GL_R16:
case GL_R8:
*outFormat = GL_RED; *outFormat = GL_RED;
break; } else {
*outFormat = GL_RGBA; // Ultimate fallback
// Color Signed Normalized }
case GL_RGBA_SNORM: break;
case GL_RGBA16_SNORM:
case GL_RGBA8_SNORM:
*outFormat = GL_RGBA;
break;
case GL_RGB_SNORM:
case GL_RGB16_SNORM:
case GL_RGB8_SNORM:
*outFormat = GL_RGB;
break;
case GL_RG_SNORM:
case GL_RG16_SNORM:
case GL_RG8_SNORM:
*outFormat = GL_RG;
break;
case GL_RED_SNORM:
case GL_R16_SNORM:
case GL_R8_SNORM:
*outFormat = GL_RED;
break;
// Color Integer
case GL_RGBA32UI:
case GL_RGBA16UI:
case GL_RGBA8UI:
case GL_RGBA32I:
case GL_RGBA16I:
case GL_RGBA8I:
*outFormat = GL_RGBA_INTEGER;
break;
case GL_RGB32UI:
case GL_RGB16UI:
case GL_RGB8UI:
case GL_RGB32I:
case GL_RGB16I:
case GL_RGB8I:
*outFormat = GL_RGB_INTEGER;
break;
case GL_RG32UI:
case GL_RG16UI:
case GL_RG8UI:
case GL_RG32I:
case GL_RG16I:
case GL_RG8I:
*outFormat = GL_RG_INTEGER;
break;
case GL_R32UI:
case GL_R16UI:
case GL_R8UI:
case GL_R32I:
case GL_R16I:
case GL_R8I:
*outFormat = GL_RED_INTEGER;
break;
// Color Float
case GL_RGBA32F:
case GL_RGBA16F:
*outFormat = GL_RGBA;
break;
case GL_RGB32F:
case GL_RGB16F:
*outFormat = GL_RGB;
break;
case GL_RG32F:
case GL_RG16F:
*outFormat = GL_RG;
break;
case GL_R32F:
case GL_R16F:
*outFormat = GL_RED;
break;
// Color sRGB
case GL_SRGB:
case GL_SRGB8:
*outFormat = GL_RGB;
break;
// Color sized other
case GL_RGB9_E5:
case GL_R11F_G11F_B10F:
*outFormat = GL_RGB;
break;
case GL_RGB10_A2:
case GL_RGB5_A1:
*outFormat = GL_RGBA;
break;
// Depth
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT:
*outFormat = GL_DEPTH_COMPONENT;
break;
// Depth Stencil
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outFormat = GL_DEPTH_STENCIL;
break;
default:
MGLOG_E("NormalizePixelFormat: outFormat: unhandled internalFormat: %s", MG_Util::ConvertGLEnumToString(internalFormat).c_str());
// Fallback handling for other formats
// Try to infer format from internal format name
if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGBA") != nullptr) {
*outFormat = GL_RGBA;
} else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RGB") != nullptr) {
*outFormat = GL_RGB;
} else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RG") != nullptr) {
*outFormat = GL_RG;
} else if (strstr(MG_Util::ConvertGLEnumToString(internalFormat).c_str(), "RED") != nullptr) {
*outFormat = GL_RED;
} else {
*outFormat = GL_RGBA; // Ultimate fallback
}
break;
} }
} }
// type // type
if (outType) { if (outType) {
switch (internalFormat) { switch (internalFormat) {
// Color Unsigned Normalized // Color Unsigned Normalized
case GL_RGBA16: case GL_RGBA16:
case GL_RGB16: case GL_RGB16:
case GL_RG16: case GL_RG16:
case GL_R16: case GL_R16:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) { if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
// converted to GL_RGBA32F // converted to GL_RGBA32F
*outType = GL_FLOAT;
break;
} else {
*outType = GL_UNSIGNED_SHORT;
break;
}
case GL_RGBA8:
case GL_RGB8:
case GL_RG8:
case GL_R8:
*outType = GL_UNSIGNED_BYTE;
break;
// Color Signed Normalized
case GL_RGBA16_SNORM:
case GL_RGB16_SNORM:
case GL_RG16_SNORM:
case GL_R16_SNORM:
*outType = GL_SHORT;
break;
case GL_RGBA8_SNORM:
case GL_RGB8_SNORM:
case GL_RG8_SNORM:
case GL_R8_SNORM:
*outType = GL_BYTE;
break;
// Color Unsigned Integer
case GL_RGBA32UI:
case GL_RGB32UI:
case GL_RG32UI:
case GL_R32UI:
*outType = GL_UNSIGNED_INT;
break;
case GL_RGBA16UI:
case GL_RGB16UI:
case GL_RG16UI:
case GL_R16UI:
*outType = GL_UNSIGNED_SHORT;
break;
case GL_RGBA8UI:
case GL_RGB8UI:
case GL_RG8UI:
case GL_R8UI:
*outType = GL_UNSIGNED_BYTE;
break;
// Color Integer
case GL_RGBA32I:
case GL_RGB32I:
case GL_RG32I:
case GL_R32I:
*outType = GL_INT;
break;
case GL_RGBA16I:
case GL_RGB16I:
case GL_RG16I:
case GL_R16I:
*outType = GL_SHORT;
break;
case GL_RGBA8I:
case GL_RGB8I:
case GL_RG8I:
case GL_R8I:
*outType = GL_BYTE;
break;
// Color Float
case GL_RGBA32F:
case GL_RGB32F:
case GL_RG32F:
case GL_R32F:
*outType = GL_FLOAT; *outType = GL_FLOAT;
break; break;
case GL_RGBA16F: } else {
case GL_RGB16F:
case GL_RG16F:
case GL_R16F:
*outType = GL_HALF_FLOAT;
break;
// Color sRGB
case GL_SRGB8:
*outType = GL_UNSIGNED_BYTE;
break;
// Color sized other
case GL_RGB9_E5:
*outType = GL_UNSIGNED_INT_5_9_9_9_REV;
break;
case GL_R11F_G11F_B10F:
*outType = GL_UNSIGNED_INT_10F_11F_11F_REV;
break;
case GL_RGB10_A2:
*outType = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case GL_RGB5_A1:
*outType = GL_UNSIGNED_SHORT_5_5_5_1;
break;
// Depth
case GL_DEPTH_COMPONENT16:
*outType = GL_UNSIGNED_SHORT; *outType = GL_UNSIGNED_SHORT;
break; break;
case GL_DEPTH_COMPONENT24: }
*outType = GL_UNSIGNED_INT; case GL_RGBA8:
break; case GL_RGB8:
case GL_DEPTH_COMPONENT32: case GL_RG8:
*outType = GL_UNSIGNED_INT; case GL_R8:
break; *outType = GL_UNSIGNED_BYTE;
case GL_DEPTH_COMPONENT32F: break;
*outType = GL_FLOAT;
break;
case GL_DEPTH_COMPONENT:
*outType = GL_UNSIGNED_INT;
break;
// Depth Stencil // Color Signed Normalized
case GL_DEPTH32F_STENCIL8: case GL_RGBA16_SNORM:
case GL_DEPTH_STENCIL: case GL_RGB16_SNORM:
*outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; case GL_RG16_SNORM:
break; case GL_R16_SNORM:
*outType = GL_SHORT;
break;
case GL_RGBA8_SNORM:
case GL_RGB8_SNORM:
case GL_RG8_SNORM:
case GL_R8_SNORM:
*outType = GL_BYTE;
break;
default: // Color Unsigned Integer
MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s", MG_Util::ConvertGLEnumToString(internalFormat).c_str()); case GL_RGBA32UI:
// Fallback handling for other formats case GL_RGB32UI:
*outType = GL_UNSIGNED_BYTE; case GL_RG32UI:
break; case GL_R32UI:
*outType = GL_UNSIGNED_INT;
break;
case GL_RGBA16UI:
case GL_RGB16UI:
case GL_RG16UI:
case GL_R16UI:
*outType = GL_UNSIGNED_SHORT;
break;
case GL_RGBA8UI:
case GL_RGB8UI:
case GL_RG8UI:
case GL_R8UI:
*outType = GL_UNSIGNED_BYTE;
break;
// Color Integer
case GL_RGBA32I:
case GL_RGB32I:
case GL_RG32I:
case GL_R32I:
*outType = GL_INT;
break;
case GL_RGBA16I:
case GL_RGB16I:
case GL_RG16I:
case GL_R16I:
*outType = GL_SHORT;
break;
case GL_RGBA8I:
case GL_RGB8I:
case GL_RG8I:
case GL_R8I:
*outType = GL_BYTE;
break;
// Color Float
case GL_RGBA32F:
case GL_RGB32F:
case GL_RG32F:
case GL_R32F:
*outType = GL_FLOAT;
break;
case GL_RGBA16F:
case GL_RGB16F:
case GL_RG16F:
case GL_R16F:
*outType = GL_HALF_FLOAT;
break;
// Color sRGB
case GL_SRGB8:
*outType = GL_UNSIGNED_BYTE;
break;
// Color sized other
case GL_RGB9_E5:
*outType = GL_UNSIGNED_INT_5_9_9_9_REV;
break;
case GL_R11F_G11F_B10F:
*outType = GL_UNSIGNED_INT_10F_11F_11F_REV;
break;
case GL_RGB10_A2:
*outType = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case GL_RGB5_A1:
*outType = GL_UNSIGNED_SHORT_5_5_5_1;
break;
// Depth
case GL_DEPTH_COMPONENT16:
*outType = GL_UNSIGNED_SHORT;
break;
case GL_DEPTH_COMPONENT24:
*outType = GL_UNSIGNED_INT;
break;
case GL_DEPTH_COMPONENT32:
*outType = GL_UNSIGNED_INT;
break;
case GL_DEPTH_COMPONENT32F:
*outType = GL_FLOAT;
break;
case GL_DEPTH_COMPONENT:
*outType = GL_UNSIGNED_INT;
break;
// Depth Stencil
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
break;
default:
MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s",
MG_Util::ConvertGLEnumToString(internalFormat).c_str());
// Fallback handling for other formats
*outType = GL_UNSIGNED_BYTE;
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"
// } // }
// } // }
} }