mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
Merge branch 'Feat/Backend-Direct-GLES' into dev
This commit is contained in:
+22
-22
@@ -107,6 +107,7 @@ set(SOURCE_FILES
|
|||||||
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
|
||||||
|
MobileGL/MG_Util/Converters/EGLToStr/EGLEnumConverter.cpp
|
||||||
MobileGL/MG_Util/Converters/MGToStr/DataTypeConverter.cpp
|
MobileGL/MG_Util/Converters/MGToStr/DataTypeConverter.cpp
|
||||||
MobileGL/MG_Util/Converters/MGToStr/RenderStateEnumConverter.cpp
|
MobileGL/MG_Util/Converters/MGToStr/RenderStateEnumConverter.cpp
|
||||||
MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.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/SpvcSession.cpp
|
||||||
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
|
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
|
||||||
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
|
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
|
||||||
|
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
|
||||||
|
|
||||||
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
|
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
|
||||||
|
|
||||||
@@ -203,6 +205,22 @@ set(SOURCE_FILES
|
|||||||
MobileGL/MG_State/GLState/RenderbufferState/RenderbufferState.cpp
|
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
|
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||||
${SOURCE_FILES}
|
${SOURCE_FILES}
|
||||||
)
|
)
|
||||||
@@ -222,21 +240,12 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${MOBILEGL_INCLUDE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/MobileGL
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
# Diligent-Common
|
${MOBILEGL_LINK_LIBRARIES}
|
||||||
# Diligent-GraphicsEngineOpenGL-shared
|
|
||||||
# Diligent-GraphicsEngineVk-shared
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
|
||||||
PRIVATE
|
|
||||||
glslang::glslang
|
|
||||||
spirv-cross-c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(${CMAKE_PROJECT_NAME}_s STATIC
|
add_library(${CMAKE_PROJECT_NAME}_s STATIC
|
||||||
@@ -258,21 +267,12 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC
|
target_include_directories(${CMAKE_PROJECT_NAME}_s PUBLIC
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${MOBILEGL_INCLUDE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/MobileGL
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
||||||
PRIVATE
|
PRIVATE
|
||||||
# Diligent-Common
|
${MOBILEGL_LINK_LIBRARIES}
|
||||||
# Diligent-GraphicsEngineOpenGL-shared
|
|
||||||
# Diligent-GraphicsEngineVk-shared
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
|
||||||
PRIVATE
|
|
||||||
glslang::glslang
|
|
||||||
spirv-cross-c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (TRACY_ENABLE)
|
if (TRACY_ENABLE)
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@
|
|||||||
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
||||||
#define MOBILEGL_LOG_ENABLE_FILE 1
|
#define MOBILEGL_LOG_ENABLE_FILE 1
|
||||||
#define MOBILEGL_LOG_ENABLE_ANDROID 1
|
#define MOBILEGL_LOG_ENABLE_ANDROID 1
|
||||||
#define MOBILEGL_ENABLE_SCOPE_MARKER 1
|
#define MOBILEGL_ENABLE_SCOPE_MARKER 0
|
||||||
|
|
||||||
// Require C++23
|
// Require C++23
|
||||||
// Clang/Android NDK still doesn't have support for that :(
|
// Clang/Android NDK still doesn't have support for that :(
|
||||||
|
|||||||
@@ -53,12 +53,20 @@
|
|||||||
#include <spirv_cross/spirv_cross_c.h>
|
#include <spirv_cross/spirv_cross_c.h>
|
||||||
|
|
||||||
// Include OpenGL and EGL headers
|
// Include OpenGL and EGL headers
|
||||||
|
#ifdef GLAPI
|
||||||
|
#undef GLAPI
|
||||||
|
#endif
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#define GL_GLEXT_PROTOTYPES
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#include "GL/gl.h"
|
||||||
#include <GL/glcorearb.h>
|
#include <GL/glcorearb.h>
|
||||||
#undef GL_GLEXT_PROTOTYPES
|
#undef GL_GLEXT_PROTOTYPES
|
||||||
|
|
||||||
#include <GL/glext.h>
|
#include <GL/glext.h>
|
||||||
|
|
||||||
|
#define GL_GLES_PROTOTYPES 0
|
||||||
#include <GLES3/gl32.h>
|
#include <GLES3/gl32.h>
|
||||||
|
#undef GL_GLES_PROTOTYPES
|
||||||
|
|
||||||
// Include glslang headers
|
// Include glslang headers
|
||||||
#include <glslang/Include/Types.h>
|
#include <glslang/Include/Types.h>
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const auto& backendBufferObject = backendBufferIt->second;
|
const auto& backendBufferObject = backendBufferIt->second;
|
||||||
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
||||||
} else {
|
} 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
|
// 4. Mipmap levels changed
|
||||||
|
|
||||||
if (!stateTextureObject->IsComplete()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,14 +371,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||||
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(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 glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
|
||||||
auto* pData = (levelDirty && levelByteSize != 0)
|
auto* pData = (levelDirty && levelByteSize != 0)
|
||||||
? textureMipmapObject->MapMipmapData(uploadTarget, level)
|
? textureMipmapObject->MapMipmapData(uploadTarget, level)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p", __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,
|
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();
|
errorLopper.Clear();
|
||||||
MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
@@ -873,6 +873,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
spvc_compiler_options options;
|
spvc_compiler_options options;
|
||||||
spvcSession.CreateOptions(&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_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_ES, SPVC_TRUE);
|
||||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE);
|
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);
|
source = ForceSupporterOutput(source);
|
||||||
|
|
||||||
// TODO: probably a patch system?
|
// TODO: probably a patch system?
|
||||||
String findStr = "if (distance_weight_sum == 0.0)";
|
// String findStr = "if (distance_weight_sum == 0.0)";
|
||||||
String replaceStr = "if (distance_weight_sum <= 0.0001)";
|
// String replaceStr = "if (distance_weight_sum <= 0.0001)";
|
||||||
auto pos = source.find(findStr);
|
// auto pos = source.find(findStr);
|
||||||
while (pos != String::npos) {
|
// while (pos != String::npos) {
|
||||||
MGLOG_D("Applying patch #1 to Photon...");
|
// MGLOG_D("Applying patch #1 to Photon...");
|
||||||
source.replace(pos, findStr.length(), replaceStr);
|
// source.replace(pos, findStr.length(), replaceStr);
|
||||||
pos = source.find(findStr, pos);
|
// pos = source.find(findStr, pos);
|
||||||
}
|
// }
|
||||||
|
|
||||||
findStr = "1000000.0";
|
String findStr = "1000000.0";
|
||||||
replaceStr = "65500.0";
|
String replaceStr = "65500.0";
|
||||||
pos = source.find(findStr);
|
auto pos = source.find(findStr);
|
||||||
while (pos != String::npos) {
|
while (pos != String::npos) {
|
||||||
MGLOG_D("Applying patch #2 to Photon...");
|
MGLOG_D("Applying patch #2 to Photon...");
|
||||||
source.replace(pos, findStr.length(), replaceStr);
|
source.replace(pos, findStr.length(), replaceStr);
|
||||||
pos = source.find(findStr, pos);
|
pos = source.find(findStr, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
findStr = "if (gtao.w == 0.0)";
|
// findStr = "if (gtao.w == 0.0)";
|
||||||
replaceStr = "if (abs(gtao.w) <= 0.00001)";
|
// replaceStr = "if (abs(gtao.w) <= 0.00001)";
|
||||||
pos = source.find(findStr);
|
// pos = source.find(findStr);
|
||||||
while (pos != String::npos) {
|
// while (pos != String::npos) {
|
||||||
MGLOG_D("Applying patch #3 to Photon...");
|
// MGLOG_D("Applying patch #3 to Photon...");
|
||||||
source.replace(pos, findStr.length(), replaceStr);
|
// source.replace(pos, findStr.length(), replaceStr);
|
||||||
pos = source.find(findStr, pos);
|
// pos = source.find(findStr, pos);
|
||||||
}
|
// }
|
||||||
|
|
||||||
findStr = "== 0.0";
|
// findStr = "== 0.0";
|
||||||
replaceStr = "<= 0.00001";
|
// replaceStr = "<= 0.00001";
|
||||||
pos = source.find(findStr);
|
// pos = source.find(findStr);
|
||||||
while (pos != String::npos) {
|
// while (pos != String::npos) {
|
||||||
MGLOG_D("Applying patch #4 to Photon...");
|
// MGLOG_D("Applying patch #4 to Photon...");
|
||||||
source.replace(pos, findStr.length(), replaceStr);
|
// source.replace(pos, findStr.length(), replaceStr);
|
||||||
pos = source.find(findStr, pos);
|
// pos = source.find(findStr, pos);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const char* sourceCStr = source.c_str();
|
const char* sourceCStr = source.c_str();
|
||||||
MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr);
|
MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr);
|
||||||
|
|||||||
@@ -73,7 +73,11 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean BindAPI(EGLenum api) {
|
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) {
|
EGLSurface GetCurrentSurface(EGLint readdraw) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
|
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
|
||||||
#include <MG_Backend/DirectGLES/DirectGLES.h>
|
#include <MG_Backend/DirectGLES/DirectGLES.h>
|
||||||
|
#include "MG_Util/BackendLoaders/OpenGL/Loader.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
@@ -159,9 +160,11 @@ namespace MobileGL {
|
|||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
case GL_ARRAY_BUFFER_BINDING: {
|
case GL_ARRAY_BUFFER_BINDING: {
|
||||||
*params = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex)
|
auto obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
|
||||||
.GetBoundObject()
|
if (obj)
|
||||||
->GetExternalIndex();
|
*params = obj->GetExternalIndex();
|
||||||
|
else
|
||||||
|
*params = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_BLEND:
|
case GL_BLEND:
|
||||||
@@ -817,7 +820,11 @@ namespace MobileGL {
|
|||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
|
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;
|
break;
|
||||||
case GL_UNIFORM_BUFFER_SIZE:
|
case GL_UNIFORM_BUFFER_SIZE:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
|
|||||||
@@ -516,11 +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__,
|
||||||
|
programObject.GetExternalIndex(), 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__,
|
||||||
|
programObject.GetExternalIndex(), 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);
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ namespace MobileGL {
|
|||||||
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
|
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
|
||||||
auto textureObject = bindingSlot.GetBoundObject();
|
auto textureObject = bindingSlot.GetBoundObject();
|
||||||
TextureInternalFormat textureInternalFormat = textureObject->GetFormat();
|
TextureInternalFormat textureInternalFormat = textureObject->GetFormat();
|
||||||
|
MGLOG_D("%s: working on texture %d", __func__, textureObject->GetExternalIndex());
|
||||||
|
|
||||||
// ===================== Error Checking ==============================
|
// ===================== Error Checking ==============================
|
||||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||||
@@ -165,6 +166,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
free(processedPixels);
|
free(processedPixels);
|
||||||
|
|
||||||
|
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
|
||||||
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
|
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,6 +684,8 @@ namespace MobileGL {
|
|||||||
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
||||||
const SizeT internalBytes = width * height * internalBpp;
|
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__,
|
MGLOG_D("%s: texture object had internal format %s, new format %s", __func__,
|
||||||
MG_Util::ConvertTextureInternalFormatToString(textureObject->GetFormat()).c_str(),
|
MG_Util::ConvertTextureInternalFormatToString(textureObject->GetFormat()).c_str(),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(textureInternalFormat).c_str());
|
MG_Util::ConvertTextureInternalFormatToString(textureInternalFormat).c_str());
|
||||||
@@ -707,8 +711,12 @@ namespace MobileGL {
|
|||||||
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
|
||||||
|
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;
|
||||||
@@ -731,8 +739,6 @@ namespace MobileGL {
|
|||||||
textureMipmapObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput);
|
textureMipmapObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
|
|
||||||
|
|
||||||
free(processedPixels);
|
free(processedPixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -453,8 +453,14 @@ 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) {
|
||||||
|
auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv);
|
||||||
|
MOBILEGL_ASSERT(success, "SanitizeBinary failed");
|
||||||
|
}
|
||||||
|
|
||||||
for (SizeT i = 0; i < m_generatedSpirv.size(); i++) {
|
for (SizeT i = 0; i < m_generatedSpirv.size(); i++) {
|
||||||
auto& spv = m_generatedSpirv[i];
|
auto& spv = m_generatedSpirv[i];
|
||||||
|
|
||||||
auto shaderType = shaderTypes[i];
|
auto shaderType = shaderTypes[i];
|
||||||
MGLOG_D("ProgramObject %u: GenerateBinary - parsing SPIR-V meta data for module %zu "
|
MGLOG_D("ProgramObject %u: GenerateBinary - parsing SPIR-V meta data for module %zu "
|
||||||
"(shaderType=%u, wordCount=%zu)",
|
"(shaderType=%u, wordCount=%zu)",
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ namespace MobileGL {
|
|||||||
RGB8Snorm,
|
RGB8Snorm,
|
||||||
RGB10,
|
RGB10,
|
||||||
RGB12,
|
RGB12,
|
||||||
|
RGB16,
|
||||||
RGB16Snorm,
|
RGB16Snorm,
|
||||||
RGBA2,
|
RGBA2,
|
||||||
RGBA4,
|
RGBA4,
|
||||||
|
|||||||
@@ -164,13 +164,24 @@ namespace MobileGL {
|
|||||||
|
|
||||||
SizeT levelCount = m_textureStorage.GetLevelCount();
|
SizeT levelCount = m_textureStorage.GetLevelCount();
|
||||||
if (levelCount == 0) {
|
if (levelCount == 0) {
|
||||||
|
MGLOG_D("%s: not complete because levelCount == 0", __func__);
|
||||||
return false;
|
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) {
|
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) {
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
project(MobileGLTest)
|
project(MobileGLTest)
|
||||||
|
|
||||||
message(STATUS "Generating build files for MobileGL Test...")
|
message(STATUS "Generating build files for MobileGL Test...")
|
||||||
@@ -14,8 +14,8 @@ set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..)
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
googletest
|
googletest
|
||||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
GIT_TAG v1.17.0
|
||||||
)
|
)
|
||||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
|||||||
@@ -922,26 +922,26 @@ TEST_F(ProgramTest, CompileAndLinkWithExplicitVertexIn) {
|
|||||||
|
|
||||||
auto programObject = MG_State::pGLContext->GetCurrentProgram();
|
auto programObject = MG_State::pGLContext->GetCurrentProgram();
|
||||||
auto& spirvs = programObject->GetGeneratedSpirv();
|
auto& spirvs = programObject->GetGeneratedSpirv();
|
||||||
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(vertexSpirv);
|
MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirv);
|
||||||
spvc_compiler_options options;
|
spvc_compiler_options options;
|
||||||
spvcSession.CreateOptions(&options);
|
spvcSession.CreateOptions(&options);
|
||||||
|
|
||||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 460);
|
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_ES, SPVC_FALSE);
|
||||||
// spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, 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;
|
const char* result = nullptr;
|
||||||
spvcSession.Compile(&result);
|
spvcSession.Compile(&result);
|
||||||
printf("%s\n\n", result);
|
printf("%s\n\n", result);
|
||||||
const char* ret = strstr(result, needle);
|
const char* ret = strstr(result, needle);
|
||||||
if (ret) pSrcVertIn = (char*)ret;
|
if (ret) pSrcVertIn = (char*)ret;
|
||||||
// }
|
}
|
||||||
ASSERT_TRUE(pSrcVertIn != nullptr) << "Not found expected string in generated shader.\n(Searching for \"" << needle
|
ASSERT_TRUE(pSrcVertIn != nullptr) << "Not found expected string in generated shader.\n(Searching for \"" << needle
|
||||||
<< "\")";
|
<< "\")";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -457,8 +457,9 @@ namespace MobileGL {
|
|||||||
void *libGLES = nullptr, *libEGL = nullptr;
|
void *libGLES = nullptr, *libEGL = nullptr;
|
||||||
|
|
||||||
static const char* LibPathPrefixes[] = {
|
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/",
|
||||||
"/opt/vc/lib/", "/usr/local/lib/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/", nullptr};
|
"", // 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* LibExts[] = {"so", "so.1", "so.2", "dylib", "dll", nullptr};
|
||||||
static const char* GLES3Libs[] = {"libGLESv3_CM", "libGLESv3", "libGLESv2_CM", "libGLESv2", nullptr};
|
static const char* GLES3Libs[] = {"libGLESv3_CM", "libGLESv3", "libGLESv2_CM", "libGLESv2", nullptr};
|
||||||
static const char* EGLLibs[] = {"libEGL", 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() {
|
void InitGLES() {
|
||||||
|
|||||||
@@ -576,6 +576,8 @@ namespace MobileGL {
|
|||||||
Version version;
|
Version version;
|
||||||
Bool hasPersistentMapping;
|
Bool hasPersistentMapping;
|
||||||
Bool hasNorm16Texture;
|
Bool hasNorm16Texture;
|
||||||
|
|
||||||
|
Int uniformBufferOffsetAlignment;
|
||||||
};
|
};
|
||||||
} // namespace Caps
|
} // namespace Caps
|
||||||
|
|
||||||
|
|||||||
@@ -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 <GL/gl.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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 <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL {
|
||||||
|
namespace MG_Util {
|
||||||
|
String ConvertEGLEnumToString(GLenum value);
|
||||||
|
}
|
||||||
|
} // namespace MobileGL
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "TextureEnumConverter.h"
|
#include "TextureEnumConverter.h"
|
||||||
#include "GL/glext.h"
|
|
||||||
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
|
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
@@ -116,6 +115,8 @@ namespace MobileGL {
|
|||||||
return TextureInternalFormat::RGB10;
|
return TextureInternalFormat::RGB10;
|
||||||
case GL_RGB12:
|
case GL_RGB12:
|
||||||
return TextureInternalFormat::RGB12;
|
return TextureInternalFormat::RGB12;
|
||||||
|
case GL_RGB16:
|
||||||
|
return TextureInternalFormat::RGB16;
|
||||||
case GL_RGB16_SNORM:
|
case GL_RGB16_SNORM:
|
||||||
return TextureInternalFormat::RGB16Snorm;
|
return TextureInternalFormat::RGB16Snorm;
|
||||||
case GL_RGBA2:
|
case GL_RGBA2:
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "GLEnumConverter.h"
|
#include "GLEnumConverter.h"
|
||||||
#include <GL/gl.h>
|
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_Util {
|
namespace MG_Util {
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "ShaderCompiler.h"
|
#include "ShaderCompiler.h"
|
||||||
|
|
||||||
|
#include "SpirvPasses/EliminateFloatEqualsZeroPass.h"
|
||||||
|
#include "spirv-tools/libspirv.h"
|
||||||
|
#include "spirv-tools/optimizer.hpp"
|
||||||
|
|
||||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||||
#include <MG_Util/Converters/GLToGlslang/ProgramEnumConverter.h>
|
#include <MG_Util/Converters/GLToGlslang/ProgramEnumConverter.h>
|
||||||
|
|
||||||
@@ -182,7 +187,7 @@ namespace MobileGL {
|
|||||||
return std::unexpected(r);
|
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());
|
MGLOG_D("%s: got explicitly set - layout(location = %d) %s;", __func__, loc, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +227,17 @@ namespace MobileGL {
|
|||||||
return allSpirv;
|
return allSpirv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary, Vector<uint32_t>& outputBinary) {
|
||||||
|
using namespace spvtools;
|
||||||
|
Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5);
|
||||||
|
|
||||||
|
optimizer
|
||||||
|
.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass())
|
||||||
|
;
|
||||||
|
|
||||||
|
return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary);
|
||||||
|
}
|
||||||
|
|
||||||
Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) {
|
Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) {
|
||||||
spvc_compiler_options options;
|
spvc_compiler_options options;
|
||||||
session.CreateOptions(&options);
|
session.CreateOptions(&options);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ 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 Result<String> DecompileShader(SpvcSession& session);
|
static Result<String> DecompileShader(SpvcSession& session);
|
||||||
};
|
};
|
||||||
} // namespace ShaderTranspiler
|
} // namespace ShaderTranspiler
|
||||||
|
|||||||
@@ -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 <vector>
|
||||||
|
|
||||||
|
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<const uint32_t*>(&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<Operand> 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<Instruction>(
|
||||||
|
context(),
|
||||||
|
spv::Op::OpExtInst,
|
||||||
|
float_type_id,
|
||||||
|
context()->TakeNextId(),
|
||||||
|
abs_operands
|
||||||
|
));
|
||||||
|
|
||||||
|
// 4. build Abs(x) < Epsilon
|
||||||
|
// OpFOrdLessThan %bool_type %abs_val %eps
|
||||||
|
std::vector<Operand> 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<Instruction>(
|
||||||
|
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<EliminateFloatEqualsZeroPass>());
|
||||||
|
}
|
||||||
|
} // namespace ShaderTranspiler
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 <Includes.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "PixelStoreProcessor.h"
|
#include "PixelStoreProcessor.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Util::PixelStoreProcessor {
|
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;
|
if (width <= 0 || pixelSize == 0) return 0;
|
||||||
|
|
||||||
const SizeT rowBytes = static_cast<SizeT>(width) * pixelSize;
|
const SizeT rowBytes = static_cast<SizeT>(width) * pixelSize;
|
||||||
@@ -97,8 +97,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
|
|
||||||
const Int effectiveWidth = (params.RowLength > 0) ? params.RowLength : width;
|
const Int effectiveWidth = (params.RowLength > 0) ? params.RowLength : width;
|
||||||
const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height;
|
const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height;
|
||||||
const SizeT inputStride = CalculateStride(effectiveWidth, pixelSize, params.Alignment);
|
const SizeT inputRowStride = CalculateRowStride(effectiveWidth, pixelSize, params.Alignment);
|
||||||
const SizeT outputStride = static_cast<SizeT>(width) * pixelSize;
|
const SizeT outputRowStride = static_cast<SizeT>(width) * pixelSize;
|
||||||
|
|
||||||
const Int startX = params.SkipPixels;
|
const Int startX = params.SkipPixels;
|
||||||
const Int startY = params.SkipRows;
|
const Int startY = params.SkipRows;
|
||||||
@@ -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)", __func__,
|
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);
|
startX, 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;
|
||||||
@@ -126,8 +126,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
const Uint8* src = static_cast<const Uint8*>(inputPixels);
|
const Uint8* src = static_cast<const Uint8*>(inputPixels);
|
||||||
Uint8* dst = static_cast<Uint8*>(outputPixels);
|
Uint8* dst = static_cast<Uint8*>(outputPixels);
|
||||||
|
|
||||||
src += static_cast<SizeT>(startZ) * static_cast<SizeT>(effectiveHeight) * inputStride;
|
src += static_cast<SizeT>(startZ) * static_cast<SizeT>(effectiveHeight) * inputRowStride;
|
||||||
src += static_cast<SizeT>(startY) * inputStride;
|
src += static_cast<SizeT>(startY) * inputRowStride;
|
||||||
src += static_cast<SizeT>(startX) * pixelSize;
|
src += static_cast<SizeT>(startX) * pixelSize;
|
||||||
|
|
||||||
Bool isByteType =
|
Bool isByteType =
|
||||||
@@ -161,12 +161,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
// else
|
// else
|
||||||
// MGLOG_D("%s: pixel0 = %x", __func__, *((Uint32*)layerDst));
|
// MGLOG_D("%s: pixel0 = %x", __func__, *((Uint32*)layerDst));
|
||||||
|
|
||||||
layerSrc += inputStride;
|
layerSrc += inputRowStride;
|
||||||
layerDst += static_cast<SizeT>(copyWidth) * pixelSize;
|
layerDst += outputRowStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
src += static_cast<SizeT>(effectiveHeight) * inputStride;
|
src += static_cast<SizeT>(effectiveHeight) * inputRowStride;
|
||||||
dst += static_cast<SizeT>(copyHeight) * static_cast<SizeT>(copyWidth) * pixelSize;
|
dst += static_cast<SizeT>(copyHeight) * outputRowStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputPixels;
|
return outputPixels;
|
||||||
@@ -184,12 +184,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
Int depth = dimension.z();
|
Int depth = dimension.z();
|
||||||
|
|
||||||
const Int outputWidth = (params.RowLength > 0) ? params.RowLength : width;
|
const Int outputWidth = (params.RowLength > 0) ? params.RowLength : width;
|
||||||
const SizeT outputStride = CalculateStride(outputWidth, pixelSize, params.Alignment);
|
const SizeT outputRowStride = CalculateRowStride(outputWidth, pixelSize, params.Alignment);
|
||||||
const SizeT inputStride = static_cast<SizeT>(width) * pixelSize;
|
const SizeT inputRowStride = static_cast<SizeT>(width) * pixelSize;
|
||||||
|
|
||||||
const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height;
|
const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height;
|
||||||
|
|
||||||
outSize = static_cast<SizeT>(outputStride) * static_cast<SizeT>(effectiveHeight) * static_cast<SizeT>(depth);
|
outSize = static_cast<SizeT>(outputRowStride) * static_cast<SizeT>(effectiveHeight) * static_cast<SizeT>(depth);
|
||||||
void* outputPixels = malloc(outSize);
|
void* outputPixels = malloc(outSize);
|
||||||
if (!outputPixels) {
|
if (!outputPixels) {
|
||||||
outSize = 0;
|
outSize = 0;
|
||||||
@@ -201,8 +201,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
const Uint8* src = static_cast<const Uint8*>(inputPixels);
|
const Uint8* src = static_cast<const Uint8*>(inputPixels);
|
||||||
Uint8* dst = static_cast<Uint8*>(outputPixels);
|
Uint8* dst = static_cast<Uint8*>(outputPixels);
|
||||||
|
|
||||||
dst += static_cast<SizeT>(params.SkipImages) * static_cast<SizeT>(effectiveHeight) * outputStride;
|
dst += static_cast<SizeT>(params.SkipImages) * static_cast<SizeT>(effectiveHeight) * outputRowStride;
|
||||||
dst += static_cast<SizeT>(params.SkipRows) * outputStride;
|
dst += static_cast<SizeT>(params.SkipRows) * outputRowStride;
|
||||||
dst += static_cast<SizeT>(params.SkipPixels) * pixelSize;
|
dst += static_cast<SizeT>(params.SkipPixels) * pixelSize;
|
||||||
|
|
||||||
Vector<Uint8> tempRow(static_cast<SizeT>(width) * pixelSize);
|
Vector<Uint8> tempRow(static_cast<SizeT>(width) * pixelSize);
|
||||||
@@ -224,12 +224,12 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
|
|||||||
|
|
||||||
Memcpy(layerDst, tempRow.data(), static_cast<SizeT>(width) * pixelSize);
|
Memcpy(layerDst, tempRow.data(), static_cast<SizeT>(width) * pixelSize);
|
||||||
|
|
||||||
layerSrc += inputStride;
|
layerSrc += inputRowStride;
|
||||||
layerDst += outputStride;
|
layerDst += outputRowStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
src += static_cast<SizeT>(height) * inputStride;
|
src += static_cast<SizeT>(height) * inputRowStride;
|
||||||
dst += static_cast<SizeT>(effectiveHeight) * outputStride;
|
dst += static_cast<SizeT>(effectiveHeight) * outputRowStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputPixels;
|
return outputPixels;
|
||||||
|
|||||||
Reference in New Issue
Block a user