// // Created by BZLZHH on 2025/3/15. // #include "GL_Drawing.h" namespace MG_GL::GL { 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 } void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex) { // TODO } void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) { // TODO } void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) { // TODO } void DrawBuffer(GLenum buf) { // TODO } }