Compare commits

..
64 changed files with 1554 additions and 7461 deletions
-3
View File
@@ -3,6 +3,3 @@
################################################################################
/build
.cxx
/.vs
/out/build
-3
View File
@@ -1,3 +0,0 @@
[submodule "3rdparty/DiligentCore"]
path = 3rdparty/DiligentCore
url = https://github.com/DiligentGraphics/DiligentCore.git
Submodule 3rdparty/DiligentCore deleted from f36e638805
+4 -14
View File
@@ -55,9 +55,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp
MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.cpp
MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.cpp
# MG_GL/State
MG/MG_GL/State/Core/GLState.cpp
@@ -90,7 +88,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ./includes)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
target_link_libraries(${CMAKE_PROJECT_NAME}
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang.a
${CMAKE_SOURCE_DIR}/library/arm64-v8a/libspirv-cross-c-shared.so
#${CMAKE_SOURCE_DIR}/library/arm64-v8a/libshaderconv.so
@@ -112,23 +110,15 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
vulkan
)
add_subdirectory(3rdparty/DiligentCore)
target_include_directories(MobileGL PUBLIC
${CMAKE_SOURCE_DIR}/include
)
)
target_link_libraries(MobileGL
PRIVATE
Diligent-Common
Diligent-GraphicsEngineOpenGL-shared
Diligent-GraphicsEngineVk-shared
)
if (PROFILING)
find_package(Threads)
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk)
add_library(perfetto STATIC ${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk/perfetto.cc)
target_link_libraries(MobileGL PRIVATE perfetto ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(MobileGL perfetto ${CMAKE_THREAD_LIBS_INIT})
target_compile_definitions(MobileGL PUBLIC PROFILING=1)
endif()
+27 -42
View File
@@ -21,20 +21,20 @@
#define MG_EXPORT extern "C" __attribute__((visibility("default")))
#endif
namespace MG_Global {
template<typename K, typename V>
namespace ankerl {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
template<typename T>
template <typename T>
using unordered_set = ankerl::unordered_dense::set<T>;
}
namespace MG_Constants {
namespace Common {
inline constexpr int LOG_LEVEL_DEBUG = 0x0010;
inline constexpr int LOG_LEVEL_INFO = 0x0011;
inline constexpr int LOG_LEVEL_WARN = 0x0012;
inline constexpr int LOG_LEVEL_ERROR = 0x0013;
inline constexpr int LOG_LEVEL_WARN = 0x0011;
inline constexpr int LOG_LEVEL_ERROR = 0x0012;
inline constexpr int LOG_LEVEL_INFO = 0x0013;
inline constexpr int LOG_LEVEL_FATAL = 0x0014;
@@ -43,15 +43,10 @@ namespace MG_Constants {
inline constexpr int LOG_TARGET_FILE = 0x02;
inline constexpr int LOG_TARGET_ANDROID = 0x04; // Android logcat
inline constexpr int LOG_TARGET_ALL = LOG_TARGET_CONSOLE | LOG_TARGET_FILE | LOG_TARGET_ANDROID;
template <typename T>
bool Contains(T item, const std::vector<T> vec) {
return std::find(vec.begin(), vec.end(), item) != vec.end();
}
}
namespace Blend {
static const std::vector<GLenum> VALID_FACTORS = {
static const ankerl::unordered_set<GLenum> VALID_FACTORS = {
GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
@@ -60,55 +55,51 @@ namespace MG_Constants {
}
namespace Depth {
static const std::vector<GLenum> VALID_FUNCS = {
static const ankerl::unordered_set<GLenum> VALID_FUNCS = {
GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS
}; // OpenGL 3
}
namespace CommonState {
static const std::vector<GLenum> VALID_CAPS = {
static const ankerl::unordered_set<GLenum> VALID_CAPS = {
GL_BLEND, GL_DEPTH_TEST, GL_STENCIL_TEST, GL_SCISSOR_TEST, GL_CULL_FACE,
GL_POLYGON_OFFSET_FILL, GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_COVERAGE
}; // OpenGL 3
}
namespace Framebuffer {
static const std::vector<GLenum> VALID_ATTACHMENTS = {
static const ankerl::unordered_set<GLenum> VALID_ATTACHMENTS = {
GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT
}; // OpenGL 3
static const std::vector<GLenum> VALID_TARGETS = {
static const ankerl::unordered_set<GLenum> VALID_TARGETS = {
GL_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER
}; // OpenGL 3
static const std::vector<GLenum> VALID_ACCESS = {
static const ankerl::unordered_set<GLenum> VALID_ACCESS = {
GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE
}; // OpenGL 3
}
namespace Buffer {
static const std::vector<GLenum> VALID_PARAM_NAMES = {
static const ankerl::unordered_set<GLenum> VALID_PARAM_NAMES = {
GL_BUFFER_ACCESS, GL_BUFFER_MAPPED, GL_BUFFER_SIZE, GL_BUFFER_USAGE
}; // OpenGL 3
static const std::vector<GLenum> VALID_TARGETS = {
static const ankerl::unordered_set<GLenum> VALID_TARGETS = {
GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TEXTURE_BUFFER,
GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER
}; // OpenGL 3
static const std::vector<GLenum> VALID_ACCESS = {
static const ankerl::unordered_set<GLenum> VALID_ACCESS = {
GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE
}; // OpenGL 3
}
namespace VertexArray {
constexpr uint32_t MAX_VERTEX_ATTRIBS = 32;
}
namespace PixelStore {
static const MG_Global::unordered_map<GLenum, GLint> DEFAULT_VALUES_MAP = {
static const ankerl::unordered_map<GLenum, GLint> DEFAULT_VALUES_MAP = {
{GL_PACK_SWAP_BYTES, GL_FALSE},
{GL_PACK_LSB_FIRST, GL_FALSE},
{GL_PACK_ROW_LENGTH, 0},
@@ -127,7 +118,7 @@ namespace MG_Constants {
{GL_UNPACK_ALIGNMENT, 4}
}; // OpenGL 3
static const std::vector<GLenum> VALID_PARAM_NAMES = {
static const ankerl::unordered_set<GLenum> VALID_PARAM_NAMES = {
GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT,
GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT,
GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH,
@@ -141,18 +132,18 @@ namespace MG_Constants {
inline const GLuint MAX_TEXTURE_UNITS = 80;
const GLsizei MAX_TEXTURE_SIZE = 32768;
const GLsizei MAX_ARRAY_LAYERS = 256;
inline const std::vector<GLenum> VALID_TARGETS = {
inline const ankerl::unordered_set<GLenum> VALID_TARGETS = {
GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_1D_ARRAY, GL_PROXY_TEXTURE_1D_ARRAY,
GL_TEXTURE_RECTANGLE, GL_PROXY_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_PROXY_TEXTURE_CUBE_MAP
}; // OpenGL 3
inline const std::vector<GLenum> VALID_FORMATS = {
inline const ankerl::unordered_set<GLenum> VALID_FORMATS = {
GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL
}; // OpenGL 3
inline const std::vector<GLenum> VALID_INTERNAL_FORMATS = {
inline const ankerl::unordered_set<GLenum> VALID_INTERNAL_FORMATS = {
GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL,
GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, GL_RGBA16, GL_RGBA16F, GL_RGBA16I,
GL_RGBA16UI, GL_RGBA8, GL_RGBA8UI, GL_SRGB8_ALPHA8, GL_RGB10_A2, GL_RGB10_A2UI,
@@ -167,7 +158,7 @@ namespace MG_Constants {
GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8
}; // OpenGL 3
inline const std::vector<GLenum> VALID_TYPES = {
inline const ankerl::unordered_set<GLenum> VALID_TYPES = {
GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5,
GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV,
@@ -175,14 +166,14 @@ namespace MG_Constants {
GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV
}; // OpenGL 3
inline const std::vector<GLenum> VALID_TEXTURE_PARAM_NAMES = {
inline const ankerl::unordered_set<GLenum> VALID_TEXTURE_PARAM_NAMES = {
GL_TEXTURE_BASE_LEVEL, GL_TEXTURE_COMPARE_FUNC, GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_MIN_FILTER,
GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MAX_LEVEL, GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G,
GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A, GL_TEXTURE_SWIZZLE_RGBA, GL_TEXTURE_WRAP_S,
GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R, GL_TEXTURE_LOD_BIAS, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_BORDER_COLOR
}; // OpenGL 3
inline const std::vector<GLenum> VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = {
inline const ankerl::unordered_set<GLenum> VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = {
GL_TEXTURE_WIDTH, GL_TEXTURE_HEIGHT, GL_TEXTURE_DEPTH, GL_TEXTURE_INTERNAL_FORMAT,
GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE,
GL_TEXTURE_DEPTH_SIZE, GL_TEXTURE_COMPRESSED, GL_TEXTURE_COMPRESSED_IMAGE_SIZE
@@ -190,15 +181,9 @@ namespace MG_Constants {
}
namespace Backend {
#define BACKEND_VULKAN 0x0015
#define BACKEND_METAL 0x0016
#define BACKEND_GLES 0x0017
#define BACKEND_DILIGENT 0x0018
inline const int BACKEND_DILIGENT_VULKAN = 0x0020;
inline const int BACKEND_DILIGENT_METAL = 0x0021; // not ready currently
inline const int BACKEND_DILIGENT_OPENGL = 0x0022;
#define BACKEND_VULKAN 0x0015
#define BACKEND_METAL 0x0016
#define BACKEND_GLES 0x0017
}
inline const char* RenderName = "MobileGL";
+78 -47
View File
@@ -1,9 +1,85 @@
//
// Created by BZLZHH on 2025/3/15.
//
#pragma once
#define BACKEND_TYPE BACKEND_DILIGENT
#include "Constants.h"
#define BACKEND_TYPE BACKEND_GLES
#include "Global.h"
#ifndef MOBILEGL_GLES_LOADER_H
#include "MG_GL/BackendLoader/GLES/Loader.h"
#endif
#ifndef MOBILEGL_GL_FRAMEBUFFER_H
#include "MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h"
#endif
#ifndef MOBILEGL_GL_GETTER_H
#include "MG_GL/Implementations/GL/Getter/GL_Getter.h"
#endif
#ifndef MOBILEGL_BACKENDINFO_H
#include "MG_GL/Implementations/GL/Getter/BackendInfo.h"
#endif
#ifndef MOBILEGL_GL_BUFFER_H
#include "MG_GL/Implementations/GL/Buffer/GL_Buffer.h"
#endif
#ifndef MOBILEGL_GL_DRAWING_H
#include "MG_GL/Implementations/GL/Drawing/GL_Drawing.h"
#endif
#ifndef MOBILEGL_GL_PROGRAM_H
#include "MG_GL/Implementations/GL/Program/GL_Program.h"
#endif
#ifndef MOBILEGL_GL_TEXTURE_H
#include "MG_GL/Implementations/GL/Texture/GL_Texture.h"
#endif
#ifndef MOBILEGL_GL_VERTEXARRAY_H
#include "MG_GL/Implementations/GL/VertexArray/GL_VertexArray.h"
#endif
#ifndef MOBILEGL_GLSTATE_H
#include "MG_GL/State/Core/GLState.h"
#endif
#ifndef MOBILEGL_COMMONSTATE_H
#include "MG_GL/State/Common/CommonState.h"
#endif
#ifndef MOBILEGL_TEXTURESTATE_H
#include "MG_GL/State/Texture/TextureState.h"
#endif
#ifndef MOBILEGL_VERTEXARRAYSTATE_H
#include "MG_GL/State/VertexArray/VertexArrayState.h"
#endif
#ifndef MOBILEGL_BUFFERSTATE_H
#include "MG_GL/State/Buffer/BufferState.h"
#endif
#ifndef MOBILEGL_SHADEROBJECT_H
#include "MG_GL/State/Program/ShaderObject.h"
#endif
#ifndef MOBILEGL_PROGRAMSTATE_H
#include "MG_GL/State/Program/ProgramState.h"
#endif
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
#include "MG_GL/State/Framebuffer/FramebufferState.h"
#endif
#ifndef MOBILEGL_LOOKUP_H
#include "MG_GL/Implementations/GLX/LookUp/LookUp.h"
#endif
#ifndef MOBILEGL_DEBUG_H
#include "MG_UTIL/Debug/Debug.h"
#endif
#ifndef MOBILEGL_GLSLTOOL_H
#include "MG_UTIL/Program/GLSLTool.h"
#endif
#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H
#include "MG_UTIL/Program/DebugTool.h"
#endif
#ifndef MOBILEGL_GL_COMMON_H
#include "MG_GL/Implementations/GL/Common/GL_Common.h"
#endif
#ifndef MOBILEGL_EGL_VK_EMU_H
#include "MG_GL/Implementations/EGL/VK/EGL_EMU.h"
#endif
#ifndef MOBILEGL_EGL_GLES_EGL_WRAP_H
#include "MG_GL/Implementations/EGL/GLES/EGL_WRAP.h"
#endif
#ifndef MOBILEGL_TESTDRAWING_H
#include "MG_RHI/GLES/Test/TestDrawing.h"
#endif
#include <cstring>
#include <iostream>
@@ -14,7 +90,6 @@
#include <string>
#include <map>
#include <vector>
#include <cctype>
#include <stdexcept>
#include <atomic>
#include <regex>
@@ -26,7 +101,6 @@
#include <unordered_map>
#include <queue>
#include <format>
#include <memory>
#include <glslang/Public/ShaderLang.h>
#include <glslang/Include/Types.h>
#include <glslang/Public/ShaderLang.h>
@@ -38,7 +112,6 @@
#include <GLES3/gl32.h>
#include "MG_Include/UncertainBool.hpp"
#include "MG_Include/IndexGenerator.hpp"
#ifdef _WIN32
#include <Windows.h>
@@ -65,45 +138,3 @@
#include <EGL/egl.h>
#include <GL/gl.h>
#include <GL/glext.h>
#if BACKEND_TYPE == BACKEND_DILIGENT
#include "EngineFactory.h"
#include "EngineFactoryOpenGL.h"
#include "EngineFactoryVk.h"
#include "RefCntAutoPtr.hpp"
#include "PipelineState.h"
#include "GraphicsTypes.h"
#include "DeviceContext.h"
#endif
#include "Constants.h"
#include "Global.h"
#include "MG_GL/Implementations/EGL/Diligent/DiligentConfig.h"
#include "MG_GL/BackendLoader/GLES/Loader.h"
#include "MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h"
#include "MG_GL/Implementations/GL/Getter/GL_Getter.h"
#include "MG_GL/Implementations/GL/Getter/BackendInfo.h"
#include "MG_GL/Implementations/GL/Buffer/GL_Buffer.h"
#include "MG_GL/Implementations/GL/Drawing/GL_Drawing.h"
#include "MG_GL/Implementations/GL/Program/GL_Program.h"
#include "MG_GL/Implementations/GL/Texture/GL_Texture.h"
#include "MG_GL/Implementations/GL/VertexArray/GL_VertexArray.h"
#include "MG_GL/State/Common/CommonState.h"
#include "MG_GL/State/Texture/TextureState.h"
#include "MG_GL/State/VertexArray/VertexArrayState.h"
#include "MG_GL/State/Buffer/BufferState.h"
#include "MG_GL/State/Program/ShaderObject.h"
#include "MG_GL/State/Program/ProgramState.h"
#include "MG_GL/State/Framebuffer/FramebufferState.h"
#include "MG_GL/State/Core/GLState.h"
#include "MG_GL/Implementations/EGL/Diligent/EGL_impl.h"
#include "MG_GL/Implementations/GLX/LookUp/LookUp.h"
#include "MG_UTIL/Debug/Debug.h"
#include "MG_UTIL/Program/GLSLTool.h"
#include "MG_UTIL/Program/DebugTool.h"
#include "MG_GL/Implementations/GL/Common/GL_Common.h"
#include "MG_GL/Implementations/EGL/VK/EGL_EMU.h"
#include "MG_GL/Implementations/EGL/GLES/EGL_WRAP.h"
#include "MG_RHI/GLES/Test/TestDrawing.h"
-2
View File
@@ -8,9 +8,7 @@ void MG_Initialize() {
MG_Util::Debug::LogInit();
MG_Util::Debug::LogI("MobileGL Initializing...");
MG_State::Init();
#if BACKEND_TYPE == BACKEND_GLES
MG_GL::BackendLoader::Init();
#endif
}
void MG_Destroy() {
+1 -1
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/4/26.
//
#include "../../../Includes.h"
#include "Loader.h"
#if BACKEND_TYPE == BACKEND_GLES
+2
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GLES_LOADER_H
#define MOBILEGL_GLES_LOADER_H
#include "../../../Includes.h"
#if BACKEND_TYPE == BACKEND_GLES
#define APIENTRY_GLES
@@ -1,9 +0,0 @@
//
// Created by BZLZHH on 2025/5/25.
//
#pragma once
namespace MG_Diligent {
inline const int DILIGENT_BACKEND_TYPE = MG_Constants::Backend::BACKEND_DILIGENT_VULKAN;
}
File diff suppressed because it is too large Load Diff
@@ -1,264 +0,0 @@
//
// Created by Swung 0x48 on 2025-05-18.
//
#ifndef MOBILEGL_DILIGENT_EGL_IMPL_H
#define MOBILEGL_DILIGENT_EGL_IMPL_H
#if BACKEND_TYPE == BACKEND_DILIGENT
namespace MG_Diligent {
extern Diligent::IRenderDevice* g_pDevice;
extern Diligent::IDeviceContext* g_pContext;
extern Diligent::ISwapChain* g_pSwapChain;
extern MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_BufferMap;
extern MG_Global::unordered_map<GLuint, Diligent::ITexture*> g_TextureMap;
extern MG_Global::unordered_map<GLuint, Diligent::ITextureView*> g_TextureViewMap;
struct GLFramebufferInfo
{
// Diligent::IFramebuffer* pFramebuffer = nullptr;
// Diligent::IRenderPass* pRenderPass = nullptr;
std::vector<Diligent::ITextureView*> ColorRTVs;
Diligent::ITextureView* pDepthStencilRTV = nullptr;
Diligent::TEXTURE_FORMAT DepthStencilFormat = Diligent::TEX_FORMAT_UNKNOWN;
bool HasDepthStencil = false;
std::vector<Diligent::OptimizedClearValue> ClearValues;
// ...
};
extern MG_Global::unordered_map<GLuint, GLFramebufferInfo> g_FramebufferMap;
extern MG_Global::unordered_map<GLuint, Diligent::IShader*> g_ShaderMap;
struct GLProgramInfo
{
GLuint id;
std::vector<Diligent::IShader*> AttachedShaders;
std::vector<GLuint> AttachedShadersID;
Diligent::IPipelineState* pPipelineState = nullptr;
Diligent::IShaderResourceBinding* pResourceBinding = nullptr;
uint64_t psoStateHash = 0;
bool psoDirty = true;
std::vector<Diligent::LayoutElement> inputLayout;
GLuint DefaultFBO = 0;
ProgramObject programObj;
// Uniform names, in the order of their index in uniform buffer
std::vector<std::string> uniformBufferNames;
Diligent::IBuffer* pDefaultUBO = nullptr;
std::unordered_map<std::string, Diligent::SHADER_TYPE> uniformStages;
std::unordered_map<std::string, size_t> uniformOffsets;
// ...
};
extern MG_Global::unordered_map<GLuint, GLProgramInfo> g_ProgramMap;
extern MG_Global::unordered_map<GLuint, Diligent::ISampler*> g_SamplerMap;
extern MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_UniformBufferMap;
extern Diligent::IBuffer* g_TriangleFanIndexBuffer;
inline Diligent::PRIMITIVE_TOPOLOGY GLPrimitiveTopologyToDiligent(GLenum Topology)
{
switch (Topology)
{
case GL_TRIANGLE_STRIP:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case GL_TRIANGLES:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case GL_TRIANGLE_FAN:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
// TODO: Handle other topologies
default:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
}
}
class PipelineStateManager {
private:
struct PSOKey {
uint64_t programHash;
uint64_t stateHash;
bool operator==(const PSOKey &other) const {
return programHash == other.programHash && stateHash == other.stateHash;
}
};
struct PSOKeyHash {
size_t operator()(const PSOKey &key) const {
return std::hash<uint64_t>()(key.programHash) ^
std::hash<uint64_t>()(key.stateHash);
}
};
std::unordered_map<PSOKey, Diligent::IPipelineState *, PSOKeyHash> psoCache;
public:
Diligent::IPipelineState *GetOrCreatePSO(
GLuint program,
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void MarkPSODirty(GLuint program);
void ReleasePSO(GLuint program);
private:
Diligent::FILTER_TYPE ConvertGLFilter(GLenum filter) {
switch (filter) {
case GL_NEAREST:
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
return Diligent::FILTER_TYPE_POINT;
case GL_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_LINEAR:
return Diligent::FILTER_TYPE_LINEAR;
default:
return Diligent::FILTER_TYPE_LINEAR;
}
}
Diligent::FILTER_TYPE ConvertGLMipFilter(GLenum filter) {
switch (filter) {
case GL_NEAREST_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_NEAREST:
return Diligent::FILTER_TYPE_POINT;
case GL_NEAREST_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_LINEAR:
return Diligent::FILTER_TYPE_LINEAR;
case GL_NEAREST:
case GL_LINEAR:
return Diligent::FILTER_TYPE_LINEAR;
default:
return Diligent::FILTER_TYPE_LINEAR;
}
}
Diligent::TEXTURE_ADDRESS_MODE ConvertGLWrapMode(GLenum wrap) {
switch (wrap) {
case GL_REPEAT:
return Diligent::TEXTURE_ADDRESS_WRAP;
case GL_MIRRORED_REPEAT:
return Diligent::TEXTURE_ADDRESS_MIRROR;
case GL_CLAMP_TO_EDGE:
return Diligent::TEXTURE_ADDRESS_CLAMP;
case GL_CLAMP_TO_BORDER:
return Diligent::TEXTURE_ADDRESS_BORDER;
case GL_MIRROR_CLAMP_TO_EDGE:
return Diligent::TEXTURE_ADDRESS_MIRROR_ONCE;
default:
return Diligent::TEXTURE_ADDRESS_WRAP;
}
}
Diligent::BLEND_FACTOR ConvertGLBlendFactor(GLenum factor) {
switch (factor) {
case GL_ZERO:
return Diligent::BLEND_FACTOR_ZERO;
case GL_ONE:
return Diligent::BLEND_FACTOR_ONE;
case GL_SRC_COLOR:
return Diligent::BLEND_FACTOR_SRC_COLOR;
case GL_ONE_MINUS_SRC_COLOR:
return Diligent::BLEND_FACTOR_INV_SRC_COLOR;
case GL_DST_COLOR:
return Diligent::BLEND_FACTOR_DEST_COLOR;
case GL_ONE_MINUS_DST_COLOR:
return Diligent::BLEND_FACTOR_INV_DEST_COLOR;
case GL_SRC_ALPHA:
return Diligent::BLEND_FACTOR_SRC_ALPHA;
case GL_ONE_MINUS_SRC_ALPHA:
return Diligent::BLEND_FACTOR_INV_SRC_ALPHA;
case GL_DST_ALPHA:
return Diligent::BLEND_FACTOR_DEST_ALPHA;
case GL_ONE_MINUS_DST_ALPHA:
return Diligent::BLEND_FACTOR_INV_DEST_ALPHA;
default:
return Diligent::BLEND_FACTOR_ONE;
}
}
Diligent::COMPARISON_FUNCTION ConvertGLDepthFunc(GLenum func) {
switch (func) {
case GL_LESS:
return Diligent::COMPARISON_FUNC_LESS;
case GL_LEQUAL:
return Diligent::COMPARISON_FUNC_LESS_EQUAL;
case GL_GREATER:
return Diligent::COMPARISON_FUNC_GREATER;
case GL_GEQUAL:
return Diligent::COMPARISON_FUNC_GREATER_EQUAL;
case GL_EQUAL:
return Diligent::COMPARISON_FUNC_EQUAL;
case GL_NOTEQUAL:
return Diligent::COMPARISON_FUNC_NOT_EQUAL;
case GL_ALWAYS:
return Diligent::COMPARISON_FUNC_ALWAYS;
case GL_NEVER:
return Diligent::COMPARISON_FUNC_NEVER;
default:
return Diligent::COMPARISON_FUNC_LESS;
}
}
uint64_t CalculateStateHash(
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void ConfigurePSO(
Diligent::GraphicsPipelineStateCreateInfo &PSOCreateInfo,
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void ConfigureResourceLayout(
Diligent::GraphicsPipelineStateCreateInfo& PSOCreateInfo,
GLProgramInfo& programInfo);
};
extern PipelineStateManager g_PSOManager;
void BuildInputLayout(GLuint program, VertexArrayState& vaState,
std::vector<Diligent::LayoutElement>& inputLayout);
extern bool initialized;
// extern bool IsInRenderPass;
extern GLuint g_NextResourceId;
}
namespace MG_EGL::Diligent {
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint* attrib_list);
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config);
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list);
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor);
EGLDisplay eglGetDisplay(NativeDisplayType display);
EGLint eglGetError();
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
EGLBoolean eglTerminate(EGLDisplay dpy);
EGLBoolean eglReleaseThread(void);
EGLContext eglGetCurrentContext(void);
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
EGLBoolean eglBindAPI(EGLenum api);
EGLSurface eglGetCurrentSurface(EGLint readdraw);
EGLBoolean eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value);
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
}
MG_EXPORT __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname);
#endif
#endif //MOBILEGL_DILIGENT_EGL_IMPL_H
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/4/26.
//
#include "../../../../Includes.h"
#include "EGL_WRAP.h"
#if BACKEND_TYPE == BACKEND_GLES
@@ -48,12 +48,7 @@ MG_EXPORT EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint
MG_EXPORT EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) {
LOAD_EGL(eglCreateWindowSurface)
EGLSurface surface = egl_eglCreateWindowSurface(dpy, config, win, attrib_list);
// auto* pFactoryOpenGL = GetEngineFactoryOpenGL();
return surface;
return egl_eglCreateWindowSurface(dpy, config, win, attrib_list);
}
MG_EXPORT EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) {
+2 -2
View File
@@ -5,10 +5,10 @@
#ifndef MOBILEGL_EGL_GLES_EGL_WRAP_H
#define MOBILEGL_EGL_GLES_EGL_WRAP_H
#include "../../../../Includes.h"
#if BACKEND_TYPE == BACKEND_GLES
#endif
#endif //MOBILEGL_EGL_GLES_EGL_WRAP_H
+4 -4
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/3/30.
//
#include "../../../../Includes.h"
#include "EGL_EMU.h"
#if BACKEND_TYPE == BACKEND_VULKAN
@@ -11,9 +11,9 @@ std::atomic<uintptr_t> g_nextSurfaceId{1};
EGLenum g_currentAPI = EGL_OPENGL_ES_API;
std::mutex g_globalMutex;
MG_Global::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
MG_Global::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
MG_Global::unordered_map<EGLContext, VulkanContext> g_contexts;
ankerl::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
ankerl::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
ankerl::unordered_map<EGLContext, VulkanContext> g_contexts;
EGLint g_lastError = EGL_SUCCESS;
thread_local EGLContext tls_currentContext = EGL_NO_CONTEXT;
+5 -3
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_EGL_VK_EMU_H
#define MOBILEGL_EGL_VK_EMU_H
#include "../../../../Includes.h"
#if BACKEND_TYPE == BACKEND_VULKAN
struct EGLInternalConfig {
@@ -67,9 +69,9 @@ extern std::atomic<uintptr_t> g_nextSurfaceId;
extern EGLenum g_currentAPI;
extern std::mutex g_globalMutex;
extern MG_Global::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
extern MG_Global::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
extern MG_Global::unordered_map<EGLContext, VulkanContext> g_contexts;
extern ankerl::unordered_map<EGLDisplay, VulkanDisplay> g_displays;
extern ankerl::unordered_map<EGLSurface, VulkanSurface> g_surfaces;
extern ankerl::unordered_map<EGLContext, VulkanContext> g_contexts;
extern EGLint g_lastError;
extern thread_local EGLContext tls_currentContext;
@@ -2,18 +2,9 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Buffer.h"
namespace MG_GL::GL {
Diligent::VALUE_TYPE ConvertGLIndexTypeToDiligent(GLenum type) {
switch (type) {
case GL_UNSIGNED_BYTE: return Diligent::VT_UINT8;
case GL_UNSIGNED_SHORT: return Diligent::VT_UINT16;
case GL_UNSIGNED_INT: return Diligent::VT_UINT32;
default: return Diligent::VT_UNDEFINED;
}
}
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
GLbitfield access) {
MG_Util::Debug::LogD("glMapBufferRange, target: %s, offset: %lld, length: %lld, access: 0x%X",
@@ -40,38 +31,6 @@ namespace MG_GL::GL {
static_cast<long long>(length));
GLenum result = MG_State::SyncBufferMemory(target, offset, length);
if (result == GL_NO_ERROR) {
GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target);
if (buffer == 0) return;
auto& bufferObj = *MG_State_T::bufferState->GetBufferObject(buffer);
if (!bufferObj.isMapped) return;
size_t start = static_cast<size_t>(offset);
size_t end = start + static_cast<size_t>(length);
auto it = MG_Diligent::g_BufferMap.find(buffer);
if (it == MG_Diligent::g_BufferMap.end())
return;
Diligent::IBuffer* pBuffer = it->second;
if (pBuffer && bufferObj.data.size() >= end) {
const auto& Desc = pBuffer->GetDesc();
if (Desc.Usage == Diligent::USAGE_STAGING || Desc.Usage == Diligent::USAGE_DYNAMIC || Desc.Usage == Diligent::USAGE_UNIFIED) {
void * data;
MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE,
Diligent::MAP_FLAG_DISCARD, data);
if (data) {
void* dst = static_cast<char*>(data) + offset;
const void* src = bufferObj.data.data() + offset;
memcpy(dst, src, length);
MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE);
}
} else {
// For USAGE_DEFAULT or USAGE_IMMUTABLE, use UpdateBuffer
MG_Diligent::g_pContext->UpdateBuffer(pBuffer, static_cast<Diligent::Uint64>(offset), static_cast<Diligent::Uint64>(length), bufferObj.data.data() + offset, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
}
return;
}
MG_State::SetError(result);
@@ -91,25 +50,6 @@ namespace MG_GL::GL {
static_cast<long long>(size));
GLenum result = MG_State::CopyBufferRange(readTarget, writeTarget, readOffset, writeOffset, size);
if (result == GL_NO_ERROR) {
GLuint srcBuffer = MG_State_T::bufferState->GetCurrentBinding(readTarget);
GLuint dstBuffer = MG_State_T::bufferState->GetCurrentBinding(writeTarget);
if (srcBuffer == 0 || dstBuffer == 0) return;
auto itsrc = MG_Diligent::g_BufferMap.find(srcBuffer);
auto itdst = MG_Diligent::g_BufferMap.find(dstBuffer);
if (itsrc == MG_Diligent::g_BufferMap.end() || itdst == MG_Diligent::g_BufferMap.end()) return;
Diligent::IBuffer* pSrcBuffer = itsrc->second;
Diligent::IBuffer* pDstBuffer = itdst->second;
if (pSrcBuffer && pDstBuffer) {
MG_Diligent::g_pContext->CopyBuffer(pSrcBuffer, static_cast<Diligent::Uint64>(readOffset),
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
pDstBuffer, static_cast<Diligent::Uint64>(writeOffset),
static_cast<Diligent::Uint64>(size),
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
return;
}
MG_State::SetError(result);
@@ -138,31 +78,6 @@ namespace MG_GL::GL {
MG_Util::Debug::LogE("glUnmapBuffer failed: %s", MG_Util::Debug::GLEnumToString(err));
return GL_FALSE;
}
GLuint buffer = MG_State_T::bufferState->currentBindings_[target];
auto& bufferObj = *MG_State_T::bufferState->GetBufferObject(buffer);
auto it = MG_Diligent::g_BufferMap.find(buffer);
if (it == MG_Diligent::g_BufferMap.end())
return GL_FALSE;
Diligent::IBuffer* pBuffer = it->second;
if (pBuffer) {
const auto& Desc = pBuffer->GetDesc();
if (Desc.Usage == Diligent::USAGE_STAGING || Desc.Usage == Diligent::USAGE_DYNAMIC || Desc.Usage == Diligent::USAGE_UNIFIED) {
void * data;
MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE,
Diligent::MAP_FLAG_DISCARD, data);
if (data) {
memcpy(data, bufferObj.data.data(), bufferObj.data.size());
MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE);
}
} else {
// For USAGE_DEFAULT or USAGE_IMMUTABLE, use UpdateBuffer
MG_Diligent::g_pContext->UpdateBuffer(pBuffer, 0, bufferObj.data.size(), bufferObj.data.data(), Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
}
MG_Util::Debug::LogD("glUnmapBuffer succeeded");
return GL_TRUE;
}
@@ -197,69 +112,8 @@ namespace MG_GL::GL {
MG_Util::Debug::LogD("glBufferData, target: %s, size: %zd, data: %p, usage: %s",
MG_Util::Debug::GLEnumToString(target), size, data, MG_Util::Debug::GLEnumToString(usage));
GLenum result = MG_State::CommitBufferStorage(target, size, data, usage);
if (result == GL_NO_ERROR) {
GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target);
if (buffer == 0) return;
auto& bufferObj = *MG_State_T::bufferState->GetBufferObject(buffer);
if (bufferObj.isDynamic) return; // Dynamic buffer should be created by glDraw*
if (size <= 0) return; // ignore 0-sized reallocation
bufferObj.dirty = false;
auto it = MG_Diligent::g_BufferMap.find(buffer);
if (it == MG_Diligent::g_BufferMap.end())
return;
Diligent::IBuffer*& pBuffer = it->second;
Diligent::BufferDesc BuffDesc;
std::string name;
BuffDesc.Size = static_cast<Diligent::Uint64>(size);
switch (target) {
case GL_ARRAY_BUFFER:
// BuffDesc.BindFlags = Diligent::BIND_VERTEX_BUFFER;
name += std::format("VBO {}", buffer);
break;
case GL_ELEMENT_ARRAY_BUFFER:
// BuffDesc.BindFlags = Diligent::BIND_INDEX_BUFFER;
name += std::format("IBO {}", buffer);
break;
case GL_UNIFORM_BUFFER:
// BuffDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER;
name += std::format("UBO {}", buffer);
break;
default:
BuffDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE;
name += std::format("SRV {}", buffer);
break;
}
BuffDesc.BindFlags |= Diligent::BIND_VERTEX_BUFFER |
Diligent::BIND_INDEX_BUFFER |
Diligent::BIND_UNIFORM_BUFFER;
BuffDesc.Name = name.c_str();
BuffDesc.Usage = Diligent::USAGE_DEFAULT;
if (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()) ) {
if (pBuffer) {
pBuffer->Release();
pBuffer = nullptr;
}
Diligent::BufferData BuffData;
// Initial data must not be null for immutable buffers
BuffData.pData = BuffDesc.Usage != Diligent::USAGE_IMMUTABLE ? nullptr : bufferObj.data.data();
BuffData.DataSize = static_cast<Diligent::Uint64>(size);
MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, &BuffData, &pBuffer);
}
if (data != nullptr && BuffDesc.Usage != Diligent::USAGE_IMMUTABLE) {
MG_Diligent::g_pContext->UpdateBuffer(pBuffer, 0,
static_cast<Diligent::Uint64>(size), data,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -286,9 +140,8 @@ namespace MG_GL::GL {
GLenum result = MG_State::GenBufferNames(n, buffers);
if (result == GL_NO_ERROR) {
MG_Util::Debug::LogD("Generated buffer names:");
for (GLsizei i = 0; i < n; ++i) {
for (GLsizei i = 0; i < n; ++i) {
MG_Util::Debug::LogD(" Buffer[%d] = %u", i, buffers[i]);
MG_Diligent::g_BufferMap[buffers[i]] = nullptr;
}
return;
}
@@ -321,57 +174,13 @@ namespace MG_GL::GL {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target);
if (buffer == 0) return;
auto& bufferObj = *MG_State_T::bufferState->GetBufferObject(buffer);
if (bufferObj.isDynamic) return; // Dynamic buffer should be created by glDraw*
auto it = MG_Diligent::g_BufferMap.find(buffer);
if (it == MG_Diligent::g_BufferMap.end())
return;
Diligent::IBuffer* pBuffer = it->second;
if (pBuffer) {
const auto& Desc = pBuffer->GetDesc();
if (Desc.Usage == Diligent::USAGE_STAGING || Desc.Usage == Diligent::USAGE_DYNAMIC || Desc.Usage == Diligent::USAGE_UNIFIED) {
void* pMappedData = nullptr;
MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE, Diligent::MAP_FLAG_DISCARD, pMappedData);
if (pMappedData)
{
memcpy(static_cast<Diligent::Uint8*>(pMappedData) + offset, data, size);
MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE);
} else {
MG_Util::Debug::LogE("Failed to map buffer for BufferSubData");
}
} else {
// For USAGE_DEFAULT or USAGE_IMMUTABLE, use UpdateBuffer
MG_Diligent::g_pContext->UpdateBuffer(pBuffer, static_cast<Diligent::Uint64>(offset),
static_cast<Diligent::Uint64>(size), data,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
}
}
}
void DeleteBuffers(GLsizei n, const GLuint *buffers) {
MG_Util::Debug::LogD("glDeleteBuffers, n: %d, buffers: %p", n, buffers);
GLenum result = MG_State::DeleteBuffers(n, buffers);
if (result == GL_NO_ERROR) {
for (GLsizei i = 0; i < n; ++i) {
GLuint buffer = buffers[i];
if (buffer != 0) {
auto it = MG_Diligent::g_BufferMap.find(buffer);
if (it != MG_Diligent::g_BufferMap.end()) {
if (it->second) {
it->second->Release();
}
MG_Diligent::g_BufferMap.erase(it);
}
}
}
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GL_BUFFER_H
#define MOBILEGL_GL_BUFFER_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
+19 -124
View File
@@ -2,100 +2,23 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Common.h"
namespace MG_GL::GL {
void CreateRenderPassAndFramebuffer(GLuint framebuffer,
const FramebufferObject& fbo,
MG_Diligent::GLFramebufferInfo& fbInfo);
void Clear(GLbitfield mask) {
GLuint drawFramebuffer = MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER];
if (drawFramebuffer == 0) {
drawFramebuffer = 0;
}
auto it = MG_Diligent::g_FramebufferMap.find(drawFramebuffer);
if (it == MG_Diligent::g_FramebufferMap.end()) {
MG_Util::Debug::LogE("Framebuffer not found: %u", drawFramebuffer);
MG_Util::Debug::LogD("glClear, mask: 0x%X", mask);
GLenum result = MG_State::glClear(mask);
if (result == GL_NO_ERROR) {
return;
}
MG_Diligent::GLFramebufferInfo& fbInfo = it->second;
auto& commonState = *MG_State_T::commonState;
MG_Util::Debug::LogD("Setting render targets: %zu color attachments", fbInfo.ColorRTVs.size());
MG_Diligent::g_pContext->SetRenderTargets(
static_cast<Diligent::Uint32>(fbInfo.ColorRTVs.size()),
fbInfo.ColorRTVs.data(),
fbInfo.pDepthStencilRTV,
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
// if (MG_Diligent::IsInRenderPass) {
// MG_Util::Debug::LogD("Ending render pass before clear operation");
// MG_Diligent::g_pContext->EndRenderPass();
// MG_Diligent::IsInRenderPass = false;
// }
// MG_Util::Debug::LogD("Beginning render pass for clear operation");
// if (!fbInfo.pRenderPass) {
// MG_GL::GL::CreateRenderPassAndFramebuffer(drawFramebuffer,
// *MG_State_T::framebufferState->GetCurrentFBO(GL_DRAW_FRAMEBUFFER), fbInfo);
// }
// Diligent::BeginRenderPassAttribs beginAttribs;
// beginAttribs.pRenderPass = fbInfo.pRenderPass;
// beginAttribs.pFramebuffer = fbInfo.pFramebuffer;
// beginAttribs.StateTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
// beginAttribs.ClearValueCount = 0;
// beginAttribs.pClearValues = nullptr;
// MG_Diligent::g_pContext->BeginRenderPass(beginAttribs);
// MG_Diligent::IsInRenderPass = true;
if (mask & GL_COLOR_BUFFER_BIT) {
for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) {
if (fbInfo.ColorRTVs[i]) {
MG_Util::Debug::LogD("Clearing color attachment %zu", i);
MG_Diligent::g_pContext->ClearRenderTarget(
fbInfo.ColorRTVs[i],
commonState.clearColor,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
}
}
}
if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
if (fbInfo.pDepthStencilRTV) {
Diligent::Uint32 clearFlags = 0;
if (mask & GL_DEPTH_BUFFER_BIT) clearFlags |= Diligent::CLEAR_DEPTH_FLAG;
if (mask & GL_STENCIL_BUFFER_BIT) clearFlags |= Diligent::CLEAR_STENCIL_FLAG;
MG_Util::Debug::LogD("Clearing depth/stencil (flags: %u)", clearFlags);
MG_Diligent::g_pContext->ClearDepthStencil(
fbInfo.pDepthStencilRTV,
static_cast<Diligent::CLEAR_DEPTH_STENCIL_FLAGS>(clearFlags),
commonState.clearDepth,
0,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
}
}
// MG_Util::Debug::LogD("Ending render pass after clear operation");
// MG_Diligent::g_pContext->EndRenderPass();
// MG_Diligent::IsInRenderPass = false;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result));
}
void Enable(GLenum cap) {
MG_Util::Debug::LogD("glEnable, cap: %s", MG_Util::Debug::GLEnumToString(cap));
GLenum result = MG_State::glEnable(cap);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error enabling capability: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -103,10 +26,7 @@ namespace MG_GL::GL {
void Disable(GLenum cap) {
MG_Util::Debug::LogD("glDisable, cap: %s", MG_Util::Debug::GLEnumToString(cap));
GLenum result = MG_State::glDisable(cap);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error disabling capability: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -116,10 +36,7 @@ namespace MG_GL::GL {
MG_Util::Debug::GLEnumToString(sfactor),
MG_Util::Debug::GLEnumToString(dfactor));
GLenum result = MG_State::glBlendFunc(sfactor, dfactor);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting blend func: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -131,10 +48,7 @@ namespace MG_GL::GL {
MG_Util::Debug::GLEnumToString(srcAlpha),
MG_Util::Debug::GLEnumToString(dstAlpha));
GLenum result = MG_State::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting separate blend func: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -142,10 +56,7 @@ namespace MG_GL::GL {
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
MG_Util::Debug::LogD("glClearColor, rgba: [%.2f, %.2f, %.2f, %.2f]", red, green, blue, alpha);
GLenum result = MG_State::glClearColor(red, green, blue, alpha);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting clear color: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -153,10 +64,7 @@ namespace MG_GL::GL {
void ClearDepth(GLdouble depth) {
MG_Util::Debug::LogD("glClearDepth, depth: %.3f", depth);
GLenum result = MG_State::glClearDepth(depth);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting clear depth: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -164,10 +72,7 @@ namespace MG_GL::GL {
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
MG_Util::Debug::LogD("glColorMask, rgba: [%d, %d, %d, %d]", red, green, blue, alpha);
GLenum result = MG_State::glColorMask(red, green, blue, alpha);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting color mask: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -175,10 +80,7 @@ namespace MG_GL::GL {
void DepthFunc(GLenum func) {
MG_Util::Debug::LogD("glDepthFunc, func: %s", MG_Util::Debug::GLEnumToString(func));
GLenum result = MG_State::glDepthFunc(func);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting depth func: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -186,10 +88,7 @@ namespace MG_GL::GL {
void DepthMask(GLboolean flag) {
MG_Util::Debug::LogD("glDepthMask, flag: %d", flag);
GLenum result = MG_State::glDepthMask(flag);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting depth mask: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -198,20 +97,16 @@ namespace MG_GL::GL {
MG_Util::Debug::LogD("glViewport, x: %d, y: %d, width: %d, height: %d",
x, y, width, height);
GLenum result = MG_State::glViewport(x, y, width, height);
if (result == GL_NO_ERROR) {
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error setting viewport: %s", MG_Util::Debug::GLEnumToString(result));
}
void PixelStorei(GLenum pname, GLint param) {
MG_Util::Debug::LogD("glPixelStorei, pname: %s, param: %d", MG_Util::Debug::GLEnumToString(pname), param);
MG_Util::Debug::LogD("glPixelStorei, pname: %d, param: %d", pname, param);
GLenum result = MG_State::SetPixelStoreInt(pname,param);
if (result == GL_NO_ERROR) {
MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_);
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GL_COMMON_H
#define MOBILEGL_GL_COMMON_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
void ClearDepth(GLdouble depth);
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
File diff suppressed because it is too large Load Diff
@@ -4,17 +4,15 @@
#ifndef MOBILEGL_GL_DRAWING_H
#define MOBILEGL_GL_DRAWING_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
bool IsSamplerType(GLenum type);
Diligent::VALUE_TYPE ConvertGLTypeToDiligent(GLenum type);
void PrepareForDraw(GLenum mode, GLsizei* pCount, GLenum& type, const void*& pIndices);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count);
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex);
void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount);
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex);
void DrawBuffer(GLenum buf);
}
#endif //MOBILEGL_GL_DRAWING_H
@@ -2,235 +2,13 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Framebuffer.h"
namespace MG_GL::GL {
void ReleaseFramebufferResources(MG_Diligent::GLFramebufferInfo& fbInfo) {
// if (fbInfo.pFramebuffer) {
// fbInfo.pFramebuffer->Release();
// fbInfo.pFramebuffer = nullptr;
// }
// if (fbInfo.pRenderPass) {
// fbInfo.pRenderPass->Release();
// fbInfo.pRenderPass = nullptr;
// }
}
void CreateRenderPassAndFramebuffer(GLuint framebuffer,
const FramebufferObject& fbo,
MG_Diligent::GLFramebufferInfo& fbInfo) {
Diligent::Uint32 width = 0;
Diligent::Uint32 height = 0;
if (framebuffer == 0) {
if (MG_Diligent::g_pSwapChain) {
width = MG_Diligent::g_pSwapChain->GetDesc().Width;
height = MG_Diligent::g_pSwapChain->GetDesc().Height;
MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Using swap chain dimensions: %ux%u", width, height);
} else {
MG_Util::Debug::LogE("CreateRenderPassAndFramebuffer: Swap chain not initialized for default framebuffer");
return;
}
} else if (!fbInfo.ColorRTVs.empty() && fbInfo.ColorRTVs[0]) {
const auto& desc = fbInfo.ColorRTVs[0]->GetTexture()->GetDesc();
width = desc.Width;
height = desc.Height;
MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Using color attachment 0 for dimensions: %ux%u", width, height);
} else if (fbInfo.pDepthStencilRTV) {
const auto& desc = fbInfo.pDepthStencilRTV->GetTexture()->GetDesc();
width = desc.Width;
height = desc.Height;
MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Using depth/stencil attachment for dimensions: %ux%u", width, height);
} else {
MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Failed to determine framebuffer dimensions. No attachments.");
return;
}
if (width == 0 || height == 0) {
MG_Util::Debug::LogE("CreateRenderPassAndFramebuffer: Failed to determine framebuffer dimensions. Width or Height is 0.");
return;
}
// Diligent::RenderPassDesc RPDesc;
// std::vector<Diligent::RenderPassAttachmentDesc> Attachments;
// std::vector<Diligent::SubpassDesc> Subpasses;
// std::vector<Diligent::AttachmentReference> ColorRefs;
//
// for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) {
// if (fbInfo.ColorRTVs[i]) {
// Diligent::RenderPassAttachmentDesc ColorAttachment;
// ColorAttachment.Format = framebuffer != 0 ? fbInfo.ColorRTVs[i]->GetDesc().Format:
// MG_Diligent::g_pSwapChain->GetDesc().ColorBufferFormat;
// ColorAttachment.SampleCount = 1;
// ColorAttachment.InitialState = Diligent::RESOURCE_STATE_RENDER_TARGET;
// ColorAttachment.FinalState = Diligent::RESOURCE_STATE_RENDER_TARGET;
// ColorAttachment.LoadOp = Diligent::ATTACHMENT_LOAD_OP_LOAD;
// ColorAttachment.StoreOp = Diligent::ATTACHMENT_STORE_OP_STORE;
// Attachments.push_back(ColorAttachment);
//
// Diligent::AttachmentReference ColorRef;
// ColorRef.AttachmentIndex = static_cast<Diligent::Uint32>(Attachments.size() - 1);
// ColorRef.State = Diligent::RESOURCE_STATE_RENDER_TARGET;
// ColorRefs.push_back(ColorRef);
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Added color attachment %zu", i);
// }
// }
// Diligent::AttachmentReference DepthRef;
// if (fbInfo.pDepthStencilRTV) {
// Diligent::RenderPassAttachmentDesc DepthAttachment;
// DepthAttachment.Format = fbInfo.DepthStencilFormat;
// DepthAttachment.SampleCount = 1;
// DepthAttachment.InitialState = Diligent::RESOURCE_STATE_DEPTH_WRITE;
// DepthAttachment.FinalState = Diligent::RESOURCE_STATE_DEPTH_WRITE;
// DepthAttachment.LoadOp = Diligent::ATTACHMENT_LOAD_OP_LOAD;
// DepthAttachment.StoreOp = Diligent::ATTACHMENT_STORE_OP_STORE;
// DepthAttachment.StencilLoadOp = Diligent::ATTACHMENT_LOAD_OP_LOAD;
// DepthAttachment.StencilStoreOp = Diligent::ATTACHMENT_STORE_OP_STORE;
// Attachments.push_back(DepthAttachment);
//
// DepthRef.AttachmentIndex = static_cast<Diligent::Uint32>(Attachments.size() - 1);
// DepthRef.State = Diligent::RESOURCE_STATE_DEPTH_WRITE;
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Added depth/stencil attachment");
// }
// Diligent::SubpassDesc Subpass;
// Subpass.RenderTargetAttachmentCount = static_cast<Diligent::Uint32>(ColorRefs.size());
// Subpass.pRenderTargetAttachments = ColorRefs.empty() ? nullptr : ColorRefs.data();
// Subpass.pDepthStencilAttachment = fbInfo.pDepthStencilRTV ? &DepthRef : nullptr;
// Subpasses.push_back(Subpass);
//
// RPDesc.AttachmentCount = static_cast<Diligent::Uint32>(Attachments.size());
// RPDesc.pAttachments = Attachments.empty() ? nullptr : Attachments.data();
// RPDesc.SubpassCount = static_cast<Diligent::Uint32>(Subpasses.size());
// RPDesc.pSubpasses = Subpasses.data();
//
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Creating RenderPass with %u attachments and %u subpasses.",
// RPDesc.AttachmentCount, RPDesc.SubpassCount);
//
// MG_Diligent::g_pDevice->CreateRenderPass(RPDesc, &fbInfo.pRenderPass);
// if (!fbInfo.pRenderPass) {
// MG_Util::Debug::LogE("CreateRenderPassAndFramebuffer: Failed to create RenderPass.");
// return;
// }
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: RenderPass created successfully.");
// Diligent::FramebufferDesc FBDesc;
// FBDesc.Name = "Framebuffer";
//// FBDesc.pRenderPass = fbInfo.pRenderPass;
// FBDesc.AttachmentCount = static_cast<Diligent::Uint32>(Attachments.size());
//
// std::vector<Diligent::ITextureView *> FBAtachments(Attachments.size());
// for (size_t i = 0; i < ColorRefs.size(); ++i) {
// if (i < fbInfo.ColorRTVs.size() && fbInfo.ColorRTVs[i]) {
// FBAtachments[i] = fbInfo.ColorRTVs[i];
// }
// }
//
// if (fbInfo.pDepthStencilRTV) {
// FBAtachments[ColorRefs.size()] = fbInfo.pDepthStencilRTV;
// }
// FBDesc.ppAttachments = FBAtachments.data();
// FBDesc.Width = width;
// FBDesc.Height = height;
// FBDesc.NumArraySlices = 1;
//
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: FramebufferDesc Details:");
// MG_Util::Debug::LogD(" Name: %s", FBDesc.Name ? FBDesc.Name : "N/A");
// MG_Util::Debug::LogD(" pRenderPass: %p", FBDesc.pRenderPass);
// MG_Util::Debug::LogD(" AttachmentCount: %u", FBDesc.AttachmentCount);
// for (Diligent::Uint32 i = 0; i < FBDesc.AttachmentCount; ++i) {
// if (FBDesc.ppAttachments && FBDesc.ppAttachments[i]) {
// Diligent::ITexture* pTexture = FBDesc.ppAttachments[i]->GetTexture();
// if (pTexture) {
// const auto& texDesc = pTexture->GetDesc();
// MG_Util::Debug::LogD(" Attachment %u: Texture '%s', Dim: %ux%u",
// i, texDesc.Name ? texDesc.Name : "N/A", texDesc.Width, texDesc.Height);
// } else {
// MG_Util::Debug::LogW(" Attachment %u: TextureView's texture is nullptr", i);
// }
// } else if (!FBDesc.ppAttachments) {
// MG_Util::Debug::LogW(" FBDesc.ppAttachments is nullptr. Cannot access attachment %u.", i);
// } else {
// MG_Util::Debug::LogD(" Attachment %u: nullptr", i);
// }
// }
// MG_Util::Debug::LogD(" Width: %u", FBDesc.Width);
// MG_Util::Debug::LogD(" Height: %u", FBDesc.Height);
// MG_Util::Debug::LogD(" NumArraySlices: %u", FBDesc.NumArraySlices);
// MG_Util::Debug::LogD(" fbInfo.pFramebuffer: %p", fbInfo.pFramebuffer);
fbInfo.ClearValues.clear();
for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) {
Diligent::OptimizedClearValue clearValue;
clearValue.Color[0] = 0.0f;
clearValue.Color[1] = 0.0f;
clearValue.Color[2] = 0.0f;
clearValue.Color[3] = 1.0f;
fbInfo.ClearValues.push_back(clearValue);
}
if (fbInfo.pDepthStencilRTV) {
Diligent::OptimizedClearValue clearValue;
clearValue.DepthStencil.Depth = 1.0f;
clearValue.DepthStencil.Stencil = 0;
fbInfo.ClearValues.push_back(clearValue);
}
// MG_Diligent::g_pDevice->CreateFramebuffer(FBDesc, &fbInfo.pFramebuffer);
// if (!fbInfo.pFramebuffer) {
// MG_Util::Debug::LogE("CreateRenderPassAndFramebuffer: Failed to create Framebuffer.");
// return;
// }
// MG_Util::Debug::LogD("CreateRenderPassAndFramebuffer: Framebuffer created successfully.");
}
void UpdateDefaultFramebuffer() {
auto it = MG_Diligent::g_FramebufferMap.find(0);
if (it == MG_Diligent::g_FramebufferMap.end()) {
MG_Diligent::g_FramebufferMap[0] = MG_Diligent::GLFramebufferInfo();
}
MG_Diligent::GLFramebufferInfo& fbInfo = MG_Diligent::g_FramebufferMap[0];
ReleaseFramebufferResources(fbInfo);
if (MG_Diligent::g_pSwapChain) {
Diligent::ITextureView* pRTV = MG_Diligent::g_pSwapChain->GetCurrentBackBufferRTV();
Diligent::ITextureView* pDSV = MG_Diligent::g_pSwapChain->GetDepthBufferDSV();
if (pRTV) {
fbInfo.ColorRTVs = { pRTV };
} else {
MG_Util::Debug::LogE("Failed to get swap chain back buffer RTV");
}
if (pDSV) {
fbInfo.pDepthStencilRTV = pDSV;
fbInfo.DepthStencilFormat = MG_Diligent::g_pSwapChain->GetDesc().DepthBufferFormat;
fbInfo.HasDepthStencil = true;
} else {
MG_Util::Debug::LogE("Failed to get swap chain depth buffer DSV");
}
CreateRenderPassAndFramebuffer(0, FramebufferObject(), fbInfo);
} else {
MG_Util::Debug::LogE("Swap chain not initialized for default framebuffer");
}
}
void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
MG_Util::Debug::LogD("glGenFramebuffers, n: %d, framebuffers: %p", n, framebuffers);
GLenum result = MG_State::CreateFramebuffers(n, framebuffers);
if (result == GL_NO_ERROR) {
for (GLsizei i = 0; i < n; ++i) {
MG_Diligent::GLFramebufferInfo fbInfo;
MG_Diligent::g_FramebufferMap[framebuffers[i]] = fbInfo;
}
return;
};
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Framebuffer generation failed: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -243,205 +21,18 @@ namespace MG_GL::GL {
MG_State::SetError(result);
MG_Util::Debug::LogE("Failed to delete framebuffer %u: %s",
framebuffers[i], MG_Util::Debug::GLEnumToString(result));
} else {
GLuint fb = framebuffers[i];
auto it = MG_Diligent::g_FramebufferMap.find(fb);
if (it != MG_Diligent::g_FramebufferMap.end()) {
MG_Diligent::GLFramebufferInfo& fbInfo = it->second;
// if (fbInfo.pFramebuffer) {
// fbInfo.pFramebuffer->Release();
// }
// if (fbInfo.pRenderPass) {
// fbInfo.pRenderPass->Release();
// }
for (auto& rtv : fbInfo.ColorRTVs) {
if (rtv) rtv->Release();
}
if (fbInfo.pDepthStencilRTV) {
fbInfo.pDepthStencilRTV->Release();
}
MG_Diligent::g_FramebufferMap.erase(it);
}
}
}
}
void BindFramebuffer(GLenum target, GLuint framebuffer) {
MG_Util::Debug::LogD("BindFramebuffer: Start. Target: %s, Framebuffer: %u",
MG_Util::Debug::LogD("glBindFramebuffer, target: %s, fb: %u",
MG_Util::Debug::GLEnumToString(target), framebuffer);
GLenum result = MG_State::BindFramebuffer(target, framebuffer);
if (result == GL_NO_ERROR) {
MG_Util::Debug::LogD("BindFramebuffer: MG_State::BindFramebuffer successful.");
// if (MG_Diligent::IsInRenderPass) {
// MG_Util::Debug::LogD("BindFramebuffer: Ending current render pass.");
// MG_Diligent::g_pContext->EndRenderPass();
// MG_Diligent::IsInRenderPass = false;
// MG_Util::Debug::LogD("BindFramebuffer: Current render pass ended.");
// } else {
// MG_Util::Debug::LogD("BindFramebuffer: No active render pass to end.");
// }
if (framebuffer == 0) {
MG_Util::Debug::LogD("BindFramebuffer: Framebuffer is 0 (default framebuffer). Updating default framebuffer.");
UpdateDefaultFramebuffer();
MG_Util::Debug::LogD("BindFramebuffer: Default framebuffer updated.");
}
FramebufferObject* pFBO = MG_State_T::framebufferState->GetCurrentFBO(target);
MG_Util::Debug::LogD("BindFramebuffer: Retrieved FBO from state: %p", pFBO);
auto it = MG_Diligent::g_FramebufferMap.find(framebuffer);
if (it == MG_Diligent::g_FramebufferMap.end()) {
MG_Util::Debug::LogE("BindFramebuffer: Framebuffer %u not found in g_FramebufferMap. Aborting.", framebuffer);
return;
}
MG_Util::Debug::LogD("BindFramebuffer: Framebuffer %u found in g_FramebufferMap.", framebuffer);
MG_Diligent::GLFramebufferInfo& fbInfo = it->second;
// if (/*!fbInfo.pRenderPass || */!fbInfo.pFramebuffer) {
// MG_Util::Debug::LogD("BindFramebuffer: RenderPass or Framebuffer not yet created for framebuffer %u. Creating now.", framebuffer);
// CreateRenderPassAndFramebuffer(framebuffer, pFBO ? *pFBO : FramebufferObject(), fbInfo);
// MG_Util::Debug::LogD("BindFramebuffer: RenderPass and Framebuffer creation attempted for framebuffer %u.", framebuffer);
// } else {
// MG_Util::Debug::LogD("BindFramebuffer: RenderPass and Framebuffer already exist for framebuffer %u.", framebuffer);
// }
MG_Util::Debug::LogD("BindFramebuffer: Setting render targets. ColorRTVs count: %zu, DepthStencilRTV: %p",
fbInfo.ColorRTVs.size(), fbInfo.pDepthStencilRTV);
MG_Diligent::g_pContext->SetRenderTargets(
static_cast<Diligent::Uint32>(fbInfo.ColorRTVs.size()),
fbInfo.ColorRTVs.empty() ? nullptr : fbInfo.ColorRTVs.data(),
fbInfo.pDepthStencilRTV,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
MG_Util::Debug::LogD("BindFramebuffer: SetRenderTargets called.");
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Framebuffer bind error: %s", MG_Util::Debug::GLEnumToString(result));
}
void AttachTexture2DToFramebuffer(GLuint fbo, GLuint texture, GLenum attachment, GLint level) {
auto it = MG_Diligent::g_FramebufferMap.find(fbo);
if (it == MG_Diligent::g_FramebufferMap.end()) {
MG_Util::Debug::LogE("Framebuffer %u not found in map", fbo);
return;
}
MG_Diligent::GLFramebufferInfo& fbInfo = it->second;
// if (fbInfo.pFramebuffer) {
// fbInfo.pFramebuffer->Release();
// fbInfo.pFramebuffer = nullptr;
// MG_Util::Debug::LogD("Released existing framebuffer");
// }
// if (fbInfo.pRenderPass) {
// fbInfo.pRenderPass->Release();
// fbInfo.pRenderPass = nullptr;
// MG_Util::Debug::LogD("Released existing render pass");
// }
if (texture == 0) {
MG_Util::Debug::LogD("Unbinding attachment: %s", MG_Util::Debug::GLEnumToString(attachment));
if (attachment == GL_DEPTH_ATTACHMENT ||
attachment == GL_STENCIL_ATTACHMENT ||
attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
if (fbInfo.pDepthStencilRTV) {
fbInfo.pDepthStencilRTV->Release();
fbInfo.pDepthStencilRTV = nullptr;
MG_Util::Debug::LogD("Released depth/stencil attachment");
}
} else {
size_t index = attachment - GL_COLOR_ATTACHMENT0;
if (index < fbInfo.ColorRTVs.size() && fbInfo.ColorRTVs[index]) {
fbInfo.ColorRTVs[index]->Release();
fbInfo.ColorRTVs[index] = nullptr;
bool allNull = true;
for (const auto& rtv : fbInfo.ColorRTVs) {
if (rtv != nullptr) {
allNull = false;
break;
}
}
if (allNull) fbInfo.ColorRTVs.clear();
MG_Util::Debug::LogD("Released color attachment %zu", index);
}
}
} else {
Diligent::ITexture* pTexture = MG_Diligent::g_TextureMap[texture];
if (!pTexture) {
MG_Util::Debug::LogE("Texture %u exists in map but pointer is null", texture);
return;
}
const auto& texDesc = pTexture->GetDesc();
MG_Util::Debug::LogD("Attaching texture: %s (size: %ux%u)",
texDesc.Name,
texDesc.Width, texDesc.Height);
Diligent::TextureViewDesc ViewDesc;
ViewDesc.TextureDim = Diligent::RESOURCE_DIM_TEX_2D;
ViewDesc.MostDetailedMip = level;
ViewDesc.NumMipLevels = 1;
if (attachment == GL_DEPTH_ATTACHMENT ||
attachment == GL_STENCIL_ATTACHMENT ||
attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
MG_Util::Debug::LogD("Creating depth/stencil attachment");
if (fbInfo.pDepthStencilRTV) {
fbInfo.pDepthStencilRTV->Release();
fbInfo.pDepthStencilRTV = nullptr;
MG_Util::Debug::LogD("Released existing depth/stencil attachment");
}
ViewDesc.ViewType = Diligent::TEXTURE_VIEW_DEPTH_STENCIL;
fbInfo.DepthStencilFormat = texDesc.Format;
pTexture->CreateView(ViewDesc, &fbInfo.pDepthStencilRTV);
if (fbInfo.pDepthStencilRTV) {
fbInfo.HasDepthStencil = true;
MG_Util::Debug::LogD("Created new depth/stencil RTV");
} else {
MG_Util::Debug::LogE("Failed to create depth/stencil RTV");
}
} else {
size_t index = attachment - GL_COLOR_ATTACHMENT0;
MG_Util::Debug::LogD("Creating color attachment at index %zu", index);
if (index >= fbInfo.ColorRTVs.size()) {
fbInfo.ColorRTVs.resize(index + 1, nullptr);
MG_Util::Debug::LogD("Resized color attachments to %zu", fbInfo.ColorRTVs.size());
}
if (fbInfo.ColorRTVs[index]) {
fbInfo.ColorRTVs[index]->Release();
fbInfo.ColorRTVs[index] = nullptr;
MG_Util::Debug::LogD("Released existing color attachment %zu", index);
}
ViewDesc.ViewType = Diligent::TEXTURE_VIEW_RENDER_TARGET;
pTexture->CreateView(ViewDesc, &fbInfo.ColorRTVs[index]);
if (fbInfo.ColorRTVs[index]) {
MG_Util::Debug::LogD("Created new color RTV at index %zu", index);
} else {
MG_Util::Debug::LogE("Failed to create color RTV at index %zu", index);
}
}
}
}
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level) {
@@ -449,52 +40,13 @@ namespace MG_GL::GL {
MG_Util::Debug::GLEnumToString(target),
MG_Util::Debug::GLEnumToString(attachment),
MG_Util::Debug::GLEnumToString(textarget),
texture,
level);
if (target == GL_FRAMEBUFFER) {
MG_Util::Debug::LogD("Got target == GL_FRAMEBUFFER, treating as GL_DRAW_FRAMEBUFFER");
target = GL_DRAW_FRAMEBUFFER;
}
MG_Util::Debug::LogD(" Current READ_FRAMEBUFFER binding: %u", MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER]);
MG_Util::Debug::LogD(" Current DRAW_FRAMEBUFFER binding: %u", MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]);
texture, level);
GLenum result = MG_State::AttachTexture2DToFramebuffer(
target, attachment, textarget, texture, level
);
if (result == GL_NO_ERROR) {
// if (target == GL_FRAMEBUFFER) {
// if (MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER] == MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]) {
// MG_Util::Debug::LogD(" Target is GL_FRAMEBUFFER and READ/DRAW bindings are the same (%u). Applying to GL_DRAW_FRAMEBUFFER.",
// MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]);
// target = GL_DRAW_FRAMEBUFFER;
// } else {
// MG_Util::Debug::LogD(" Target is GL_FRAMEBUFFER and READ/DRAW bindings differ. Applying to both if non-zero.");
// if (MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER] != 0) {
// MG_Util::Debug::LogD(" Attaching to READ_FRAMEBUFFER: %u", MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER]);
// AttachTexture2DToFramebuffer(MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER],
// texture, attachment, level);
// }
// if (MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER] != 0) {
// MG_Util::Debug::LogD(" Attaching to DRAW_FRAMEBUFFER: %u", MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]);
// AttachTexture2DToFramebuffer(MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER],
// texture, attachment, level);
// }
// MG_Util::Debug::LogD("FramebufferTexture2D completed successfully after separate READ/DRAW attachments.");
// return;
// }
// }
GLuint fboToModify = MG_State_T::framebufferState->currentBindings_[target];
MG_Util::Debug::LogD(" Target is %s. Applying to bound FBO: %u",
MG_Util::Debug::GLEnumToString(target), fboToModify);
AttachTexture2DToFramebuffer(fboToModify,
texture, attachment, level);
MG_Util::Debug::LogD("FramebufferTexture2D completed successfully for target %s (FBO %u).", MG_Util::Debug::GLEnumToString(target), fboToModify);
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Texture attachment failed: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -504,7 +56,8 @@ namespace MG_GL::GL {
MG_Util::Debug::GLEnumToString(target));
GLenum result = MG_State::ValidateFramebufferCompleteness(target);
if (result >= GL_FRAMEBUFFER_COMPLETE) {
MG_Util::Debug::LogD("Framebuffer status: %s", MG_Util::Debug::GLEnumToString(result));
MG_Util::Debug::LogD("Framebuffer status: %s",
MG_Util::Debug::GLEnumToString(result));
return result;
}
MG_State::SetError(result);
@@ -515,92 +68,6 @@ namespace MG_GL::GL {
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
// if (MG_Diligent::IsInRenderPass) {
// MG_Util::Debug::LogD("Ending current render pass.");
// MG_Diligent::g_pContext->EndRenderPass();
// MG_Diligent::IsInRenderPass = false;
// MG_Util::Debug::LogD("Current render pass ended.");
// }
// explicitly unbind the texture
MG_Diligent::g_pContext->SetRenderTargets(0, nullptr, nullptr, Diligent::RESOURCE_STATE_TRANSITION_MODE_NONE);
GLuint readFB = MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER];
GLuint drawFB = MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER];
MG_Diligent::GLFramebufferInfo* pSrcFB = nullptr;
MG_Diligent::GLFramebufferInfo* pDstFB = nullptr;
if (readFB != 0) pSrcFB = &MG_Diligent::g_FramebufferMap[readFB];
if (drawFB != 0) pDstFB = &MG_Diligent::g_FramebufferMap[drawFB];
if (!pSrcFB) pSrcFB = &MG_Diligent::g_FramebufferMap[0];
if (!pDstFB) pDstFB = &MG_Diligent::g_FramebufferMap[0];
bool copyColor = (mask & GL_COLOR_BUFFER_BIT) != 0;
bool copyDepth = (mask & GL_DEPTH_BUFFER_BIT) != 0;
bool copyStencil = (mask & GL_STENCIL_BUFFER_BIT) != 0;
if (copyColor && !pSrcFB->ColorRTVs.empty() && !pDstFB->ColorRTVs.empty()) {
for (size_t i = 0; i < pSrcFB->ColorRTVs.size() && i < pDstFB->ColorRTVs.size(); ++i) {
if (pSrcFB->ColorRTVs[i] && pDstFB->ColorRTVs[i]) {
Diligent::CopyTextureAttribs CopyAttribs;
CopyAttribs.pSrcTexture = pSrcFB->ColorRTVs[i]->GetTexture();
CopyAttribs.pDstTexture = pDstFB->ColorRTVs[i]->GetTexture();
CopyAttribs.SrcTextureTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
CopyAttribs.DstTextureTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
Diligent::Box SrcBox;
SrcBox.MinX = srcX0;
SrcBox.MinY = srcY0;
SrcBox.MaxX = srcX1;
SrcBox.MaxY = srcY1;
CopyAttribs.pSrcBox = &SrcBox;
CopyAttribs.DstX = dstX0;
CopyAttribs.DstY = dstY0;
MG_Diligent::g_pContext->CopyTexture(CopyAttribs);
}
}
}
if ((copyDepth || copyStencil) && pSrcFB->pDepthStencilRTV && pDstFB->pDepthStencilRTV) {
Diligent::CopyTextureAttribs CopyAttribs;
CopyAttribs.pSrcTexture = pSrcFB->pDepthStencilRTV->GetTexture();
CopyAttribs.pDstTexture = pDstFB->pDepthStencilRTV->GetTexture();
CopyAttribs.SrcTextureTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
CopyAttribs.DstTextureTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
Diligent::Box SrcBox;
SrcBox.MinX = srcX0;
SrcBox.MinY = srcY0;
SrcBox.MaxX = srcX1;
SrcBox.MaxY = srcY1;
CopyAttribs.pSrcBox = &SrcBox;
CopyAttribs.DstX = dstX0;
CopyAttribs.DstY = dstY0;
MG_Diligent::g_pContext->CopyTexture(CopyAttribs);
}
// TODO
}
void DrawBuffer(GLenum buf) {
MG_Util::Debug::LogD("glDrawBuffer, buf: %s", MG_Util::Debug::GLEnumToString(buf));
}
void DrawBuffers(GLsizei n, const GLenum *bufs) {
MG_Util::Debug::LogD("glDrawBuffers, n: %d, bufs: [", n);
for (int i = 0; i < n; ++i) {
MG_Util::Debug::LogD("%s,", MG_Util::Debug::GLEnumToString(bufs[i]));
}
MG_Util::Debug::LogD("]");
}
void ReadBuffer(GLenum buf) {
MG_Util::Debug::LogD("glReadBuffer, buf: %s", MG_Util::Debug::GLEnumToString(buf));
}
}
}
@@ -5,18 +5,15 @@
#ifndef MOBILEGL_GL_FRAMEBUFFER_H
#define MOBILEGL_GL_FRAMEBUFFER_H
namespace MG_GL::GL {
void UpdateDefaultFramebuffer();
#include "../../../../Includes.h"
namespace MG_GL::GL {
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
void BindFramebuffer(GLenum target, GLuint framebuffer);
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GLenum CheckFramebufferStatus(GLenum target);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
void DrawBuffer(GLenum buf);
void DrawBuffers(GLsizei n, const GLenum *bufs);
void ReadBuffer(GLenum mode);
}
#endif //MOBILEGL_GL_FRAMEBUFFER_H
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GLFuncsDefinitions.h"
#define DECLARE_GL_FUNCTION_STUB_HEAD(type,name,...) \
MG_EXPORT type gl##name(__VA_ARGS__) {
@@ -57,7 +57,7 @@ DECLARE_GL_FUNCTION_HEAD(void, CompileShader, GLuint shader) DECLARE_GL_FUNCTION
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTexImage2D, target,level,internalformat,width,height,border,imageSize,data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTexSubImage2D, target,level,xoffset,yoffset,width,height,format,imageSize,data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTexImage2D, target,level,internalformat,x,y,width,height,border)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyTexSubImage2D, target,level,xoffset,yoffset,x,y,width,height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTexSubImage2D, target,level,xoffset,yoffset,x,y,width,height)
DECLARE_GL_FUNCTION_HEAD(GLuint, CreateProgram) DECLARE_GL_FUNCTION_END(GLuint, CreateProgram)
DECLARE_GL_FUNCTION_HEAD(GLuint, CreateShader, GLenum type) DECLARE_GL_FUNCTION_END(GLuint, CreateShader, type)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CullFace, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CullFace, mode)
@@ -174,7 +174,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4f, GLuint index, GLfloat x, GLf
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4fv, GLuint index, const GLfloat *v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4fv, index,v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribPointer, index,size,type,normalized,stride,pointer)
DECLARE_GL_FUNCTION_HEAD(void, Viewport, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Viewport, x,y,width,height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReadBuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ReadBuffer, src)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReadBuffer, GLenum src) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReadBuffer, src)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawRangeElements, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawRangeElements, mode,start,end,count,type,indices)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexImage3D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexImage3D, target,level,internalformat,width,height,depth,border,format,type,pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexSubImage3D, target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)
@@ -190,7 +190,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLi
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint *params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id,pname,params)
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void **params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target,pname,params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawBuffers, GLsizei n, const GLenum *bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n,bufs)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawBuffers, GLsizei n, const GLenum *bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawBuffers, n,bufs)
DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix2x3fv, location,count,transpose,value)
DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix3x2fv, location,count,transpose,value)
DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix2x4fv, location,count,transpose,value)
@@ -5,4 +5,6 @@
#ifndef MOBILEGL_GL_FUNCS_DEFINITIONS_H
#define MOBILEGL_GL_FUNCS_DEFINITIONS_H
#include "../../../../Includes.h"
#endif //MOBILEGL_GL_FUNCS_DEFINITIONS_H
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "BackendInfo.h"
namespace MG_GL::Getter {
const std::string GetBackendName() {
@@ -12,17 +12,6 @@ namespace MG_GL::Getter {
return "Metal";
#elif BACKEND_TYPE == BACKEND_GLES
return "OpenGL ES";
#elif BACKEND_TYPE == BACKEND_DILIGENT
switch (MG_Diligent::DILIGENT_BACKEND_TYPE) {
case MG_Constants::Backend::BACKEND_DILIGENT_VULKAN:
return "DiligentEngine (Vulkan)";
case MG_Constants::Backend::BACKEND_DILIGENT_METAL:
return "DiligentEngine (Metal)";
case MG_Constants::Backend::BACKEND_DILIGENT_OPENGL:
return "DiligentEngine (OpenGL)";
default:
return "DiligentEngine (Unknown Backend)";
}
#else
return "<Unknown Backend>";
#endif
@@ -35,78 +24,11 @@ namespace MG_GL::Getter {
return "MobileGlumtl";
#elif BACKEND_TYPE == BACKEND_GLES
return "MobileGlues";
#elif BACKEND_TYPE == BACKEND_DILIGENT
switch (MG_Diligent::DILIGENT_BACKEND_TYPE) {
case MG_Constants::Backend::BACKEND_DILIGENT_VULKAN:
return "MobileGlued-vk";
case MG_Constants::Backend::BACKEND_DILIGENT_METAL:
return "MobileGlued-mtl";
case MG_Constants::Backend::BACKEND_DILIGENT_OPENGL:
return "MobileGlued-gl";
default:
return "MobileGlued-unknown";
}
#else
return "<Unknown MobileGL Version>";
#endif
}
const std::string GetBackendGfxAPIName() {
#if BACKEND_TYPE == BACKEND_VULKAN
return "Vulkan";
#elif BACKEND_TYPE == BACKEND_METAL
return "Metal";
#elif BACKEND_TYPE == BACKEND_GLES
return "OpenGL ES";
#elif BACKEND_TYPE == BACKEND_DILIGENT
switch (MG_Diligent::DILIGENT_BACKEND_TYPE) {
case MG_Constants::Backend::BACKEND_DILIGENT_VULKAN:
return "Vulkan";
case MG_Constants::Backend::BACKEND_DILIGENT_METAL:
return "Metal";
case MG_Constants::Backend::BACKEND_DILIGENT_OPENGL:
return "OpenGL";
default:
return "<unknown>";
}
#else
return "<Unknown Backend>";
#endif
}
const std::string GetGPUName() {
#if BACKEND_TYPE == BACKEND_DILIGENT
if (MG_Diligent::g_pDevice)
return MG_Diligent::g_pDevice->GetAdapterInfo().Description;
return "<not set yet>";
#else
return "<unknown GPU>";
#endif
}
const uint32_t GetBackendGfxAPIVersionMajor() {
#if BACKEND_TYPE == BACKEND_DILIGENT
if (MG_Diligent::g_pDevice)
return MG_Diligent::g_pDevice->GetDeviceInfo().APIVersion.Major;
return 0;
#else
return 0;
#endif
}
const uint32_t GetBackendGfxAPIVersionMinor() {
#if BACKEND_TYPE == BACKEND_DILIGENT
if (MG_Diligent::g_pDevice)
return MG_Diligent::g_pDevice->GetDeviceInfo().APIVersion.Minor;
return 0;
#else
return 0;
#endif
}
void LogMGInfo() {
std::string MGName = MG_GL::Getter::GetMGName() + " (MobileGL Core)";
@@ -157,8 +79,6 @@ namespace MG_GL::Getter {
std::to_string(minor)+"." + std::to_string(patch);
#elif BACKEND_TYPE == BACKEND_GLES
backendVersion = std::string((const char*)::GLES::glGetString(GL_VERSION));
#elif BACKEND_TYPE == BACKEND_DILIGENT
backendVersion = "Diligent";
#else
backendVersion = "<Unknown Backend>";
#endif
@@ -5,12 +5,10 @@
#ifndef MOBILEGL_BACKENDINFO_H
#define MOBILEGL_BACKENDINFO_H
#include "../../../../Includes.h"
namespace MG_GL::Getter {
const std::string GetGPUName();
const std::string GetBackendName();
const std::string GetBackendGfxAPIName();
const uint32_t GetBackendGfxAPIVersionMajor();
const uint32_t GetBackendGfxAPIVersionMinor();
const std::string GetMGName();
void LogMGInfo();
}
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Getter.h"
namespace MG_GL::GL {
static std::string rendererString;
@@ -15,7 +15,7 @@ namespace MG_GL::GL {
MG_Util::Debug::LogD("glGetString, name: %s", MG_Util::Debug::GLEnumToString(name));
switch (name) {
case GL_VENDOR:
return (const GLubyte *)"MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
return (const GLubyte *)"MobileGL-Dev";
case GL_VERSION: {
static std::string versionStr;
if (versionStr.empty()) {
@@ -44,11 +44,7 @@ namespace MG_GL::GL {
}
return (const GLubyte *)rendererString.c_str();
*/
return (const GLubyte *)std::format("{} | {} {}.{}",
MG_GL::Getter::GetGPUName(),
MG_GL::Getter::GetBackendGfxAPIName(),
MG_GL::Getter::GetBackendGfxAPIVersionMajor(),
MG_GL::Getter::GetBackendGfxAPIVersionMinor()).c_str();
return (const GLubyte *)(MG_GL::Getter::GetMGName() + " (MobileGL Core) Renderer").c_str();
}
case GL_SHADING_LANGUAGE_VERSION:
return (const GLubyte *) "4.50 MobileGL with glslang";
@@ -187,7 +183,7 @@ namespace MG_GL::GL {
break;
case GL_MAX_VERTEX_ATTRIBS:
// TODO: Check the real value
params[0] = MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS;
params[0] = 64;
break;
// Texture state
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GL_GETTER_H
#define MOBILEGL_GL_GETTER_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
const GLubyte* GetString(GLenum name);
const GLubyte* GetStringi(GLenum name, GLuint index);
@@ -2,197 +2,15 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Program.h"
namespace MG_GL::GL {
void CreateDefaultUBO(MG_Diligent::GLProgramInfo& programInfo, size_t uboSize) {
MG_Util::Debug::LogD("CreateDefaultUBO for program, size = %zu", uboSize);
if (uboSize > 0) {
Diligent::BufferDesc BuffDesc;
BuffDesc.Name = "MG_DEFAULT_UBO";
BuffDesc.Size = uboSize;
BuffDesc.Usage = Diligent::USAGE_DYNAMIC;
BuffDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER;
BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE;
MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, nullptr, &programInfo.pDefaultUBO);
MG_Util::Debug::LogD("Created default UBO: size = %zu", uboSize);
} else {
MG_Util::Debug::LogD("UBO size is 0, default UBO not created.");
}
}
size_t RecordUniformOffsets(MG_Diligent::GLProgramInfo& programInfo, const MG_Global::unordered_map<GLuint, std::string>& shaderSources) {
MG_Util::Debug::LogD("RecordUniformOffsets for program %u using SPIRV-Cross", programInfo.id);
size_t uboTotalSize = 0;
programInfo.uniformOffsets.clear();
GLuint reflectionShaderId = 0;
for (auto shaderId : programInfo.AttachedShadersID) {
auto& shaderObj = MG_State_T::programState->shaders_[shaderId];
MG_Util::Debug::LogD(" Checking attached shader %u, type: %s", shaderId, MG_Util::Debug::GLEnumToString(shaderObj.type));
if (shaderObj.type == GL_VERTEX_SHADER) {
reflectionShaderId = shaderId;
MG_Util::Debug::LogD(" Found vertex shader %u for reflection.", reflectionShaderId);
break;
}
}
if (!reflectionShaderId && !programInfo.AttachedShadersID.empty()) {
reflectionShaderId = programInfo.AttachedShadersID[0];
MG_Util::Debug::LogD(" No vertex shader found, using first attached shader %u for reflection.", reflectionShaderId);
}
if (!reflectionShaderId) {
MG_Util::Debug::LogW(" No suitable shader found for UBO reflection.");
return uboTotalSize;
}
MG_Util::Debug::LogD(" Using shader %u for UBO reflection.", reflectionShaderId);
auto itSource = shaderSources.find(reflectionShaderId);
if (itSource == shaderSources.end()) {
MG_Util::Debug::LogE(" Could not find source for reflection shader %u.", reflectionShaderId);
return uboTotalSize;
}
MG_Util::Debug::LogD(" Found source for shader %u.", reflectionShaderId);
MG_Util::Debug::LogD(" Shader source for reflection:\n%s", itSource->second.c_str());
std::string infoLog;
auto spirv = MG_Util::Program::CompileGLSLToSPIRV(
MG_State_T::programState->shaders_[reflectionShaderId].type,
itSource->second,
infoLog,
true
);
if (spirv.empty()) {
MG_Util::Debug::LogE("GLSL to SPIR-V compilation failed for shader %u: %s", reflectionShaderId, infoLog.c_str());
return uboTotalSize;
}
MG_Util::Debug::LogD(" Successfully compiled GLSL to SPIR-V for shader %u.", reflectionShaderId);
spvc_context context = nullptr;
spvc_parsed_ir ir = nullptr;
spvc_compiler compiler = nullptr;
spvc_resources resources = nullptr;
if (spvc_context_create(&context) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to create context: %s", spvc_context_get_last_error_string(context));
return uboTotalSize;
}
if (spvc_context_parse_spirv(context, spirv.data(), spirv.size(), &ir) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to parse SPIR-V: %s", spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return uboTotalSize;
}
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to create compiler: %s", spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return uboTotalSize;
}
MG_Util::Debug::LogD(" spvc_context_create_compiler successful.");
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to create shader resources: %s", spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return uboTotalSize;
}
MG_Util::Debug::LogD(" spvc_compiler_create_shader_resources successful.");
const spvc_reflected_resource* ubo_list = nullptr;
size_t ubo_count = 0;
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &ubo_list, &ubo_count) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to get resource list for UBO: %s", spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return uboTotalSize;
}
MG_Util::Debug::LogD(" Found %zu UBO resources.", ubo_count);
for (size_t i = 0; i < ubo_count; i++) {
const char* name = ubo_list[i].name;
if (!name || strcmp(name, "MG_DEFAULT_UBO") != 0) {
MG_Util::Debug::LogD(" Skipping UBO '%s'.", name ? name : "<unnamed>");
continue;
}
MG_Util::Debug::LogD(" Found UBO 'MG_DEFAULT_UBO'.");
spvc_type_id ubo_type_id = ubo_list[i].type_id;
spvc_type ubo_type = spvc_compiler_get_type_handle(compiler, ubo_type_id);
size_t currentUboSize = 0;
if (spvc_compiler_get_declared_struct_size(compiler, ubo_type, &currentUboSize) != SPVC_SUCCESS) {
MG_Util::Debug::LogE("SPIRV-Cross: Failed to get declared struct size: %s", spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return uboTotalSize;
}
uboTotalSize = currentUboSize;
MG_Util::Debug::LogD(" UBO 'MG_DEFAULT_UBO' total size: %zu", uboTotalSize);
size_t member_count = spvc_type_get_num_member_types(ubo_type);
for (size_t member_index = 0; member_index < member_count; member_index++) {
const char* member_name = programInfo.uniformBufferNames[member_index].c_str();
unsigned offset;
spvc_compiler_type_struct_member_offset(compiler, ubo_type, member_index, &offset);
if (member_name) {
programInfo.uniformOffsets[member_name] = offset;
MG_Util::Debug::LogD(
" Uniform '%s' offset = %u (via SPIRV-Cross)",
member_name,
offset
);
}
}
break;
}
spvc_context_destroy(context);
MG_Util::Debug::LogD("RecordUniformOffsets completed for program %u, UBO total size: %zu", programInfo.id, uboTotalSize);
return uboTotalSize;
}
Diligent::VALUE_TYPE ConvertGLTypeToDiligent(GLenum type) {
switch (type) {
case GL_FLOAT: return Diligent::VT_FLOAT32;
case GL_FLOAT_VEC2: return Diligent::VT_FLOAT32;
case GL_FLOAT_VEC3: return Diligent::VT_FLOAT32;
case GL_FLOAT_VEC4: return Diligent::VT_FLOAT32;
case GL_SHORT: return Diligent::VT_INT16;
case GL_UNSIGNED_SHORT: return Diligent::VT_UINT16;
case GL_BYTE: return Diligent::VT_INT8;
case GL_UNSIGNED_BYTE: return Diligent::VT_UINT8;
case GL_INT: return Diligent::VT_INT32;
case GL_INT_VEC2: return Diligent::VT_INT32;
case GL_INT_VEC3: return Diligent::VT_INT32;
case GL_INT_VEC4: return Diligent::VT_INT32;
case GL_UNSIGNED_INT: return Diligent::VT_UINT32;
case GL_UNSIGNED_INT_VEC2: return Diligent::VT_UINT32;
case GL_UNSIGNED_INT_VEC3: return Diligent::VT_UINT32;
case GL_UNSIGNED_INT_VEC4: return Diligent::VT_UINT32;
case GL_FLOAT_MAT2: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT3: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT4: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT2x3: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT2x4: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT3x2: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT3x4: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT4x2: return Diligent::VT_FLOAT32;
case GL_FLOAT_MAT4x3: return Diligent::VT_FLOAT32;
default: return Diligent::VT_UNDEFINED;
}
}
GLuint CreateShader(GLenum type) {
MG_Util::Debug::LogD("glCreateShader, type: %s", MG_Util::Debug::GLEnumToString(type));
GLuint shader;
GLenum result = MG_State::CreateShader(type, &shader);
if (result == GL_NO_ERROR) {
MG_Util::Debug::LogD("Created shader ID: %u", shader);
MG_Diligent::g_ShaderMap[shader] = nullptr;
return shader;
}
MG_State::SetError(result);
@@ -216,29 +34,15 @@ namespace MG_GL::GL {
void DeleteShader(GLuint shader) {
MG_Util::Debug::LogD("glDeleteShader, shader: %u", shader);
GLenum result = MG_State::DeleteShader(shader);
if (result == GL_NO_ERROR) {
// Do not delete the shader object since it may be used in glDraw*.
/*
auto it = MG_Diligent::g_ShaderMap.find(shader);
if (it != MG_Diligent::g_ShaderMap.end()) {
if (it->second) {
it->second->Release();
}
MG_Diligent::g_ShaderMap.erase(it);
}
return;
*/
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogW("Error deleting shader: %s", MG_Util::Debug::GLEnumToString(result));
MG_Util::Debug::LogE("Error deleting shader: %s", MG_Util::Debug::GLEnumToString(result));
}
void DeleteProgram(GLuint program) {
MG_Util::Debug::LogD("glDeleteProgram, program: %u", program);
GLenum result = MG_State::DeleteProgram(program);
if (result == GL_NO_ERROR) {
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error deleting program: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -246,20 +50,13 @@ namespace MG_GL::GL {
void AttachShader(GLuint program, GLuint shader) {
MG_Util::Debug::LogD("glAttachShader, program: %u, shader: %u", program, shader);
GLenum result = MG_State::LinkShaderToProgram(program, shader);
if (result == GL_NO_ERROR) {
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error attaching shader: %s", MG_Util::Debug::GLEnumToString(result));
}
void ShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint* length) {
MG_Util::Debug::LogD("glShaderSource, shader: %u, count: %d", shader, count);
if (count > 0 && string != nullptr && string[0] != nullptr) {
MG_Util::Debug::LogD("Shader source for shader %u:\n%s", shader, string[0]);
} else {
MG_Util::Debug::LogD("Shader source for shader %u is empty or null.", shader);
}
GLenum result = MG_State::UploadShaderSource(shader, count, (const GLchar **)string, length);
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
@@ -268,206 +65,31 @@ namespace MG_GL::GL {
void CompileShader(GLuint shader) {
MG_Util::Debug::LogD("glCompileShader, shader: %u", shader);
// Defer actual compilation to LinkProgram
GLenum result = MG_State::BuildShaderStage(shader);
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error marking shader for compilation: %s", MG_Util::Debug::GLEnumToString(result));
MG_Util::Debug::LogE("Error compiling shader: %s", MG_Util::Debug::GLEnumToString(result));
}
void LinkProgram(GLuint program) {
MG_Util::Debug::LogD("glLinkProgram, program: %u", program);
GLenum result = MG_State::FinalizeProgramPipeline(program);
if (result != GL_NO_ERROR) {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error linking program: %s", MG_Util::Debug::GLEnumToString(result));
return;
}
auto& programInfo = MG_Diligent::g_ProgramMap[program];
auto& programObj = MG_State_T::programState->programs_[program];
programInfo.id = program;
for (const auto& shaderId : programObj.attachedShaders) {
programInfo.AttachedShadersID.push_back(shaderId);
}
MG_Global::unordered_map<GLuint, std::string> shaderSources;
MG_Global::unordered_map<GLuint, std::string> finalShaderSources;
for (GLuint shaderId : programObj.attachedShaders) {
auto it = MG_State_T::programState->shaders_.find(shaderId);
if (it != MG_State_T::programState->shaders_.end() && !it->second.markedForDeletion) {
shaderSources[it->first] = it->second.source;
// MG_Util::Program::RenameGLSLBuiltinsForVulkan(shaderSources[it->first]);
}
}
MG_Util::Program::GenerateDefaultUBOForGLSL_Multi(shaderSources, programInfo.uniformBufferNames);
MG_Util::Debug::LogD("LinkProgram: uniformBufferNames for %u:", program);
for (auto& name: programInfo.uniformBufferNames) {
MG_Util::Debug::LogD(" %s", name.c_str());
}
for (GLuint shaderId : programObj.attachedShaders) {
auto it = MG_State_T::programState->shaders_.find(shaderId);
if (it != MG_State_T::programState->shaders_.end() && !it->second.markedForDeletion) {
std::string shaderSource;
if (it->second.type == GL_VERTEX_SHADER) {
std::string infoLog;
const char* fragmentShaderSource = nullptr;
for (GLuint otherShaderId : programObj.attachedShaders) {
if (otherShaderId != shaderId && MG_State_T::programState->shaders_[otherShaderId].type == GL_FRAGMENT_SHADER) {
fragmentShaderSource = shaderSources[otherShaderId].c_str();
break;
}
}
auto spirv = MG_Util::Program::CompileGLSLToSPIRV(it->second.type,
shaderSources[shaderId],
infoLog, true, GL_FRAGMENT_SHADER, fragmentShaderSource);
if (spirv.empty()) {
MG_Util::Debug::LogE("Failed to compile vertex shader %u: %s", shaderId,
infoLog.c_str());
continue;
}
shaderSource = MG_Util::Program::BindInputLayoutLocationsForGLSL(spirv,
programObj.attribLocations);
} else if (it->second.type == GL_FRAGMENT_SHADER) {
std::string infoLog;
const char* vertexShaderSource = nullptr;
for (GLuint otherShaderId : programObj.attachedShaders) {
if (otherShaderId != shaderId && MG_State_T::programState->shaders_[otherShaderId].type == GL_VERTEX_SHADER) {
vertexShaderSource = shaderSources[otherShaderId].c_str();
break;
}
}
auto spirv = MG_Util::Program::CompileGLSLToSPIRV(it->second.type,
shaderSources[shaderId],
infoLog, true,
GL_VERTEX_SHADER, vertexShaderSource);
if (spirv.empty()) {
MG_Util::Debug::LogE("Failed to compile fragment shader %u to SPIRV: %s", shaderId,
infoLog.c_str());
continue;
}
shaderSource = MG_Util::Program::CompileSPIRVToGLSL(spirv, 450, false, true);
} else {
shaderSource = it->second.source;
}
finalShaderSources[it->first] = shaderSource;
}
}
MG_Util::Debug::LogD("Shader sources after UBO generation for program %u:", program);
for (const auto& [shaderId, source] : finalShaderSources) {
MG_Util::Debug::LogD(" Program %u Shader %u:\n%s", program, shaderId, source.c_str());
}
size_t uboTotalSize = RecordUniformOffsets(programInfo, finalShaderSources);
CreateDefaultUBO(programInfo, uboTotalSize);
// Compile attached shaders
for (GLuint shaderId : programInfo.AttachedShadersID) {
auto& shaderObj = MG_State_T::programState->shaders_[shaderId];
// Compile only if not already compiled in Diligent
if (MG_Diligent::g_ShaderMap.find(shaderId) == MG_Diligent::g_ShaderMap.end() || MG_Diligent::g_ShaderMap[shaderId] == nullptr) {
GLenum shaderType = shaderObj.type;
std::string sourceStr = finalShaderSources[shaderId];
MG_Util::Program::RenameGLSLBuiltinsForVulkan(sourceStr);
MG_Util::Debug::LogD("Shader ID: %u, type: %s\nConverted source:\n%s",
shaderId, MG_Util::Debug::GLEnumToString(shaderType), sourceStr.c_str());
Diligent::ShaderCreateInfo ShaderCI;
ShaderCI.Source = sourceStr.c_str();
ShaderCI.EntryPoint = "main";
switch (shaderType) {
case GL_VERTEX_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_VERTEX; break;
case GL_FRAGMENT_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_PIXEL; break;
case GL_GEOMETRY_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_GEOMETRY; break;
case GL_TESS_CONTROL_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_HULL; break;
case GL_TESS_EVALUATION_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_DOMAIN; break;
case GL_COMPUTE_SHADER: ShaderCI.Desc.ShaderType = Diligent::SHADER_TYPE_COMPUTE; break;
default: MG_Util::Debug::LogW("Unsupported shader type for compilation: %u", shaderType); continue;
}
ShaderCI.Desc.Name = ("Shader_" + std::to_string(shaderId)).c_str();
ShaderCI.SourceLanguage = Diligent::SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM;
Diligent::IShader* pShader = nullptr;
Diligent::RefCntAutoPtr<Diligent::IDataBlob> pMsg;
MG_Diligent::g_pDevice->CreateShader(ShaderCI, &pShader, &pMsg);
if (pShader) {
MG_Diligent::g_ShaderMap[shaderId] = pShader;
programInfo.AttachedShaders.push_back(pShader);
shaderObj.compiled = UncertainBool::True;
shaderObj.compileStatus = GL_TRUE;
MG_Util::Debug::LogD("Successfully compiled shader ID: %u for program %u", shaderId, program);
} else {
shaderObj.compiled = UncertainBool::False;
shaderObj.compileStatus = GL_FALSE;
MG_Util::Debug::LogE("Failed to compile shader ID: %u for program %u. \ncompiler info:\n%s", shaderId, program, pMsg->GetConstDataPtr<char>());
}
} else {
// Shader already compiled, just add to programInfo
programInfo.AttachedShaders.push_back(MG_Diligent::g_ShaderMap[shaderId]);
}
}
programInfo.inputLayout.clear();
auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO();
if (!pVAO) return;
// for (const auto& [index, attrib] : pVAO->attribs) {
for (uint32_t index = 0; index < MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS; ++index) {
const auto& attrib = pVAO->attribs[index];
if (attrib.enabled) {
Diligent::LayoutElement elem;
elem.InputIndex = index;
elem.BufferSlot = 0;
elem.NumComponents = attrib.size;
elem.ValueType = ConvertGLTypeToDiligent(attrib.type);
elem.IsNormalized = attrib.normalized;
elem.RelativeOffset = static_cast<GLuint>(reinterpret_cast<size_t>(attrib.pointer));
programInfo.inputLayout.push_back(elem);
}
}
programInfo.psoDirty = true;
programInfo.psoStateHash = 0;
programInfo.uniformStages.clear();
programInfo.programObj = MG_State_T::programState->programs_[program];
if (programInfo.pResourceBinding) {
programInfo.pResourceBinding->Release();
programInfo.pResourceBinding = nullptr;
}
programObj.linked = true;
programObj.linkStatus = GL_TRUE;
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error linking program: %s", MG_Util::Debug::GLEnumToString(result));
}
void UseProgram(GLuint program) {
MG_Util::Debug::LogD("glUseProgram, program: %u", program);
GLenum result = MG_State::ActivateRenderProgram(program);
if (result == GL_NO_ERROR) {
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error using program: %s", MG_Util::Debug::GLEnumToString(result));
}
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name) {
MG_Util::Debug::LogD("glBindAttribLocation, program: %u, index: %u, name: %s", program, index, name);
GLenum result = MG_State::DefineProgramAttributeLocation(program, index, name);
GLenum result = MG_State::DefineProgramAttributeBinding(program, index, name);
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error binding attribute: %s", MG_Util::Debug::GLEnumToString(result));
@@ -475,7 +97,7 @@ namespace MG_GL::GL {
GLint GetAttribLocation(GLuint program, const GLchar* name) {
MG_Util::Debug::LogD("glGetAttribLocation, program: %u, name: %s", program, name);
GLint location = MG_State::QueryProgramAttributeLocation(program, name);
GLint location = MG_State::QueryProgramAttributeBinding(program, name);
if (location != -1) return location;
MG_State::SetError(GL_INVALID_OPERATION);
MG_Util::Debug::LogE("Attribute not found: %s", name);
@@ -497,7 +119,7 @@ namespace MG_GL::GL {
GLenum result = MG_State::QueryProgramStateIntVector(program, pname, params);
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogW("Error getting program param: %s", MG_Util::Debug::GLEnumToString(result));
MG_Util::Debug::LogE("Error getting program param: %s", MG_Util::Debug::GLEnumToString(result));
}
void GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
@@ -5,9 +5,9 @@
#ifndef MOBILEGL_GL_PROGRAM_H
#define MOBILEGL_GL_PROGRAM_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
Diligent::VALUE_TYPE ConvertGLTypeToDiligent(GLenum type);
GLuint CreateShader(GLenum type);
GLuint CreateProgram();
void DeleteShader(GLuint shader);
@@ -2,187 +2,9 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_Texture.h"
namespace MG_GL::GL {
Diligent::TEXTURE_FORMAT ConvertInternalFormat(GLint internalFormat) {
switch (internalFormat) {
case GL_RGBA: return Diligent::TEX_FORMAT_RGBA8_UNORM;
case GL_RGBA8: return Diligent::TEX_FORMAT_RGBA8_UNORM;
case GL_RGBA8_SNORM: return Diligent::TEX_FORMAT_RGBA8_SNORM;
case GL_RGBA16F: return Diligent::TEX_FORMAT_RGBA16_FLOAT;
case GL_RGBA32F: return Diligent::TEX_FORMAT_RGBA32_FLOAT;
case GL_RGB: return Diligent::TEX_FORMAT_RGBA8_UNORM;
case GL_RGB8: return Diligent::TEX_FORMAT_RGBA8_UNORM; // Diligent doesn't have RGB8, promote to RGBA8
case GL_RGB16F: return Diligent::TEX_FORMAT_RGBA16_FLOAT; // Promote
case GL_RGB32F: return Diligent::TEX_FORMAT_RGBA32_FLOAT; // Promote
case GL_DEPTH_COMPONENT: return Diligent::TEX_FORMAT_D32_FLOAT;
case GL_DEPTH_COMPONENT16: return Diligent::TEX_FORMAT_D16_UNORM;
case GL_DEPTH_COMPONENT24: return Diligent::TEX_FORMAT_D24_UNORM_S8_UINT; // No D24_UNORM, use with stencil
case GL_DEPTH_COMPONENT32: return Diligent::TEX_FORMAT_D32_FLOAT;
case GL_DEPTH_COMPONENT32F: return Diligent::TEX_FORMAT_D32_FLOAT;
case GL_DEPTH_STENCIL: return Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
case GL_DEPTH24_STENCIL8: return Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
case GL_DEPTH32F_STENCIL8: return Diligent::TEX_FORMAT_D32_FLOAT_S8X24_UINT;
case GL_RED: return Diligent::TEX_FORMAT_R8_UNORM;
case GL_R8: return Diligent::TEX_FORMAT_R8_UNORM;
case GL_R16F: return Diligent::TEX_FORMAT_R16_FLOAT;
case GL_R32F: return Diligent::TEX_FORMAT_R32_FLOAT;
case GL_RG: return Diligent::TEX_FORMAT_RG8_UNORM;
case GL_RG8: return Diligent::TEX_FORMAT_RG8_UNORM;
case GL_RG16F: return Diligent::TEX_FORMAT_RG16_FLOAT;
case GL_RG32F: return Diligent::TEX_FORMAT_RG32_FLOAT;
default: return Diligent::TEX_FORMAT_RGBA8_UNORM;
}
}
size_t GetBytesPerPixel(GLenum format, GLenum type) {
int components = 0;
switch (format) {
case GL_RED: components = 1; break;
case GL_RG: components = 2; break;
case GL_RGB: components = 3; break;
case GL_RGBA: components = 4; break;
case GL_DEPTH_COMPONENT: components = 1; break;
case GL_DEPTH_STENCIL: components = 2; break;
default: components = 4; break;
}
size_t typeSize = 0;
switch (type) {
case GL_UNSIGNED_BYTE:
case GL_BYTE: typeSize = 1; break;
case GL_UNSIGNED_SHORT:
case GL_SHORT: typeSize = 2; break;
case GL_UNSIGNED_INT:
case GL_INT:
case GL_FLOAT: typeSize = 4; break;
default: typeSize = 1; break;
}
return components * typeSize;
}
Diligent::FILTER_TYPE ConvertCompareFilter(Diligent::FILTER_TYPE& filter, bool compare) {
if (compare) {
switch (filter) {
case Diligent::FILTER_TYPE_POINT: return Diligent::FILTER_TYPE_COMPARISON_POINT;
case Diligent::FILTER_TYPE_LINEAR: return Diligent::FILTER_TYPE_COMPARISON_LINEAR;
case Diligent::FILTER_TYPE_ANISOTROPIC: return Diligent::FILTER_TYPE_COMPARISON_ANISOTROPIC;
default: return filter;
}
} else {
switch (filter) {
case Diligent::FILTER_TYPE_COMPARISON_POINT: return Diligent::FILTER_TYPE_POINT;
case Diligent::FILTER_TYPE_COMPARISON_LINEAR: return Diligent::FILTER_TYPE_LINEAR;
case Diligent::FILTER_TYPE_COMPARISON_ANISOTROPIC: return Diligent::FILTER_TYPE_ANISOTROPIC;
default: return filter;
}
}
}
bool IsCompareFilter(Diligent::FILTER_TYPE filter) {
switch (filter) {
case Diligent::FILTER_TYPE_COMPARISON_POINT: return true;
case Diligent::FILTER_TYPE_COMPARISON_LINEAR: return true;
case Diligent::FILTER_TYPE_COMPARISON_ANISOTROPIC: return true;
default: return false;
}
}
void FillFilterTypeFromGLEnum(GLenum pname, GLenum param, Diligent::FILTER_TYPE& minFilter, Diligent::FILTER_TYPE& magFilter, Diligent::FILTER_TYPE& mipFilter) {
if (pname == GL_TEXTURE_COMPARE_MODE) {
bool compare = (param == GL_COMPARE_REF_TO_TEXTURE);
minFilter = ConvertCompareFilter(minFilter, compare);
magFilter = ConvertCompareFilter(magFilter, compare);
mipFilter = ConvertCompareFilter(mipFilter, compare);
return;
}
Diligent::FILTER_TYPE* pFilter = nullptr;
if (pname == GL_TEXTURE_MIN_FILTER) {
pFilter = &minFilter;
} else if (pname == GL_TEXTURE_MAG_FILTER) {
pFilter = &magFilter;
} else {
MG_Util::Debug::LogD("FillFilterTypeFromGLEnum: not allowed pname!");
return;
}
Diligent::FILTER_TYPE& filter = *pFilter;
bool filterIsCompare = IsCompareFilter(filter);
bool mipFilterIsCompare = IsCompareFilter(mipFilter);
switch (param) {
case GL_NEAREST:
filter = Diligent::FILTER_TYPE_POINT;
if (pname == GL_TEXTURE_MIN_FILTER)
mipFilter = Diligent::FILTER_TYPE_POINT;
break;
case GL_LINEAR:
filter = Diligent::FILTER_TYPE_LINEAR;
if (pname == GL_TEXTURE_MIN_FILTER)
mipFilter = Diligent::FILTER_TYPE_POINT;
break;
case GL_NEAREST_MIPMAP_NEAREST:
filter = Diligent::FILTER_TYPE_POINT;
mipFilter = Diligent::FILTER_TYPE_POINT;
break;
case GL_LINEAR_MIPMAP_NEAREST:
filter = Diligent::FILTER_TYPE_LINEAR;
mipFilter = Diligent::FILTER_TYPE_POINT;
break;
case GL_NEAREST_MIPMAP_LINEAR:
filter = Diligent::FILTER_TYPE_POINT;
mipFilter = Diligent::FILTER_TYPE_LINEAR;
break;
case GL_LINEAR_MIPMAP_LINEAR:
filter = Diligent::FILTER_TYPE_LINEAR;
mipFilter = Diligent::FILTER_TYPE_LINEAR;
break;
default:
break;
}
filter = ConvertCompareFilter(filter, filterIsCompare);
mipFilter = ConvertCompareFilter(mipFilter, mipFilterIsCompare);
}
Diligent::COMPARISON_FUNCTION ConvertComparsionFunc(GLint param) {
switch (param) {
case GL_LEQUAL: return Diligent::COMPARISON_FUNC_LESS_EQUAL;
case GL_GEQUAL: return Diligent::COMPARISON_FUNC_GREATER_EQUAL;
case GL_LESS: return Diligent::COMPARISON_FUNC_LESS;
case GL_GREATER: return Diligent::COMPARISON_FUNC_GREATER;
case GL_EQUAL: return Diligent::COMPARISON_FUNC_EQUAL;
case GL_NOTEQUAL: return Diligent::COMPARISON_FUNC_NOT_EQUAL;
case GL_ALWAYS: return Diligent::COMPARISON_FUNC_ALWAYS;
case GL_NEVER: return Diligent::COMPARISON_FUNC_NEVER;
default:
MG_Util::Debug::LogE("%s: not handled param: %s", __func__, MG_Util::Debug::GLEnumToString(param));
return Diligent::COMPARISON_FUNC_NEVER;
}
}
Diligent::TEXTURE_ADDRESS_MODE ConvertAddressMode(GLint param) {
switch (param) {
case GL_REPEAT: return Diligent::TEXTURE_ADDRESS_WRAP;
case GL_CLAMP_TO_EDGE: return Diligent::TEXTURE_ADDRESS_CLAMP;
case GL_MIRRORED_REPEAT: return Diligent::TEXTURE_ADDRESS_MIRROR;
default:
MG_Util::Debug::LogE("%s: not handled param: %s", __func__, MG_Util::Debug::GLEnumToString(param));
return Diligent::TEXTURE_ADDRESS_WRAP;
}
}
void ActiveTexture(GLenum texture) {
MG_Util::Debug::LogD("glActiveTexture, texture: %d", texture);
GLenum result = MG_State::BindTextureUnit(texture);
@@ -195,9 +17,8 @@ namespace MG_GL::GL {
void BindTexture(GLenum target, GLuint texture) {
MG_Util::Debug::LogD("glBindTexture, target: %d, texture: %d", target, texture);
GLenum result = MG_State::BindTexture(target, texture);
if (result == GL_NO_ERROR) {
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -205,27 +26,8 @@ namespace MG_GL::GL {
void DeleteTextures(GLsizei n, const GLuint* textures) {
MG_Util::Debug::LogD("glDeleteTextures, n: %d, textures: %p", n, textures);
GLenum result = MG_State::DeleteTextures(n, textures);
if (result == GL_NO_ERROR) {
for (GLsizei i = 0; i < n; ++i) {
GLuint tex = textures[i];
auto texIt = MG_Diligent::g_TextureMap.find(tex);
if (texIt != MG_Diligent::g_TextureMap.end()) {
if (texIt->second) {
texIt->second->Release();
}
MG_Diligent::g_TextureMap.erase(texIt);
}
auto srvIt = MG_Diligent::g_TextureViewMap.find(tex);
if (srvIt != MG_Diligent::g_TextureViewMap.end()) {
if (srvIt->second) {
srvIt->second->Release();
}
MG_Diligent::g_TextureViewMap.erase(srvIt);
}
}
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -233,453 +35,52 @@ namespace MG_GL::GL {
void GenTextures(GLsizei n, GLuint* textures) {
MG_Util::Debug::LogD("glGenTextures, n: %d, textures: %p", n, textures);
GLenum result = MG_State::CreateTextures(n, textures);
if (result == GL_NO_ERROR) {
for (GLsizei i = 0; i < n; ++i) {
MG_Diligent::g_TextureMap[textures[i]] = nullptr;
MG_Diligent::g_TextureViewMap[textures[i]] = nullptr;
}
if (result == GL_NO_ERROR)
return;
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
Diligent::Uint32 CalculateMipLevels(GLsizei width, GLsizei height) {
Diligent::Uint32 levels = 1;
GLsizei size = std::max(width, height);
while (size > 1) {
size >>= 1;
levels++;
}
return levels;
}
void TexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border,
void TexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const void* data) {
MG_Util::Debug::LogD("glTexImage2D, target: %d, level: %d, internalFormat: %d, width: %d, height: %d, format: %d, type: %d, data: %p",
target, level, internalFormat, width, height, format, type, data);
GLenum result = MG_State::UploadTexture2D(target, level, internalFormat, width, height,
border, format, type, data);
if (result != GL_NO_ERROR) {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
GLenum result = MG_State::UploadTexture2D(target, level, internalFormat, width, height, border, format, type, data);
if (result == GL_NO_ERROR)
return;
}
MG_Util::Debug::LogD("TexImage2D: MG_State::UploadTexture2D successful.");
auto& texState = *MG_State_T::textureState;
auto activeUnit = texState.activeTextureUnit_;
auto unitState = &texState.textureUnits_[activeUnit];
GLuint boundTextureID = unitState->GetBoundTexture(target);
if (boundTextureID == 0) {
MG_Util::Debug::LogD("TexImage2D: No texture bound to active unit. Returning.");
return;
}
Diligent::ITexture* pTexture = nullptr;
Diligent::ITextureView* pSRV = nullptr;
auto texIt = MG_Diligent::g_TextureMap.find(boundTextureID);
if (texIt != MG_Diligent::g_TextureMap.end()) {
pTexture = texIt->second;
}
auto srvIt = MG_Diligent::g_TextureViewMap.find(boundTextureID);
if (srvIt != MG_Diligent::g_TextureViewMap.end()) {
pSRV = srvIt->second;
}
Diligent::TEXTURE_FORMAT newFormat = ConvertInternalFormat(internalFormat);
MG_Util::Debug::LogD("TexImage2D: New internalFormat: %d maps to Diligent format: %d",
internalFormat, newFormat);
bool needCreateTexture = false;
bool isBaseLevel = (level == 0);
if (!pTexture) {
MG_Util::Debug::LogD("TexImage2D: No existing Diligent texture found for GL name %u. Creating new.", boundTextureID);
needCreateTexture = true;
} else {
Diligent::TextureDesc existingDesc = pTexture->GetDesc();
if (isBaseLevel &&
(existingDesc.Width != static_cast<Diligent::Uint32>(width) ||
existingDesc.Height != static_cast<Diligent::Uint32>(height) ||
existingDesc.Format != newFormat)) {
MG_Util::Debug::LogD("TexImage2D: Base level properties changed. Recreating texture.");
MG_Util::Debug::LogD("TexImage2D: Old (W:%u, H:%u, F:%d), New (W:%d, H:%d, F:%d)",
existingDesc.Width, existingDesc.Height, existingDesc.Format,
width, height, newFormat);
needCreateTexture = true;
} else if (level >= static_cast<GLint>(existingDesc.MipLevels)) {
MG_Util::Debug::LogD("TexImage2D: Level %d exceeds current mip levels (%d). Recreating texture.",
level, existingDesc.MipLevels);
needCreateTexture = true;
}
}
if (needCreateTexture) {
if (pSRV) {
MG_Util::Debug::LogD("TexImage2D: Releasing existing SRV %p", (void*)pSRV);
pSRV->Release();
MG_Diligent::g_TextureViewMap[boundTextureID] = nullptr;
pSRV = nullptr;
}
if (pTexture) {
MG_Util::Debug::LogD("TexImage2D: Releasing existing texture %p", (void*)pTexture);
pTexture->Release();
MG_Diligent::g_TextureMap[boundTextureID] = nullptr;
pTexture = nullptr;
}
Diligent::Uint32 mipLevels = 1;
if (isBaseLevel) {
mipLevels = CalculateMipLevels(width, height);
} else if (pTexture) {
mipLevels = pTexture->GetDesc().MipLevels;
}
Diligent::TextureDesc TexDesc;
if constexpr (MG_Global::Common::LogLevel <= MG_Constants::Common::LOG_LEVEL_DEBUG) {
TexDesc.Name = std::format("GL Texture {}", boundTextureID).c_str();
}
TexDesc.Type = Diligent::RESOURCE_DIM_TEX_2D;
TexDesc.Width = width;
TexDesc.Height = height;
TexDesc.Format = newFormat;
TexDesc.MipLevels = mipLevels;
bool isDepthStencil = false;
switch (internalFormat) {
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_STENCIL:
case GL_DEPTH24_STENCIL8:
case GL_DEPTH32F_STENCIL8:
isDepthStencil = true;
break;
default:
isDepthStencil = false;
}
if (isDepthStencil) {
TexDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE | Diligent::BIND_DEPTH_STENCIL;
} else {
TexDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE | Diligent::BIND_RENDER_TARGET;
}
MG_Util::Debug::LogD("TexImage2D: Creating new Diligent texture with Width: %d, Height: %d, Format: %d, MipLevels: %u",
width, height, newFormat, mipLevels);
Diligent::ITexture* newTexture = nullptr;
MG_Diligent::g_pDevice->CreateTexture(TexDesc, nullptr, &newTexture);
if (newTexture) {
MG_Util::Debug::LogD("TexImage2D: Created new Diligent texture %p for GL name %u.",
(void*)newTexture, boundTextureID);
Diligent::TextureViewDesc SRVDesc;
SRVDesc.ViewType = Diligent::TEXTURE_VIEW_SHADER_RESOURCE;
SRVDesc.TextureDim = Diligent::RESOURCE_DIM_TEX_2D;
SRVDesc.MostDetailedMip = 0;
SRVDesc.NumMipLevels = TexDesc.MipLevels;
Diligent::ITextureView* newSRV = nullptr;
newTexture->CreateView(SRVDesc, &newSRV);
MG_Util::Debug::LogD("TexImage2D: Created new SRV %p for texture.", (void*)newSRV);
MG_Diligent::g_TextureMap[boundTextureID] = newTexture;
MG_Diligent::g_TextureViewMap[boundTextureID] = newSRV;
pTexture = newTexture;
pSRV = newSRV;
} else {
MG_Util::Debug::LogE("TexImage2D: Failed to create new texture!");
return;
}
}
if (pTexture && data) {
Diligent::TextureSubResData SubResData;
SubResData.pData = data;
SubResData.Stride = width * GetBytesPerPixel(format, type);
Diligent::Box UpdateBox;
UpdateBox.MinX = 0;
UpdateBox.MaxX = width;
UpdateBox.MinY = 0;
UpdateBox.MaxY = height;
UpdateBox.MinZ = 0;
UpdateBox.MaxZ = 1;
MG_Util::Debug::LogD("TexImage2D: Updating texture. Level: %d, Box: [%u,%u]x[%u,%u], Stride: %llu",
level, UpdateBox.MinX, UpdateBox.MaxX, UpdateBox.MinY, UpdateBox.MaxY, SubResData.Stride);
MG_Diligent::g_pContext->UpdateTexture(
pTexture,
level,
0,
UpdateBox,
SubResData,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
MG_Util::Debug::LogD("TexImage2D: UpdateTexture completed for level %d.", level);
}
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
MG_Util::Debug::LogD("glTexParameterf, target: %d, pname: %d, param: %f", target, pname, param);
GLenum result = MG_State::SetTexturePropertyFloat(target, pname, param);
if (result == GL_NO_ERROR) {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
if (result == GL_NO_ERROR)
return;
}
// TODO: Fix sampler
auto& texState = *MG_State_T::textureState;
auto activeUnit = texState.activeTextureUnit_;
auto unitState = &texState.textureUnits_[activeUnit];
GLuint boundTextureID = unitState->GetBoundTexture(target);
if (boundTextureID == 0) {
MG_Util::Debug::LogD("TexParameterf: No texture bound. Skipping sampler update.");
return;
}
Diligent::SamplerDesc SamDesc;
auto it = MG_Diligent::g_SamplerMap.find(boundTextureID);
if (it != MG_Diligent::g_SamplerMap.end() && it->second) {
SamDesc = it->second->GetDesc();
} else {
SamDesc.MinFilter = Diligent::FILTER_TYPE_LINEAR;
SamDesc.MagFilter = Diligent::FILTER_TYPE_LINEAR;
SamDesc.AddressU = Diligent::TEXTURE_ADDRESS_WRAP;
SamDesc.AddressV = Diligent::TEXTURE_ADDRESS_WRAP;
SamDesc.AddressW = Diligent::TEXTURE_ADDRESS_WRAP;
}
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
case GL_TEXTURE_MAG_FILTER:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
case GL_TEXTURE_WRAP_S:
SamDesc.AddressU = ConvertAddressMode(param);
break;
case GL_TEXTURE_WRAP_T:
SamDesc.AddressV = ConvertAddressMode(param);
break;
case GL_TEXTURE_WRAP_R:
SamDesc.AddressW = ConvertAddressMode(param);
break;
case GL_TEXTURE_MIN_LOD:
SamDesc.MinLOD = (float)param;
break;
case GL_TEXTURE_MAX_LOD:
SamDesc.MaxLOD = param;
break;
case GL_TEXTURE_COMPARE_FUNC:
SamDesc.ComparisonFunc = ConvertComparsionFunc(param);
break;
case GL_TEXTURE_COMPARE_MODE:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
default:
MG_Util::Debug::LogE("%s: not handled pname: %s", __func__, MG_Util::Debug::GLEnumToString(pname));
}
Diligent::ISampler* pNewSampler = nullptr;
MG_Diligent::g_pDevice->CreateSampler(SamDesc, &pNewSampler);
if (it != MG_Diligent::g_SamplerMap.end()) {
if (it->second) {
it->second->Release();
}
it->second = pNewSampler;
} else {
MG_Diligent::g_SamplerMap[boundTextureID] = pNewSampler;
}
MG_Util::Debug::LogD("TexParameterf: Updated sampler for texture %u", boundTextureID);
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
void TexParameteri(GLenum target, GLenum pname, GLint param) {
MG_Util::Debug::LogD("glTexParameteri, target: %d, pname: %d, param: %d", target, pname, param);
GLenum result = MG_State::SetTexturePropertyInt(target, pname, param);
if (result != GL_NO_ERROR) {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
if (result == GL_NO_ERROR)
return;
}
// TODO: Fix sampler
auto& texState = *MG_State_T::textureState;
auto activeUnit = texState.activeTextureUnit_;
auto unitState = &texState.textureUnits_[activeUnit];
GLuint boundTextureID = unitState->GetBoundTexture(target);
if (boundTextureID == 0) {
MG_Util::Debug::LogD("TexParameteri: No texture bound. Skipping sampler update.");
return;
}
Diligent::SamplerDesc SamDesc;
auto it = MG_Diligent::g_SamplerMap.find(boundTextureID);
if (it != MG_Diligent::g_SamplerMap.end() && it->second) {
SamDesc = it->second->GetDesc();
} else {
SamDesc.MinFilter = Diligent::FILTER_TYPE_LINEAR;
SamDesc.MagFilter = Diligent::FILTER_TYPE_LINEAR;
SamDesc.AddressU = Diligent::TEXTURE_ADDRESS_WRAP;
SamDesc.AddressV = Diligent::TEXTURE_ADDRESS_WRAP;
SamDesc.AddressW = Diligent::TEXTURE_ADDRESS_WRAP;
}
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
case GL_TEXTURE_MAG_FILTER:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MagFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
case GL_TEXTURE_WRAP_S:
SamDesc.AddressU = ConvertAddressMode(param);
break;
case GL_TEXTURE_WRAP_T:
SamDesc.AddressV = ConvertAddressMode(param);
break;
case GL_TEXTURE_WRAP_R:
SamDesc.AddressW = ConvertAddressMode(param);
break;
case GL_TEXTURE_MIN_LOD:
SamDesc.MinLOD = (float)param;
break;
case GL_TEXTURE_MAX_LOD:
SamDesc.MaxLOD = (float)param;
break;
case GL_TEXTURE_COMPARE_FUNC:
SamDesc.ComparisonFunc = ConvertComparsionFunc(param);
break;
case GL_TEXTURE_COMPARE_MODE:
FillFilterTypeFromGLEnum(pname, param, SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter);
break;
default:
MG_Util::Debug::LogE("%s: not handled pname: %s", __func__, MG_Util::Debug::GLEnumToString(pname));
}
Diligent::ISampler* pNewSampler = nullptr;
MG_Diligent::g_pDevice->CreateSampler(SamDesc, &pNewSampler);
if (it != MG_Diligent::g_SamplerMap.end()) {
if (it->second) {
it->second->Release();
}
it->second = pNewSampler;
} else {
MG_Diligent::g_SamplerMap[boundTextureID] = pNewSampler;
}
MG_Util::Debug::LogD("TexParameteri: Updated sampler for texture %u", boundTextureID);
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLenum type, const void* pixels) {
MG_Util::Debug::LogD("glTexSubImage2D, target: %d, level: %d, xoffset: %d, yoffset: %d, width: %d, height: %d, format: %d, type: %d, pixels: %p",
target, level, xoffset, yoffset, width, height, format, type, pixels);
GLenum result = MG_State::UpdateTextureRegion2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
if (result != GL_NO_ERROR) {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
if (result == GL_NO_ERROR)
return;
}
auto& texState = *MG_State_T::textureState;
auto activeUnit = texState.activeTextureUnit_;
auto unitState = &texState.textureUnits_[activeUnit];
GLuint boundTextureID = unitState->GetBoundTexture(target);
MG_Util::Debug::LogD("TexSubImage2D: bound texture: GL name %u", boundTextureID);
if (boundTextureID == 0) {
MG_Util::Debug::LogD("TexSubImage2D: No texture bound to active unit. Skipping update.");
return;
}
Diligent::ITexture* pTexture = nullptr;
auto texIt = MG_Diligent::g_TextureMap.find(boundTextureID);
if (texIt != MG_Diligent::g_TextureMap.end()) {
pTexture = texIt->second;
}
if (!pTexture) {
MG_Util::Debug::LogW("TexSubImage2D: Diligent texture not found for GL name %u", boundTextureID);
return;
}
const auto& texDesc = pTexture->GetDesc();
if (!(texDesc.BindFlags & Diligent::BIND_SHADER_RESOURCE)) {
MG_Util::Debug::LogE("TexSubImage2D: Texture %u does not have BIND_SHADER_RESOURCE flag", boundTextureID);
return;
}
auto rowLength = MG_State::QueryPixelStoreInt(GL_UNPACK_ROW_LENGTH);
rowLength = ((rowLength > 0) ? rowLength : width);
auto skipRows = MG_State::QueryPixelStoreInt(GL_UNPACK_SKIP_ROWS);
auto skipPixels = MG_State::QueryPixelStoreInt(GL_UNPACK_SKIP_PIXELS);
auto bpp = GetBytesPerPixel(format, type);
char* pixelStart = (char*)pixels + bpp * (rowLength * skipRows + skipPixels);
Diligent::TextureSubResData SubResData;
SubResData.Stride = rowLength * bpp;
SubResData.pData = pixelStart;
Diligent::Box UpdateBox;
UpdateBox.MinX = xoffset;
UpdateBox.MaxX = xoffset + width;
UpdateBox.MinY = yoffset;
UpdateBox.MaxY = yoffset + height;
UpdateBox.MinZ = 0;
UpdateBox.MaxZ = 1;
MG_Util::Debug::LogD("TexSubImage2D: Got GL_UNPACK_ROW_LENGTH = %d", rowLength);
MG_Util::Debug::LogD("TexSubImage2D: Updating region [%d,%d]-[%d,%d] at level %d, %d bytes",
xoffset, yoffset, xoffset+width, yoffset+height, level, width * height * GetBytesPerPixel(format, type));
// if (MG_Diligent::IsInRenderPass) {
// MG_Diligent::g_pContext->EndRenderPass();
// MG_Diligent::IsInRenderPass = false;
// }
MG_Diligent::g_pContext->UpdateTexture(
pTexture,
level,
0,
UpdateBox,
SubResData,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
MG_Util::Debug::LogD("TexSubImage2D: Update completed successfully");
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params) {
MG_Util::Debug::LogD("glGetTexLevelParameteriv, target: %d, level: %d, pname: %d, params: %p",
target, level, pname, params);
@@ -689,10 +90,4 @@ namespace MG_GL::GL {
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
MG_Util::Debug::LogD("glCopyTexSubImage2D, target: %d, level: %d, xoffset: %d, yoffset: %d, x: %d, y: %d, width: %d, height: %d",
target, level, xoffset, yoffset, x, y, width, height);
}
}
}
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GL_TEXTURE_H
#define MOBILEGL_GL_TEXTURE_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
void ActiveTexture(GLenum texture);
void BindTexture(GLenum target, GLuint texture);
@@ -15,7 +17,6 @@ namespace MG_GL::GL {
void TexParameteri(GLenum target, GLenum pname, GLint param);
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
}
#endif //MOBILEGL_GL_TEXTURE_H
@@ -2,15 +2,13 @@
// Created by BZLZHH on 2025/3/15.
//
#include "../../../../Includes.h"
#include "GL_VertexArray.h"
namespace MG_GL::GL {
void GenVertexArrays(GLsizei n, GLuint* arrays) {
MG_Util::Debug::LogD("glGenVertexArrays, n: %d, arrays: %p", n, arrays);
GLenum result = MG_State::GenVertexArraysNames(n, arrays);
if (result == GL_NO_ERROR) {
return;
}
if (result == GL_NO_ERROR) return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GL_VERTEXARRAY_H
#define MOBILEGL_GL_VERTEXARRAY_H
#include "../../../../Includes.h"
namespace MG_GL::GL {
void GenVertexArrays(GLsizei n, GLuint* arrays);
void BindVertexArray(GLuint array);
@@ -2,7 +2,7 @@
// Created by Swung 0x48 on 2025/6/20.
//
#include "../../../../Includes.h"
#include "GLXFuncsDefinitions.h"
MG_EXPORT void* glXGetProcAddress(const char *name) {
return MG_GL::GLX::GetProcAddress(name);
@@ -5,4 +5,6 @@
#ifndef MOBILEGL_GLX_FUNCS_DEFINITIONS_H
#define MOBILEGL_GLX_FUNCS_DEFINITIONS_H
#include "../../../../Includes.h"
#endif //MOBILEGL_GLX_FUNCS_DEFINITIONS_H
+55 -72
View File
@@ -4,33 +4,38 @@
// TODO: Add more gl error check for buffer state manager.
#include "../../../Includes.h"
#include "BufferState.h"
//GLenum BufferState::GenName(GLuint *buffer) {
// MG_Util::Debug::LogD("MG_State: Buffer: GenName");
// if (!buffer)
// return GL_INVALID_VALUE;
//
// GLuint id = 0;
// if (freeId_.empty()) {
// id = lastId_++;
// } else {
// id = freeId_.back();
// freeId_.pop_back();
// }
//
// *buffer = id;
// MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id);
//
// return GL_NO_ERROR;
//}
GLenum BufferState::GenName(GLuint *buffer) {
MG_Util::Debug::LogD("MG_State: Buffer: GenName");
if (!buffer)
return GL_INVALID_VALUE;
GLuint id = 0;
if (freeId_.empty()) {
id = lastId_++;
} else {
id = freeId_.back();
freeId_.pop_back();
}
*buffer = id;
MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id);
return GL_NO_ERROR;
}
GLenum BufferState::GenNameN(GLsizei n, GLuint* buffers) {
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN called with n=%d", n);
if (n < 0 || buffers == nullptr) return GL_INVALID_VALUE;
indexGenerator_.Generate(n, buffers);
if (n < 0) return GL_INVALID_VALUE;
for (GLsizei i = 0; i < n; ++i) {
GLenum result = GenName(&buffers[i]);
if (result != GL_NO_ERROR) {
MG_Util::Debug::LogE("MG_State: Buffer: GenNameN failed with error 0x%x", result);
return result;
}
}
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN created buffers successfully");
return GL_NO_ERROR;
}
@@ -43,14 +48,7 @@ GLenum BufferState::Create(GLuint buffer) {
if (ValidateAllocatedHandle(buffer))
return GL_INVALID_VALUE;
if (bufferObjects_.size() <= buffer) {
bufferObjects_.resize(buffer + 1);
}
if (bufferObjects_[buffer] == nullptr) {
bufferObjects_[buffer] = std::make_unique<BufferObject>();
}
BufferObject& obj = *GetBufferObject(buffer);
BufferObject& obj = buffers_[buffer];
MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", buffer);
obj.generated = true;
obj.dirty = true;
@@ -73,12 +71,9 @@ GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* da
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = *GetBufferObject(it->second);
BufferObject& obj = buffers_[it->second];
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target);
obj.usage = usage;
obj.isDynamic = (usage == GL_DYNAMIC_DRAW || usage == GL_DYNAMIC_READ ||
usage == GL_DYNAMIC_COPY || usage == GL_STREAM_DRAW);
obj.data.reserve(std::bit_ceil((size_t)size));
obj.data.resize(size);
if (data) {
memcpy(obj.data.data(), data, size);
@@ -99,7 +94,7 @@ GLenum BufferState::CommitStorageRegion(GLenum target, GLintptr offset, GLsizeip
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = *GetBufferObject(it->second);
BufferObject& obj = buffers_[it->second];
MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData get buffer object %u at target 0x%x", it->second, target);
if (static_cast<size_t>(offset + size) > obj.data.size()) return GL_INVALID_VALUE;
@@ -128,7 +123,7 @@ GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLs
return GL_INVALID_OPERATION;
}
BufferObject& obj = *GetBufferObject(it->second);
BufferObject& obj = buffers_[it->second];
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second);
if (obj.isMapped) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second);
@@ -164,7 +159,7 @@ GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = *GetBufferObject(it->second);
BufferObject& obj = buffers_[it->second];
if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT))
return GL_INVALID_OPERATION;
@@ -188,8 +183,8 @@ GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLint
if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer)
return GL_INVALID_OPERATION;
BufferObject& src = *GetBufferObject(readBuffer);
BufferObject& dst = *GetBufferObject(writeBuffer);
BufferObject& src = buffers_[readBuffer];
BufferObject& dst = buffers_[writeBuffer];
if (static_cast<size_t>(readOffset + size) > src.data.size() ||
static_cast<size_t>(writeOffset + size) > dst.data.size())
@@ -209,7 +204,7 @@ GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** map
default:
flags = access;
}
return AcquireBufferMemoryRange(target, 0, GetBufferObject(currentBindings_[target])->data.size(), flags, mappedPointer);
return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), flags, mappedPointer);
}
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
@@ -220,7 +215,7 @@ GLenum BufferState::ReleaseBufferMemory(GLenum target) {
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = *GetBufferObject(it->second);
BufferObject& obj = buffers_[it->second];
if (!obj.isMapped)
return GL_INVALID_OPERATION;
@@ -237,28 +232,28 @@ GLenum BufferState::ReleaseBufferMemory(GLenum target) {
return GL_NO_ERROR;
}
bool BufferState::ValidateAllocatedHandle(GLuint buffer) const {
bool isValid = buffer != 0 && bufferObjects_.size() > buffer && bufferObjects_[buffer] != nullptr;
bool BufferState::ValidateAllocatedHandle(GLuint buffer) {
bool isValid = buffers_.find(buffer) != buffers_.end();
MG_Util::Debug::LogD("MG_State: Buffer: ValidateAllocatedHandle called on buffer %u returns %d", buffer, isValid);
return isValid;
}
bool BufferState::ValidateGeneratedName(GLuint buffer) const {
bool isValid = indexGenerator_.IsValid(buffer);
MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %s", buffer, isValid ? "true" : "false");
return isValid;
bool BufferState::ValidateGeneratedName(GLuint buffer) {
bool inFreeList = std::find(freeId_.begin(), freeId_.end(), buffer) != freeId_.end();
bool lessThanLast = buffer < lastId_; // lastId_ is not generated yet
MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %d", buffer, lessThanLast && !inFreeList);
return lessThanLast && !inFreeList;
}
void BufferState::Delete(GLuint buffer) {
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer);
if (bufferObjects_.size() > buffer)
bufferObjects_[buffer].reset();
indexGenerator_.Delete(buffer);
buffers_.erase(buffer);
if (ValidateGeneratedName(buffer))
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
//freeId_.emplace_back(buffer);
for (auto& [target, id] : currentBindings_) {
if (id == buffer) id = 0;
}
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u successfully", buffer);
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer);
}
GLenum BufferState::DeleteN(GLsizei n, const GLuint* buffers) {
@@ -273,9 +268,8 @@ GLenum BufferState::DeleteN(GLsizei n, const GLuint* buffers) {
}
bool BufferState::IsValidTarget_(GLenum target) {
bool ret = MG_Constants::Common::Contains(target, MG_Constants::Buffer::VALID_TARGETS);
MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, ret);
return ret;
MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end()));
return !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end());
}
GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const {
@@ -288,7 +282,7 @@ GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* p
return GL_INVALID_ENUM;
}
if (!MG_Constants::Common::Contains(pname, MG_Constants::Buffer::VALID_PARAM_NAMES)) {
if (MG_Constants::Buffer::VALID_PARAM_NAMES.find(pname) == MG_Constants::Buffer::VALID_PARAM_NAMES.end()) {
return GL_INVALID_ENUM;
}
@@ -297,12 +291,12 @@ GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* p
return GL_INVALID_OPERATION;
}
GLuint bufferId = bindingIt->second;
if (!ValidateAllocatedHandle(bufferId)) {
auto bufferIt = buffers_.find(bufferId);
if (bufferIt == buffers_.end()) {
return GL_INVALID_OPERATION;
}
const BufferObject& buffer = *bufferObjects_[bufferId];
const BufferObject& buffer = bufferIt->second;
switch (pname) {
case GL_BUFFER_ACCESS:
@@ -331,15 +325,4 @@ GLuint BufferState::GetCurrentBinding(GLenum target) const {
return it->second;
}
return 0;
}
BufferState::BufferObject* BufferState::GetBufferObject(GLuint buffer) {
if (bufferObjects_.size() <= buffer) {
return nullptr;
}
// if (bufferObjects_[buffer] == nullptr) {
// raise(SIGTRAP);
//// bufferObjects_[buffer] = std::make_unique<BufferObject>();
// }
return bufferObjects_[buffer].get();
}
}
+13 -12
View File
@@ -4,8 +4,14 @@
#ifndef MOBILEGL_BUFFERSTATE_H
#define MOBILEGL_BUFFERSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
class BufferState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
public:
struct BufferObject {
GLenum usage = GL_STATIC_DRAW;
@@ -14,7 +20,6 @@ public:
bool dirty = false; // TODO: encapsulate this with an public API to RHI
bool isMapped = false;
bool generated = false;
bool isDynamic = false;
GLenum accessMode = GL_READ_WRITE;
GLintptr mapOffset = 0;
GLsizeiptr mapLength = 0;
@@ -22,7 +27,7 @@ public:
};
// Return: the validity of the operation, according to OpenGL 3 standard
// GLenum GenName(GLuint* buffer);
GLenum GenName(GLuint* buffer);
GLenum GenNameN(GLsizei n, GLuint* buffers);
GLenum Create(GLuint buffer);
GLenum Bind(GLenum target, GLuint buffer);
@@ -36,20 +41,16 @@ public:
GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const;
GLenum DeleteN(GLsizei n, const GLuint* buffers);
bool ValidateAllocatedHandle(GLuint buffer) const;
bool ValidateGeneratedName(GLuint buffer) const;
bool ValidateAllocatedHandle(GLuint buffer);
bool ValidateGeneratedName(GLuint buffer);
void Delete(GLuint buffer);
GLuint GetCurrentBinding(GLenum target) const;
BufferObject* GetBufferObject(GLuint buffer);
MG_Global::unordered_map<GLenum, GLuint> currentBindings_;
// MG_Global::unordered_map<GLuint, BufferObject> buffers_;
unordered_map<GLenum, GLuint> currentBindings_;
unordered_map<GLuint, BufferObject> buffers_;
private:
// std::vector<GLuint> freeId_;
// GLuint lastId_ = 1;
IndexGenerator<GLuint> indexGenerator_;
std::vector<std::unique_ptr<BufferObject>> bufferObjects_;
std::vector<GLuint> freeId_;
GLuint lastId_ = 1;
static bool IsValidTarget_(GLenum target);
};
+11 -12
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/4/30.
//
#include "../../../Includes.h"
#include "CommonState.h"
CommonState::CommonState() {
pixelStoreParams[GL_PACK_ALIGNMENT] = 4;
@@ -10,7 +10,7 @@ CommonState::CommonState() {
}
GLenum CommonState::SetPixelStoreInt(GLenum pname, GLint param) {
if (!MG_Constants::Common::Contains(pname, MG_Constants::PixelStore::VALID_PARAM_NAMES)) {
if (MG_Constants::PixelStore::VALID_PARAM_NAMES.find(pname) == MG_Constants::PixelStore::VALID_PARAM_NAMES.end()) {
return GL_INVALID_ENUM;
}
@@ -61,7 +61,7 @@ GLint CommonState::QueryPixelStoreInt(GLenum pname) {
}
GLenum CommonState::Enable(GLenum cap) {
if (!MG_Constants::Common::Contains(cap, MG_Constants::CommonState::VALID_CAPS)) {
if (MG_Constants::CommonState::VALID_CAPS.find(cap) == MG_Constants::CommonState::VALID_CAPS.end()) {
return GL_INVALID_ENUM;
}
capabilities[cap] = true;
@@ -69,7 +69,7 @@ GLenum CommonState::Enable(GLenum cap) {
}
GLenum CommonState::Disable(GLenum cap) {
if (!MG_Constants::Common::Contains(cap, MG_Constants::CommonState::VALID_CAPS)) {
if (MG_Constants::CommonState::VALID_CAPS.find(cap) == MG_Constants::CommonState::VALID_CAPS.end()) {
return GL_INVALID_ENUM;
}
capabilities[cap] = false;
@@ -77,8 +77,8 @@ GLenum CommonState::Disable(GLenum cap) {
}
GLenum CommonState::BlendFunc(GLenum sfactor, GLenum dfactor) {
if (!MG_Constants::Common::Contains(sfactor, MG_Constants::Blend::VALID_FACTORS) ||
!MG_Constants::Common::Contains(dfactor, MG_Constants::Blend::VALID_FACTORS)) {
if (MG_Constants::Blend::VALID_FACTORS.find(sfactor) == MG_Constants::Blend::VALID_FACTORS.end() ||
MG_Constants::Blend::VALID_FACTORS.find(dfactor) == MG_Constants::Blend::VALID_FACTORS.end()) {
return GL_INVALID_ENUM;
}
@@ -89,10 +89,10 @@ GLenum CommonState::BlendFunc(GLenum sfactor, GLenum dfactor) {
GLenum CommonState::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum srcAlpha, GLenum dstAlpha) {
if (!MG_Constants::Common::Contains(srcRGB, MG_Constants::Blend::VALID_FACTORS) ||
!MG_Constants::Common::Contains(dstRGB, MG_Constants::Blend::VALID_FACTORS) ||
!MG_Constants::Common::Contains(srcAlpha, MG_Constants::Blend::VALID_FACTORS) ||
!MG_Constants::Common::Contains(dstAlpha, MG_Constants::Blend::VALID_FACTORS)) {
if (MG_Constants::Blend::VALID_FACTORS.find(srcRGB) == MG_Constants::Blend::VALID_FACTORS.end() ||
MG_Constants::Blend::VALID_FACTORS.find(dstRGB) == MG_Constants::Blend::VALID_FACTORS.end() ||
MG_Constants::Blend::VALID_FACTORS.find(srcAlpha) == MG_Constants::Blend::VALID_FACTORS.end() ||
MG_Constants::Blend::VALID_FACTORS.find(dstAlpha) == MG_Constants::Blend::VALID_FACTORS.end()) {
return GL_INVALID_ENUM;
}
blendSrcRGB = srcRGB;
@@ -133,11 +133,10 @@ GLenum CommonState::ColorMask(GLboolean red, GLboolean green, GLboolean blue, GL
}
GLenum CommonState::DepthFunc(GLenum func) {
if (!MG_Constants::Common::Contains(func, MG_Constants::Depth::VALID_FUNCS)) {
if (MG_Constants::Depth::VALID_FUNCS.find(func) == MG_Constants::Depth::VALID_FUNCS.end()) {
return GL_INVALID_ENUM;
}
depthFunc = func;
MG_Util::Debug::LogD("%s(%s)", __func__, MG_Util::Debug::GLEnumToString(func));
return GL_NO_ERROR;
}
+7 -2
View File
@@ -4,8 +4,13 @@
#ifndef MOBILEGL_COMMONSTATE_H
#define MOBILEGL_COMMONSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
class CommonState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
public:
// Viewport
GLint viewport[4] = {0, 0, 0, 0};
@@ -14,7 +19,7 @@ public:
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
// Pixel storage parameters
MG_Global::unordered_map<GLenum, GLint> pixelStoreParams;
unordered_map<GLenum, GLint> pixelStoreParams;
// Blend state
GLenum blendSrcRGB = GL_ONE;
@@ -32,7 +37,7 @@ public:
GLboolean depthMask = GL_TRUE;
// Capability enables
MG_Global::unordered_map<GLenum, bool> capabilities;
unordered_map<GLenum, bool> capabilities;
CommonState();
+5 -5
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/4/4.
//
#include "../../../Includes.h"
#include "GLState.h"
std::queue<GLenum> MG_State_T::glErrorQueue;
TextureState* MG_State_T::textureState = nullptr;
@@ -298,12 +298,12 @@ namespace MG_State {
return MG_State_T::programState->ActivateRenderProgram(program);
}
GLenum DefineProgramAttributeLocation(GLuint program, GLuint index, const GLchar* name) {
return MG_State_T::programState->DefineProgramAttributeLocation(program, index, name);
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name) {
return MG_State_T::programState->DefineProgramAttributeBinding(program, index, name);
}
GLint QueryProgramAttributeLocation(GLuint program, const GLchar* name) {
return MG_State_T::programState->QueryProgramAttributeLocation(program, name);
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name) {
return MG_State_T::programState->QueryProgramAttributeBinding(program, name);
}
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name) {
+4 -2
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GLSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
struct MG_State_T {
static std::queue<GLenum> glErrorQueue;
static TextureState* textureState;
@@ -93,8 +95,8 @@ namespace MG_State {
GLenum BuildShaderStage(GLuint shader);
GLenum FinalizeProgramPipeline(GLuint program);
GLenum ActivateRenderProgram(GLuint program);
GLenum DefineProgramAttributeLocation(GLuint program, GLuint index, const GLchar* name);
GLint QueryProgramAttributeLocation(GLuint program, const GLchar* name);
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name);
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name);
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name);
GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params);
GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params);
@@ -5,6 +5,10 @@
// TODO: Add more gl error check for framebuffer state manager.
// TODO: Check if the state machine really meets up to OpenGL 3 standard.
#include "FramebufferState.h"
// Re-Include Includes.h, cuz of the absence of GLState.h
#undef MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
GLenum FramebufferState::Create(GLuint* framebuffer) {
@@ -38,7 +42,7 @@ GLenum FramebufferState::Delete(GLuint framebuffer) {
}
GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
if (!MG_Constants::Common::Contains(target, MG_Constants::Framebuffer::VALID_TARGETS))
if (MG_Constants::Framebuffer::VALID_TARGETS.find(target) == MG_Constants::Framebuffer::VALID_TARGETS.end())
return GL_INVALID_ENUM;
if (framebuffer != 0 && !ValidateHandle(framebuffer))
return GL_INVALID_OPERATION;
@@ -53,28 +57,10 @@ GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level) {
if (!MG_Constants::Common::Contains(attachment, MG_Constants::Framebuffer::VALID_ATTACHMENTS) ||
!MG_Constants::Common::Contains(textarget, MG_Constants::Texture::VALID_TARGETS))
if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() ||
MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end())
return GL_INVALID_ENUM;
if (target == GL_FRAMEBUFFER) {
target = GL_DRAW_FRAMEBUFFER;
// if (currentBindings_[GL_READ_FRAMEBUFFER] == currentBindings_[GL_DRAW_FRAMEBUFFER]) {
// target = GL_DRAW_FRAMEBUFFER;
// } else {
// if (currentBindings_[GL_READ_FRAMEBUFFER] != 0) {
// GLenum err = AttachTexture2D(GL_READ_FRAMEBUFFER, attachment, textarget, texture, level);
// if (err != GL_NO_ERROR)
// return err;
// }
// if (currentBindings_[GL_DRAW_FRAMEBUFFER] != 0) {
// GLenum err = AttachTexture2D(GL_DRAW_FRAMEBUFFER, attachment, textarget, texture, level);
// if (err != GL_NO_ERROR)
// return err;
// }
// return GL_NO_ERROR;
// }
}
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
FramebufferObject* fbo = GetCurrentFBO(target);
if (!fbo) return GL_INVALID_OPERATION;
if (texture != 0 && !MG_State_T::textureState->IsTexture(texture))
@@ -4,6 +4,9 @@
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
#define MOBILEGL_FRAMEBUFFERSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
struct FramebufferAttachment {
GLenum type = GL_NONE;
@@ -14,7 +17,7 @@ struct FramebufferAttachment {
struct FramebufferObject {
bool generated = false;
MG_Global::unordered_map<GLenum, FramebufferAttachment> attachments;
ankerl::unordered_map<GLenum, FramebufferAttachment> attachments;
GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
GLsizei width = 0;
GLsizei height = 0;
@@ -32,10 +35,10 @@ public:
GLenum ValidateCompleteness(GLenum target);
FramebufferObject* GetCurrentFBO(GLenum target);
MG_Global::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW
ankerl::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW
private:
MG_Global::unordered_map<GLuint, FramebufferObject> framebuffers_;
ankerl::unordered_map<GLuint, FramebufferObject> framebuffers_;
std::set<GLuint> freeIds_;
GLuint lastId_ = 0;
bool ValidateHandle(GLuint framebuffer);
+28 -51
View File
@@ -4,6 +4,11 @@
// TODO: Add more gl error check for buffer state manager.
// TODO: Check if the state machine really meets up to OpenGL 3 standard.
#include "ProgramState.h"
// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp.
#undef MOBILEGL_GLSLTOOL_H
#undef MOBILEGL_PROGRAM_DEBUGTOOL_H
#include "../../../Includes.h"
ProgramState::ProgramState() {
@@ -105,21 +110,7 @@ GLenum ProgramState::FinalizeProgramPipeline(GLuint program) {
std::vector<std::vector<unsigned>> allSpirv =
MG_Util::Program::CompileMultipleShadersToSPIRV(*this, prog, prog.infoLog);
if (!prog.infoLog.empty() || allSpirv.empty()) {
prog.linked = UncertainBool::False;
prog.linkStatus = GL_FALSE;
prog.infoLog = "Program linking failed during SPIR-V compilation: " + prog.infoLog;
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str());
return GL_INVALID_OPERATION;
}
MG_Util::Program::ReflectSPIRVUniforms(allSpirv, prog, prog.infoLog);
for (size_t i = 0; i < prog.attachedShaders.size(); ++i) {
GLuint shaderId = prog.attachedShaders[i];
shaders_[shaderId].source = MG_Util::Program::CompileSPIRVToGLSL(allSpirv[i], 450, false, false);
}
if (!prog.infoLog.empty()) {
prog.linked = UncertainBool::False;
prog.linkStatus = GL_FALSE;
@@ -127,8 +118,10 @@ GLenum ProgramState::FinalizeProgramPipeline(GLuint program) {
MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str());
return GL_INVALID_OPERATION;
}
// TODO: Support explicitly assign attrib locations in the shaders.
for (auto& [name, index] : prog.attribBindings) {
prog.attribLocations[name] = index;
}
prog.linked = {UncertainBool::Unknown, UncertainBool::True};
prog.linkStatus = GL_TRUE;
@@ -154,28 +147,28 @@ GLenum ProgramState::ActivateRenderProgram(GLuint program) {
return GL_NO_ERROR;
}
GLenum ProgramState::DefineProgramAttributeLocation(GLuint program, GLuint index, const GLchar* name) {
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeLocation called, program=%u, index=%u, name=%s",
GLenum ProgramState::DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name) {
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding called, program=%u, index=%u, name=%s",
program, index, name);
if (!ValidateProgram_(program)) {
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeLocation error: invalid program id %u", program);
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: invalid program id %u", program);
return GL_INVALID_VALUE;
}
if (index >= GL_MAX_VERTEX_ATTRIBS) {
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeLocation error: index %u out of range", index);
MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: index %u out of range", index);
return GL_INVALID_VALUE;
}
programs_[program].attribLocations[name] = index;
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeLocation success: %s -> %u", name, index);
programs_[program].attribBindings[name] = index;
MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding success: %s -> %u", name, index);
return GL_NO_ERROR;
}
GLint ProgramState::QueryProgramAttributeLocation(GLuint program, const GLchar* name) {
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeLocation called, program=%u, name=%s",
GLint ProgramState::QueryProgramAttributeBinding(GLuint program, const GLchar* name) {
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding called, program=%u, name=%s",
program, name);
if (!ValidateProgram_(program)) {
MG_Util::Debug::LogE("MG_State: Program: QueryProgramAttributeLocation error: invalid program id %u", program);
MG_Util::Debug::LogE("MG_State: Program: QueryProgramAttributeBinding error: invalid program id %u", program);
return -1;
}
@@ -183,27 +176,11 @@ GLint ProgramState::QueryProgramAttributeLocation(GLuint program, const GLchar*
auto it = prog.attribLocations.find(name);
if (it != prog.attribLocations.end()) {
GLint loc = it->second;
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeLocation success: %s -> %d", name, loc);
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding success: %s -> %d", name, loc);
return loc;
} else {
MG_Util::Debug::LogW("MG_State: Program: QueryProgramAttributeLocation warning: name '%s' not found, generating new one...", name);
// Find the next available location
GLint loc = (GLint)prog.attribLocations.size();
bool locInUse;
do {
locInUse = false;
for (const auto& pair : prog.attribLocations) {
if (pair.second == loc) {
locInUse = true;
loc++;
break;
}
}
} while (locInUse);
prog.attribLocations[name] = loc;
MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeLocation success: %s -> %d", name, loc);
return prog.attribLocations[name];
}
MG_Util::Debug::LogW("MG_State: Program: QueryProgramAttributeBinding warning: name '%s' not found", name);
return -1;
}
GLenum ProgramState::QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params) {
@@ -431,26 +408,26 @@ GLuint ProgramState::GetCurrentProgram() const {
return currentProgram_;
}
const ShaderObject* ProgramState::GetShaderObject(GLuint shader) const {
ShaderObject ProgramState::GetShaderObject(GLuint shader) const {
MG_Util::Debug::LogD("MG_State: Program: GetShaderObject called, shader=%u", shader);
auto it = shaders_.find(shader);
if (it == shaders_.end()) {
MG_Util::Debug::LogW("MG_State: Program: GetShaderObject warning: invalid shader id %u", shader);
return nullptr;
return ShaderObject();
}
MG_Util::Debug::LogD("MG_State: Program: GetShaderObject success, returning object");
return &(it->second);
return it->second;
}
const ProgramObject* ProgramState::GetProgramObject(GLuint program) const {
ProgramObject ProgramState::GetProgramObject(GLuint program) const {
MG_Util::Debug::LogD("MG_State: Program: GetProgramObject called, program=%u", program);
auto it = programs_.find(program);
if (it == programs_.end()) {
MG_Util::Debug::LogW("MG_State: Program: GetProgramObject warning: invalid program id %u", program);
return nullptr;
return ProgramObject();
}
MG_Util::Debug::LogD("MG_State: Program: GetProgramObject success, returning object");
return &(it->second);
return it->second;
}
bool ProgramState::ValidateProgram_(GLuint program) {
@@ -474,7 +451,7 @@ void ProgramState::CleanupShaders_() {
}
if (!inUse) {
MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ deleting shader %u", it->first);
// freeShaderIds_.insert(it->first);
freeShaderIds_.insert(it->first);
it = shaders_.erase(it);
continue;
}
+15 -9
View File
@@ -4,6 +4,11 @@
#ifndef MOBILEGL_PROGRAMSTATE_H
#define MOBILEGL_PROGRAMSTATE_H
#define MOBILEGL_GLSTATE_H
#define MOBILEGL_PROGRAM_DEBUGTOOL_H
#define MOBILEGL_GLSLTOOL_H
#include "../../../Includes.h"
struct ShaderObject {
GLenum type;
@@ -36,16 +41,17 @@ struct ProgramObject {
bool dirty;
GLint linkStatus;
std::string infoLog;
MG_Global::unordered_map<std::string, GLint> attribLocations;
MG_Global::unordered_map<std::string, GLint> uniformLocations;
MG_Global::unordered_map<std::string, UniformValue> uniformValues;
ankerl::unordered_map<std::string, GLint> attribBindings;
ankerl::unordered_map<std::string, GLint> attribLocations;
ankerl::unordered_map<std::string, GLint> uniformLocations;
ankerl::unordered_map<std::string, UniformValue> uniformValues;
bool markedForDeletion;
};
class ProgramState {
public:
MG_Global::unordered_map<GLuint, ShaderObject> shaders_;
MG_Global::unordered_map<GLuint, ProgramObject> programs_;
ankerl::unordered_map<GLuint, ShaderObject> shaders_;
ankerl::unordered_map<GLuint, ProgramObject> programs_;
std::set<GLuint> freeShaderIds_;
std::set<GLuint> freeProgramIds_;
GLuint lastShaderId_ = 0;
@@ -65,8 +71,8 @@ public:
GLenum BuildShaderStage(GLuint shader);
GLenum FinalizeProgramPipeline(GLuint program);
GLenum ActivateRenderProgram(GLuint program);
GLenum DefineProgramAttributeLocation(GLuint program, GLuint index, const GLchar* name);
GLint QueryProgramAttributeLocation(GLuint program, const GLchar* name);
GLenum DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name);
GLint QueryProgramAttributeBinding(GLuint program, const GLchar* name);
GLint QueryProgramUniformLocation(GLuint program, const GLchar* name);
GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params);
GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params);
@@ -104,8 +110,8 @@ public:
DECLARE_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3)
#undef DECLARE_MATRIX_FUNCTIONS
const ProgramObject* GetProgramObject(GLuint program) const;
const ShaderObject* GetShaderObject(GLuint program) const;
ProgramObject GetProgramObject(GLuint program) const;
ShaderObject GetShaderObject(GLuint program) const;
GLuint GetCurrentProgram() const;
bool SetProgramStatus(GLuint program, GLboolean status);
bool SetShaderStatus(GLuint shader, GLboolean status);
+9
View File
@@ -2,6 +2,11 @@
// Created by BZLZHH on 2025/5/3.
//
#include "ShaderObject.h"
// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp.
#undef MOBILEGL_GLSLTOOL_H
#undef MOBILEGL_PROGRAM_DEBUGTOOL_H
#include "../../../Includes.h"
GLenum ProgramState::CreateShader(GLenum type, GLuint* shader) {
@@ -37,6 +42,10 @@ GLenum ProgramState::DeleteShader(GLuint shader) {
MG_Util::Debug::LogE("MG_State: Program: DeleteShader error: invalid shader id %u", shader);
return GL_INVALID_VALUE;
}
if (shaders_[shader].markedForDeletion) {
MG_Util::Debug::LogW("MG_State: Program: DeleteShader warning: shader %u already marked for deletion", shader);
return GL_NO_ERROR;
}
bool inUse = false;
for (auto& [progId, program] : programs_) {
+4
View File
@@ -5,4 +5,8 @@
#ifndef MOBILEGL_SHADEROBJECT_H
#define MOBILEGL_SHADEROBJECT_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
#endif //MOBILEGL_SHADEROBJECT_H
+20 -15
View File
@@ -2,6 +2,10 @@
// Created by BZLZHH on 2025/4/4.
//
#include "TextureState.h"
// Re-Include Includes.h, cuz of the absence of GLState.h
#undef MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
// TextureObject
@@ -117,7 +121,7 @@ GLenum TextureState::CreateN(GLsizei n, GLuint* textures) {
GLenum TextureState::Bind(GLenum target, GLuint texture) {
MG_Util::Debug::LogD("MG_State: Texture: Bind called with target=0x%x, texture=%u", target, texture);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: Bind invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
@@ -142,6 +146,7 @@ GLenum TextureState::Bind(GLenum target, GLuint texture) {
}
}
TextureUnitState& unit = textureUnits_[activeTextureUnit_];
TextureObject* texObj = nullptr;
auto it = this->textures.find(texture);
@@ -493,12 +498,12 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset,
GLenum TextureState::SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param) {
MG_Util::Debug::LogD("MG_State: Texture: SetTexturePropertyFloat called target=0x%x, pname=0x%x, param=%f", target, pname, param);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyFloat invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
if (!MG_Constants::Common::Contains(pname, MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES)) {
if (MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES.find(pname) == MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyFloat invalid pname=0x%x", pname);
return GL_INVALID_ENUM;
}
@@ -545,12 +550,12 @@ GLenum TextureState::SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloa
GLenum TextureState::SetTexturePropertyInt(GLenum target, GLenum pname, GLint param) {
MG_Util::Debug::LogD("MG_State: Texture: SetTexturePropertyInt called target=0x%x, pname=0x%x, param=%d", target, pname, param);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyInt invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
if (!MG_Constants::Common::Contains(pname, MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES)) {
if (MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES.find(pname) == MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyInt invalid pname=0x%x", pname);
return GL_INVALID_ENUM;
}
@@ -641,7 +646,7 @@ GLenum TextureState::DeleteN(GLsizei n, const GLuint* textures) {
GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params) {
MG_Util::Debug::LogD("MG_State: Texture: QueryLevelPropertyIntVector called target=0x%x, level=%d, pname=0x%x", target, level, pname);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: QueryLevelPropertyIntVector invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
@@ -651,7 +656,7 @@ GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLe
return GL_INVALID_VALUE;
}
if (!MG_Constants::Common::Contains(pname, MG_Constants::Texture::VALID_TEXTURE_PARAM_NAMES)) {
if (MG_Constants::Texture::VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES.find(pname) == MG_Constants::Texture::VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: QueryLevelPropertyIntVector invalid pname=0x%x", pname);
return GL_INVALID_ENUM;
}
@@ -695,7 +700,7 @@ GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLe
return GL_NO_ERROR;
}
MG_Global::unordered_map<GLuint, TextureObject>::iterator texIt;
unordered_map<GLuint, TextureObject>::iterator texIt;
if (!isProxyTexture) {
texIt = textures.find(boundTexture);
@@ -801,7 +806,7 @@ GLenum TextureState::CheckUploadingTexture2DValidity_(GLenum target, GLint level
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, const void* data) {
MG_Util::Debug::LogD("MG_State: Texture: CheckUploadingTexture2DValidity_ called target=0x%x, level=%d", target, level);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
@@ -841,17 +846,17 @@ GLenum TextureState::CheckUploadingTexture2DValidity_(GLenum target, GLint level
return GL_INVALID_VALUE;
}
if (!MG_Constants::Common::Contains((GLenum)internalFormat, MG_Constants::Texture::VALID_INTERNAL_FORMATS)) {
if (MG_Constants::Texture::VALID_INTERNAL_FORMATS.find(internalFormat) == MG_Constants::Texture::VALID_INTERNAL_FORMATS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ invalid internalFormat=0x%x", internalFormat);
return GL_INVALID_VALUE;
}
if (!MG_Constants::Common::Contains((GLenum)format, MG_Constants::Texture::VALID_FORMATS)) {
if (MG_Constants::Texture::VALID_FORMATS.find(format) == MG_Constants::Texture::VALID_FORMATS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ invalid format=0x%x", format);
return GL_INVALID_ENUM;
}
if (!MG_Constants::Common::Contains((GLenum)type, MG_Constants::Texture::VALID_TYPES)) {
if (MG_Constants::Texture::VALID_TYPES.find(type) == MG_Constants::Texture::VALID_TYPES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ invalid type=0x%x", type);
return GL_INVALID_ENUM;
}
@@ -923,7 +928,7 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint
MG_Util::Debug::LogD("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ called target=0x%x, level=%d, x=%d, y=%d, w=%d, h=%d",
target, level, xoffset, yoffset, width, height);
if (!MG_Constants::Common::Contains(target, MG_Constants::Texture::VALID_TARGETS)) {
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
@@ -973,12 +978,12 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint
return GL_INVALID_OPERATION;
}
if (!MG_Constants::Common::Contains(format, MG_Constants::Texture::VALID_FORMATS)) {
if (MG_Constants::Texture::VALID_FORMATS.find(format) == MG_Constants::Texture::VALID_FORMATS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ invalid format=0x%x", format);
return GL_INVALID_ENUM;
}
if (!MG_Constants::Common::Contains(type, MG_Constants::Texture::VALID_TYPES)) {
if (MG_Constants::Texture::VALID_TYPES.find(type) == MG_Constants::Texture::VALID_TYPES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ invalid type=0x%x", type);
return GL_INVALID_ENUM;
}
+20 -11
View File
@@ -4,6 +4,9 @@
#ifndef MOBILEGL_TEXTURESTATE_H
#define MOBILEGL_TEXTURESTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
struct ComponentSizes {
GLint red = 0;
@@ -16,8 +19,10 @@ struct ComponentSizes {
};
struct TextureParams {
MG_Global::unordered_map<GLenum, GLfloat> texPropertiesFloat;
MG_Global::unordered_map<GLenum, GLint> texPropertiesInt;
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
unordered_map<GLenum, GLfloat> texPropertiesFloat;
unordered_map<GLenum, GLint> texPropertiesInt;
struct MipmapLevel {
GLsizei width = 0;
GLsizei height = 0;
@@ -28,7 +33,7 @@ struct TextureParams {
bool hasData = false;
bool dirty = false; // TODO: encapsulate this with an public API to RHI
};
MG_Global::unordered_map<GLint, MipmapLevel> mipmapData;
unordered_map<GLint, MipmapLevel> mipmapData;
};
class TextureObject {
@@ -42,31 +47,35 @@ public:
};
class TextureUnitState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
private:
GLenum activeTarget = GL_TEXTURE_2D;
public:
unordered_map<GLenum, GLuint> boundTextures;
void Bind(GLenum target, GLuint texture);
GLuint GetBoundTexture(GLenum target);
GLenum activeTarget = GL_TEXTURE_2D;
MG_Global::unordered_map<GLenum, GLuint> boundTextures;
};
class TextureState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
private:
GLuint lastUsedID_ = 1;
// MG_Global::unordered_set<GLuint> freeIDs_;
// ankerl::unordered_set<GLuint> freeIDs_;
std::vector<GLuint> freeID_;
MG_Global::unordered_map<GLenum, TextureObject> proxyTextures_;
unordered_map<GLenum, TextureObject> proxyTextures_;
static GLint GetUnpackParam_(GLenum pname);
public:
TextureState();
bool IsTextureGenerated(GLuint texture);
bool IsTexture(GLuint texture);
MG_Global::unordered_map<GLuint, TextureObject> textures;
unordered_map<GLuint, TextureObject> textures;
// Return: the validity of the operation, according to OpenGL 3 standard
GLenum BindUnit(GLenum textureUnit);
@@ -4,7 +4,7 @@
// TODO: Add more gl error check for vertex array state manager.
#include "../../../Includes.h"
#include "VertexArrayState.h"
VertexArrayState::VertexArrayState() {
vaos_[0];
@@ -107,7 +107,7 @@ bool VertexArrayState::ValidateAllocatedHandle(GLuint array) {
GLenum VertexArrayState::EnableAttrib(GLuint index) {
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
GetCurrentVAO()->attribs[index].enabled = true;
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
@@ -118,7 +118,7 @@ GLenum VertexArrayState::EnableAttrib(GLuint index) {
GLenum VertexArrayState::DisableAttrib(GLuint index) {
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
GetCurrentVAO()->attribs[index].enabled = false;
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
@@ -132,7 +132,7 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
GLuint currentArrayBuffer) {
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
VertexAttribState state;
state.size = size;
@@ -142,7 +142,8 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
state.pointer = pointer;
state.buffer = currentArrayBuffer;
state.isInteger = isInteger;
state.enabled = vaos_[currentVao_].attribs[index].enabled;
if (vaos_[currentVao_].attribs.count(index) && vaos_[currentVao_].attribs[index].enabled)
state.enabled = true;
vaos_[currentVao_].attribs[index] = state;
@@ -4,9 +4,12 @@
#ifndef MOBILEGL_VERTEXARRAYSTATE_H
#define MOBILEGL_VERTEXARRAYSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
struct VertexAttribState {
bool enabled = false;
bool enabled;
GLint size = 4;
GLenum type = GL_FLOAT;
GLboolean normalized = GL_FALSE;
@@ -21,7 +24,7 @@ struct VertexArrayObject {
bool attribDirty = false;
bool eboDirty = false;
GLuint elementBuffer = 0;
std::array<VertexAttribState, MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS> attribs;
ankerl::unordered_map<GLuint, VertexAttribState> attribs;
};
class VertexArrayState {
@@ -47,7 +50,7 @@ public:
bool ValidateAllocatedHandle(GLuint array);
GLuint currentVao_ = 0;
MG_Global::unordered_map<GLuint, VertexArrayObject> vaos_;
ankerl::unordered_map<GLuint, VertexArrayObject> vaos_;
private:
std::set<GLuint> freeIds_;
GLuint lastId_ = 0;
-73
View File
@@ -1,73 +0,0 @@
//
// Created by yello on 2025-06-27.
//
#ifndef INDEXGENERATOR_H
#define INDEXGENERATOR_H
#include <vector>
#include <cstddef> // For size_t
#include <algorithm> // For std::min
#include <memory>
template <typename IndexType>
class IndexGenerator {
public:
// 构造函数
IndexGenerator() : next_index_(1) {}
explicit IndexGenerator(IndexType n) : next_index_(1) {
is_valid_.reserve(n);
}
// 生成n个新正整数
void Generate(size_t n, IndexType *indices) {
if (n <= 0) {
return;
}
// 优先给出被删除的索引
size_t count_from_freed = std::min(n, freed_indices_.size());
for (size_t i = 0; i < count_from_freed; ++i) {
indices[i] = freed_indices_.back();
freed_indices_.pop_back();
// 标记为有效,确保is_valid_的大小足够
if (indices[i] >= is_valid_.size()) {
is_valid_.resize(static_cast<size_t>(indices[i]) + 1, false); // 0代表无效,1代表有效
}
is_valid_[indices[i]] = true; // 标记为有效
}
// 如果还需要更多的索引,则生成新的索引
for (size_t i = count_from_freed; i < n; ++i) {
indices[i] = next_index_++;
// 确保is_valid_的大小足够
if (indices[i] >= is_valid_.size()) {
is_valid_.resize(static_cast<size_t>(indices[i]) + 1, false);
}
is_valid_[indices[i]] = true; // 标记为有效
}
}
// 删除一个已经给出的正整数
void Delete(IndexType index) {
// 检查索引是否有效且未被删除
// 这里的检查是为了避免重复删除或删除未生成的索引
if (index < is_valid_.size() && is_valid_[index] == true) {
is_valid_[index] = false; // 标记为无效
freed_indices_.push_back(index); // 添加到已删除列表中
}
}
// 检查一个正整数是否之前已经被给出,并且没有被删除
bool IsValid(IndexType index) const {
// 如果索引超出is_valid_的范围,或者对应的位置是0,则认为无效
return index < is_valid_.size() && is_valid_[index] == true;
}
private:
IndexType next_index_; // 下一个将要生成的正整数
std::vector<IndexType> freed_indices_; // 存储被删除的索引
std::vector<bool> is_valid_; // 标记索引是否有效。0代表无效,1代表有效。
};
#endif //INDEXGENERATOR_H
+3 -9
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/4/26.
//
#include "../../../Includes.h"
#include "TestDrawing.h"
namespace MG_RHI::GLES::Test {
constexpr int DISPLAY_COLUMNS = 8;
@@ -14,7 +14,6 @@ namespace MG_RHI::GLES::Test {
}
bool CheckShaderCompileStatus(GLuint shader, const char* type) {
#if BACKEND_TYPE == BACKEND_GLES
GLint success;
::GLES::glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
@@ -23,12 +22,10 @@ namespace MG_RHI::GLES::Test {
MG_Util::Debug::LogE("Shader compilation error (%s): %s", type, infoLog);
return false;
}
#endif
return true;
}
bool CheckProgramLinkStatus(GLuint program) {
#if BACKEND_TYPE == BACKEND_GLES
GLint success;
::GLES::glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
@@ -37,13 +34,11 @@ namespace MG_RHI::GLES::Test {
MG_Util::Debug::LogE("Program link error: %s", infoLog);
return false;
}
#endif
return true;
}
// TODO: Use the textures state from MG_RHI(another state?) rather than directly from MG_State
void DrawAllTextures() {
#if BACKEND_TYPE == BACKEND_GLES
::GLES::glClearColor(1,1,1,1);
::GLES::glClear(GL_COLOR_BUFFER_BIT);
@@ -53,8 +48,8 @@ namespace MG_RHI::GLES::Test {
GLuint quadVBO = 0;
GLint uTexLoc = -1;
GLint uMVPLoc = -1;
MG_Global::unordered_map<GLuint, GLuint> textureCache;
MG_Global::unordered_map<GLuint, bool> textureDirty;
ankerl::unordered_map<GLuint, GLuint> textureCache;
ankerl::unordered_map<GLuint, bool> textureDirty;
};
static ScreenResources sRes;
@@ -235,6 +230,5 @@ namespace MG_RHI::GLES::Test {
::GLES::glUseProgram(origProgram);
::GLES::glViewport(origViewport[0], origViewport[1],
origViewport[2], origViewport[3]);
#endif
}
}
+2
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_TESTDRAWING_H
#define MOBILEGL_TESTDRAWING_H
#include "../../../Includes.h"
namespace MG_RHI::GLES::Test {
void DrawAllTextures();
}
+1039 -1798
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_DEBUG_H
#define MOBILEGL_DEBUG_H
#include "../../Includes.h"
#define FORCE_SYNC_WITH_LOG_FILE 0
namespace MG_Util {
@@ -21,7 +23,6 @@ namespace MG_Util {
void LogWrite(const char* format, va_list args);
const char* GLEnumToString(::GLenum value);
const char* DiligentBlendFactorToString(Diligent::BLEND_FACTOR value);
}
}
+8 -7
View File
@@ -2,7 +2,7 @@
// Created by BZLZHH on 2025/5/3.
//
#include "../../Includes.h"
#include "DebugTool.h"
namespace MG_Util::Program {
std::string GLTypeToString(GLenum type) {
@@ -54,7 +54,7 @@ namespace MG_Util::Program {
std::ostringstream ss;
ss << "[";
const size_t elemCount = std::min<size_t>(value.numElements, 16);
const size_t elemCount = std::min<size_t>(value.count, 16);
switch(value.type) {
case GL_FLOAT:
@@ -116,17 +116,17 @@ namespace MG_Util::Program {
}
void DumpUniforms(const ProgramState& state, GLuint program) {
if constexpr (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
return;
auto* prog = state.GetProgramObject(program);
if (!prog->linked.toBool()) {
auto prog = (ProgramObject)state.GetProgramObject(program);
if (!prog.linked.toBool()) {
MG_Util::Debug::LogE("Program %u not linked", program);
return;
}
MG_Util::Debug::LogD("=== Dumping uniforms for program %u ===", program);
for(const auto& [name, loc] : prog->uniformLocations) {
const auto& value = prog->uniformValues.at(name);
for(const auto& [name, loc] : prog.uniformLocations) {
const auto& value = prog.uniformValues.at(name);
MG_Util::Debug::LogD("Uniform: %-24s Location: %-4d Type: %-16s Count: %-3d Value: %s",
name.c_str(),
loc,
@@ -142,6 +142,7 @@ namespace MG_Util::Program {
GLuint current = state.GetCurrentProgram();
if (current == 0) {
MG_Util::Debug::LogE("No active program");
return;
}
DumpUniforms(state, current);
+1
View File
@@ -4,6 +4,7 @@
#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H
#define MOBILEGL_PROGRAM_DEBUGTOOL_H
#include "../../Includes.h"
namespace MG_Util::Program {
std::string GLTypeToString(GLenum type);
+25 -749
View File
@@ -2,666 +2,10 @@
// Created by BZLZHH on 2025/5/3.
//
#include "../../Includes.h"
#include "GLSLTool.h"
namespace MG_Util::Program {
void RenameGLSLBuiltinsForVulkan(std::string &src) {
// static const std::vector<std::pair<std::regex, std::string>> rules = {
// { std::regex(R"(gl_VertexID)"), "gl_VertexIndex" },
// { std::regex(R"(gl_InstanceID)"), "gl_InstanceIndex" }
// };
//
// for (auto &rule : rules) {
// src = std::regex_replace(src, rule.first, rule.second);
// }
size_t pos = src.find("gl_VertexID");
if (pos != std::string::npos) {
src.replace(pos, strlen("gl_VertexID"), "gl_VertexIndex");
}
pos = src.find("gl_InstanceID");
if (pos != std::string::npos) {
src.replace(pos, strlen("gl_InstanceID"), "gl_InstanceIndex");
}
}
std::string BindInputLayoutLocationsForGLSL(
std::vector<uint32_t>& spirv,
MG_Global::unordered_map<std::string, GLint>& name_location_map)
{
spvc_context context = nullptr;
spvc_parsed_ir ir = nullptr;
spvc_compiler compiler = nullptr;
spvc_resources resources = nullptr;
spvc_result result = SPVC_SUCCESS;
const char* glsl_source = nullptr;
std::string output_glsl;
if ((result = spvc_context_create(&context)) != SPVC_SUCCESS)
{
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to create context.");
return {};
}
if ((result = spvc_context_parse_spirv(context,
spirv.data(),
spirv.size(),
&ir)) != SPVC_SUCCESS)
{
spvc_context_destroy(context);
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to parse SPIR-V.");
return {};
}
if ((result = spvc_context_create_compiler(
context,
SPVC_BACKEND_GLSL,
ir,
SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
&compiler)) != SPVC_SUCCESS)
{
spvc_context_destroy(context);
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to create compiler.");
return {};
}
if ((result = spvc_compiler_create_shader_resources(compiler, &resources)) != SPVC_SUCCESS)
{
spvc_context_destroy(context);
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to create shader resources.");
return {};
}
const spvc_reflected_resource* inputs = nullptr;
size_t num_inputs = 0;
if ((result = spvc_resources_get_resource_list_for_type(
resources,
SPVC_RESOURCE_TYPE_STAGE_INPUT,
&inputs,
&num_inputs)) != SPVC_SUCCESS)
{
spvc_context_destroy(context);
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to get stage inputs.");
return {};
}
std::unordered_map<std::string, spvc_variable_id> name_to_id;
for (size_t i = 0; i < num_inputs; ++i)
{
name_to_id[inputs[i].name] = inputs[i].id;
}
std::unordered_set<GLint> used_locations;
for (auto& kv : name_location_map)
{
const auto& name = kv.first;
GLint loc = kv.second;
auto it = name_to_id.find(name);
if (it == name_to_id.end())
{
MG_Util::Debug::LogW("[SPIRV-Cross] Input name not found: %s", name.c_str());
continue;
}
spvc_compiler_set_decoration(
compiler,
it->second,
SpvDecorationLocation,
loc);
used_locations.insert(loc);
}
GLint next_free_loc = 0;
for (size_t i = 0; i < num_inputs; ++i)
{
auto& res = inputs[i];
const auto& name = res.name;
auto var_id = res.id;
if (name_location_map.find(name) != name_location_map.end())
continue;
uint32_t curr_loc = 0;
bool has_loc = false;
curr_loc = spvc_compiler_get_decoration(compiler, var_id, SpvDecorationLocation);
if (spvc_compiler_has_decoration(compiler, var_id, SpvDecorationLocation))
has_loc = true;
if (has_loc && !used_locations.contains(curr_loc))
{
used_locations.insert((GLint)curr_loc);
continue;
}
while (used_locations.count(next_free_loc))
++next_free_loc;
spvc_compiler_set_decoration(
compiler,
var_id,
SpvDecorationLocation,
next_free_loc);
MG_Util::Debug::LogI("[SPIRV-Cross] Auto assigned '%s' to location %d", name, next_free_loc);
used_locations.insert(next_free_loc);
}
spvc_compiler_options options = nullptr;
spvc_compiler_create_compiler_options(compiler, &options);
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 450);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_FLIP_VERTEX_Y, SPVC_TRUE);
spvc_compiler_install_compiler_options(compiler, options);
if ((result = spvc_compiler_compile(compiler, &glsl_source)) != SPVC_SUCCESS)
{
MG_Util::Debug::LogE("[SPIRV-Cross] Failed to compile: %s",
spvc_context_get_last_error_string(context));
spvc_context_destroy(context);
return {};
}
output_glsl = glsl_source;
spvc_context_destroy(context);
MG_Util::Debug::LogI("[SPIRV-Cross] GLSL output:\n%s", output_glsl.c_str());
size_t pos = output_glsl.find("\n gl_Position.y = -gl_Position.y;\n}");
if (pos != std::string::npos)
{
output_glsl.replace(
pos,
strlen("\n gl_Position.y = -gl_Position.y;\n}"),
"\n gl_Position.y = -gl_Position.y;\n gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n}");
}
return output_glsl;
}
static std::vector<bool> buildCommentMask(const std::string &src) {
enum State {
NORMAL,
LINE_COMMENT,
BLOCK_COMMENT,
STRING_LITERAL,
CHAR_LITERAL
};
std::vector<bool> isComment(src.size(), false);
State state = NORMAL;
for (size_t i = 0; i < src.size(); ++i) {
switch (state) {
case NORMAL:
if (i + 1 < src.size() && src[i] == '/' && src[i + 1] == '/') {
state = LINE_COMMENT;
isComment[i] = true;
isComment[i + 1] = true;
++i;
}
else if (i + 1 < src.size() && src[i] == '/' && src[i + 1] == '*') {
state = BLOCK_COMMENT;
isComment[i] = true;
isComment[i + 1] = true;
++i;
}
else if (src[i] == '"') {
state = STRING_LITERAL;
}
else if (src[i] == '\'') {
state = CHAR_LITERAL;
}
break;
case LINE_COMMENT:
isComment[i] = true;
if (src[i] == '\n') {
state = NORMAL;
}
break;
case BLOCK_COMMENT:
isComment[i] = true;
if (i + 1 < src.size() && src[i] == '*' && src[i + 1] == '/') {
isComment[i + 1] = true;
state = NORMAL;
++i;
}
break;
case STRING_LITERAL:
if (src[i] == '\\' && (i + 1 < src.size())) {
i++;
}
else if (src[i] == '"') {
state = NORMAL;
}
break;
case CHAR_LITERAL:
if (src[i] == '\\' && (i + 1 < src.size())) {
i++;
}
else if (src[i] == '\'') {
state = NORMAL;
}
break;
}
}
return isComment;
}
static bool isPreprocessorLine(const std::string &src, size_t pos) {
size_t lineStart = src.rfind('\n', pos);
if (lineStart == std::string::npos) {
lineStart = 0;
} else {
lineStart += 1;
}
size_t firstNonSpace = src.find_first_not_of(" \t\r\n", lineStart);
if (firstNonSpace != std::string::npos && src[firstNonSpace] == '#') {
return true;
}
return false;
}
static inline bool isInComment(const std::vector<bool> &mask, size_t pos) {
if (pos >= mask.size()) return false;
return mask[pos];
}
static inline void leftTrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
static inline void rightTrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
static inline void trim(std::string &s) {
leftTrim(s);
rightTrim(s);
}
static size_t findNextNonSpace(const std::string& str, size_t pos) {
return str.find_first_not_of(" \t\r\n", pos);
}
static std::string extractVarNameFromUniformDecl(const std::string& decl) {
const std::regex layoutRegex(R"(\s*layout\s*\([^)]*\))");
std::string declNoLayout = std::regex_replace(decl, layoutRegex, "");
size_t uniformPos = declNoLayout.find("uniform");
if (uniformPos != std::string::npos) {
declNoLayout = declNoLayout.substr(uniformPos + 7);
}
trim(declNoLayout);
size_t semiPos = declNoLayout.rfind(';');
if (semiPos != std::string::npos) {
declNoLayout = declNoLayout.substr(0, semiPos);
}
trim(declNoLayout);
size_t lastSpace = declNoLayout.find_last_of(" \t\r\n");
if (lastSpace == std::string::npos) {
return declNoLayout;
}
std::string candidate = declNoLayout.substr(lastSpace + 1);
size_t bracketPos = candidate.find('[');
if (bracketPos != std::string::npos) {
candidate = candidate.substr(0, bracketPos);
}
return candidate;
}
std::pair<std::string, std::string> GenerateDefaultUBOForGLSL(const std::pair<std::string,
std::string>& glslSources) {
std::string source1 = glslSources.first;
std::string source2 = glslSources.second;
std::vector<bool> commentMask1 = buildCommentMask(source1);
std::vector<bool> commentMask2 = buildCommentMask(source2);
const std::regex layoutRegex(R"(\s*layout\s*\([^)]*\))");
std::set<std::string> allUniformNames;
std::vector<std::string> mergedUniforms;
std::vector<std::pair<size_t, size_t>> removalSpans1;
std::vector<std::pair<size_t, size_t>> removalSpans2;
auto processSource = [&](std::string& source, const std::vector<bool>& commentMask,
std::vector<std::pair<size_t, size_t>>& removalSpans,
bool isFirstSource)
{
size_t searchPos = 0;
while ((searchPos = source.find("uniform", searchPos)) != std::string::npos) {
if (isInComment(commentMask, searchPos)) {
searchPos++;
continue;
}
if (isPreprocessorLine(source, searchPos)) {
searchPos++;
continue;
}
if (searchPos > 0 && (std::isalnum(source[searchPos - 1]) || source[searchPos - 1] == '_')) {
searchPos++;
continue;
}
size_t nextCharPos = findNextNonSpace(source, searchPos + 7);
if (nextCharPos == std::string::npos) break;
if (source[nextCharPos] == '{') {
searchPos = nextCharPos + 1;
continue;
}
size_t bracePos = source.find('{', nextCharPos);
size_t semicolonPos = source.find(';', nextCharPos);
if (bracePos != std::string::npos && (semicolonPos == std::string::npos || bracePos < semicolonPos)) {
searchPos = bracePos + 1;
continue;
}
if (semicolonPos == std::string::npos) {
searchPos++;
continue;
}
size_t declStart = searchPos;
size_t declLength = semicolonPos - searchPos + 1;
std::string declaration = source.substr(declStart, declLength);
std::string declNoLayout = std::regex_replace(declaration, layoutRegex, "");
std::string afterUniform = declNoLayout.substr(declNoLayout.find("uniform") + 7);
trim(afterUniform);
size_t sep = afterUniform.find_first_of(" \t\r\n[");
std::string typeToken = (sep == std::string::npos ? afterUniform : afterUniform.substr(0, sep));
bool isSamplerOrImage = false;
if (typeToken.rfind("sampler", 0) == 0 ||
typeToken.rfind("isampler", 0) == 0 ||
typeToken.rfind("usampler", 0) == 0 ||
typeToken.rfind("image", 0) == 0)
{
isSamplerOrImage = true;
}
if (isSamplerOrImage) {
searchPos = declStart + declLength;
continue;
}
std::string varName = extractVarNameFromUniformDecl(declaration);
if (isFirstSource) {
mergedUniforms.push_back(declaration);
allUniformNames.insert(varName);
} else {
if (allUniformNames.find(varName) == allUniformNames.end()) {
mergedUniforms.push_back(declaration);
allUniformNames.insert(varName);
}
}
size_t removeStart = declStart;
{
size_t scanBack = declStart;
while (scanBack > 0 && std::isspace((unsigned char)source[scanBack - 1])) {
scanBack--;
}
if (scanBack >= 6) {
size_t maybeLayout = source.rfind("layout", scanBack - 6);
if (maybeLayout != std::string::npos) {
size_t parenOpen = source.find('(', maybeLayout + 6);
if (parenOpen != std::string::npos && parenOpen < scanBack) {
size_t parenClose = source.find(')', parenOpen);
if (parenClose != std::string::npos && parenClose < declStart) {
std::string between = source.substr(maybeLayout, declStart - maybeLayout);
const std::regex onlyLayout(R"(layout\s*\([^)]*\)\s*)");
if (std::regex_match(between, onlyLayout)) {
removeStart = maybeLayout;
}
}
}
}
}
}
removalSpans.emplace_back(removeStart, (declStart + declLength) - removeStart);
searchPos = declStart + declLength;
}
};
processSource(source1, commentMask1, removalSpans1, true);
processSource(source2, commentMask2, removalSpans2, false);
if (mergedUniforms.empty()) {
return glslSources;
}
std::sort(removalSpans1.rbegin(), removalSpans1.rend());
for (auto &span : removalSpans1) {
source1.erase(span.first, span.second);
}
source1 = std::regex_replace(source1, std::regex(R"((\r\n|\n|\r){2,})"), "$1");
std::sort(removalSpans2.rbegin(), removalSpans2.rend());
for (auto &span : removalSpans2) {
source2.erase(span.first, span.second);
}
source2 = std::regex_replace(source2, std::regex(R"((\r\n|\n|\r){2,})"), "$1");
std::string uboBlock = "\nlayout(std140) uniform MG_DEFAULT_UBO\n{\n";
for (auto &decl : mergedUniforms) {
std::string cleaned = std::regex_replace(decl, layoutRegex, "");
std::string memberDecl = cleaned.substr(cleaned.find("uniform") + 7);
size_t semiPos = memberDecl.rfind(';');
if (semiPos != std::string::npos) {
memberDecl.erase(semiPos);
}
trim(memberDecl);
uboBlock += " " + memberDecl + ";\n";
}
uboBlock += "};\n";
auto insertUBO = [&](std::string& source) {
size_t insertPos = 0, lastDirectivePos = 0;
size_t searchPos = 0;
while ((searchPos = source.find('#', searchPos)) != std::string::npos) {
if (isInComment(commentMask1, searchPos)) {
searchPos++;
continue;
}
size_t eol = source.find('\n', searchPos);
if (eol == std::string::npos) break;
std::string line = source.substr(searchPos, eol - searchPos);
if (line.find("#version") != std::string::npos || line.find("#extension") != std::string::npos) {
lastDirectivePos = eol + 1;
}
searchPos = eol + 1;
}
insertPos = lastDirectivePos;
source.insert(insertPos, uboBlock);
};
insertUBO(source1);
insertUBO(source2);
return {source1, source2};
}
void GenerateDefaultUBOForGLSL_Multi(
MG_Global::unordered_map<GLuint, std::string> &shaderSources, std::vector<std::string>& outUniformBufferNames) {
if (shaderSources.empty()) return;
outUniformBufferNames.clear();
std::unordered_map<GLuint, std::vector<bool>> commentMasks;
for (auto const& [id, source] : shaderSources) {
commentMasks[id] = buildCommentMask(source);
}
const std::regex layoutRegex(R"(\s*layout\s*\([^)]*\))");
std::set<std::string> allUniformNames;
std::vector<std::string> mergedUniforms;
std::unordered_map<GLuint, std::vector<std::pair<size_t, size_t>>> removalSpansPerShader;
for (auto& [id, source] : shaderSources) {
std::vector<bool>& commentMask = commentMasks[id];
// Ensure an entry exists for this shader ID, even if no uniforms are found
auto& removalSpans = removalSpansPerShader[id];
size_t searchPos = 0;
while ((searchPos = source.find("uniform", searchPos)) != std::string::npos) {
if (isInComment(commentMask, searchPos)) {
searchPos++;
continue;
}
if (isPreprocessorLine(source, searchPos)) {
searchPos++;
continue;
}
if (searchPos > 0 && (std::isalnum(source[searchPos - 1]) ||
source[searchPos - 1] == '_')) {
searchPos++;
continue;
}
size_t nextCharPos = findNextNonSpace(source, searchPos + 7);
if (nextCharPos == std::string::npos) break;
if (source[nextCharPos] == '{') {
searchPos = nextCharPos + 1;
continue;
}
size_t bracePos = source.find('{', nextCharPos);
size_t semicolonPos = source.find(';', nextCharPos);
if (bracePos != std::string::npos &&
(semicolonPos == std::string::npos || bracePos < semicolonPos)) {
searchPos = bracePos + 1;
continue;
}
if (semicolonPos == std::string::npos) {
searchPos++;
continue;
}
size_t declStart = searchPos;
size_t declLength = semicolonPos - searchPos + 1;
std::string declaration = source.substr(declStart, declLength);
std::string declNoLayout = std::regex_replace(declaration, layoutRegex, "");
std::string afterUniform = declNoLayout.substr(declNoLayout.find("uniform") + 7);
trim(afterUniform);
size_t sep = afterUniform.find_first_of(" \t\r\n[");
std::string typeToken = (sep == std::string::npos ? afterUniform : afterUniform.substr(0, sep));
bool isSamplerOrImage =
typeToken.rfind("sampler", 0) == 0 ||
typeToken.rfind("isampler", 0) == 0 ||
typeToken.rfind("usampler", 0) == 0 ||
typeToken.rfind("image", 0) == 0;
if (isSamplerOrImage) {
searchPos = declStart + declLength;
continue;
}
std::string varName = extractVarNameFromUniformDecl(declaration);
if (allUniformNames.find(varName) == allUniformNames.end()) {
mergedUniforms.push_back(declaration);
allUniformNames.insert(varName);
// save the uniform names in order
outUniformBufferNames.emplace_back(varName);
}
size_t removeStart = declStart;
size_t scanBack = declStart;
while (scanBack > 0 && std::isspace(static_cast<unsigned char>(source[scanBack - 1]))) {
scanBack--;
}
if (scanBack >= 6) {
size_t maybeLayout = source.rfind("layout", scanBack - 6);
if (maybeLayout != std::string::npos) {
size_t parenOpen = source.find('(', maybeLayout + 6);
if (parenOpen != std::string::npos && parenOpen < scanBack) {
size_t parenClose = source.find(')', parenOpen);
if (parenClose != std::string::npos && parenClose < declStart) {
std::string between = source.substr(maybeLayout, declStart - maybeLayout);
const std::regex onlyLayout(R"(layout\s*\([^)]*\)\s*)");
if (std::regex_match(between, onlyLayout)) {
removeStart = maybeLayout;
}
}
}
}
}
removalSpans.emplace_back(removeStart, (declStart + declLength) - removeStart);
searchPos = declStart + declLength;
}
}
if (mergedUniforms.empty()) return;
for (auto& [id, source] : shaderSources) {
auto& removalSpans = removalSpansPerShader[id];
std::sort(removalSpans.rbegin(), removalSpans.rend());
for (auto& span : removalSpans) {
source.erase(span.first, span.second);
}
}
std::string uboBlock = "\nlayout(std140) uniform MG_DEFAULT_UBO\n{\n";
for (auto& decl : mergedUniforms) {
std::string cleaned = std::regex_replace(decl, layoutRegex, "");
std::string memberDecl = cleaned.substr(cleaned.find("uniform") + 7);
size_t semiPos = memberDecl.rfind(';');
if (semiPos != std::string::npos) {
memberDecl.erase(semiPos);
}
trim(memberDecl);
uboBlock += " " + memberDecl + ";\n";
}
uboBlock += "};\n";
MG_Util::Debug::LogD("UBO Generated:\n%s", uboBlock.c_str());
for (auto& [id, source] : shaderSources) {
size_t insertPos = 0, lastDirectivePos = 0;
size_t searchPos = 0;
while ((searchPos = source.find('#', searchPos)) != std::string::npos) {
if (isInComment(commentMasks[id], searchPos)) {
searchPos++;
continue;
}
size_t eol = source.find('\n', searchPos);
if (eol == std::string::npos) break;
std::string line = source.substr(searchPos, eol - searchPos);
if (line.find("#version") != std::string::npos ||
line.find("#extension") != std::string::npos) {
lastDirectivePos = eol + 1;
}
searchPos = eol + 1;
}
insertPos = lastDirectivePos;
source.insert(insertPos, uboBlock);
}
}
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source,
glslang::TShader *&shader, bool isVkGLSL) {
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader) {
std::string infoLog;
using namespace glslang;
@@ -677,12 +21,8 @@ namespace MG_Util::Program {
shader = new TShader(language);
const char *src = source.c_str();
shader->setStrings(&src, 1);
if (isVkGLSL) {
shader->setPreamble("#define gl_VertexID gl_VertexIndex\n"
"#define gl_InstanceID gl_InstanceIndex\n");
}
shader->setEnvInput(EShSourceGlsl, language, EShClientVulkan, glslVersion);
shader->setEnvClient(EShClientOpenGL, isVkGLSL ? EShTargetVulkan_1_3 : EShTargetOpenGL_450);
shader->setEnvClient(EShClientOpenGL, EShTargetOpenGL_450);
shader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_6);
shader->setAutoMapLocations(true);
shader->setAutoMapBindings(true);
@@ -690,7 +30,7 @@ namespace MG_Util::Program {
// Is InitResources() really correct?
TBuiltInResource resources = InitResources();
if (!shader->parse(&resources, glslVersion, true, isVkGLSL ? EShMsgVulkanRules : EShMsgDefault)) {
if (!shader->parse(&resources, glslVersion, true, EShMsgDefault)) {
infoLog += "Error: [glslang] Cannot compile the " + GetShaderTypeName(shaderType) + ":\n"
+ std::to_string(shader->getInfoLog());
return infoLog;
@@ -705,12 +45,12 @@ namespace MG_Util::Program {
std::vector<EShLanguage> usedShaderTypes;
TProgram program;
for (GLuint shaderId : prog.attachedShaders) {
auto* shaderObject = state.GetShaderObject(shaderId);
EShLanguage shLanguage = GetEShLanguageByShaderType(shaderObject->type);
auto shaderObject = state.GetShaderObject(shaderId);
EShLanguage shLanguage = GetEShLanguageByShaderType(shaderObject.type);
TShader* shader = nullptr;
std::string infoLogOfShader = CompileGLSLToTShader(shaderObject->type, shaderObject->source, shader);
std::string infoLogOfShader = CompileGLSLToTShader(shaderObject.type, shaderObject.source, shader);
if (!infoLogOfShader.empty()) {
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderObject->type) +
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderObject.type) +
" :\n" + infoLogOfShader;
return {};
}
@@ -722,21 +62,6 @@ namespace MG_Util::Program {
return {};
}
std::unique_ptr<glslang::TIoMapResolver> resolver;
for (unsigned stage = 0; stage < EShLangCount; stage++) {
auto* pResolver = program.getGlslIoResolver((EShLanguage)stage);
if (pResolver) {
resolver = std::unique_ptr<glslang::TIoMapResolver>(pResolver);
break;
}
}
auto ioMapper = std::unique_ptr<glslang::TIoMapper>(glslang::GetGlslIoMapper());
if (!program.mapIO(resolver.get(), ioMapper.get())) {
infoLog = "Error: [glslang] Cannot mapIO:\n" + std::to_string(program.getInfoLog());
return {};
}
SpvOptions spvOptions;
spvOptions.disableOptimizer = false;
@@ -750,40 +75,21 @@ namespace MG_Util::Program {
return allSpirv;
}
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string &source,
std::string &infoLog, bool isVkGLSL, GLenum additionalShaderType,
const std::string& additionalShaderSource
) {
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string &source, std::string &infoLog) {
using namespace glslang;
TShader* shader = nullptr;
std::string infoLogOfShader = CompileGLSLToTShader(shaderType, source, shader, isVkGLSL);
std::string infoLogOfShader = CompileGLSLToTShader(shaderType, source, shader);
if (!infoLogOfShader.empty()) {
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderType) + ":\n" + infoLogOfShader;
return {};
}
TProgram program;
if (additionalShaderType == GL_VERTEX_SHADER)
program.addShader(shader);
if (additionalShaderType && !additionalShaderSource.empty()) {
TShader* additionalShader = nullptr;
std::string additionalInfoLog = CompileGLSLToTShader(additionalShaderType, additionalShaderSource, additionalShader, isVkGLSL);
if (!additionalInfoLog.empty()) {
infoLog = "Error: [glslang] Cannot compile additional " + GetShaderTypeName(additionalShaderType) + ":\n" + additionalInfoLog;
return {};
}
program.addShader(additionalShader);
}
if (additionalShaderType != GL_VERTEX_SHADER)
program.addShader(shader);
if (!program.link(isVkGLSL ? EShMsgVulkanRules : EShMsgDefault)) {
program.addShader(shader);
if (!program.link(EShMsgDefault)) {
infoLog = "Error: [glslang] Cannot link the program of the single shader:\n" + std::to_string(program.getInfoLog());
return {};
}
program.mapIO();
std::vector<unsigned> spirv;
SpvOptions spvOptions;
@@ -802,7 +108,7 @@ namespace MG_Util::Program {
return;
}
MG_Global::unordered_set<GLint> used_locations;
ankerl::unordered_set<GLint> used_locations;
GLint auto_location = 0;
for (auto spirv: allSpirv) {
spvc_parsed_ir ir = nullptr;
@@ -858,47 +164,15 @@ namespace MG_Util::Program {
const spvc_reflected_resource &res = *res_ptr;
const char *name = res.name;
if (name[0] == '_') continue;
unsigned spirv_location = spvc_compiler_get_decoration(compiler, res.id,
SpvDecorationLocation);
GLint final_location;
spvc_type_id type_id = res.type_id;
spvc_type type = spvc_compiler_get_type_handle(compiler, type_id);
spvc_basetype base_type = spvc_type_get_basetype(type);
GLenum gl_type = GL_NONE;
if (spirv_location >= 0 && base_type != SPVC_BASETYPE_SAMPLED_IMAGE) {
auto conflict_it = used_locations.find(spirv_location);
if (conflict_it != used_locations.end()) {
// Check if the conflicting uniform is a sampler
std::string conflicting_name;
for (const auto& entry : prog.uniformLocations) {
if (entry.second == spirv_location) {
conflicting_name = entry.first;
break;
}
}
if(conflicting_name == std::string(name)) {
continue;
} else if (!conflicting_name.empty() && prog.uniformValues.count(conflicting_name) &&
MG_GL::GL::IsSamplerType(prog.uniformValues[conflicting_name].type)) {
// Reassign location for the sampler
GLint new_sampler_loc = auto_location++;
while (used_locations.find(new_sampler_loc) != used_locations.end()) new_sampler_loc++;
prog.uniformLocations[conflicting_name] = new_sampler_loc;
used_locations.erase(conflict_it); // Remove old sampler location
used_locations.insert(new_sampler_loc); // Add new sampler location
} else {
infoLog += "\nLocation conflict for uniform: " + std::string(name) + " at location " + std::to_string(spirv_location);
infoLog += "\nExisting uniforms and locations:";
for (const auto& entry : prog.uniformLocations) {
infoLog += "\n " + entry.first + ": " + std::to_string(entry.second);
}
infoLog += "\nUsed locations set:";
for (GLint loc : used_locations) infoLog += " " + std::to_string(loc);
continue;
}
if (spirv_location > 0) {
if (used_locations.find(spirv_location) != used_locations.end()) {
infoLog += "\nLocation conflict for uniform: " + std::string(name);
continue;
}
final_location = spirv_location;
} else {
@@ -910,6 +184,11 @@ namespace MG_Util::Program {
used_locations.insert(final_location);
spvc_type_id type_id = res.type_id;
spvc_type type = spvc_compiler_get_type_handle(compiler, type_id);
spvc_basetype base_type = spvc_type_get_basetype(type);
GLenum gl_type = GL_NONE;
if (base_type == SPVC_BASETYPE_SAMPLED_IMAGE) {
SpvDim dim = spvc_type_get_image_dimension(type);
bool is_array = spvc_type_get_image_arrayed(type);
@@ -1122,7 +401,7 @@ namespace MG_Util::Program {
spvc_context_destroy(context);
}
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES, bool isVkGLSL) {
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES) {
spvc_context context = nullptr;
spvc_parsed_ir ir = nullptr;
spvc_compiler compiler_glsl = nullptr;
@@ -1141,15 +420,12 @@ namespace MG_Util::Program {
spvc_compiler_create_shader_resources(compiler_glsl, &resources);
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
spvc_compiler_create_compiler_options(compiler_glsl, &options);
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, glslVersion);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, isES ? SPVC_TRUE : SPVC_FALSE);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, isVkGLSL ? SPVC_TRUE : SPVC_FALSE);
spvc_compiler_install_compiler_options(compiler_glsl, options);
spvc_compiler_compile(compiler_glsl, &result);
if (!result) {
MG_Util::Debug::LogE("Failed to compile the shader to GLSL: %s", spvc_context_get_last_error_string(context));
return{};
}
@@ -1159,4 +435,4 @@ namespace MG_Util::Program {
return essl;
}
}
}
+5 -14
View File
@@ -5,6 +5,8 @@
#ifndef MOBILEGL_GLSLTOOL_H
#define MOBILEGL_GLSLTOOL_H
#include "../../Includes.h"
namespace MG_Util::Program {
inline static TBuiltInResource InitResources()
{
@@ -171,22 +173,11 @@ namespace MG_Util::Program {
}
}
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string& source,
std::string& infoLog, bool isVkGLSL = false, GLenum additionalShaderType = 0,
const std::string& additionalShaderSource = {});
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source,
glslang::TShader *&shader, bool isVkGLSL = false);
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string& source, std::string& infoLog);
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader);
std::vector<std::vector<unsigned>> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog);
void ReflectSPIRVUniforms(const std::vector<std::vector<unsigned>>& allSpirv, ProgramObject& prog, std::string& infoLog);
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES, bool isVkGLSL = false);
std::pair<std::string, std::string> GenerateDefaultUBOForGLSL(const std::pair<std::string,
std::string>& glslSources);
void GenerateDefaultUBOForGLSL_Multi(
MG_Global::unordered_map<GLuint, std::string> &shaderSources, std::vector<std::string>& outUniformBufferNames);
std::string BindInputLayoutLocationsForGLSL(std::vector<uint32_t>& spirv,
MG_Global::unordered_map<std::string, GLint>&
name_location_map);
void RenameGLSLBuiltinsForVulkan(std::string &src);
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES);
}
#endif //MOBILEGL_GLSLTOOL_H
+15 -12
View File
@@ -1,16 +1,19 @@
# MobileGL
> [!NOTE]
> **Important Note**: This project will undergo a complete redesign and rewrite in several weeks. The current implementation will be replaced completely.
## Third party components
**SPIRV-Cross** by **KhronosGroup**: [github](https://github.com/KhronosGroup/SPIRV-Cross)
**SPIRV-Cross** by **KhronosGroup** - [Apache License 2.0](https://github.com/KhronosGroup/SPIRV-Cross/blob/master/LICENSE): [github](https://github.com/KhronosGroup/SPIRV-Cross)
**glslang** by **KhronosGroup**: [github](https://github.com/KhronosGroup/glslang)
**glslang** by **KhronosGroup** - [Various Licenses](https://github.com/KhronosGroup/glslang/blob/main/LICENSE.txt): [github](https://github.com/KhronosGroup/glslang)
*(Unused Currently)* **GlslOptimizerV2** by **aiekick**: [github](https://github.com/aiekick/GlslOptimizerV2)
*(Unused Currently)* **GlslOptimizerV2** by **aiekick** - [Apache License 2.0](https://github.com/aiekick/GlslOptimizerV2/blob/master/LICENSE): [github](https://github.com/aiekick/GlslOptimizerV2)
**unordered_dense** by **Martin Leitner-Ankerl**: [github](https://github.com/martinus/unordered_dense)
**unordered_dense** by **Martin Leitner-Ankerl** - [MIT License](https://github.com/martinus/unordered_dense/blob/main/LICENSE): [github](https://github.com/martinus/unordered_dense)
**OpenGL Mathematics (*GLM*)** by **G-Truc Creation**: [github](https://github.com/g-truc/glm)
**OpenGL Mathematics (*GLM*)** by **G-Truc Creation** - [MIT License](https://github.com/g-truc/glm/blob/master/copying.txt): [github](https://github.com/g-truc/glm)
## Progress
@@ -27,11 +30,11 @@
**Target**: **OpenGL implementation compatible with Minecraft 1.17 to 1.21.5**
| Component | Development Progress\* |
|--------------------------------|------------------------|
| **OpenGL State Manager** | **65 / 65** |
| **Abstraction Layer (MG_RHI)** | **0 / 61** |
| **OpenGL ES Backend** | **N/A** (of MG_RHI) |
| **Vulkan Backend** | **planned** |
| Component | Development Progress* |
|--------------------------------|-----------------------|
| **OpenGL State Manager** | **65 / 65** |
| **Abstraction Layer (MG_RHI)** | **0 / 61** |
| **OpenGL ES Backend** | **N/A** (of MG_RHI) |
| **Vulkan Backend** | **planned** |
\* *The number of functions that have been implemented*
* *The number of functions that have been implemented*