From f5a14c20a9115ed827fb26f3740e54a338993085 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sat, 7 Jun 2025 19:41:32 +0800 Subject: [PATCH] [Feat] (DiligentEngine): Implement most rendering by DiligentEngine. --- MG/Constants.h | 42 +- MG/Global.h | 2 +- MG/Includes.h | 4 + .../Implementations/EGL/Diligent/EGL_impl.cpp | 676 +++++++++++++----- .../Implementations/EGL/Diligent/EGL_impl.h | 261 ++++++- MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp | 6 +- MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h | 6 +- .../Implementations/GL/Buffer/GL_Buffer.cpp | 165 ++++- .../Implementations/GL/Common/GL_Common.cpp | 116 ++- .../Implementations/GL/Drawing/GL_Drawing.cpp | 494 ++++++++++++- .../GL/Framebuffer/GL_Framebuffer.cpp | 457 +++++++++++- .../GL/Framebuffer/GL_Framebuffer.h | 2 + .../Implementations/GL/Program/GL_Program.cpp | 274 ++++++- .../Implementations/GL/Program/GL_Program.h | 2 + .../Implementations/GL/Texture/GL_Texture.cpp | 388 +++++++++- .../GL/VertexArray/GL_VertexArray.cpp | 4 +- MG/MG_GL/State/Buffer/BufferState.h | 8 +- MG/MG_GL/State/Common/CommonState.h | 7 +- MG/MG_GL/State/Core/GLState.h | 1 + .../State/Framebuffer/FramebufferState.cpp | 5 +- MG/MG_GL/State/Framebuffer/FramebufferState.h | 7 +- MG/MG_GL/State/Program/ProgramState.h | 13 +- MG/MG_GL/State/Program/ShaderObject.h | 1 + MG/MG_GL/State/Texture/TextureState.cpp | 3 +- MG/MG_GL/State/Texture/TextureState.h | 21 +- MG/MG_GL/State/VertexArray/VertexArrayState.h | 5 +- MG/MG_RHI/GLES/Test/TestDrawing.cpp | 4 +- MG/MG_UTIL/Program/GLSLTool.cpp | 481 ++++++++++++- MG/MG_UTIL/Program/GLSLTool.h | 4 + 29 files changed, 3146 insertions(+), 313 deletions(-) diff --git a/MG/Constants.h b/MG/Constants.h index e4f43943..839ac2c5 100644 --- a/MG/Constants.h +++ b/MG/Constants.h @@ -21,11 +21,11 @@ #define MG_EXPORT extern "C" __attribute__((visibility("default"))) #endif -namespace ankerl { - template +namespace MG_Global { + template using unordered_map = ankerl::unordered_dense::map; - - template + + template using unordered_set = ankerl::unordered_dense::set; } @@ -39,7 +39,7 @@ namespace MG_Constants { } namespace Blend { - static const ankerl::unordered_set VALID_FACTORS = { + static const MG_Global::unordered_set 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, @@ -48,51 +48,51 @@ namespace MG_Constants { } namespace Depth { - static const ankerl::unordered_set VALID_FUNCS = { + static const MG_Global::unordered_set VALID_FUNCS = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS }; // OpenGL 3 } namespace CommonState { - static const ankerl::unordered_set VALID_CAPS = { + static const MG_Global::unordered_set 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 ankerl::unordered_set VALID_ATTACHMENTS = { + static const MG_Global::unordered_set VALID_ATTACHMENTS = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT }; // OpenGL 3 - static const ankerl::unordered_set VALID_TARGETS = { + static const MG_Global::unordered_set VALID_TARGETS = { GL_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER }; // OpenGL 3 - static const ankerl::unordered_set VALID_ACCESS = { + static const MG_Global::unordered_set VALID_ACCESS = { GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE }; // OpenGL 3 } namespace Buffer { - static const ankerl::unordered_set VALID_PARAM_NAMES = { + static const MG_Global::unordered_set VALID_PARAM_NAMES = { GL_BUFFER_ACCESS, GL_BUFFER_MAPPED, GL_BUFFER_SIZE, GL_BUFFER_USAGE }; // OpenGL 3 - static const ankerl::unordered_set VALID_TARGETS = { + static const MG_Global::unordered_set 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 ankerl::unordered_set VALID_ACCESS = { + static const MG_Global::unordered_set VALID_ACCESS = { GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE }; // OpenGL 3 } namespace PixelStore { - static const ankerl::unordered_map DEFAULT_VALUES_MAP = { + static const MG_Global::unordered_map DEFAULT_VALUES_MAP = { {GL_PACK_SWAP_BYTES, GL_FALSE}, {GL_PACK_LSB_FIRST, GL_FALSE}, {GL_PACK_ROW_LENGTH, 0}, @@ -111,7 +111,7 @@ namespace MG_Constants { {GL_UNPACK_ALIGNMENT, 4} }; // OpenGL 3 - static const ankerl::unordered_set VALID_PARAM_NAMES = { + static const MG_Global::unordered_set 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, @@ -125,18 +125,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 ankerl::unordered_set VALID_TARGETS = { + inline const MG_Global::unordered_set 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 ankerl::unordered_set VALID_FORMATS = { + inline const MG_Global::unordered_set VALID_FORMATS = { GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL }; // OpenGL 3 - inline const ankerl::unordered_set VALID_INTERNAL_FORMATS = { + inline const MG_Global::unordered_set 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, @@ -151,7 +151,7 @@ namespace MG_Constants { GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8 }; // OpenGL 3 - inline const ankerl::unordered_set VALID_TYPES = { + inline const MG_Global::unordered_set 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, @@ -159,14 +159,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 ankerl::unordered_set VALID_TEXTURE_PARAM_NAMES = { + inline const MG_Global::unordered_set 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 ankerl::unordered_set VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = { + inline const MG_Global::unordered_set 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 diff --git a/MG/Global.h b/MG/Global.h index 630410bd..35ecc225 100644 --- a/MG/Global.h +++ b/MG/Global.h @@ -27,7 +27,7 @@ namespace MG_Global { } namespace Common { - inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_INFO; + inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_DEBUG; #ifdef __ANDROID__ inline const char* LOG_FILE_PATH = "/sdcard/MG/latest.log"; diff --git a/MG/Includes.h b/MG/Includes.h index e2628141..d8b828ea 100644 --- a/MG/Includes.h +++ b/MG/Includes.h @@ -32,6 +32,9 @@ #ifndef MOBILEGL_GL_VERTEXARRAY_H #include "MG_GL/Implementations/GL/VertexArray/GL_VertexArray.h" #endif +#ifndef MOBILEGL_DILIGENT_EGL_IMPL_H +#include "MG_GL/Implementations/EGL/Diligent/EGL_impl.h" +#endif #ifndef MOBILEGL_GLSTATE_H #include "MG_GL/State/Core/GLState.h" #endif @@ -90,6 +93,7 @@ #include #include #include +#include #include #include #include diff --git a/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.cpp b/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.cpp index aa955cb5..c6763622 100644 --- a/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.cpp +++ b/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.cpp @@ -4,56 +4,416 @@ #include "EGL_impl.h" +#undef MOBILEGL_GLSLTOOL_H +#undef MOBILEGL_PROGRAM_DEBUGTOOL_H +#include "../../../../Includes.h" + typedef Diligent::IEngineFactoryVk* (*Diligent_GetEngineFactoryVk_t)(); typedef Diligent::IEngineFactoryOpenGL* (*Diligent_GetEngineFactoryOpenGL_t)(); +namespace MG_Diligent { + Diligent::IRenderDevice* g_pDevice; + Diligent::IDeviceContext* g_pContext; + Diligent::ISwapChain* g_pSwapChain; + MG_Global::unordered_map g_BufferMap; + MG_Global::unordered_map g_TextureMap; + MG_Global::unordered_map g_TextureViewMap; + MG_Global::unordered_map g_FramebufferMap; + MG_Global::unordered_map g_ShaderMap; + MG_Global::unordered_map g_ProgramMap; + MG_Global::unordered_map g_SamplerMap; + MG_Global::unordered_map g_UniformBufferMap; + bool IsInRenderPass = false; + bool initialized = false; + + void PipelineStateManager::ConfigurePSO( + Diligent::GraphicsPipelineStateCreateInfo &PSOCreateInfo, + GLProgramInfo &programInfo, + CommonState &commonState, + VertexArrayState &vaState, + GLFramebufferInfo& fbInfo) { + PSOCreateInfo.PSODesc.Name = "Program_PSO"; + PSOCreateInfo.PSODesc.PipelineType = Diligent::PIPELINE_TYPE_GRAPHICS; + + __android_log_print(ANDROID_LOG_DEBUG, "Diligent Engine", "Num AttachedShaders: %zu", programInfo.AttachedShaders.size()); + for (auto shader: programInfo.AttachedShaders) { + __android_log_print(ANDROID_LOG_DEBUG, "Diligent Engine", "AttachedShader: %p, Type: %d", shader, shader->GetDesc().ShaderType); + switch (shader->GetDesc().ShaderType) { + case Diligent::SHADER_TYPE_VERTEX: + PSOCreateInfo.pVS = shader; + break; + case Diligent::SHADER_TYPE_PIXEL: + PSOCreateInfo.pPS = shader; + break; + case Diligent::SHADER_TYPE_GEOMETRY: + PSOCreateInfo.pGS = shader; + break; + default: + break; + } + } + + PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements = programInfo.inputLayout.data(); + PSOCreateInfo.GraphicsPipeline.InputLayout.NumElements = programInfo.inputLayout.size(); + + PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + PSOCreateInfo.GraphicsPipeline.NumRenderTargets = fbInfo.ColorRTVs.size(); + for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) { + if (fbInfo.ColorRTVs[i]) { + PSOCreateInfo.GraphicsPipeline.RTVFormats[i] = + fbInfo.ColorRTVs[i]->GetDesc().Format; + } else { + PSOCreateInfo.GraphicsPipeline.RTVFormats[i] = Diligent::TEX_FORMAT_RGBA8_UNORM; + } + } + + if (fbInfo.DepthStencilFormat != Diligent::TEX_FORMAT_UNKNOWN) { + PSOCreateInfo.GraphicsPipeline.DSVFormat = fbInfo.DepthStencilFormat; + } else { + PSOCreateInfo.GraphicsPipeline.DSVFormat = Diligent::TEX_FORMAT_D32_FLOAT; + } + + Diligent::BlendStateDesc &blendDesc = PSOCreateInfo.GraphicsPipeline.BlendDesc; + blendDesc.IndependentBlendEnable = false; + blendDesc.RenderTargets[0].BlendEnable = commonState.capabilities[GL_BLEND]; + blendDesc.RenderTargets[0].SrcBlend = ConvertGLBlendFactor(commonState.blendSrcRGB); + blendDesc.RenderTargets[0].DestBlend = ConvertGLBlendFactor(commonState.blendDstRGB); + blendDesc.RenderTargets[0].BlendOp = Diligent::BLEND_OPERATION_ADD; + blendDesc.RenderTargets[0].SrcBlendAlpha = ConvertGLBlendFactor( + commonState.blendSrcAlpha); + blendDesc.RenderTargets[0].DestBlendAlpha = ConvertGLBlendFactor( + commonState.blendDstAlpha); + blendDesc.RenderTargets[0].BlendOpAlpha = Diligent::BLEND_OPERATION_ADD; + blendDesc.RenderTargets[0].RenderTargetWriteMask = Diligent::COLOR_MASK_ALL; + + Diligent::DepthStencilStateDesc &depthStencilDesc = PSOCreateInfo.GraphicsPipeline.DepthStencilDesc; + depthStencilDesc.DepthEnable = commonState.capabilities[GL_DEPTH_TEST]; + depthStencilDesc.DepthWriteEnable = commonState.depthMask; + depthStencilDesc.DepthFunc = ConvertGLDepthFunc(commonState.depthFunc); + + Diligent::RasterizerStateDesc &rasterizerDesc = PSOCreateInfo.GraphicsPipeline.RasterizerDesc; + rasterizerDesc.CullMode = commonState.capabilities[GL_CULL_FACE] ? + Diligent::CULL_MODE_BACK : Diligent::CULL_MODE_NONE; + rasterizerDesc.FrontCounterClockwise = true; + + ConfigureResourceLayout(PSOCreateInfo, programInfo); + } + + void PipelineStateManager::ReleasePSO(GLuint program) { + auto &programInfo = g_ProgramMap[program]; + if (programInfo.pPipelineState) { + MG_Util::Debug::LogD("Releasing PSO for program %u", program); + programInfo.pPipelineState->Release(); + programInfo.pPipelineState = nullptr; + MG_Util::Debug::LogD("PSO released for program %u", program); + } + programInfo.psoDirty = true; + } + + void PipelineStateManager::MarkPSODirty(GLuint program) { + auto &programInfo = g_ProgramMap[program]; + programInfo.psoDirty = true; + MG_Util::Debug::LogD("Marked PSO dirty for program %u", program); + } + + Diligent::IPipelineState *PipelineStateManager::GetOrCreatePSO( + GLuint program, + GLProgramInfo &programInfo, + CommonState &commonState, + VertexArrayState &vaState, + GLFramebufferInfo& fbInfo) { + uint64_t currentStateHash = CalculateStateHash(commonState, vaState, fbInfo); + + if (programInfo.pPipelineState && + programInfo.psoStateHash == currentStateHash && + !programInfo.psoDirty) { + return programInfo.pPipelineState; + } + + PSOKey key{program, currentStateHash}; + + auto it = psoCache.find(key); + if (it != psoCache.end()) { + return it->second; + } + + Diligent::GraphicsPipelineStateCreateInfo PSOCreateInfo; + ConfigurePSO(PSOCreateInfo, programInfo, commonState, vaState, fbInfo); + + Diligent::IPipelineState *pNewPSO = nullptr; + MG_Util::Debug::LogD("Creating new PSO for program %u", program); + g_pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &pNewPSO); + if (pNewPSO) { + MG_Util::Debug::LogD("PSO created successfully for program %u: %p", program, pNewPSO); + } else { + MG_Util::Debug::LogE("Failed to create PSO for program %u", program); + } + + psoCache[key] = pNewPSO; + + return pNewPSO; + } + + void PipelineStateManager::ConfigureResourceLayout( + Diligent::GraphicsPipelineStateCreateInfo& PSOCreateInfo, + const GLProgramInfo& programInfo) + { + MG_Util::Debug::LogD("Begin configuring resource layout for pipeline"); + + auto& ResourceLayout = PSOCreateInfo.PSODesc.ResourceLayout; + ResourceLayout.DefaultVariableType = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + + std::vector Variables; + std::vector ImmutableSamplers; + + MG_Global::unordered_map shaderSourcesMap; + + ProgramObject programObj = MG_State_T::programState->programs_[programInfo.id]; + + 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) { + shaderSourcesMap[it->first] = it->second.source; + } + } + + MG_Util::Program::GenerateDefaultUBOForGLSL_Multi(shaderSourcesMap); + + for (auto shader : programInfo.AttachedShaders) { + GLuint shaderId = 0; + for (auto const& [key, val] : MG_Diligent::g_ShaderMap) { + if (val == shader) { + shaderId = key; + break; + } + } + MG_Util::Debug::LogD("Processing shader ID: %u", shaderId); + + auto& shaderObj = MG_State_T::programState->shaders_[shaderId]; + + std::string compilationLog; + auto spirv = + MG_Util::Program::CompileGLSLToSPIRV(shaderObj.type, + shaderSourcesMap[shaderId], + compilationLog); + if (spirv.empty()) { + MG_Util::Debug::LogE("Failed to compile shader %u: %s", shaderId, compilationLog.c_str()); + continue; + } else { + MG_Util::Debug::LogD("Shader %u (modified) compiled to SPIR-V successfully", shaderId); + } + + spvc_context context = nullptr; + spvc_parsed_ir parsed_ir = nullptr; + spvc_compiler compiler = nullptr; + spvc_resources resources = nullptr; + + spvc_result result = spvc_context_create(&context); + if (result != SPVC_SUCCESS) { + MG_Util::Debug::LogE("spvc_context_create failed for shader %u", shaderId); + continue; + } + + result = spvc_context_parse_spirv(context, + spirv.data(), + spirv.size(), + &parsed_ir); + + if (result != SPVC_SUCCESS) { + MG_Util::Debug::LogE("spvc_context_parse_spirv failed for shader %u", shaderId); + spvc_context_destroy(context); + continue; + } + + result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, + parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler); + + if (result != SPVC_SUCCESS) { + MG_Util::Debug::LogE("spvc_context_create_compiler failed for shader %u", shaderId); + spvc_context_destroy(context); + continue; + } + + result = spvc_compiler_create_shader_resources(compiler, &resources); + if (result != SPVC_SUCCESS) { + MG_Util::Debug::LogE("spvc_compiler_create_shader_resources failed for shader %u", shaderId); + spvc_context_destroy(context); + continue; + } + + Diligent::SHADER_TYPE shaderType; + switch (shaderObj.type) { + case GL_VERTEX_SHADER: + shaderType = Diligent::SHADER_TYPE_VERTEX; + break; + case GL_FRAGMENT_SHADER: + shaderType = Diligent::SHADER_TYPE_PIXEL; + break; + case GL_GEOMETRY_SHADER: + shaderType = Diligent::SHADER_TYPE_GEOMETRY; + break; + case GL_COMPUTE_SHADER: + shaderType = Diligent::SHADER_TYPE_COMPUTE; + break; + default: + shaderType = Diligent::SHADER_TYPE_UNKNOWN; + } + + MG_Util::Debug::LogD("Shader %u mapped to Diligent shader type %d", shaderId, shaderType); + + const spvc_reflected_resource* resourceList = nullptr; + size_t resourceCount = 0; + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, + &resourceList, &resourceCount); + MG_Util::Debug::LogD("Shader %u has %zu uniform buffers", shaderId, resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + bool already_added = false; + for(const auto& existing_var : Variables) { + if (strcmp(existing_var.Name, resourceList[i].name) == 0) { + already_added = true; + MG_Util::Debug::LogD("Uniform buffer %s already added, skipping.", resourceList[i].name); + break; + } + } + if (already_added) continue; + + Diligent::ShaderResourceVariableDesc varDesc; + varDesc.Name = strdup(resourceList[i].name); + varDesc.ShaderStages = Diligent::SHADER_TYPE_ALL; // TODO + varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + MG_Util::Debug::LogD("Uniform buffer: %s, Stage: %u, Type: %u", varDesc.Name, varDesc.ShaderStages, varDesc.Type); + Variables.push_back(varDesc); + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, + &resourceList, &resourceCount); + MG_Util::Debug::LogD("Shader %u has %zu sampled images", shaderId, resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + Diligent::ShaderResourceVariableDesc varDesc; + varDesc.Name = strdup(resourceList[i].name); + varDesc.ShaderStages = shaderType; + varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + MG_Util::Debug::LogD("Sampled image: %s", varDesc.Name); + Variables.push_back(varDesc); + + const char* samplerName = varDesc.Name; + + if (samplerName) { + auto& texState = *MG_State_T::textureState; + GLuint activeTextureUnit = texState.activeTextureUnit_; + if (activeTextureUnit < texState.textureUnits_.size()) { + auto& unitState = texState.textureUnits_[activeTextureUnit]; + GLuint boundTexture = unitState.GetBoundTexture(GL_TEXTURE_2D); + if (boundTexture != 0) { + auto texIt = texState.textures.find(boundTexture); + if (texIt != texState.textures.end()) { + auto& texObj = texIt->second; + Diligent::ImmutableSamplerDesc samplerDesc; + samplerDesc.ShaderStages = shaderType; + samplerDesc.SamplerOrTextureName = samplerName; + + auto minFilterIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_MIN_FILTER); + samplerDesc.Desc.MinFilter = (minFilterIt != texObj.params.texPropertiesInt.end()) ? + ConvertGLFilter(minFilterIt->second) : Diligent::FILTER_TYPE_LINEAR; + + auto magFilterIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_MAG_FILTER); + samplerDesc.Desc.MagFilter = (magFilterIt != texObj.params.texPropertiesInt.end()) ? + ConvertGLFilter(magFilterIt->second) : Diligent::FILTER_TYPE_LINEAR; + + samplerDesc.Desc.MipFilter = ConvertGLMipFilter( + minFilterIt != texObj.params.texPropertiesInt.end() ? + minFilterIt->second : GL_LINEAR_MIPMAP_LINEAR); + + auto wrapSIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_WRAP_S); + samplerDesc.Desc.AddressU = (wrapSIt != texObj.params.texPropertiesInt.end()) ? + ConvertGLWrapMode(wrapSIt->second) : Diligent::TEXTURE_ADDRESS_WRAP; + + auto wrapTIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_WRAP_T); + samplerDesc.Desc.AddressV = (wrapTIt != texObj.params.texPropertiesInt.end()) ? + ConvertGLWrapMode(wrapTIt->second) : Diligent::TEXTURE_ADDRESS_WRAP; + + samplerDesc.Desc.AddressW = Diligent::TEXTURE_ADDRESS_CLAMP; + + MG_Util::Debug::LogD("Created immutable sampler for: %s", samplerName); + ImmutableSamplers.push_back(samplerDesc); + } + } + } + } + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS, + &resourceList, &resourceCount); + MG_Util::Debug::LogD("Shader %u has %zu separate samplers", shaderId, resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + Diligent::ShaderResourceVariableDesc varDesc; + varDesc.Name = strdup(resourceList[i].name); + varDesc.ShaderStages = shaderType; + varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + Variables.push_back(varDesc); + + Diligent::ImmutableSamplerDesc samplerDesc; + samplerDesc.ShaderStages = shaderType; + samplerDesc.Desc.MinFilter = Diligent::FILTER_TYPE_LINEAR; + samplerDesc.Desc.MagFilter = Diligent::FILTER_TYPE_LINEAR; + samplerDesc.Desc.MipFilter = Diligent::FILTER_TYPE_LINEAR; + samplerDesc.Desc.AddressU = Diligent::TEXTURE_ADDRESS_WRAP; + samplerDesc.Desc.AddressV = Diligent::TEXTURE_ADDRESS_WRAP; + samplerDesc.Desc.AddressW = Diligent::TEXTURE_ADDRESS_CLAMP; + samplerDesc.SamplerOrTextureName = resourceList[i].name; + + MG_Util::Debug::LogD("Added fallback immutable sampler: %s", samplerDesc.SamplerOrTextureName); + ImmutableSamplers.push_back(samplerDesc); + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE, + &resourceList, &resourceCount); + MG_Util::Debug::LogD("Shader %u has %zu storage images", shaderId, resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + Diligent::ShaderResourceVariableDesc varDesc; + varDesc.Name = strdup(resourceList[i].name); + varDesc.ShaderStages = shaderType; + varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; + MG_Util::Debug::LogD("Storage image: %s", varDesc.Name); + Variables.push_back(varDesc); + } + + spvc_context_destroy(context); + } + + if (!Variables.empty()) { + ResourceLayout.Variables = Variables.data(); + ResourceLayout.NumVariables = static_cast(Variables.size()); + MG_Util::Debug::LogD("Added %u shader resource variables", ResourceLayout.NumVariables); + } + + if (!ImmutableSamplers.empty()) { + ResourceLayout.ImmutableSamplers = ImmutableSamplers.data(); + ResourceLayout.NumImmutableSamplers = static_cast(ImmutableSamplers.size()); + MG_Util::Debug::LogD("Added %u immutable samplers", ResourceLayout.NumImmutableSamplers); + } + + MG_Util::Debug::LogD("Finished configuring resource layout"); + } + + + PipelineStateManager g_PSOManager; +} + using namespace Diligent; namespace MG_EGL::Diligent { - static const char *VSSource = R"( -struct PSInput -{ - float4 Pos : SV_POSITION; - float3 Color : COLOR; -}; - -void main(in uint VertId : SV_VertexID, - out PSInput PSIn) -{ - float4 Pos[3]; - Pos[0] = float4(-0.5, -0.5, 0.0, 1.0); - Pos[1] = float4( 0.0, +0.5, 0.0, 1.0); - Pos[2] = float4(+0.5, -0.5, 0.0, 1.0); - - float3 Col[3]; - Col[0] = float3(1.0, 0.0, 0.0); // red - Col[1] = float3(0.0, 1.0, 0.0); // green - Col[2] = float3(0.0, 0.0, 1.0); // blue - - PSIn.Pos = Pos[VertId]; - PSIn.Color = Col[VertId]; -} -)"; - - static const char *PSSource = R"( -struct PSInput -{ - float4 Pos : SV_POSITION; - float3 Color : COLOR; -}; - -struct PSOutput -{ - float4 Color : SV_TARGET; -}; - -void main(in PSInput PSIn, - out PSOutput PSOut) -{ - PSOut.Color = float4(PSIn.Color.rgb, 1.0); -} -)"; - void LoadDiligentCoreOpenGL(NativeWindowType window) { void *handle = dlopen("libGraphicsEngineOpenGL.so", RTLD_LAZY); auto Diligent_GetEngineFactoryOpenGL = @@ -67,8 +427,15 @@ void main(in PSInput PSIn, ::Diligent::SwapChainDesc SCDesc; + MG_Util::Debug::LogD("Creating OpenGL device and swap chain"); pFactoryOpenGL->CreateDeviceAndSwapChainGL( - EngineCI, &ctx.pDevice, &ctx.pContext, SCDesc, &ctx.pSwapChain); + EngineCI, &MG_Diligent::g_pDevice, &MG_Diligent::g_pContext, SCDesc, &MG_Diligent::g_pSwapChain); + if (MG_Diligent::g_pDevice && MG_Diligent::g_pContext && MG_Diligent::g_pSwapChain) { + MG_Util::Debug::LogD("OpenGL device created: device=%p, context=%p, swapchain=%p", + MG_Diligent::g_pDevice, MG_Diligent::g_pContext, MG_Diligent::g_pSwapChain); + } else { + MG_Util::Debug::LogE("Failed to create OpenGL device"); + } } void LoadDiligentCoreVulkan(NativeWindowType window) { @@ -82,11 +449,25 @@ void main(in PSInput PSIn, ::Diligent::SwapChainDesc SCDesc; + MG_Util::Debug::LogD("Creating Vulkan device and contexts"); pFactoryVk->CreateDeviceAndContextsVk( - EngineCI, &ctx.pDevice, &ctx.pContext); + EngineCI, &MG_Diligent::g_pDevice, &MG_Diligent::g_pContext); + if (MG_Diligent::g_pDevice && MG_Diligent::g_pContext) { + MG_Util::Debug::LogD("Vulkan device created: device=%p, context=%p", + MG_Diligent::g_pDevice, MG_Diligent::g_pContext); + } else { + MG_Util::Debug::LogE("Failed to create Vulkan device"); + } + AndroidNativeWindow nativeWindow{window}; + MG_Util::Debug::LogD("Creating Vulkan swap chain"); pFactoryVk->CreateSwapChainVk( - ctx.pDevice, ctx.pContext, SCDesc, nativeWindow, &ctx.pSwapChain); + MG_Diligent::g_pDevice, MG_Diligent::g_pContext, SCDesc, nativeWindow, &MG_Diligent::g_pSwapChain); + if (MG_Diligent::g_pSwapChain) { + MG_Util::Debug::LogD("Vulkan swap chain created: %p", MG_Diligent::g_pSwapChain); + } else { + MG_Util::Debug::LogE("Failed to create Vulkan swap chain"); + } } void LoadDiligentCore(NativeWindowType window) { @@ -102,81 +483,48 @@ void main(in PSInput PSIn, } + void CreateDefaultRenderPass() { + ::Diligent::RenderPassDesc RPDesc; + RPDesc.AttachmentCount = 2; + ::Diligent::RenderPassAttachmentDesc Attachments[2]; + RPDesc.pAttachments = Attachments; + + Attachments[0].Format = ::Diligent::TEX_FORMAT_RGBA8_UNORM; + Attachments[0].InitialState = ::Diligent::RESOURCE_STATE_RENDER_TARGET; + Attachments[0].FinalState = ::Diligent::RESOURCE_STATE_RENDER_TARGET; + Attachments[0].LoadOp = ::Diligent::ATTACHMENT_LOAD_OP_CLEAR; + Attachments[0].StoreOp = ::Diligent::ATTACHMENT_STORE_OP_STORE; + + Attachments[1].Format = ::Diligent::TEX_FORMAT_D24_UNORM_S8_UINT; + Attachments[1].InitialState = ::Diligent::RESOURCE_STATE_DEPTH_WRITE; + Attachments[1].FinalState = ::Diligent::RESOURCE_STATE_DEPTH_WRITE; + Attachments[1].LoadOp = ::Diligent::ATTACHMENT_LOAD_OP_CLEAR; + Attachments[1].StoreOp = ::Diligent::ATTACHMENT_STORE_OP_STORE; + + ::Diligent::AttachmentReference RTAttachmentRef{0, ::Diligent::RESOURCE_STATE_RENDER_TARGET}; + ::Diligent::AttachmentReference DSAttachmentRef{1, ::Diligent::RESOURCE_STATE_DEPTH_WRITE}; + + ::Diligent::SubpassDesc Subpasses[1]; + Subpasses[0].RenderTargetAttachmentCount = 1; + Subpasses[0].pRenderTargetAttachments = &RTAttachmentRef; + Subpasses[0].pDepthStencilAttachment = &DSAttachmentRef; + + RPDesc.SubpassCount = 1; + RPDesc.pSubpasses = Subpasses; + + MG_Util::Debug::LogD("Creating default render pass"); + MG_Diligent::g_pDevice->CreateRenderPass(RPDesc, &MG_Diligent::g_FramebufferMap[0].pRenderPass); + if (MG_Diligent::g_FramebufferMap[0].pRenderPass) { + MG_Util::Debug::LogD("Default render pass created: %p", MG_Diligent::g_FramebufferMap[0].pRenderPass); + } else { + MG_Util::Debug::LogE("Failed to create default render pass"); + } + } + EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) { LoadDiligentCore(window); - - RenderPassAttachmentDesc RPAttachmentDescs[2]; - RPAttachmentDescs[0].Format = ctx.pSwapChain->GetDesc().ColorBufferFormat; - RPAttachmentDescs[0].InitialState = RESOURCE_STATE_RENDER_TARGET; - RPAttachmentDescs[0].FinalState = RESOURCE_STATE_RENDER_TARGET; - RPAttachmentDescs[0].LoadOp = ATTACHMENT_LOAD_OP_CLEAR; - RPAttachmentDescs[0].StoreOp = ATTACHMENT_STORE_OP_STORE; - RPAttachmentDescs[1].Format = ctx.pSwapChain->GetDesc().DepthBufferFormat; - RPAttachmentDescs[1].InitialState = RESOURCE_STATE_DEPTH_WRITE; - RPAttachmentDescs[1].FinalState = RESOURCE_STATE_DEPTH_WRITE; - RPAttachmentDescs[1].LoadOp = ATTACHMENT_LOAD_OP_CLEAR; - RPAttachmentDescs[1].StoreOp = ATTACHMENT_STORE_OP_DISCARD; - - SubpassDesc Subpass; - Subpass.InputAttachmentCount = 0; - Subpass.RenderTargetAttachmentCount = 1; - AttachmentReference RTAttachmentRef = {0, RESOURCE_STATE_RENDER_TARGET}; - Subpass.pRenderTargetAttachments = &RTAttachmentRef; - AttachmentReference DSAttachmentRef = {1, RESOURCE_STATE_DEPTH_WRITE}; - Subpass.pDepthStencilAttachment = &DSAttachmentRef; - - RenderPassDesc RPDesc; - RPDesc.Name = "Main render pass"; - RPDesc.AttachmentCount = 2; - RPDesc.pAttachments = RPAttachmentDescs; - RPDesc.SubpassCount = 1; - RPDesc.pSubpasses = &Subpass; - - ctx.pDevice->CreateRenderPass(RPDesc, &ctx.pRenderPass); - - GraphicsPipelineStateCreateInfo PSOCreateInfo; - PSOCreateInfo.PSODesc.Name = "Simple triangle PSO"; - - PSOCreateInfo.PSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS; - - PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 0; - PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_UNKNOWN; - PSOCreateInfo.GraphicsPipeline.DSVFormat = TEX_FORMAT_UNKNOWN; - PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - PSOCreateInfo.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE; - PSOCreateInfo.GraphicsPipeline.DepthStencilDesc.DepthEnable = False; - PSOCreateInfo.GraphicsPipeline.pRenderPass = ctx.pRenderPass; - - ShaderCreateInfo ShaderCI; - ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; - ShaderCI.Desc.UseCombinedTextureSamplers = true; - RefCntAutoPtr pVS; - { - ShaderCI.Desc.ShaderType = SHADER_TYPE_VERTEX; - ShaderCI.EntryPoint = "main"; - ShaderCI.Desc.Name = "Triangle vertex shader"; - ShaderCI.Source = VSSource; - ctx.pDevice->CreateShader(ShaderCI, &pVS); - } - - RefCntAutoPtr pPS; - { - ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; - ShaderCI.EntryPoint = "main"; - ShaderCI.Desc.Name = "Triangle pixel shader"; - ShaderCI.Source = PSSource; - ctx.pDevice->CreateShader(ShaderCI, &pPS); - } - - PSOCreateInfo.pVS = pVS; - PSOCreateInfo.pPS = pPS; - ctx.pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &ctx.pPSO); - - const auto& SCDesc = ctx.pSwapChain->GetDesc(); - ctx.pFramebuffers.resize(SCDesc.BufferCount); - - ctx.pContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_NONE); + MG_GL::GL::UpdateDefaultFramebuffer(); return (EGLSurface) 1; } @@ -251,63 +599,39 @@ void main(in PSInput PSIn, return EGL_TRUE; } - static int swapBuffersCount = 0; - static int bufferCount = 0; EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { - const float ClearColor[] = {0.350f, 0.350f, 0.350f, 1.0f}; + MG_Util::Debug::LogD("Flushing context"); + MG_Diligent::g_pContext->Flush(); - // Framebuffer Creation - if (!bufferCount) bufferCount = ctx.pSwapChain->GetDesc().BufferCount; - ITextureView* pDSV = ctx.pSwapChain->GetDepthBufferDSV(); - if (swapBuffersCount < bufferCount) { - ITextureView *pRTV = ctx.pSwapChain->GetCurrentBackBufferRTV(); - ITextureView *attachments[2]; - attachments[0] = pRTV; - attachments[1] = pDSV; + MG_Util::Debug::LogD("Presenting swap chain"); + MG_Diligent::g_pSwapChain->Present(); + MG_GL::GL::UpdateDefaultFramebuffer(); + + MG_Util::Debug::LogD("Finishing frame"); + MG_Diligent::g_pContext->FinishFrame(); - FramebufferDesc FBDesc; - FBDesc.Name = ("Main framebuffer " + std::to_string(swapBuffersCount)).c_str(); - FBDesc.pRenderPass = ctx.pRenderPass; - FBDesc.AttachmentCount = 2; - FBDesc.ppAttachments = attachments; - ctx.pDevice->CreateFramebuffer(FBDesc, &ctx.pFramebuffers[swapBuffersCount]); + auto& fbInfo = MG_Diligent::g_FramebufferMap[0]; + if (fbInfo.pRenderPass && fbInfo.pFramebuffer) { + MG_Util::Debug::LogD("Setting render targets: %zu color attachments", fbInfo.ColorRTVs.size()); + MG_Diligent::g_pContext->SetRenderTargets( + static_cast(fbInfo.ColorRTVs.size()), + fbInfo.ColorRTVs.data(), + fbInfo.pDepthStencilRTV, + ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); + + MG_Util::Debug::LogD("Beginning render pass: pass=%p, fb=%p", fbInfo.pRenderPass, fbInfo.pFramebuffer); + MG_Diligent::g_pContext->BeginRenderPass( + ::Diligent::BeginRenderPassAttribs{ + fbInfo.pRenderPass, + fbInfo.pFramebuffer, + ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + } + ); } - - BeginRenderPassAttribs beginRenderPassAttribs; - - beginRenderPassAttribs.pFramebuffer = ctx.pFramebuffers[swapBuffersCount % bufferCount]; - beginRenderPassAttribs.pRenderPass = ctx.pRenderPass; - beginRenderPassAttribs.ClearValueCount = 2; - OptimizedClearValue optimizedClearValues[2]; - optimizedClearValues[0].Color[0] = ClearColor[0]; - optimizedClearValues[0].Color[1] = ClearColor[1]; - optimizedClearValues[0].Color[2] = ClearColor[2]; - optimizedClearValues[0].Color[3] = ClearColor[3]; - optimizedClearValues[1].DepthStencil.Depth = 1.f; - optimizedClearValues[1].DepthStencil.Stencil = 0; - - beginRenderPassAttribs.pClearValues = optimizedClearValues; - beginRenderPassAttribs.StateTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; - - ctx.pContext->BeginRenderPass(beginRenderPassAttribs); - - Viewport vp = {0, 0, (float)ctx.pSwapChain->GetDesc().Width, (float)ctx.pSwapChain->GetDesc().Height, 0, 1}; - ctx.pContext->SetViewports(1, &vp, ctx.pSwapChain->GetDesc().Width, ctx.pSwapChain->GetDesc().Height); - - ctx.pContext->SetPipelineState(ctx.pPSO); - - DrawAttribs drawAttrs; - drawAttrs.NumVertices = 3; - drawAttrs.Flags = DRAW_FLAG_VERIFY_ALL; - ctx.pContext->Draw(drawAttrs); - - ctx.pContext->EndRenderPass(); - - ctx.pContext->Flush(); - - ctx.pSwapChain->Present(); - - swapBuffersCount++; + const auto& SCDesc = MG_Diligent::g_pSwapChain->GetDesc(); + MG_Util::Debug::LogD("Setting viewport: width=%d, height=%d", SCDesc.Width, SCDesc.Height); + MG_Diligent::g_pContext->SetViewports(1, nullptr, 0, 0); return EGL_TRUE; } @@ -382,6 +706,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) return (__eglMustCastToProperFunctionPointerType)(&eglGetProcAddress); } +#define MG_EGL_PROC_EXPORT(name) \ + if (strncmp(procname, #name, strlen(#name)) == 0) { \ + return (__eglMustCastToProperFunctionPointerType)(&MG_EGL::Diligent::name); \ + } + MG_EGL_PROC_EXPORT(eglCreateWindowSurface); MG_EGL_PROC_EXPORT(eglChooseConfig); MG_EGL_PROC_EXPORT(eglCreateContext); @@ -401,6 +730,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) MG_EGL_PROC_EXPORT(eglSwapInterval); MG_EGL_PROC_EXPORT(eglSwapBuffers); MG_EGL_PROC_EXPORT(eglCreatePbufferSurface); +#undef MG_EGL_PROC_EXPORT /* TODO: Call real eglGetProcAddress() to get the rest (should be real native GLES functions) */ if (!libEGL) { @@ -411,4 +741,4 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) return real_eglGetProcAddress(procname); return nullptr; -} +} \ No newline at end of file diff --git a/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.h b/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.h index b483b329..0050b517 100644 --- a/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.h +++ b/MG/MG_GL/Implementations/EGL/Diligent/EGL_impl.h @@ -2,30 +2,254 @@ // Created by Swung 0x48 on 2025-05-18. // -#ifndef MOBILEGL_EGL_IMPL_H -#define MOBILEGL_EGL_IMPL_H +#ifndef MOBILEGL_DILIGENT_EGL_IMPL_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../../Includes.h" #include "DiligentConfig.h" #if BACKEND_TYPE == BACKEND_DILIGENT -namespace MG_EGL::Diligent { - struct DeviceContext { - public: - ::Diligent::RefCntAutoPtr<::Diligent::IRenderDevice> pDevice; - ::Diligent::RefCntAutoPtr<::Diligent::IDeviceContext> pContext; - ::Diligent::RefCntAutoPtr<::Diligent::ISwapChain> pSwapChain; - ::Diligent::RefCntAutoPtr<::Diligent::IPipelineState> pPSO; - ::Diligent::RefCntAutoPtr<::Diligent::IRenderPass> pRenderPass; - std::vector<::Diligent::RefCntAutoPtr<::Diligent::IFramebuffer>> pFramebuffers; - bool initialized = false; - int majorVer = 1; - int minorVer = 5; +namespace MG_Diligent { + extern Diligent::IRenderDevice* g_pDevice; + extern Diligent::IDeviceContext* g_pContext; + extern Diligent::ISwapChain* g_pSwapChain; + extern MG_Global::unordered_map g_BufferMap; + extern MG_Global::unordered_map g_TextureMap; + extern MG_Global::unordered_map g_TextureViewMap; + extern MG_Global::unordered_map g_BufferMap; + + struct GLFramebufferInfo + { + Diligent::IFramebuffer* pFramebuffer = nullptr; + Diligent::IRenderPass* pRenderPass = nullptr; + std::vector ColorRTVs; + Diligent::ITextureView* pDepthStencilRTV = nullptr; + Diligent::TEXTURE_FORMAT DepthStencilFormat = Diligent::TEX_FORMAT_UNKNOWN; + bool HasDepthStencil = false; + std::vector ClearValues; + // ... + }; + extern MG_Global::unordered_map g_FramebufferMap; + extern MG_Global::unordered_map g_ShaderMap; + struct GLProgramInfo + { + GLuint id; + std::vector AttachedShaders; + std::vector AttachedShadersID; + Diligent::IPipelineState* pPipelineState = nullptr; + Diligent::IShaderResourceBinding* pResourceBinding = nullptr; + uint64_t psoStateHash = 0; + bool psoDirty = true; + std::vector inputLayout; + GLuint DefaultFBO = 0; + ProgramObject programObj; + Diligent::IBuffer* pDefaultUBO = nullptr; + std::unordered_map uniformStages; + std::unordered_map uniformOffsets; + // ... + }; + extern MG_Global::unordered_map g_ProgramMap; + + extern MG_Global::unordered_map g_SamplerMap; + extern MG_Global::unordered_map g_UniformBufferMap; + + 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()(key.programHash) ^ + std::hash()(key.stateHash); + } + }; + + std::unordered_map psoCache; + + public: + Diligent::IPipelineState *GetOrCreatePSO( + GLuint program, + GLProgramInfo &programInfo, + CommonState &commonState, + VertexArrayState &vaState, + GLFramebufferInfo& fbInfo); + + 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) { + uint64_t hash = 0; + + MG_Global::unordered_map capabilities = commonState.capabilities; + + hash ^= std::hash()(commonState.blendSrcRGB); + hash ^= std::hash()(commonState.blendDstRGB); + hash ^= std::hash()(commonState.blendSrcAlpha); + hash ^= std::hash()(commonState.blendDstAlpha); + hash ^= std::hash()(capabilities[GL_BLEND]); + + hash ^= std::hash()(commonState.depthFunc); + hash ^= std::hash()(commonState.depthMask); + hash ^= std::hash()(capabilities[GL_DEPTH_TEST]); + + hash ^= std::hash()(0); // TODO: Cull Face Mode + hash ^= std::hash()(capabilities[GL_CULL_FACE]); + + hash ^= std::hash()(capabilities[GL_STENCIL_TEST]); + + auto *pVAO = vaState.GetCurrentVAO(); + for (const auto &[index, attrib]: pVAO->attribs) { + if (attrib.enabled) { + hash ^= std::hash()(index); + hash ^= std::hash()(attrib.size); + hash ^= std::hash()(attrib.type); + hash ^= std::hash()(attrib.normalized); + } + } + + hash ^= std::hash()(fbInfo.ColorRTVs.size()); + for (const auto& rtv : fbInfo.ColorRTVs) { + if (rtv) { + hash ^= std::hash()(rtv->GetDesc().Format); + } + } + + hash ^= std::hash()(fbInfo.DepthStencilFormat); + + return hash; + } + + void ConfigurePSO( + Diligent::GraphicsPipelineStateCreateInfo &PSOCreateInfo, + GLProgramInfo &programInfo, + CommonState &commonState, + VertexArrayState &vaState, + GLFramebufferInfo& fbInfo); + + void ConfigureResourceLayout( + Diligent::GraphicsPipelineStateCreateInfo& PSOCreateInfo, + const GLProgramInfo& programInfo); }; - static struct DeviceContext ctx; + extern PipelineStateManager g_PSOManager; + + extern bool initialized; + extern bool IsInRenderPass; +} + +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); @@ -48,14 +272,9 @@ namespace MG_EGL::Diligent { EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); } -#define MG_EGL_PROC_EXPORT(name) \ - if (strncmp(procname, #name, strlen(#name)) == 0) { \ - return (__eglMustCastToProperFunctionPointerType)(&MG_EGL::Diligent::name); \ - } - MG_EXPORT __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname); #endif -#endif //MOBILEGL_EGL_IMPL_H +#endif //MOBILEGL_DILIGENT_EGL_IMPL_H diff --git a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp index 31273952..f91399a8 100644 --- a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp +++ b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp @@ -11,9 +11,9 @@ std::atomic g_nextSurfaceId{1}; EGLenum g_currentAPI = EGL_OPENGL_ES_API; std::mutex g_globalMutex; -ankerl::unordered_map g_displays; -ankerl::unordered_map g_surfaces; -ankerl::unordered_map g_contexts; +MG_Global::unordered_map g_displays; +MG_Global::unordered_map g_surfaces; +MG_Global::unordered_map g_contexts; EGLint g_lastError = EGL_SUCCESS; thread_local EGLContext tls_currentContext = EGL_NO_CONTEXT; diff --git a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h index 71728b96..228f426b 100644 --- a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h +++ b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h @@ -69,9 +69,9 @@ extern std::atomic g_nextSurfaceId; extern EGLenum g_currentAPI; extern std::mutex g_globalMutex; -extern ankerl::unordered_map g_displays; -extern ankerl::unordered_map g_surfaces; -extern ankerl::unordered_map g_contexts; +extern MG_Global::unordered_map g_displays; +extern MG_Global::unordered_map g_surfaces; +extern MG_Global::unordered_map g_contexts; extern EGLint g_lastError; extern thread_local EGLContext tls_currentContext; diff --git a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp index a878e6cc..9544c298 100644 --- a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp +++ b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp @@ -5,6 +5,15 @@ #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", @@ -31,6 +40,30 @@ namespace MG_GL::GL { static_cast(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->buffers_[buffer]; + if (!bufferObj.isMapped) return; + + size_t start = static_cast(offset); + size_t end = start + static_cast(length); + + Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; + if (pBuffer && bufferObj.data.size() >= end) { + void * data; + MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE, + Diligent::MAP_FLAG_NONE, data); + + if (data) { + void* dst = static_cast(data) + offset; + const void* src = bufferObj.data.data() + offset; + memcpy(dst, src, length); + + MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE); + } + } + return; } MG_State::SetError(result); @@ -50,6 +83,22 @@ namespace MG_GL::GL { static_cast(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; + + Diligent::IBuffer* pSrcBuffer = MG_Diligent::g_BufferMap[srcBuffer]; + Diligent::IBuffer* pDstBuffer = MG_Diligent::g_BufferMap[dstBuffer]; + + if (pSrcBuffer && pDstBuffer) { + MG_Diligent::g_pContext->CopyBuffer(pSrcBuffer, static_cast(readOffset), + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + pDstBuffer, static_cast(writeOffset), + static_cast(size), + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + } + return; } MG_State::SetError(result); @@ -78,6 +127,22 @@ 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->buffers_[buffer]; + + Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; + if (pBuffer) { + void * data; + MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE, + Diligent::MAP_FLAG_NONE, data); + + if (data) { + memcpy(data, bufferObj.data.data(), bufferObj.data.size()); + MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE); + } + } + MG_Util::Debug::LogD("glUnmapBuffer succeeded"); return GL_TRUE; } @@ -112,8 +177,82 @@ 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) + if (result == GL_NO_ERROR) { + GLuint buffer = MG_State_T::bufferState->GetCurrentBinding(target); + if (buffer == 0) return; + + Diligent::IBuffer*& pBuffer = MG_Diligent::g_BufferMap[buffer]; + + Diligent::BufferDesc BuffDesc; + BuffDesc.Name = "Buffer"; + BuffDesc.Size = static_cast(size); + + switch (target) { + case GL_ARRAY_BUFFER: + BuffDesc.BindFlags = Diligent::BIND_VERTEX_BUFFER; + break; + case GL_ELEMENT_ARRAY_BUFFER: + BuffDesc.BindFlags = Diligent::BIND_INDEX_BUFFER; + break; + case GL_UNIFORM_BUFFER: + BuffDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER; + break; + default: + BuffDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE; + break; + } + + switch (usage) { + case GL_STATIC_DRAW: + BuffDesc.Usage = Diligent::USAGE_UNIFIED; + BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; + break; + case GL_DYNAMIC_DRAW: + BuffDesc.Usage = Diligent::USAGE_UNIFIED; + BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; + break; + case GL_STREAM_DRAW: + BuffDesc.Usage = Diligent::USAGE_UNIFIED; + BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; + break; + default: + BuffDesc.Usage = Diligent::USAGE_DEFAULT; + break; + } + + if (pBuffer == nullptr) { + Diligent::BufferData BuffData; + // Initial data must not be null for immutable buffers + if (BuffDesc.Usage == Diligent::USAGE_IMMUTABLE) { + BuffData.pData = data; + } + else { + BuffData.pData = nullptr; + } + BuffData.DataSize = static_cast(size); + MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, &BuffData, &pBuffer); + } + + if (data != nullptr) { + if (BuffDesc.Usage == Diligent::USAGE_DEFAULT || + BuffDesc.Usage == Diligent::USAGE_SPARSE) { + MG_Diligent::g_pContext->UpdateBuffer(pBuffer, 0, + static_cast(size), data, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + } else if (BuffDesc.Usage == Diligent::USAGE_UNIFIED || + BuffDesc.Usage == Diligent::USAGE_STAGING || + BuffDesc.Usage == Diligent::USAGE_DYNAMIC) { + void *pMappedData = nullptr; + MG_Diligent::g_pContext->MapBuffer(pBuffer, Diligent::MAP_WRITE, + Diligent::MAP_FLAG_NONE, pMappedData); + if (pMappedData) { + memcpy(pMappedData, data, size); + MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE); + } + } + } return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -140,8 +279,9 @@ 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; } @@ -174,13 +314,32 @@ 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; + + Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; + if (pBuffer) { + MG_Diligent::g_pContext->UpdateBuffer(pBuffer, static_cast(offset), + static_cast(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) + if (result == GL_NO_ERROR) { + for (GLsizei i = 0; i < n; ++i) { + GLuint buffer = buffers[i]; + if (buffer != 0) { + Diligent::IBuffer* pBuffer = MG_Diligent::g_BufferMap[buffer]; + if (pBuffer) pBuffer->Release(); + MG_Diligent::g_BufferMap.erase(buffer); + } + } return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); diff --git a/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp b/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp index 6e3f5b0d..a4a9a979 100644 --- a/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp +++ b/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp @@ -6,19 +6,73 @@ namespace MG_GL::GL { void Clear(GLbitfield mask) { - MG_Util::Debug::LogD("glClear, mask: 0x%X", mask); - GLenum result = MG_State::glClear(mask); - if (result == GL_NO_ERROR) { + 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); return; } - MG_State::SetError(result); - MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result)); + + MG_Diligent::GLFramebufferInfo& fbInfo = it->second; + auto& commonState = *MG_State_T::commonState; + + /*if (!MG_Diligent::IsInRenderPass) { + if (fbInfo.pRenderPass && fbInfo.pFramebuffer) { + Diligent::BeginRenderPassAttribs beginRenderPassAttribs; + beginRenderPassAttribs.pFramebuffer = fbInfo.pFramebuffer; + beginRenderPassAttribs.pRenderPass = fbInfo.pRenderPass; + beginRenderPassAttribs.StateTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + beginRenderPassAttribs.ClearValueCount = fbInfo.ClearValues.size(); + beginRenderPassAttribs.pClearValues = fbInfo.ClearValues.data(); + + MG_Diligent::g_pContext->BeginRenderPass(beginRenderPassAttribs); + MG_Diligent::IsInRenderPass = true; + } else { + MG_Util::Debug::LogE("Cannot begin render pass for framebuffer: %u", drawFramebuffer); + return; + } + }*/ + + if (mask & GL_COLOR_BUFFER_BIT) { + for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) { + if (fbInfo.ColorRTVs[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_Diligent::g_pContext->ClearDepthStencil( + fbInfo.pDepthStencilRTV, + static_cast(clearFlags), + commonState.clearDepth, + 0, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); + } + } } - + 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error enabling capability: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -26,7 +80,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error disabling capability: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -36,7 +93,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting blend func: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -48,7 +108,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting separate blend func: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -56,7 +119,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting clear color: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -64,7 +130,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting clear depth: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -72,7 +141,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting color mask: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -80,7 +152,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting depth func: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -88,7 +163,10 @@ 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) return; + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error setting depth mask: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -97,7 +175,9 @@ 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)); } @@ -105,8 +185,10 @@ namespace MG_GL::GL { void PixelStorei(GLenum pname, GLint param) { MG_Util::Debug::LogD("glPixelStorei, pname: %d, param: %d", pname, param); GLenum result = MG_State::SetPixelStoreInt(pname,param); - if (result == GL_NO_ERROR) + if (result == GL_NO_ERROR) { + MG_Diligent::g_PSOManager.MarkPSODirty(MG_State_T::programState->currentProgram_); return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp index 290a8706..7cdbeb20 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp @@ -5,10 +5,500 @@ #include "GL_Drawing.h" namespace MG_GL::GL { - void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) { - // TODO + void CreateRenderPassAndFramebuffer(GLuint framebuffer, + const FramebufferObject& fbo, + MG_Diligent::GLFramebufferInfo& fbInfo); + + inline bool IsSamplerType(GLenum type) { + switch (type) { + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + return true; + default: + return false; + } + } + + inline size_t GetUniformSize(GLenum type) { + switch (type) { + case GL_FLOAT: return sizeof(float); + case GL_FLOAT_VEC2: return 2 * sizeof(float); + case GL_FLOAT_VEC3: return 3 * sizeof(float); + case GL_FLOAT_VEC4: return 4 * sizeof(float); + case GL_FLOAT_MAT2: return 4 * sizeof(float); + case GL_FLOAT_MAT3: return 9 * sizeof(float); + case GL_FLOAT_MAT4: return 16 * sizeof(float); + case GL_INT: + case GL_BOOL: + return sizeof(int); + case GL_INT_VEC2: return 2 * sizeof(int); + case GL_INT_VEC3: return 3 * sizeof(int); + case GL_INT_VEC4: return 4 * sizeof(int); + case GL_UNSIGNED_INT: return sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC2: return 2 * sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC3: return 3 * sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC4: return 4 * sizeof(uint32_t); + // case GL_DOUBLE: return sizeof(double); // Not supported + // case GL_DOUBLE_VEC2: return 2 * sizeof(double); // Not supported + // case GL_DOUBLE_VEC3: return 3 * sizeof(double); // Not supported + // case GL_DOUBLE_VEC4: return 4 * sizeof(double); // Not supported + default: return 0; + } } + inline size_t AlignSize(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); + } + + inline Diligent::SHADER_TYPE GetDiligentShaderType(GLenum shaderType) { + switch (shaderType) { + case GL_VERTEX_SHADER: + return Diligent::SHADER_TYPE_VERTEX; + case GL_FRAGMENT_SHADER: + return Diligent::SHADER_TYPE_PIXEL; + case GL_GEOMETRY_SHADER: + return Diligent::SHADER_TYPE_GEOMETRY; + case GL_COMPUTE_SHADER: + return Diligent::SHADER_TYPE_COMPUTE; + case GL_TESS_CONTROL_SHADER: + return Diligent::SHADER_TYPE_DOMAIN; + case GL_TESS_EVALUATION_SHADER: + return Diligent::SHADER_TYPE_HULL; + default: + return Diligent::SHADER_TYPE_UNKNOWN; + } + } + + Diligent::SHADER_TYPE GetShaderStageForUniform(GLuint program, const std::string& name) { + auto& programInfo = MG_Diligent::g_ProgramMap[program]; + auto& programObj = MG_State_T::programState->programs_[program]; + + auto it = programInfo.uniformStages.find(name); + if (it != programInfo.uniformStages.end()) { + return it->second; + } + + Diligent::SHADER_TYPE stage = Diligent::SHADER_TYPE_ALL; + + for (auto shader : programInfo.AttachedShadersID) { + auto& shaderObj = MG_State_T::programState->shaders_[shader]; + if (shaderObj.compiledSpirv.empty()) continue; + + spvc_context context = nullptr; + spvc_parsed_ir parsed_ir = nullptr; + spvc_compiler compiler = nullptr; + spvc_resources resources = nullptr; + + spvc_result result = spvc_context_create(&context); + if (result != SPVC_SUCCESS) continue; + + result = spvc_context_parse_spirv(context, + reinterpret_cast(shaderObj.compiledSpirv.data()), + shaderObj.compiledSpirv.size() / sizeof(SpvId), + &parsed_ir); + + if (result != SPVC_SUCCESS) { + spvc_context_destroy(context); + continue; + } + + result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, + parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler); + + if (result != SPVC_SUCCESS) { + spvc_context_destroy(context); + continue; + } + + result = spvc_compiler_create_shader_resources(compiler, &resources); + if (result != SPVC_SUCCESS) { + spvc_context_destroy(context); + continue; + } + + const spvc_reflected_resource* resourceList = nullptr; + size_t resourceCount = 0; + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, + &resourceList, &resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + if (strcmp(resourceList[i].name, name.c_str()) == 0) { + stage = GetDiligentShaderType(shaderObj.type); + break; + } + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, + &resourceList, &resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + if (strcmp(resourceList[i].name, name.c_str()) == 0) { + stage = GetDiligentShaderType(shaderObj.type); + break; + } + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE, + &resourceList, &resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + if (strcmp(resourceList[i].name, name.c_str()) == 0) { + stage = GetDiligentShaderType(shaderObj.type); + break; + } + } + + spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS, + &resourceList, &resourceCount); + + for (size_t i = 0; i < resourceCount; i++) { + if (strcmp(resourceList[i].name, name.c_str()) == 0) { + stage = GetDiligentShaderType(shaderObj.type); + break; + } + } + + spvc_context_destroy(context); + } + if (stage == Diligent::SHADER_TYPE_ALL) + stage = Diligent::SHADER_TYPE_VERTEX; + programInfo.uniformStages[name] = stage; + + return stage; + } + + void UpdateSamplerAndTextureUniforms(GLuint program) { + auto& programInfo = MG_Diligent::g_ProgramMap[program]; + auto& programObj = MG_State_T::programState->programs_[program]; + + if (!programInfo.pResourceBinding) return; + + for (auto& [name, uniform] : programObj.uniformValues) { + if (!IsSamplerType(uniform.type)) continue; + + Diligent::IShaderResourceVariable* pVar = + programInfo.pResourceBinding->GetVariableByName( + GetShaderStageForUniform(program, name.c_str()), name.c_str()); + + if (!pVar) continue; + + GLuint textureID = 0; + if (!uniform.intData.empty()) { + textureID = static_cast(uniform.intData[0]); + } + + Diligent::ITextureView* pTextureView = nullptr; + if (textureID != 0) { + auto it = MG_Diligent::g_TextureViewMap.find(textureID); + if (it != MG_Diligent::g_TextureViewMap.end()) { + pTextureView = it->second; + } + } + + if (pTextureView) { + pVar->Set(pTextureView); + } + } + } + + void UpdateUniformsToDefaultUBO(GLuint program) { + MG_Util::Debug::LogD("Updating uniforms to default UBO for program %u", program); + auto& programInfo = MG_Diligent::g_ProgramMap[program]; + auto& programObj = MG_State_T::programState->programs_[program]; + + if (programObj.uniformValues.empty() || !programInfo.pDefaultUBO) { + return; + } + + void * mapped; + MG_Util::Debug::LogD("Mapping UBO for program %u", program); + MG_Diligent::g_pContext->MapBuffer(programInfo.pDefaultUBO, Diligent::MAP_WRITE, + Diligent::MAP_FLAG_DISCARD, mapped); + + if (mapped) { + MG_Util::Debug::LogD("UBO mapped successfully for program %u. Updating uniform values.", program); + uint8_t* uboData = static_cast(mapped); + + for (auto& [name, uniform] : programObj.uniformValues) { + if (IsSamplerType(uniform.type)) continue; + + auto it = programInfo.uniformOffsets.find(name); + if (it != programInfo.uniformOffsets.end()) { + size_t offset = it->second; + // MG_Util::Debug::LogD("Updating uniform '%s' at offset %zu for program %u", name.c_str(), offset, program); + + switch (uniform.type) { + case GL_FLOAT: + *reinterpret_cast(uboData + offset) = uniform.floatData[0]; + break; + case GL_FLOAT_VEC2: + memcpy(uboData + offset, uniform.floatData.data(), 2 * sizeof(float)); + break; + case GL_FLOAT_VEC3: + memcpy(uboData + offset, uniform.floatData.data(), 3 * sizeof(float)); + break; + case GL_FLOAT_VEC4: + memcpy(uboData + offset, uniform.floatData.data(), 4 * sizeof(float)); + break; + case GL_FLOAT_MAT2: + memcpy(uboData + offset, uniform.floatData.data(), 4 * sizeof(float)); + break; + case GL_FLOAT_MAT3: + memcpy(uboData + offset, uniform.floatData.data(), 9 * sizeof(float)); + break; + case GL_FLOAT_MAT4: + memcpy(uboData + offset, uniform.floatData.data(), 16 * sizeof(float)); + break; + case GL_INT: + case GL_BOOL: + *reinterpret_cast(uboData + offset) = uniform.intData[0]; + break; + case GL_INT_VEC2: + memcpy(uboData + offset, uniform.intData.data(), 2 * sizeof(int)); + break; + case GL_INT_VEC3: + memcpy(uboData + offset, uniform.intData.data(), 3 * sizeof(int)); + break; + case GL_INT_VEC4: + memcpy(uboData + offset, uniform.intData.data(), 4 * sizeof(int)); + break; + case GL_UNSIGNED_INT: + *reinterpret_cast(uboData + offset) = uniform.uintData[0]; + break; + case GL_UNSIGNED_INT_VEC2: + memcpy(uboData + offset, uniform.uintData.data(), 2 * sizeof(uint32_t)); + break; + case GL_UNSIGNED_INT_VEC3: + memcpy(uboData + offset, uniform.uintData.data(), 3 * sizeof(uint32_t)); + break; + case GL_UNSIGNED_INT_VEC4: + memcpy(uboData + offset, uniform.uintData.data(), 4 * sizeof(uint32_t)); + break; + + // Not supported types + // case GL_DOUBLE: + // *reinterpret_cast(uboData + offset) = uniform.doubleData[0]; + // break; + // case GL_DOUBLE_VEC2: + // memcpy(uboData + offset, uniform.doubleData.data(), 2 * sizeof(double)); + // break; + // case GL_DOUBLE_VEC3: + // memcpy(uboData + offset, uniform.doubleData.data(), 3 * sizeof(double)); + // break; + // case GL_DOUBLE_VEC4: + // memcpy(uboData + offset, uniform.doubleData.data(), 4 * sizeof(double)); + // break; + // case GL_DOUBLE_MAT2: + // memcpy(uboData + offset, uniform.doubleData.data(), 4 * sizeof(double)); + // break; + // case GL_DOUBLE_MAT3: + // memcpy(uboData + offset, uniform.doubleData.data(), 9 * sizeof(double)); + // break; + // case GL_DOUBLE_MAT4: + // memcpy(uboData + offset, uniform.doubleData.data(), 16 * sizeof(double)); + // break; + // ... + } + } + } + MG_Util::Debug::LogD("Finished updating uniform values in UBO for program %u.", program); + } else { + MG_Util::Debug::LogE("Failed to map UBO for program %u.", program); + } + + MG_Util::Debug::LogD("Unmapping UBO for program %u", program); + MG_Diligent::g_pContext->UnmapBuffer(programInfo.pDefaultUBO, Diligent::MAP_WRITE); + } + + void EnsureRenderPassActive() { + MG_Util::Debug::LogD("EnsureRenderPassActive called."); + if (MG_Diligent::IsInRenderPass) { + MG_Util::Debug::LogD("Render pass is already active."); + return; + } + + MG_Util::Debug::LogD("Render pass is not active, attempting to begin one."); + GLuint drawFB = MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]; + if (drawFB == 0) { + MG_Util::Debug::LogD("drawFB is 0, using default framebuffer (0)."); + drawFB = 0; + } + + auto it = MG_Diligent::g_FramebufferMap.find(drawFB); + if (it == MG_Diligent::g_FramebufferMap.end()) { + MG_Util::Debug::LogE("Framebuffer %u not found in g_FramebufferMap.", drawFB); + return; + } + + MG_Util::Debug::LogD("Found framebuffer %u in g_FramebufferMap.", drawFB); + MG_Diligent::GLFramebufferInfo& fbInfo = it->second; + + if (!fbInfo.pRenderPass || !fbInfo.pFramebuffer) { + MG_Util::Debug::LogD("RenderPass or Framebuffer not yet created for FBO %u. Creating now.", drawFB); + FramebufferObject* pFBO = MG_State_T::framebufferState->GetCurrentFBO(GL_DRAW_FRAMEBUFFER); + if (!pFBO) { + MG_Util::Debug::LogE("No current FBO found for GL_DRAW_FRAMEBUFFER when trying to create RenderPass/Framebuffer."); + return; + } + CreateRenderPassAndFramebuffer(drawFB, *pFBO, fbInfo); + if (!fbInfo.pRenderPass || !fbInfo.pFramebuffer) { + MG_Util::Debug::LogE("Failed to create RenderPass or Framebuffer for FBO %u.", drawFB); + return; + } + MG_Util::Debug::LogD("Successfully created RenderPass and Framebuffer for FBO %u.", drawFB); + } + + MG_Util::Debug::LogD("Proceeding to begin render pass for FBO %u.", drawFB); + if (fbInfo.pRenderPass && fbInfo.pFramebuffer) { + Diligent::BeginRenderPassAttribs beginRenderPassAttribs; + beginRenderPassAttribs.pFramebuffer = fbInfo.pFramebuffer; + beginRenderPassAttribs.pRenderPass = fbInfo.pRenderPass; + beginRenderPassAttribs.StateTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + beginRenderPassAttribs.ClearValueCount = fbInfo.ClearValues.size(); + beginRenderPassAttribs.pClearValues = fbInfo.ClearValues.data(); + + MG_Diligent::g_pContext->BeginRenderPass(beginRenderPassAttribs); + MG_Diligent::IsInRenderPass = true; + } else { + MG_Util::Debug::LogE("RenderPass or Framebuffer not yet created for FBO %u.", drawFB); + } + } + + void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { + GLuint program = MG_State::GetCurrentProgram(); + MG_Util::Debug::LogD("DrawElements called with mode: %d, count: %d, type: %d, program: %u", mode, count, type, program); + if (program == 0) { + MG_Util::Debug::LogE("No active program for DrawElements"); + return; + } + + auto& programInfo = MG_Diligent::g_ProgramMap[program]; + + GLuint drawFB = MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]; + if (drawFB == 0) drawFB = 0; + + auto itFB = MG_Diligent::g_FramebufferMap.find(drawFB); + if (itFB == MG_Diligent::g_FramebufferMap.end()) { + MG_Util::Debug::LogE("Framebuffer not found: %u", drawFB); + return; + } + MG_Diligent::GLFramebufferInfo& fbInfo = itFB->second; + + MG_Util::Debug::LogD("Fetching PSO for program %u", program); + programInfo.pPipelineState = MG_Diligent::g_PSOManager.GetOrCreatePSO( + program, + programInfo, + *MG_State_T::commonState, + *MG_State_T::vertexArrayState, + fbInfo + ); + + if (!programInfo.pPipelineState) { + MG_Util::Debug::LogE("Failed to get or create PSO for program %u", program); + return; + } + MG_Util::Debug::LogD("Successfully obtained PSO for program %u", program); + + if (!programInfo.pResourceBinding) { + MG_Util::Debug::LogD("Creating ShaderResourceBinding for program %u", program); + programInfo.pPipelineState->CreateShaderResourceBinding( + &programInfo.pResourceBinding, true); + if (!programInfo.pResourceBinding) { + MG_Util::Debug::LogE("Failed to create ShaderResourceBinding for program %u", program); + return; + } + MG_Util::Debug::LogD("Successfully created ShaderResourceBinding for program %u", program); + } + + MG_Diligent::g_pContext->SetPipelineState(programInfo.pPipelineState); + + auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); + if (pVAO) { + std::vector vertexBuffers; + std::vector offsets; + for (auto& attrib : pVAO->attribs) { + if (!attrib.second.enabled) { + MG_Util::Debug::LogD("Vertex attribute %u is not enabled, skipping.", attrib.first); + continue; + } + + GLuint buffer = attrib.second.buffer; + if (buffer != 0) { + MG_Util::Debug::LogD("Processing vertex attribute %u with buffer %u", attrib.first, buffer); + auto it = MG_Diligent::g_BufferMap.find(buffer); + if (it != MG_Diligent::g_BufferMap.end()) { + MG_Util::Debug::LogD("Found buffer %u in g_BufferMap", buffer); + vertexBuffers.push_back(it->second); + offsets.push_back(static_cast( + reinterpret_cast(attrib.second.pointer))); + } else { + MG_Util::Debug::LogW("Buffer %u not found in g_BufferMap for vertex attribute %u", buffer, attrib.first); + } + } + } + + if (!vertexBuffers.empty()) { + MG_Util::Debug::LogD("Setting %zu vertex buffers", vertexBuffers.size()); + MG_Diligent::g_pContext->SetVertexBuffers( + 0, vertexBuffers.size(), vertexBuffers.data(), + (const Diligent::Uint64*) offsets.data(), + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + Diligent::SET_VERTEX_BUFFERS_FLAG_RESET + ); + } + + if (pVAO->elementBuffer != 0) { + MG_Util::Debug::LogD("Processing element buffer %u", pVAO->elementBuffer); + auto it = MG_Diligent::g_BufferMap.find(pVAO->elementBuffer); + if (it != MG_Diligent::g_BufferMap.end()) { + MG_Util::Debug::LogD("Found element buffer %u in g_BufferMap, setting index buffer.", pVAO->elementBuffer); + MG_Diligent::g_pContext->SetIndexBuffer( + it->second, 0, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); + } else { + MG_Util::Debug::LogW("Element buffer %u not found in g_BufferMap.", pVAO->elementBuffer); + } + } + } else { + MG_Util::Debug::LogD("No current VAO found."); + } + + MG_Util::Debug::LogD("Updating uniforms for program %u", program); + UpdateUniformsToDefaultUBO(program); + UpdateSamplerAndTextureUniforms(program); + + MG_Util::Debug::LogD("Committing shader resources for program %u", program); + MG_Diligent::g_pContext->CommitShaderResources( + programInfo.pResourceBinding, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); + + MG_Util::Debug::LogD("Preparing to draw indexed for program %u", program); + Diligent::DrawIndexedAttribs drawAttrs; + drawAttrs.IndexType = ConvertGLTypeToDiligent(type); + drawAttrs.NumIndices = count; + drawAttrs.Flags = Diligent::DRAW_FLAG_VERIFY_ALL; + drawAttrs.IndexType = Diligent::VT_UINT32; + + EnsureRenderPassActive(); + MG_Diligent::g_pContext->DrawIndexed(drawAttrs); + + MG_Diligent::g_pContext->EndRenderPass(); + MG_Diligent::IsInRenderPass = false; + MG_Util::Debug::LogD("DrawIndexed completed."); + } + void DrawArrays(GLenum mode, GLint first, GLsizei count) { // TODO } diff --git a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp index 1f64313d..ea25b695 100644 --- a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp +++ b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp @@ -5,10 +5,225 @@ #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; + } + + for (auto& rtv : fbInfo.ColorRTVs) { + if (rtv) { + rtv->Release(); + rtv = nullptr; + } + } + fbInfo.ColorRTVs.clear(); + + if (fbInfo.pDepthStencilRTV) { + fbInfo.pDepthStencilRTV->Release(); + fbInfo.pDepthStencilRTV = 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::LogE("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 Attachments; + std::vector Subpasses; + std::vector ColorRefs; + + for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) { + if (fbInfo.ColorRTVs[i]) { + Diligent::RenderPassAttachmentDesc ColorAttachment; + ColorAttachment.Format = fbInfo.ColorRTVs[i]->GetDesc().Format; + 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(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(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(ColorRefs.size()); + Subpass.pRenderTargetAttachments = ColorRefs.empty() ? nullptr : ColorRefs.data(); + Subpass.pDepthStencilAttachment = fbInfo.pDepthStencilRTV ? &DepthRef : nullptr; + Subpasses.push_back(Subpass); + + RPDesc.AttachmentCount = static_cast(Attachments.size()); + RPDesc.pAttachments = Attachments.empty() ? nullptr : Attachments.data(); + RPDesc.SubpassCount = static_cast(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(Attachments.size()); + + std::vector 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: Creating Framebuffer '%s' with %u attachments, Dimensions: %ux%u.", + FBDesc.Name, FBDesc.AttachmentCount, FBDesc.Width, FBDesc.Height); + + 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) return; + if (result == GL_NO_ERROR) { + for (GLsizei i = 0; i < n; ++i) { + MG_Diligent::GLFramebufferInfo fbInfo; + MG_Diligent::g_FramebufferMap[framebuffers[i]] = fbInfo; + } + return; + }; MG_State::SetError(result); MG_Util::Debug::LogE("Framebuffer generation failed: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -21,6 +236,30 @@ 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); + } } } } @@ -29,7 +268,51 @@ namespace MG_GL::GL { 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) return; + if (result == GL_NO_ERROR) { + if (MG_Diligent::IsInRenderPass) { + MG_Diligent::g_pContext->EndRenderPass(); + MG_Diligent::IsInRenderPass = false; + } + + if (framebuffer == 0) { + UpdateDefaultFramebuffer(); + } + + FramebufferObject* pFBO = MG_State_T::framebufferState->GetCurrentFBO(target); + auto it = MG_Diligent::g_FramebufferMap.find(framebuffer); + + if (it == MG_Diligent::g_FramebufferMap.end()) { + MG_Util::Debug::LogE("Framebuffer %u not found in map", framebuffer); + return; + } + + MG_Diligent::GLFramebufferInfo& fbInfo = it->second; + + if (!fbInfo.pRenderPass || !fbInfo.pFramebuffer) { + CreateRenderPassAndFramebuffer(framebuffer, pFBO ? *pFBO : FramebufferObject(), fbInfo); + } + + MG_Diligent::g_pContext->SetRenderTargets( + static_cast(fbInfo.ColorRTVs.size()), + fbInfo.ColorRTVs.empty() ? nullptr : fbInfo.ColorRTVs.data(), + fbInfo.pDepthStencilRTV, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); + + if (fbInfo.pRenderPass && fbInfo.pFramebuffer) { + Diligent::BeginRenderPassAttribs beginRenderPassAttribs; + + beginRenderPassAttribs.pFramebuffer = fbInfo.pFramebuffer; + beginRenderPassAttribs.pRenderPass = fbInfo.pRenderPass; + beginRenderPassAttribs.ClearValueCount = fbInfo.ClearValues.size(); + beginRenderPassAttribs.pClearValues = fbInfo.ClearValues.data(); + beginRenderPassAttribs.StateTransitionMode = Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + + MG_Diligent::g_pContext->BeginRenderPass(beginRenderPassAttribs); + MG_Diligent::IsInRenderPass = true; + } + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Framebuffer bind error: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -42,11 +325,114 @@ namespace MG_GL::GL { MG_Util::Debug::GLEnumToString(textarget), texture, level); + GLuint currentFB = MG_State_T::framebufferState->currentBindings_[target]; + GLenum result = MG_State::AttachTexture2DToFramebuffer( target, attachment, textarget, texture, level ); - if (result == GL_NO_ERROR) return; + if (result == GL_NO_ERROR) { + auto it = MG_Diligent::g_FramebufferMap.find(currentFB); + if (it == MG_Diligent::g_FramebufferMap.end()) { + MG_Util::Debug::LogE("Framebuffer %u not found in map", currentFB); + 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; + 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(); + 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(); + 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); + } + } + } + + MG_Util::Debug::LogD("FramebufferTexture2D completed successfully"); + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Texture attachment failed: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -56,8 +442,7 @@ 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); @@ -68,6 +453,64 @@ 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) { - // TODO + 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); + } } -} \ No newline at end of file +} diff --git a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h index 1ecf9a43..30a38fb1 100644 --- a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h +++ b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h @@ -8,6 +8,8 @@ #include "../../../../Includes.h" namespace MG_GL::GL { + void UpdateDefaultFramebuffer(); + void GenFramebuffers(GLsizei n, GLuint* framebuffers); void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers); void BindFramebuffer(GLenum target, GLuint framebuffer); diff --git a/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp b/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp index 09e51c10..b6c0a424 100644 --- a/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp +++ b/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp @@ -4,13 +4,162 @@ #include "GL_Program.h" +#undef MOBILEGL_GLSLTOOL_H +#include "../../../../Includes.h" + namespace MG_GL::GL { + inline bool IsSamplerType(GLenum type) { + switch (type) { + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + return true; + default: + return false; + } + } + + inline size_t GetUniformSize(GLenum type) { + switch (type) { + case GL_FLOAT: return sizeof(float); + case GL_FLOAT_VEC2: return 2 * sizeof(float); + case GL_FLOAT_VEC3: return 3 * sizeof(float); + case GL_FLOAT_VEC4: return 4 * sizeof(float); + case GL_FLOAT_MAT2: return 4 * sizeof(float); + case GL_FLOAT_MAT3: return 9 * sizeof(float); + case GL_FLOAT_MAT4: return 16 * sizeof(float); + case GL_INT: + case GL_BOOL: + return sizeof(int); + case GL_INT_VEC2: return 2 * sizeof(int); + case GL_INT_VEC3: return 3 * sizeof(int); + case GL_INT_VEC4: return 4 * sizeof(int); + case GL_UNSIGNED_INT: return sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC2: return 2 * sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC3: return 3 * sizeof(uint32_t); + case GL_UNSIGNED_INT_VEC4: return 4 * sizeof(uint32_t); + default: return 0; + } + } + + inline size_t AlignSize(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); + } + + void CreateDefaultUBO(MG_Diligent::GLProgramInfo& programInfo) { + MG_Util::Debug::LogD("CreateDefaultUBO for program"); + size_t uboSize = 0; + std::vector uniformSizes; + + for (auto& [name, uniform] : programInfo.programObj.uniformValues) { + if (IsSamplerType(uniform.type)) continue; + + size_t size = GetUniformSize(uniform.type); + size_t alignedSize = AlignSize(size, 16); + uniformSizes.push_back(alignedSize); + MG_Util::Debug::LogD(" Uniform '%s': size = %zu, alignedSize = %zu", + name.c_str(), size, alignedSize); + uboSize += alignedSize; + } + + 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("No non-sampler uniforms found, default UBO not created."); + } + } + + void RecordUniformOffsets(MG_Diligent::GLProgramInfo& programInfo) { + MG_Util::Debug::LogD("RecordUniformOffsets for program"); + size_t offset = 0; + programInfo.uniformOffsets.clear(); + + for (auto& [name, uniform] : programInfo.programObj.uniformValues) { + if (IsSamplerType(uniform.type)) continue; + + size_t size = GetUniformSize(uniform.type); + size_t alignedSize = AlignSize(size, 16); + + programInfo.uniformOffsets[name] = offset; + MG_Util::Debug::LogD(" Uniform '%s': offset = %zu, size = %zu, alignedSize = %zu", + name.c_str(), offset, size, alignedSize); + offset += alignedSize; + } + } + + 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_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; + } + } + + GLint GetGLTypeComponentCount(GLenum type) { + switch (type) { + case GL_FLOAT: return 1; + case GL_FLOAT_VEC2: return 2; + case GL_FLOAT_VEC3: return 3; + case GL_FLOAT_VEC4: return 4; + case GL_INT: return 1; + case GL_INT_VEC2: return 2; + case GL_INT_VEC3: return 3; + case GL_INT_VEC4: return 4; + case GL_UNSIGNED_INT: return 1; + case GL_UNSIGNED_INT_VEC2: return 2; + case GL_UNSIGNED_INT_VEC3: return 3; + case GL_UNSIGNED_INT_VEC4: return 4; + case GL_FLOAT_MAT2: return 4; + case GL_FLOAT_MAT3: return 9; + case GL_FLOAT_MAT4: return 16; // 4 * 4 + case GL_FLOAT_MAT2x3: return 6; // 2 * 3 + case GL_FLOAT_MAT2x4: return 8; // 2 * 4 + case GL_FLOAT_MAT3x2: return 6; // 3 * 2 + case GL_FLOAT_MAT3x4: return 12; // 3 * 4 + case GL_FLOAT_MAT4x2: return 8; // 4 * 2 + case GL_FLOAT_MAT4x3: return 12; // 4 * 3 + default: return 0; + } + } + 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); @@ -34,7 +183,16 @@ 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) return; + if (result == GL_NO_ERROR) { + 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; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error deleting shader: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -42,7 +200,9 @@ namespace MG_GL::GL { 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)); } @@ -50,7 +210,9 @@ 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)); } @@ -65,16 +227,114 @@ 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 compiling shader: %s", MG_Util::Debug::GLEnumToString(result)); + MG_Util::Debug::LogE("Error marking shader for compilation: %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) return; + if (result == GL_NO_ERROR) { + auto& programInfo = MG_Diligent::g_ProgramMap[program]; + auto& programObj = MG_State_T::programState->programs_[program]; + + for (const auto& shaderId : programObj.attachedShaders) { + programInfo.AttachedShadersID.push_back(shaderId); + } + + MG_Global::unordered_map shaderSources; + for (GLuint shaderId : programInfo.AttachedShadersID) { + auto& shaderObj = MG_State_T::programState->shaders_[shaderId]; + shaderSources[shaderId] = shaderObj.source; + } + + MG_Util::Program::GenerateDefaultUBOForGLSL_Multi(shaderSources); + + // 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 = shaderSources[shaderId]; + + 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; + MG_Diligent::g_pDevice->CreateShader(ShaderCI, &pShader); + + 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", shaderId, program); + } + } else { + // Shader already compiled, just add to programInfo + programInfo.AttachedShaders.push_back(MG_Diligent::g_ShaderMap[shaderId]); + } + } + + programInfo.id = program; + programInfo.inputLayout.clear(); + + auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); + if (!pVAO) return; + + for (const auto& [index, attrib] : pVAO->attribs) { + 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(reinterpret_cast(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; + } + + CreateDefaultUBO(programInfo); + RecordUniformOffsets(programInfo); + + programObj.linked = true; + programObj.linkStatus = GL_TRUE; + return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error linking program: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -82,7 +342,9 @@ namespace MG_GL::GL { 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)); } diff --git a/MG/MG_GL/Implementations/GL/Program/GL_Program.h b/MG/MG_GL/Implementations/GL/Program/GL_Program.h index 23bb8a62..59ce953b 100644 --- a/MG/MG_GL/Implementations/GL/Program/GL_Program.h +++ b/MG/MG_GL/Implementations/GL/Program/GL_Program.h @@ -8,6 +8,8 @@ #include "../../../../Includes.h" namespace MG_GL::GL { + Diligent::VALUE_TYPE ConvertGLTypeToDiligent(GLenum type); + GLuint CreateShader(GLenum type); GLuint CreateProgram(); void DeleteShader(GLuint shader); diff --git a/MG/MG_GL/Implementations/GL/Texture/GL_Texture.cpp b/MG/MG_GL/Implementations/GL/Texture/GL_Texture.cpp index be4d7b6e..6abf50fb 100644 --- a/MG/MG_GL/Implementations/GL/Texture/GL_Texture.cpp +++ b/MG/MG_GL/Implementations/GL/Texture/GL_Texture.cpp @@ -5,6 +5,80 @@ #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::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: return Diligent::TEXTURE_ADDRESS_WRAP; + } + } + void ActiveTexture(GLenum texture) { MG_Util::Debug::LogD("glActiveTexture, texture: %d", texture); GLenum result = MG_State::BindTextureUnit(texture); @@ -17,8 +91,51 @@ 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) { + auto& texState = *MG_State_T::textureState; + auto activeUnit = texState.activeTextureUnit_; + auto unitState = &texState.textureUnits_[activeUnit]; + + GLuint boundTextureID = unitState->GetBoundTexture(target); + + if (boundTextureID == 0) { + auto it = MG_Diligent::g_TextureMap.find(texture); + if (it != MG_Diligent::g_TextureMap.end()) { + if (it->second) { + it->second->Release(); + it->second = nullptr; + } + } + return; + } + + auto it = MG_Diligent::g_TextureMap.find(boundTextureID); + if (it == MG_Diligent::g_TextureMap.end() || it->second == nullptr) { + Diligent::TextureDesc TexDesc; + TexDesc.Type = (target == GL_TEXTURE_2D) ? + Diligent::RESOURCE_DIM_TEX_2D : Diligent::RESOURCE_DIM_UNDEFINED; + TexDesc.Format = Diligent::TEX_FORMAT_RGBA8_UNORM; + TexDesc.Width = 1; + TexDesc.Height = 1; + TexDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE; + + Diligent::ITexture* pTexture = nullptr; + MG_Diligent::g_pDevice->CreateTexture(TexDesc, nullptr, &pTexture); + + Diligent::ITextureView* pSRV = nullptr; + if (pTexture) { + Diligent::TextureViewDesc SRVDesc; + SRVDesc.ViewType = Diligent::TEXTURE_VIEW_SHADER_RESOURCE; + SRVDesc.TextureDim = Diligent::RESOURCE_DIM_TEX_2D; + pTexture->CreateView(SRVDesc, &pSRV); + } + + MG_Diligent::g_TextureMap[boundTextureID] = pTexture; + MG_Diligent::g_TextureViewMap[boundTextureID] = pSRV; + MG_Util::Debug::LogD("Created placeholder Diligent texture for GL name %u", boundTextureID); + } return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -26,8 +143,27 @@ 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) + 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); + } + } return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } @@ -35,21 +171,144 @@ 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) + 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; + } return; + } MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } - 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) + + 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)); return; - MG_State::SetError(result); - MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + } + + 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); + auto srvIt = MG_Diligent::g_TextureViewMap.find(boundTextureID); + + if (texIt != MG_Diligent::g_TextureMap.end()) { + pTexture = texIt->second; + } + 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; + + 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 (existingDesc.Width != static_cast(width) || + existingDesc.Height != static_cast(height) || + existingDesc.Format != newFormat) { + MG_Util::Debug::LogD("TexImage2D: Texture 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); + + if (pSRV) { + pSRV->Release(); + MG_Diligent::g_TextureViewMap[boundTextureID] = nullptr; + } + if (pTexture) { + pTexture->Release(); + MG_Diligent::g_TextureMap[boundTextureID] = nullptr; + } + + needCreateTexture = true; + } + } + + if (needCreateTexture) { + Diligent::TextureDesc TexDesc; + TexDesc.Type = Diligent::RESOURCE_DIM_TEX_2D; + TexDesc.Width = width; + TexDesc.Height = height; + TexDesc.Format = newFormat; + TexDesc.BindFlags = Diligent::BIND_SHADER_RESOURCE; + + if (level > 0) { + TexDesc.MipLevels = level + 1; + } + + MG_Util::Debug::LogD("TexImage2D: Creating new Diligent texture with Width: %d, Height: %d, Format: %d", + width, height, newFormat); + MG_Diligent::g_pDevice->CreateTexture(TexDesc, nullptr, &pTexture); + + MG_Diligent::g_TextureMap[boundTextureID] = pTexture; + MG_Util::Debug::LogD("TexImage2D: Created new Diligent texture %p for GL name %u.", + (void*)pTexture, boundTextureID); + + if (pTexture) { + Diligent::TextureViewDesc SRVDesc; + SRVDesc.ViewType = Diligent::TEXTURE_VIEW_SHADER_RESOURCE; + SRVDesc.TextureDim = Diligent::RESOURCE_DIM_TEX_2D; + SRVDesc.MostDetailedMip = 0; + SRVDesc.NumMipLevels = TexDesc.MipLevels; + + pTexture->CreateView(SRVDesc, &pSRV); + MG_Diligent::g_TextureViewMap[boundTextureID] = pSRV; + MG_Util::Debug::LogD("TexImage2D: Created new SRV %p for texture.", (void*)pSRV); + } + } + + 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; + + 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."); + } } void TexParameterf(GLenum target, GLenum pname, GLfloat param) { @@ -64,21 +323,120 @@ namespace MG_GL::GL { 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) + if (result != GL_NO_ERROR) { + MG_State::SetError(result); + MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); return; - MG_State::SetError(result); - MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + } + + 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: + SamDesc.MinFilter = (param == GL_NEAREST) ? + Diligent::FILTER_TYPE_POINT : Diligent::FILTER_TYPE_LINEAR; + break; + case GL_TEXTURE_MAG_FILTER: + SamDesc.MagFilter = (param == GL_NEAREST) ? + Diligent::FILTER_TYPE_POINT : Diligent::FILTER_TYPE_LINEAR; + 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; + } + + 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); } 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) + if (result != GL_NO_ERROR) { + MG_State::SetError(result); + MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); return; - MG_State::SetError(result); - MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + } + + 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("TexSubImage2D: No texture bound. Skipping update."); + return; + } + + Diligent::ITexture* pTexture = MG_Diligent::g_TextureMap[boundTextureID]; + if (!pTexture) { + MG_Util::Debug::LogW("TexSubImage2D: Diligent texture not found for GL name %u", boundTextureID); + return; + } + + // 4. 更新纹理子区域 + Diligent::TextureSubResData SubResData; + SubResData.pData = pixels; + SubResData.Stride = width * GetBytesPerPixel(format, type); + + Diligent::Box UpdateBox; + UpdateBox.MinX = xoffset; + UpdateBox.MaxX = xoffset + width; + UpdateBox.MinY = yoffset; + UpdateBox.MaxY = yoffset + height; + + MG_Util::Debug::LogD("TexSubImage2D: Updating region [%d,%d]-[%d,%d] at level %d", + xoffset, yoffset, xoffset+width, yoffset+height, level); + + MG_Diligent::g_pContext->UpdateTexture( + pTexture, + level, + 0, + UpdateBox, + SubResData, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION + ); } void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params) { @@ -90,4 +448,4 @@ namespace MG_GL::GL { MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); } -} \ No newline at end of file +} diff --git a/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp b/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp index 94b8d0b8..1f28e37e 100644 --- a/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp +++ b/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp @@ -8,7 +8,9 @@ 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)); } diff --git a/MG/MG_GL/State/Buffer/BufferState.h b/MG/MG_GL/State/Buffer/BufferState.h index 1e49e6f8..15af2479 100644 --- a/MG/MG_GL/State/Buffer/BufferState.h +++ b/MG/MG_GL/State/Buffer/BufferState.h @@ -5,13 +5,11 @@ #ifndef MOBILEGL_BUFFERSTATE_H #define MOBILEGL_BUFFERSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" class BufferState { - template - using unordered_map = ankerl::unordered_dense::map; - public: struct BufferObject { GLenum usage = GL_STATIC_DRAW; @@ -46,8 +44,8 @@ public: void Delete(GLuint buffer); GLuint GetCurrentBinding(GLenum target) const; - unordered_map currentBindings_; - unordered_map buffers_; + MG_Global::unordered_map currentBindings_; + MG_Global::unordered_map buffers_; private: std::vector freeId_; GLuint lastId_ = 1; diff --git a/MG/MG_GL/State/Common/CommonState.h b/MG/MG_GL/State/Common/CommonState.h index 0feccbe3..68b47756 100644 --- a/MG/MG_GL/State/Common/CommonState.h +++ b/MG/MG_GL/State/Common/CommonState.h @@ -5,12 +5,11 @@ #ifndef MOBILEGL_COMMONSTATE_H #define MOBILEGL_COMMONSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" class CommonState { - template - using unordered_map = ankerl::unordered_dense::map; public: // Viewport GLint viewport[4] = {0, 0, 0, 0}; @@ -19,7 +18,7 @@ public: GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}; // Pixel storage parameters - unordered_map pixelStoreParams; + MG_Global::unordered_map pixelStoreParams; // Blend state GLenum blendSrcRGB = GL_ONE; @@ -37,7 +36,7 @@ public: GLboolean depthMask = GL_TRUE; // Capability enables - unordered_map capabilities; + MG_Global::unordered_map capabilities; CommonState(); diff --git a/MG/MG_GL/State/Core/GLState.h b/MG/MG_GL/State/Core/GLState.h index 77451308..1762b597 100644 --- a/MG/MG_GL/State/Core/GLState.h +++ b/MG/MG_GL/State/Core/GLState.h @@ -4,6 +4,7 @@ #ifndef MOBILEGL_GLSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" diff --git a/MG/MG_GL/State/Framebuffer/FramebufferState.cpp b/MG/MG_GL/State/Framebuffer/FramebufferState.cpp index c75ac235..1ebc1b99 100644 --- a/MG/MG_GL/State/Framebuffer/FramebufferState.cpp +++ b/MG/MG_GL/State/Framebuffer/FramebufferState.cpp @@ -47,6 +47,7 @@ GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) { if (framebuffer != 0 && !ValidateHandle(framebuffer)) return GL_INVALID_OPERATION; if (target == GL_FRAMEBUFFER) { + currentBindings_[GL_FRAMEBUFFER] = framebuffer; currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer; currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer; } else { @@ -60,7 +61,7 @@ GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment, 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 (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)) @@ -85,7 +86,7 @@ GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment, } GLenum FramebufferState::ValidateCompleteness(GLenum target) { - if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER; + // if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER; FramebufferObject* fbo = GetCurrentFBO(target); if (!fbo) return GL_INVALID_OPERATION; return fbo->status; diff --git a/MG/MG_GL/State/Framebuffer/FramebufferState.h b/MG/MG_GL/State/Framebuffer/FramebufferState.h index 8af6e7a4..16d606b8 100644 --- a/MG/MG_GL/State/Framebuffer/FramebufferState.h +++ b/MG/MG_GL/State/Framebuffer/FramebufferState.h @@ -5,6 +5,7 @@ #ifndef MOBILEGL_FRAMEBUFFERSTATE_H #define MOBILEGL_FRAMEBUFFERSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" @@ -17,7 +18,7 @@ struct FramebufferAttachment { struct FramebufferObject { bool generated = false; - ankerl::unordered_map attachments; + MG_Global::unordered_map attachments; GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; GLsizei width = 0; GLsizei height = 0; @@ -35,10 +36,10 @@ public: GLenum ValidateCompleteness(GLenum target); FramebufferObject* GetCurrentFBO(GLenum target); - ankerl::unordered_map currentBindings_; // READ/DRAW + MG_Global::unordered_map currentBindings_; // READ/DRAW private: - ankerl::unordered_map framebuffers_; + MG_Global::unordered_map framebuffers_; std::set freeIds_; GLuint lastId_ = 0; bool ValidateHandle(GLuint framebuffer); diff --git a/MG/MG_GL/State/Program/ProgramState.h b/MG/MG_GL/State/Program/ProgramState.h index 5abc2c9d..62eb0371 100644 --- a/MG/MG_GL/State/Program/ProgramState.h +++ b/MG/MG_GL/State/Program/ProgramState.h @@ -5,6 +5,7 @@ #ifndef MOBILEGL_PROGRAMSTATE_H #define MOBILEGL_PROGRAMSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #define MOBILEGL_PROGRAM_DEBUGTOOL_H #define MOBILEGL_GLSLTOOL_H @@ -41,17 +42,17 @@ struct ProgramObject { bool dirty; GLint linkStatus; std::string infoLog; - ankerl::unordered_map attribBindings; - ankerl::unordered_map attribLocations; - ankerl::unordered_map uniformLocations; - ankerl::unordered_map uniformValues; + MG_Global::unordered_map attribBindings; + MG_Global::unordered_map attribLocations; + MG_Global::unordered_map uniformLocations; + MG_Global::unordered_map uniformValues; bool markedForDeletion; }; class ProgramState { public: - ankerl::unordered_map shaders_; - ankerl::unordered_map programs_; + MG_Global::unordered_map shaders_; + MG_Global::unordered_map programs_; std::set freeShaderIds_; std::set freeProgramIds_; GLuint lastShaderId_ = 0; diff --git a/MG/MG_GL/State/Program/ShaderObject.h b/MG/MG_GL/State/Program/ShaderObject.h index 7c2f1555..be6a661c 100644 --- a/MG/MG_GL/State/Program/ShaderObject.h +++ b/MG/MG_GL/State/Program/ShaderObject.h @@ -6,6 +6,7 @@ #define MOBILEGL_SHADEROBJECT_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" diff --git a/MG/MG_GL/State/Texture/TextureState.cpp b/MG/MG_GL/State/Texture/TextureState.cpp index 47e8f6d5..1858cd74 100644 --- a/MG/MG_GL/State/Texture/TextureState.cpp +++ b/MG/MG_GL/State/Texture/TextureState.cpp @@ -146,7 +146,6 @@ GLenum TextureState::Bind(GLenum target, GLuint texture) { } } - TextureUnitState& unit = textureUnits_[activeTextureUnit_]; TextureObject* texObj = nullptr; auto it = this->textures.find(texture); @@ -700,7 +699,7 @@ GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLe return GL_NO_ERROR; } - unordered_map::iterator texIt; + MG_Global::unordered_map::iterator texIt; if (!isProxyTexture) { texIt = textures.find(boundTexture); diff --git a/MG/MG_GL/State/Texture/TextureState.h b/MG/MG_GL/State/Texture/TextureState.h index 104525f0..245f5601 100644 --- a/MG/MG_GL/State/Texture/TextureState.h +++ b/MG/MG_GL/State/Texture/TextureState.h @@ -5,6 +5,7 @@ #ifndef MOBILEGL_TEXTURESTATE_H #define MOBILEGL_TEXTURESTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" @@ -19,10 +20,8 @@ struct ComponentSizes { }; struct TextureParams { - template - using unordered_map = ankerl::unordered_dense::map; - unordered_map texPropertiesFloat; - unordered_map texPropertiesInt; + MG_Global::unordered_map texPropertiesFloat; + MG_Global::unordered_map texPropertiesInt; struct MipmapLevel { GLsizei width = 0; GLsizei height = 0; @@ -33,7 +32,7 @@ struct TextureParams { bool hasData = false; bool dirty = false; // TODO: encapsulate this with an public API to RHI }; - unordered_map mipmapData; + MG_Global::unordered_map mipmapData; }; class TextureObject { @@ -47,27 +46,23 @@ public: }; class TextureUnitState { - template - using unordered_map = ankerl::unordered_dense::map; private: GLenum activeTarget = GL_TEXTURE_2D; public: - unordered_map boundTextures; + MG_Global::unordered_map boundTextures; void Bind(GLenum target, GLuint texture); GLuint GetBoundTexture(GLenum target); }; class TextureState { - template - using unordered_map = ankerl::unordered_dense::map; private: GLuint lastUsedID_ = 1; -// ankerl::unordered_set freeIDs_; +// MG_Global::unordered_set freeIDs_; std::vector freeID_; - unordered_map proxyTextures_; + MG_Global::unordered_map proxyTextures_; static GLint GetUnpackParam_(GLenum pname); public: @@ -75,7 +70,7 @@ public: bool IsTextureGenerated(GLuint texture); bool IsTexture(GLuint texture); - unordered_map textures; + MG_Global::unordered_map textures; // Return: the validity of the operation, according to OpenGL 3 standard GLenum BindUnit(GLenum textureUnit); diff --git a/MG/MG_GL/State/VertexArray/VertexArrayState.h b/MG/MG_GL/State/VertexArray/VertexArrayState.h index a3df42aa..236cf2e9 100644 --- a/MG/MG_GL/State/VertexArray/VertexArrayState.h +++ b/MG/MG_GL/State/VertexArray/VertexArrayState.h @@ -5,6 +5,7 @@ #ifndef MOBILEGL_VERTEXARRAYSTATE_H #define MOBILEGL_VERTEXARRAYSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_DILIGENT_EGL_IMPL_H #include "../../../Includes.h" @@ -24,7 +25,7 @@ struct VertexArrayObject { bool attribDirty = false; bool eboDirty = false; GLuint elementBuffer = 0; - ankerl::unordered_map attribs; + MG_Global::unordered_map attribs; }; class VertexArrayState { @@ -50,7 +51,7 @@ public: bool ValidateAllocatedHandle(GLuint array); GLuint currentVao_ = 0; - ankerl::unordered_map vaos_; + MG_Global::unordered_map vaos_; private: std::set freeIds_; GLuint lastId_ = 0; diff --git a/MG/MG_RHI/GLES/Test/TestDrawing.cpp b/MG/MG_RHI/GLES/Test/TestDrawing.cpp index b37c0f28..a8dd9c3d 100644 --- a/MG/MG_RHI/GLES/Test/TestDrawing.cpp +++ b/MG/MG_RHI/GLES/Test/TestDrawing.cpp @@ -53,8 +53,8 @@ namespace MG_RHI::GLES::Test { GLuint quadVBO = 0; GLint uTexLoc = -1; GLint uMVPLoc = -1; - ankerl::unordered_map textureCache; - ankerl::unordered_map textureDirty; + MG_Global::unordered_map textureCache; + MG_Global::unordered_map textureDirty; }; static ScreenResources sRes; diff --git a/MG/MG_UTIL/Program/GLSLTool.cpp b/MG/MG_UTIL/Program/GLSLTool.cpp index 1cd4323b..f89d2319 100644 --- a/MG/MG_UTIL/Program/GLSLTool.cpp +++ b/MG/MG_UTIL/Program/GLSLTool.cpp @@ -5,6 +5,485 @@ #include "GLSLTool.h" namespace MG_Util::Program { + static std::vector buildCommentMask(const std::string &src) { + enum State { + NORMAL, + LINE_COMMENT, + BLOCK_COMMENT, + STRING_LITERAL, + CHAR_LITERAL + }; + + std::vector 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 &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 GenerateDefaultUBOForGLSL(const std::pair& glslSources) { + std::string source1 = glslSources.first; + std::string source2 = glslSources.second; + + std::vector commentMask1 = buildCommentMask(source1); + std::vector commentMask2 = buildCommentMask(source2); + + const std::regex layoutRegex(R"(\s*layout\s*\([^)]*\))"); + std::set allUniformNames; + std::vector mergedUniforms; + std::vector> removalSpans1; + std::vector> removalSpans2; + + auto processSource = [&](std::string& source, const std::vector& commentMask, + std::vector>& 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 &shaderSources) { + if (shaderSources.empty()) return; + + std::unordered_map> commentMasks; + for (auto const& [id, source] : shaderSources) { + commentMasks[id] = buildCommentMask(source); + } + + const std::regex layoutRegex(R"(\s*layout\s*\([^)]*\))"); + std::set allUniformNames; + std::vector mergedUniforms; + std::unordered_map>> removalSpansPerShader; + + for (auto& [id, source] : shaderSources) { + std::vector& 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); + } + + size_t removeStart = declStart; + size_t scanBack = declStart; + while (scanBack > 0 && std::isspace(static_cast(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); + } + source = std::regex_replace( + source, + 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"; + + 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) { std::string infoLog; using namespace glslang; @@ -108,7 +587,7 @@ namespace MG_Util::Program { return; } - ankerl::unordered_set used_locations; + MG_Global::unordered_set used_locations; GLint auto_location = 0; for (auto spirv: allSpirv) { spvc_parsed_ir ir = nullptr; diff --git a/MG/MG_UTIL/Program/GLSLTool.h b/MG/MG_UTIL/Program/GLSLTool.h index 2488f79c..4e9156d3 100644 --- a/MG/MG_UTIL/Program/GLSLTool.h +++ b/MG/MG_UTIL/Program/GLSLTool.h @@ -178,6 +178,10 @@ namespace MG_Util::Program { std::vector> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog); void ReflectSPIRVUniforms(const std::vector>& allSpirv, ProgramObject& prog, std::string& infoLog); std::string CompileSPIRVToGLSL(std::vector spirv, uint glslVersion, bool isES); + std::pair GenerateDefaultUBOForGLSL(const std::pair& glslSources); + void GenerateDefaultUBOForGLSL_Multi( + MG_Global::unordered_map &shaderSources); } #endif //MOBILEGL_GLSLTOOL_H