diff --git a/CMakeLists.txt b/CMakeLists.txt index 3305905e..dffb06c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ set(SOURCE_FILES MobileGL/MG_Util/Metrics/BufferMetrics.cpp MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp + MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp MobileGL/MG_Util/Converters/MGToStr/DataTypeConverter.cpp MobileGL/MG_Util/Converters/MGToStr/RenderStateEnumConverter.cpp MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp @@ -135,6 +136,7 @@ set(SOURCE_FILES MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp + MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -203,6 +205,22 @@ set(SOURCE_FILES MobileGL/MG_State/GLState/RenderbufferState/RenderbufferState.cpp ) +set(MOBILEGL_LINK_LIBRARIES + glslang::glslang + spirv-cross-c + SPIRV-Tools-opt + SPIRV-Tools +) + +set(MOBILEGL_INCLUDE_DIR + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/MobileGL + ${spirv-tools_SOURCE_DIR} + ${spirv-tools_SOURCE_DIR}/include + ${spirv-tools_BINARY_DIR} + ${SPIRV-Headers_SOURCE_DIR}/include +) + add_library(${CMAKE_PROJECT_NAME} SHARED ${SOURCE_FILES} ) @@ -222,21 +240,12 @@ else() endif() target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC - ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/MobileGL + ${MOBILEGL_INCLUDE_DIR} ) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE - # Diligent-Common - # Diligent-GraphicsEngineOpenGL-shared - # Diligent-GraphicsEngineVk-shared -) - -target_link_libraries(${CMAKE_PROJECT_NAME} - PRIVATE - glslang::glslang - spirv-cross-c + ${MOBILEGL_LINK_LIBRARIES} ) add_library(${CMAKE_PROJECT_NAME}_s STATIC @@ -258,21 +267,12 @@ else() endif() target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC - ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/MobileGL + ${MOBILEGL_INCLUDE_DIR} ) target_link_libraries(${CMAKE_PROJECT_NAME}_s PRIVATE - # Diligent-Common - # Diligent-GraphicsEngineOpenGL-shared - # Diligent-GraphicsEngineVk-shared -) - -target_link_libraries(${CMAKE_PROJECT_NAME}_s - PRIVATE - glslang::glslang - spirv-cross-c + ${MOBILEGL_LINK_LIBRARIES} ) if (TRACY_ENABLE) diff --git a/MobileGL/Defines.h b/MobileGL/Defines.h index a8a8c202..d7c5bd19 100644 --- a/MobileGL/Defines.h +++ b/MobileGL/Defines.h @@ -44,7 +44,7 @@ #define MOBILEGL_LOG_ENABLE_CONSOLE 0 #define MOBILEGL_LOG_ENABLE_FILE 1 #define MOBILEGL_LOG_ENABLE_ANDROID 1 -#define MOBILEGL_ENABLE_SCOPE_MARKER 1 +#define MOBILEGL_ENABLE_SCOPE_MARKER 0 // Require C++23 // Clang/Android NDK still doesn't have support for that :( diff --git a/MobileGL/Includes.h b/MobileGL/Includes.h index 42a79893..621e7d83 100644 --- a/MobileGL/Includes.h +++ b/MobileGL/Includes.h @@ -53,12 +53,20 @@ #include // Include OpenGL and EGL headers +#ifdef GLAPI +#undef GLAPI +#endif #include #define GL_GLEXT_PROTOTYPES +#include "GL/gl.h" #include #undef GL_GLEXT_PROTOTYPES + #include + +#define GL_GLES_PROTOTYPES 0 #include +#undef GL_GLES_PROTOTYPES // Include glslang headers #include diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 2b5997bc..ab6c263d 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -259,7 +259,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto& backendBufferObject = backendBufferIt->second; backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER); } else { - MGLOG_E("No backend buffer found for index buffer binding, cannot bind index buffer."); + MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer."); } } @@ -328,7 +328,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // 4. Mipmap levels changed if (!stateTextureObject->IsComplete()) { - MGLOG_D("Texture object with ID: %u is not complete, skipping sync.", m_backendTextureId); + MGLOG_D("Texture object with ID: %u is not complete, skipping sync.", stateTextureObject->GetExternalIndex()); return; } @@ -371,14 +371,14 @@ namespace MobileGL::MG_Backend::DirectGLES { for (SizeT level = 0; level < mipmapCount; ++level) { auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); - bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, 0); + bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level); auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); auto* pData = (levelDirty && levelByteSize != 0) ? textureMipmapObject->MapMipmapData(uploadTarget, level) : nullptr; - MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p", __func__, + MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s", __func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level, - levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData); + levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData, levelDirty ? "true" : "false"); errorLopper.Clear(); MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); @@ -873,6 +873,7 @@ namespace MobileGL::MG_Backend::DirectGLES { spvc_compiler_options options; spvcSession.CreateOptions(&options); + // TODO: check ESSL version supported by backend driver spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 320); spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE); spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); @@ -898,41 +899,41 @@ namespace MobileGL::MG_Backend::DirectGLES { source = ForceSupporterOutput(source); // TODO: probably a patch system? - String findStr = "if (distance_weight_sum == 0.0)"; - String replaceStr = "if (distance_weight_sum <= 0.0001)"; - auto pos = source.find(findStr); - while (pos != String::npos) { - MGLOG_D("Applying patch #1 to Photon..."); - source.replace(pos, findStr.length(), replaceStr); - pos = source.find(findStr, pos); - } + // String findStr = "if (distance_weight_sum == 0.0)"; + // String replaceStr = "if (distance_weight_sum <= 0.0001)"; + // auto pos = source.find(findStr); + // while (pos != String::npos) { + // MGLOG_D("Applying patch #1 to Photon..."); + // source.replace(pos, findStr.length(), replaceStr); + // pos = source.find(findStr, pos); + // } - findStr = "1000000.0"; - replaceStr = "65500.0"; - pos = source.find(findStr); + String findStr = "1000000.0"; + String replaceStr = "65500.0"; + auto pos = source.find(findStr); while (pos != String::npos) { MGLOG_D("Applying patch #2 to Photon..."); source.replace(pos, findStr.length(), replaceStr); pos = source.find(findStr, pos); } - findStr = "if (gtao.w == 0.0)"; - replaceStr = "if (abs(gtao.w) <= 0.00001)"; - pos = source.find(findStr); - while (pos != String::npos) { - MGLOG_D("Applying patch #3 to Photon..."); - source.replace(pos, findStr.length(), replaceStr); - pos = source.find(findStr, pos); - } + // findStr = "if (gtao.w == 0.0)"; + // replaceStr = "if (abs(gtao.w) <= 0.00001)"; + // pos = source.find(findStr); + // while (pos != String::npos) { + // MGLOG_D("Applying patch #3 to Photon..."); + // source.replace(pos, findStr.length(), replaceStr); + // pos = source.find(findStr, pos); + // } - findStr = "== 0.0"; - replaceStr = "<= 0.00001"; - pos = source.find(findStr); - while (pos != String::npos) { - MGLOG_D("Applying patch #4 to Photon..."); - source.replace(pos, findStr.length(), replaceStr); - pos = source.find(findStr, pos); - } + // findStr = "== 0.0"; + // replaceStr = "<= 0.00001"; + // pos = source.find(findStr); + // while (pos != String::npos) { + // MGLOG_D("Applying patch #4 to Photon..."); + // source.replace(pos, findStr.length(), replaceStr); + // pos = source.find(findStr, pos); + // } const char* sourceCStr = source.c_str(); MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr); diff --git a/MobileGL/MG_Impl/EGLImpl/EGLWrapper/EGLWrapper.cpp b/MobileGL/MG_Impl/EGLImpl/EGLWrapper/EGLWrapper.cpp index c2a73ee3..7ea342de 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLWrapper/EGLWrapper.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLWrapper/EGLWrapper.cpp @@ -73,7 +73,11 @@ namespace MobileGL { } EGLBoolean BindAPI(EGLenum api) { - return MG_External::EGL::eglBindAPI(api); + // We should accept `EGL_OPENGL_API`, + // and bind to `EGL_OPENGL_ES_API` at the backend + MGLOG_D("%s: api = %s", __func__, api == EGL_OPENGL_API ? "EGL_OPENGL_API" : "EGL_OPENGL_ES_API"); + MGLOG_D("%s: calling backend as EGL_OPENGL_ES_API", __func__); + return MG_External::EGL::eglBindAPI(EGL_OPENGL_ES_API); } EGLSurface GetCurrentSurface(EGLint readdraw) { diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index c27ca8b8..913c02bf 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -18,6 +18,7 @@ #include #if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES #include +#include "MG_Util/BackendLoaders/OpenGL/Loader.h" #endif namespace MobileGL { @@ -159,9 +160,11 @@ namespace MobileGL { *params = 0; // TODO break; case GL_ARRAY_BUFFER_BINDING: { - *params = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex) - .GetBoundObject() - ->GetExternalIndex(); + auto obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject(); + if (obj) + *params = obj->GetExternalIndex(); + else + *params = 0; break; } case GL_BLEND: @@ -817,7 +820,11 @@ namespace MobileGL { *params = 0; // TODO break; case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: - *params = 256; // TODO: get real value from backend +#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES + *params = MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment; // TODO: get real value from backend +#else + *params = 256; +#endif break; case GL_UNIFORM_BUFFER_SIZE: *params = 0; // TODO diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index dc749476..b907e57d 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -516,11 +516,15 @@ namespace MobileGL { void Uniform_State(MG_State::GLState::ProgramObject& programObject, GLuint location, T* value, SizeT byteOffsetInsideUniform = 0) { if (!programObject.IsUniformOpaqueAtLocation(location)) { + MGLOG_D("%s: program = %d, location = %d, maxLocation = %d", __func__, + programObject.GetExternalIndex(), location, programObject.GetMaxUniformLocation()); auto size = programObject.GetUniformSizesInBytes(location); auto offset = programObject.GetUniformOffset(location); MOBILEGL_ASSERT(size >= ItemCount * sizeof(T), "Uniform size mismatch, expected at least %zu bytes, got %zu bytes.", ItemCount * sizeof(T), size); + MGLOG_D("%s: program = %d, location = %d, byteOffset = %d", __func__, + programObject.GetExternalIndex(), location, offset + byteOffsetInsideUniform); Memcpy((char*)programObject.MapUBO() + offset + byteOffsetInsideUniform, value, ItemCount * sizeof(T)); } else { auto* ttype = programObject.GetUniformTType(location); diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 03dbcf9e..137a2c66 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -88,6 +88,7 @@ namespace MobileGL { auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget); auto textureObject = bindingSlot.GetBoundObject(); TextureInternalFormat textureInternalFormat = textureObject->GetFormat(); + MGLOG_D("%s: working on texture %d", __func__, textureObject->GetExternalIndex()); // ===================== Error Checking ============================== if (!TextureImpl::ValidateTextureObject(textureObject)) return; @@ -165,6 +166,7 @@ namespace MobileGL { free(processedPixels); + MGLOG_D("%s: mark mip %d as dirty", __func__, level); textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true); } @@ -682,6 +684,8 @@ namespace MobileGL { const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType); const SizeT internalBytes = width * height * internalBpp; + MGLOG_D("%s: working on texture %d", __func__, textureObject->GetExternalIndex()); + MGLOG_D("%s: texture object had internal format %s, new format %s", __func__, MG_Util::ConvertTextureInternalFormatToString(textureObject->GetFormat()).c_str(), MG_Util::ConvertTextureInternalFormatToString(textureInternalFormat).c_str()); @@ -707,8 +711,12 @@ namespace MobileGL { auto textureMipmapObject = static_cast(textureObject.get()); // Allocate in TextureObject + MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level); 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) { MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__); return; @@ -731,8 +739,6 @@ namespace MobileGL { textureMipmapObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput); } - textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true); - free(processedPixels); } diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 9e3aa278..09240926 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -453,8 +453,14 @@ namespace MobileGL { MGLOG_D("ProgramObject %u: GenerateBinary - generated %zu SPIR-V modules", m_externalIndex, m_generatedSpirv.size()); + for (auto& spv: m_generatedSpirv) { + auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv); + MOBILEGL_ASSERT(success, "SanitizeBinary failed"); + } + for (SizeT i = 0; i < m_generatedSpirv.size(); i++) { auto& spv = m_generatedSpirv[i]; + auto shaderType = shaderTypes[i]; MGLOG_D("ProgramObject %u: GenerateBinary - parsing SPIR-V meta data for module %zu " "(shaderType=%u, wordCount=%zu)", diff --git a/MobileGL/MG_State/GLState/TextureState/TextureEnum.h b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h index 76820cae..7bbb50fa 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureEnum.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h @@ -100,6 +100,7 @@ namespace MobileGL { RGB8Snorm, RGB10, RGB12, + RGB16, RGB16Snorm, RGBA2, RGBA4, diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp index 641e4cba..2fbf712f 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -164,13 +164,24 @@ namespace MobileGL { SizeT levelCount = m_textureStorage.GetLevelCount(); if (levelCount == 0) { + MGLOG_D("%s: not complete because levelCount == 0", __func__); return false; } + // For some reason mojang decided to have 0x0 in last level mipmap + // Relaxing checks for that + bool hadZero = false; for (SizeT i = 0; i < levelCount; ++i) { const auto& levelSize = m_textureStorage.GetTexelSize(0, i); if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) { - return false; + hadZero = true; + } else { + if (hadZero) { + // We're checking for "zero - not zero - zero" here + // "not zero - zero - zero" should pass this test + MGLOG_D("%s: not complete because 0x0 occurred, and is not last level mipmap", __func__); + return false; + } } } diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index e97816d0..565b2ea5 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.24) project(MobileGLTest) message(STATUS "Generating build files for MobileGL Test...") @@ -14,8 +14,8 @@ set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) include(FetchContent) FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip - DOWNLOAD_EXTRACT_TIMESTAMP TRUE + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.17.0 ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index ba19555e..20b92a1d 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -922,26 +922,26 @@ TEST_F(ProgramTest, CompileAndLinkWithExplicitVertexIn) { auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& spirvs = programObject->GetGeneratedSpirv(); - auto& vertexSpirv = spirvs[1]; // 0 - fragment, 1 - vertex + // auto& vertexSpirv = spirvs[1]; // 0 - fragment, 1 - vertex char* pSrcVertIn = nullptr; const char* needle = "layout(location = 2) in vec2 UV0;"; - // for (auto spirv: spirvs) { - MG_Util::ShaderTranspiler::SpvcSession spvcSession(vertexSpirv); - spvc_compiler_options options; - spvcSession.CreateOptions(&options); + for (auto spirv: spirvs) { + MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirv); + spvc_compiler_options options; + spvcSession.CreateOptions(&options); - spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 460); - spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE); - // spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); + spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 460); + spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE); + // spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); - spvcSession.SetOptions(options); + spvcSession.SetOptions(options); - const char* result = nullptr; - spvcSession.Compile(&result); - printf("%s\n\n", result); - const char* ret = strstr(result, needle); - if (ret) pSrcVertIn = (char*)ret; - // } + const char* result = nullptr; + spvcSession.Compile(&result); + printf("%s\n\n", result); + const char* ret = strstr(result, needle); + if (ret) pSrcVertIn = (char*)ret; + } ASSERT_TRUE(pSrcVertIn != nullptr) << "Not found expected string in generated shader.\n(Searching for \"" << needle << "\")"; } diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index 780c2e8b..2a3be359 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -457,8 +457,9 @@ namespace MobileGL { void *libGLES = nullptr, *libEGL = nullptr; static const char* LibPathPrefixes[] = { - /*"", */ // We should never search in the current directory to avoid breaking LD_LIBRARY_PATH usage - "/opt/vc/lib/", "/usr/local/lib/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/", nullptr}; + "/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 + nullptr}; static const char* LibExts[] = {"so", "so.1", "so.2", "dylib", "dll", nullptr}; static const char* GLES3Libs[] = {"libGLESv3_CM", "libGLESv3", "libGLESv2_CM", "libGLESv2", nullptr}; static const char* EGLLibs[] = {"libEGL", nullptr}; @@ -528,6 +529,10 @@ namespace MobileGL { } } } + + MGLOG_I("OpenGL ES capabilities:"); + MG_External::GLES::glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment); + MGLOG_I(" GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: %d", MG_External::GLES::g_glesCaps.uniformBufferOffsetAlignment); } void InitGLES() { diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h index 1676641f..2f7b49f0 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h @@ -576,6 +576,8 @@ namespace MobileGL { Version version; Bool hasPersistentMapping; Bool hasNorm16Texture; + + Int uniformBufferOffsetAlignment; }; } // namespace Caps diff --git a/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp b/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp new file mode 100644 index 00000000..93c5ee83 --- /dev/null +++ b/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp @@ -0,0 +1,164 @@ +// MobileGL - MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.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 "EGLEnumConverter.h" +#include + +namespace MobileGL { + namespace MG_Util { + String ConvertEGLEnumToString(EGLenum value) { + switch (value) { +#define CASE(value) \ + case value: \ + return #value; + + CASE(EGL_ALPHA_SIZE) + CASE(EGL_BAD_ACCESS) + CASE(EGL_BAD_ALLOC) + CASE(EGL_BAD_ATTRIBUTE) + CASE(EGL_BAD_CONFIG) + CASE(EGL_BAD_CONTEXT) + CASE(EGL_BAD_CURRENT_SURFACE) + CASE(EGL_BAD_DISPLAY) + CASE(EGL_BAD_MATCH) + CASE(EGL_BAD_NATIVE_PIXMAP) + CASE(EGL_BAD_NATIVE_WINDOW) + CASE(EGL_BAD_PARAMETER) + CASE(EGL_BAD_SURFACE) + CASE(EGL_BLUE_SIZE) + CASE(EGL_BUFFER_SIZE) + CASE(EGL_CONFIG_CAVEAT) + CASE(EGL_CONFIG_ID) + CASE(EGL_CORE_NATIVE_ENGINE) + CASE(EGL_DEPTH_SIZE) + CASE(EGL_DRAW) + CASE(EGL_EXTENSIONS) + CASE(EGL_FALSE) + CASE(EGL_GREEN_SIZE) + CASE(EGL_HEIGHT) + CASE(EGL_LARGEST_PBUFFER) + CASE(EGL_LEVEL) + CASE(EGL_MAX_PBUFFER_HEIGHT) + CASE(EGL_MAX_PBUFFER_PIXELS) + CASE(EGL_MAX_PBUFFER_WIDTH) + CASE(EGL_NATIVE_RENDERABLE) + CASE(EGL_NATIVE_VISUAL_ID) + CASE(EGL_NATIVE_VISUAL_TYPE) + CASE(EGL_NONE) + CASE(EGL_NON_CONFORMANT_CONFIG) + CASE(EGL_NOT_INITIALIZED) + CASE(EGL_PIXMAP_BIT) + CASE(EGL_READ) + CASE(EGL_RED_SIZE) + CASE(EGL_SAMPLES) + CASE(EGL_SAMPLE_BUFFERS) + CASE(EGL_SLOW_CONFIG) + CASE(EGL_STENCIL_SIZE) + CASE(EGL_SUCCESS) + CASE(EGL_SURFACE_TYPE) + CASE(EGL_TRANSPARENT_BLUE_VALUE) + CASE(EGL_TRANSPARENT_GREEN_VALUE) + CASE(EGL_TRANSPARENT_RED_VALUE) + CASE(EGL_TRANSPARENT_RGB) + CASE(EGL_TRANSPARENT_TYPE) + CASE(EGL_TRUE) + CASE(EGL_VENDOR) + CASE(EGL_VERSION) + CASE(EGL_WIDTH) + CASE(EGL_WINDOW_BIT) + CASE(EGL_BACK_BUFFER) + CASE(EGL_BIND_TO_TEXTURE_RGB) + CASE(EGL_BIND_TO_TEXTURE_RGBA) + CASE(EGL_CONTEXT_LOST) + CASE(EGL_MIN_SWAP_INTERVAL) + CASE(EGL_MAX_SWAP_INTERVAL) + CASE(EGL_MIPMAP_TEXTURE) + CASE(EGL_MIPMAP_LEVEL) + CASE(EGL_NO_TEXTURE) + CASE(EGL_TEXTURE_2D) + CASE(EGL_TEXTURE_FORMAT) + CASE(EGL_TEXTURE_RGB) + CASE(EGL_TEXTURE_RGBA) + CASE(EGL_TEXTURE_TARGET) + CASE(EGL_ALPHA_FORMAT) + CASE(EGL_ALPHA_FORMAT_NONPRE) + CASE(EGL_ALPHA_FORMAT_PRE) + CASE(EGL_ALPHA_MASK_SIZE) + CASE(EGL_BUFFER_PRESERVED) + CASE(EGL_BUFFER_DESTROYED) + CASE(EGL_CLIENT_APIS) + CASE(EGL_COLORSPACE) + CASE(EGL_COLORSPACE_sRGB) + CASE(EGL_COLORSPACE_LINEAR) + CASE(EGL_COLOR_BUFFER_TYPE) + CASE(EGL_CONTEXT_CLIENT_TYPE) + CASE(EGL_DISPLAY_SCALING) + CASE(EGL_HORIZONTAL_RESOLUTION) + CASE(EGL_LUMINANCE_BUFFER) + CASE(EGL_LUMINANCE_SIZE) + CASE(EGL_OPENGL_ES_API) + CASE(EGL_OPENVG_API) + CASE(EGL_OPENVG_IMAGE) + CASE(EGL_PIXEL_ASPECT_RATIO) + CASE(EGL_RENDERABLE_TYPE) + CASE(EGL_RENDER_BUFFER) + CASE(EGL_RGB_BUFFER) + CASE(EGL_SINGLE_BUFFER) + CASE(EGL_SWAP_BEHAVIOR) + CASE(EGL_VERTICAL_RESOLUTION) + CASE(EGL_CONFORMANT) + CASE(EGL_CONTEXT_CLIENT_VERSION) + CASE(EGL_MATCH_NATIVE_PIXMAP) + CASE(EGL_VG_COLORSPACE_LINEAR_BIT) + CASE(EGL_MULTISAMPLE_RESOLVE_BOX_BIT) + CASE(EGL_MULTISAMPLE_RESOLVE) + CASE(EGL_MULTISAMPLE_RESOLVE_DEFAULT) + CASE(EGL_MULTISAMPLE_RESOLVE_BOX) + CASE(EGL_OPENGL_API) + CASE(EGL_CONTEXT_MINOR_VERSION) + CASE(EGL_CONTEXT_OPENGL_PROFILE_MASK) + CASE(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY) + CASE(EGL_NO_RESET_NOTIFICATION) + CASE(EGL_LOSE_CONTEXT_ON_RESET) + CASE(EGL_CONTEXT_OPENGL_DEBUG) + CASE(EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE) + CASE(EGL_CONTEXT_OPENGL_ROBUST_ACCESS) + CASE(EGL_OPENGL_ES3_BIT) + CASE(EGL_CL_EVENT_HANDLE) + CASE(EGL_SYNC_CL_EVENT) + CASE(EGL_SYNC_CL_EVENT_COMPLETE) + CASE(EGL_SYNC_PRIOR_COMMANDS_COMPLETE) + CASE(EGL_SYNC_TYPE) + CASE(EGL_SYNC_STATUS) + CASE(EGL_SYNC_CONDITION) + CASE(EGL_SIGNALED) + CASE(EGL_UNSIGNALED) + CASE(EGL_TIMEOUT_EXPIRED) + CASE(EGL_CONDITION_SATISFIED) + CASE(EGL_SYNC_FENCE) + CASE(EGL_GL_COLORSPACE) + CASE(EGL_GL_RENDERBUFFER) + CASE(EGL_GL_TEXTURE_2D) + CASE(EGL_GL_TEXTURE_LEVEL) + CASE(EGL_GL_TEXTURE_3D) + CASE(EGL_GL_TEXTURE_ZOFFSET) + CASE(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X) + CASE(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X) + CASE(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y) + CASE(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) + CASE(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z) + CASE(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) + CASE(EGL_IMAGE_PRESERVED) + + default: + return std::format("0x%x", value); + } +#undef CASE + } + } // namespace MG_Util +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.h b/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.h new file mode 100644 index 00000000..1d175d28 --- /dev/null +++ b/MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.h @@ -0,0 +1,16 @@ +// MobileGL - MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.h +// 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 + +#pragma once +#include + +namespace MobileGL { + namespace MG_Util { + String ConvertEGLEnumToString(GLenum value); + } +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp index 26621173..3a899ccf 100644 --- a/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToMG/TextureEnumConverter.cpp @@ -7,7 +7,6 @@ // End of Source File Header #include "TextureEnumConverter.h" -#include "GL/glext.h" #include "MG_Util/Converters/GLToStr/GLEnumConverter.h" namespace MobileGL { @@ -116,6 +115,8 @@ namespace MobileGL { return TextureInternalFormat::RGB10; case GL_RGB12: return TextureInternalFormat::RGB12; + case GL_RGB16: + return TextureInternalFormat::RGB16; case GL_RGB16_SNORM: return TextureInternalFormat::RGB16Snorm; case GL_RGBA2: diff --git a/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp index 33622eda..9b1da759 100644 --- a/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp @@ -7,7 +7,6 @@ // End of Source File Header #include "GLEnumConverter.h" -#include namespace MobileGL { namespace MG_Util { diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index 265a3fa0..534160a4 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -7,6 +7,11 @@ // End of Source File Header #include "ShaderCompiler.h" + +#include "SpirvPasses/EliminateFloatEqualsZeroPass.h" +#include "spirv-tools/libspirv.h" +#include "spirv-tools/optimizer.hpp" + #include #include @@ -182,7 +187,7 @@ namespace MobileGL { return std::unexpected(r); } - for (auto [name, loc] : attrib.explicitVertexInLocations) { + for (const auto& [name, loc] : attrib.explicitVertexInLocations) { MGLOG_D("%s: got explicitly set - layout(location = %d) %s;", __func__, loc, name.c_str()); } @@ -222,6 +227,17 @@ namespace MobileGL { return allSpirv; } + bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector& inputBinary, Vector& outputBinary) { + using namespace spvtools; + Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5); + + optimizer + .RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass()) + ; + + return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary); + } + Result ShaderCompiler::DecompileShader(SpvcSession& session) { spvc_compiler_options options; session.CreateOptions(&options); diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 7b167359..497832ee 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -20,6 +20,7 @@ namespace MobileGL { static Result> CompileShader(const ShaderAttrib& attrib); static Result> LinkProgram(const ProgramAttrib& attrib); static Result>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib); + static bool SanitizeAndOptimizeBinary(const Vector& inputBinary, Vector& outputBinary); static Result DecompileShader(SpvcSession& session); }; } // namespace ShaderTranspiler diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp new file mode 100644 index 00000000..89169c94 --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp @@ -0,0 +1,165 @@ +// MobileGL - MobileGL/MG_Util/ShaderTranspiler/FloatEqualsZeroEliminationPass.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 "EliminateFloatEqualsZeroPass.h" + +#include "spirv.hpp" +#include "source/opt/constants.h" +#include "source/opt/def_use_manager.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_builder.h" +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/type_manager.h" +#include + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + spvtools::opt::Pass::Status EliminateFloatEqualsZeroPass::Process() { + using namespace spvtools; + using namespace spvtools::opt; + bool modified = false; + + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + + // 2. Import `GLSL.std.450` extension ID (for abs() func) + uint32_t glsl_std_450_id = context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + if (glsl_std_450_id == 0) { + return Status::SuccessWithoutChange; + } + + // 3. iterate all function -> basic block -> insn + for (auto& func : *get_module()) { + for (auto& bb : func) { + for (auto itInst = bb.begin(); itInst != bb.end(); ) { + auto& inst = *itInst; + + bool shouldSkip = true; + + // Check if opcode is `OpFOrdEqual`, `OpFUnordEqual`, + // `OpFOrdNotEqual` or `OpFUnordNotEqual`, + // simply skip if irrelevant + switch (inst.opcode()) { + case spv::Op::OpFOrdEqual: + case spv::Op::OpFUnordEqual: + case spv::Op::OpFOrdNotEqual: + case spv::Op::OpFUnordNotEqual: + shouldSkip = false; + break; + default: + break; + } + + if (shouldSkip) { + ++itInst; + continue; + } + + // check if operand is "float 0.0" + // OpFOrdEqual ResultType ResultID Operand1 Operand2 + uint32_t op1_id = inst.GetSingleWordInOperand(0); + uint32_t op2_id = inst.GetSingleWordInOperand(1); + + uint32_t var_id = 0; + + auto is_float_zero = [&](uint32_t id) -> bool { + const analysis::Constant* c = const_mgr->FindDeclaredConstant(id); + if (c && c->AsFloatConstant() && fabs(c->AsFloatConstant()->GetFloat()) <= K_EPSILON) { + return true; + } + return false; + }; + + if (is_float_zero(op2_id)) { + var_id = op1_id; // x == 0.0 + } else if (is_float_zero(op1_id)) { + var_id = op2_id; // 0.0 == x + } else { + ++itInst; + continue; + } + + // --- Found it, continue to patch it --- + MGLOG_D("Found 1 occurrence of `FloatEqualsZero`, patching"); + + // 1. Get var type (Float) and result type (Bool) + uint32_t float_type_id = def_use_mgr->GetDef(var_id)->type_id(); + uint32_t bool_type_id = inst.type_id(); + + // 2. Create constant ID for `Epsilon` + const analysis::Constant* eps_const = const_mgr->GetConstant( + type_mgr->GetType(float_type_id), + {*(reinterpret_cast(&K_EPSILON))} + ); + uint32_t eps_id = const_mgr->GetDefiningInstruction(eps_const)->result_id(); + + // 3. Build Abs(x) inst + // OpExtInst %float_type %glsl_import Abs %x + InstructionBuilder builder( + context(), + &inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping + ); + + std::vector abs_operands; + abs_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl_std_450_id}}); + abs_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {4}}); // 4 is FAbs + abs_operands.push_back({SPV_OPERAND_TYPE_ID, {var_id}}); + + // In GLSL.std.450, `FAbs`'s OpCode == 4 + // Ref: https://registry.khronos.org/SPIR-V/specs/1.0/GLSL.std.450.html + Instruction* abs_inst = builder.AddInstruction(MakeUnique( + context(), + spv::Op::OpExtInst, + float_type_id, + context()->TakeNextId(), + abs_operands + )); + + // 4. build Abs(x) < Epsilon + // OpFOrdLessThan %bool_type %abs_val %eps + std::vector less_operands; + less_operands.push_back({SPV_OPERAND_TYPE_ID, {abs_inst->result_id()}}); + less_operands.push_back({SPV_OPERAND_TYPE_ID, {eps_id}}); + + bool isEqualOp = (inst.opcode() == spv::Op::OpFOrdEqual || inst.opcode() == spv::Op::OpFUnordEqual); + Instruction* less_than_inst = builder.AddInstruction(MakeUnique( + context(), + isEqualOp ? spv::Op::OpFOrdLessThan : spv::Op::OpFOrdGreaterThanEqual, + bool_type_id, + context()->TakeNextId(), + less_operands + )); + + // 5. Replaces all uses of old insn with new one + context()->ReplaceAllUsesWith(inst.result_id(), less_than_inst->result_id()); + + // 6. Kill old instruction (will be cleaned up by DCE later) + auto nextInstIt = context()->KillInst(&inst); + if (nextInstIt) { + itInst = nextInstIt; + } else { + ++itInst; + } + + modified = true; + } + } + } + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + } + + spvtools::Optimizer::PassToken EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass() { + return spvtools::Optimizer::PassToken(MakeUnique()); + } + } // namespace ShaderTranspiler + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.h b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.h new file mode 100644 index 00000000..57d8c56a --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.h @@ -0,0 +1,30 @@ +// MobileGL - MobileGL/MG_Util/ShaderTranspiler/FloatEqualsZeroEliminationPass.h +// 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 + +#pragma once +#include "source/opt/pass.h" +#include "spirv-tools/optimizer.hpp" + +#include + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + class EliminateFloatEqualsZeroPass: public spvtools::opt::Pass { + public: + const char* name() const override { return "float-equals-zero-elimination"; } + Status Process() override; + + static spvtools::Optimizer::PassToken CreateEliminateFloatEqualsZeroPass(); + private: + const float K_EPSILON = 0.0001f; + }; + } // namespace ShaderTranspiler + } // namespace MG_Util +} // namespace MobileGL + diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp index a4a1ef01..7439e9ed 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp @@ -9,7 +9,7 @@ #include "PixelStoreProcessor.h" namespace MobileGL::MG_Util::PixelStoreProcessor { - static SizeT CalculateStride(Int width, SizeT pixelSize, Int alignment) { + static SizeT CalculateRowStride(Int width, SizeT pixelSize, Int alignment) { if (width <= 0 || pixelSize == 0) return 0; const SizeT rowBytes = static_cast(width) * pixelSize; @@ -97,8 +97,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { const Int effectiveWidth = (params.RowLength > 0) ? params.RowLength : width; const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height; - const SizeT inputStride = CalculateStride(effectiveWidth, pixelSize, params.Alignment); - const SizeT outputStride = static_cast(width) * pixelSize; + const SizeT inputRowStride = CalculateRowStride(effectiveWidth, pixelSize, params.Alignment); + const SizeT outputRowStride = static_cast(width) * pixelSize; const Int startX = params.SkipPixels; const Int startY = params.SkipRows; @@ -108,8 +108,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { const Int copyHeight = height; const Int copyDepth = depth; - MGLOG_D("%s: start at: (%d, %d, %d), copy size: (%d, %d, %d)", __func__, - startX, startY, startZ, copyWidth, copyHeight, copyDepth); + MGLOG_D("%s: start at: (%d, %d, %d), copy size: (%d, %d, %d), i/o row stride: (%d, %dx%d)", __func__, + startX, startY, startZ, copyWidth, copyHeight, copyDepth, inputRowStride, width, pixelSize); if (copyWidth <= 0 || copyHeight <= 0 || copyDepth <= 0) { outSize = 0; @@ -126,8 +126,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { const Uint8* src = static_cast(inputPixels); Uint8* dst = static_cast(outputPixels); - src += static_cast(startZ) * static_cast(effectiveHeight) * inputStride; - src += static_cast(startY) * inputStride; + src += static_cast(startZ) * static_cast(effectiveHeight) * inputRowStride; + src += static_cast(startY) * inputRowStride; src += static_cast(startX) * pixelSize; Bool isByteType = @@ -161,12 +161,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { // else // MGLOG_D("%s: pixel0 = %x", __func__, *((Uint32*)layerDst)); - layerSrc += inputStride; - layerDst += static_cast(copyWidth) * pixelSize; + layerSrc += inputRowStride; + layerDst += outputRowStride; } - src += static_cast(effectiveHeight) * inputStride; - dst += static_cast(copyHeight) * static_cast(copyWidth) * pixelSize; + src += static_cast(effectiveHeight) * inputRowStride; + dst += static_cast(copyHeight) * outputRowStride; } return outputPixels; @@ -184,12 +184,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { Int depth = dimension.z(); const Int outputWidth = (params.RowLength > 0) ? params.RowLength : width; - const SizeT outputStride = CalculateStride(outputWidth, pixelSize, params.Alignment); - const SizeT inputStride = static_cast(width) * pixelSize; + const SizeT outputRowStride = CalculateRowStride(outputWidth, pixelSize, params.Alignment); + const SizeT inputRowStride = static_cast(width) * pixelSize; const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height; - outSize = static_cast(outputStride) * static_cast(effectiveHeight) * static_cast(depth); + outSize = static_cast(outputRowStride) * static_cast(effectiveHeight) * static_cast(depth); void* outputPixels = malloc(outSize); if (!outputPixels) { outSize = 0; @@ -201,8 +201,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { const Uint8* src = static_cast(inputPixels); Uint8* dst = static_cast(outputPixels); - dst += static_cast(params.SkipImages) * static_cast(effectiveHeight) * outputStride; - dst += static_cast(params.SkipRows) * outputStride; + dst += static_cast(params.SkipImages) * static_cast(effectiveHeight) * outputRowStride; + dst += static_cast(params.SkipRows) * outputRowStride; dst += static_cast(params.SkipPixels) * pixelSize; Vector tempRow(static_cast(width) * pixelSize); @@ -224,12 +224,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { Memcpy(layerDst, tempRow.data(), static_cast(width) * pixelSize); - layerSrc += inputStride; - layerDst += outputStride; + layerSrc += inputRowStride; + layerDst += outputRowStride; } - src += static_cast(height) * inputStride; - dst += static_cast(effectiveHeight) * outputStride; + src += static_cast(height) * inputRowStride; + dst += static_cast(effectiveHeight) * outputRowStride; } return outputPixels;