// // 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); 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: 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, Diligent::PipelineResourceLayoutDesc desc) { 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; // Try to get it from the PipelineResourceLayoutDesc first. if (desc.DefaultVariableType != Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC) { for (Diligent::Uint32 i = 0; i < desc.NumVariables; ++i) { if (desc.Variables[i].Name == name) { stage = desc.Variables[i].ShaderStages; programInfo.uniformStages[name] = stage; return stage; } } } for (Diligent::Uint32 i = 0; i < desc.NumImmutableSamplers; ++i) { if (desc.ImmutableSamplers[i].ShaderStages != Diligent::SHADER_TYPE_UNKNOWN && strcmp(desc.ImmutableSamplers[i].SamplerOrTextureName, name.c_str()) == 0) { stage = desc.ImmutableSamplers[i].ShaderStages; programInfo.uniformStages[name] = stage; return stage; } } // The code below is useless, we should remove it. 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_PIXEL; programInfo.uniformStages[name] = stage; return stage; } void UpdateSamplerAndTextureUniforms(GLuint program, Diligent::IShaderResourceBinding& pSRB, Diligent::PipelineResourceLayoutDesc desc) { MG_Util::Debug::LogD("Updating sampler and texture uniforms for program %u", program); auto& programObj = MG_State_T::programState->programs_[program]; for (auto& [name, uniform] : programObj.uniformValues) { if (!IsSamplerType(uniform.type)) continue; GLuint textureID = 0; if (!uniform.intData.empty()) { auto textureUnit = static_cast(uniform.intData[0]); auto unitState = &MG_State_T::textureState->textureUnits_[textureUnit]; textureID = unitState->GetBoundTexture(unitState->activeTarget); MG_Util::Debug::LogD("Sampler '%s' (type: %X) uses texture ID: %u", name.c_str(), uniform.type, textureID); } 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; MG_Util::Debug::LogD("Found ITextureView for texture ID %u.", textureID); } else { MG_Util::Debug::LogW("ITextureView not found for texture ID %u (sampler '%s').", textureID, name.c_str()); } } if (pTextureView) { Diligent::SHADER_TYPE stage = GetShaderStageForUniform(program, name, desc); MG_Util::Debug::LogD("Setting texture view for sampler '%s' in stage %d.", name.c_str(), stage); auto* pVar = pSRB.GetVariableByName(stage, name.c_str()); if (pVar) { pTextureView->SetSampler(MG_Diligent::g_SamplerMap[textureID]); pVar->Set(pTextureView, Diligent::SET_SHADER_RESOURCE_FLAG_ALLOW_OVERWRITE); } else { MG_Util::Debug::LogE("Failed to get shader variable for sampler '%s' in stage %d. Skipping.", name.c_str(), stage); } } else { MG_Util::Debug::LogW("No ITextureView available for sampler '%s' (texture ID: %u). Skipping.", name.c_str(), textureID); } } MG_Util::Debug::LogD("Finished updating sampler and texture uniforms for program %u.", program); } void UpdateUniformsToDefaultUBO(GLuint program, Diligent::IShaderResourceBinding& pSRB) { 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 (!programInfo.pDefaultUBO) { MG_Util::Debug::LogE("Program %u does not have a default UBO. Skipping uniform update.", program); return; } if (programObj.uniformValues.empty()) { MG_Util::Debug::LogE("Program %u has no uniforms. Skipping uniform update.", program); 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); auto* uboData = static_cast(mapped); for (auto& name: programInfo.uniformBufferNames) { auto& uniform = programObj.uniformValues[name]; 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); size_t dataSize = 0; const void* dataPtr = nullptr; if (!uniform.floatData.empty()) { dataSize = uniform.floatData.size() * sizeof(float); dataPtr = uniform.floatData.data(); } else if (!uniform.intData.empty()) { dataSize = uniform.intData.size() * sizeof(int); dataPtr = uniform.intData.data(); } else if (!uniform.uintData.empty()) { dataSize = uniform.uintData.size() * sizeof(uint32_t); dataPtr = uniform.uintData.data(); } if (dataPtr && dataSize > 0 && dataSize <= GetUniformSize(uniform.type)) { memcpy(uboData + offset, dataPtr, dataSize); } else { if (!dataPtr || dataSize == 0) { MG_Util::Debug::LogW("Cannot copy data for uniform '%s': data is null or size is zero.", name.c_str()); } else if (dataSize > GetUniformSize(uniform.type)) { MG_Util::Debug::LogW("Cannot copy data for uniform '%s': provided data size (%zu) exceeds uniform size (%zu).", name.c_str(), dataSize, GetUniformSize(uniform.type)); } // Fallback to individual assignments if memcpy is not suitable or data is malformed switch (uniform.type) { case GL_FLOAT: if (!uniform.floatData.empty()) *reinterpret_cast(uboData + offset) = uniform.floatData[0]; break; case GL_FLOAT_VEC2: case GL_FLOAT_VEC3: case GL_FLOAT_VEC4: case GL_FLOAT_MAT2: case GL_FLOAT_MAT3: case GL_FLOAT_MAT4: // memcpy handled above if data is valid break; case GL_INT: case GL_BOOL: if (!uniform.intData.empty()) *reinterpret_cast(uboData + offset) = uniform.intData[0]; break; case GL_INT_VEC2: case GL_INT_VEC3: case GL_INT_VEC4: // memcpy handled above if data is valid break; case GL_UNSIGNED_INT: if (!uniform.uintData.empty()) *reinterpret_cast(uboData + offset) = uniform.uintData[0]; break; case GL_UNSIGNED_INT_VEC2: case GL_UNSIGNED_INT_VEC3: case GL_UNSIGNED_INT_VEC4: // memcpy handled above if data is valid 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); if (programInfo.pDefaultUBO) { MG_Diligent::g_pContext->UnmapBuffer(programInfo.pDefaultUBO, Diligent::MAP_WRITE); auto* pVarVertex = pSRB.GetVariableByName(Diligent::SHADER_TYPE_VERTEX, "MG_DEFAULT_UBO"); if (pVarVertex) { pVarVertex->Set(programInfo.pDefaultUBO, Diligent::SET_SHADER_RESOURCE_FLAG_ALLOW_OVERWRITE); } else { MG_Util::Debug::LogE("Failed to get vertex shader variable 'MG_DEFAULT_UBO' for program %u.", program); } auto* pVarPixel = pSRB.GetVariableByName(Diligent::SHADER_TYPE_PIXEL, "MG_DEFAULT_UBO"); if (pVarPixel) { pVarPixel->Set(programInfo.pDefaultUBO, Diligent::SET_SHADER_RESOURCE_FLAG_ALLOW_OVERWRITE); } else { MG_Util::Debug::LogE("Failed to get pixel shader variable 'MG_DEFAULT_UBO' for program %u.", program); } } else { MG_Util::Debug::LogW("Default UBO is null for program %u. Skipping setting shader variables.", program); } } 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); } } template void generate_triangle_fan_indices(std::vector& out_data, const void* in_indices, size_t count) { const auto* pIn = static_cast(in_indices); std::vector new_indices; new_indices.reserve((count - 2) * 3); T i0 = pIn[0]; for (size_t i = 1; i < count - 1; ++i) { new_indices.push_back(i0); new_indices.push_back(pIn[i]); new_indices.push_back(pIn[i+1]); } out_data.resize(new_indices.size() * sizeof(T)); memcpy(out_data.data(), new_indices.data(), out_data.size()); } void PrepareForDraw(GLenum mode, GLsizei* pCount, GLenum type, const void*& pIndices) { if (MG_Diligent::IsInRenderPass) { MG_Util::Debug::LogD("Ending current render pass."); MG_Diligent::g_pContext->EndRenderPass(); MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("Current render pass ended."); } else { MG_Util::Debug::LogD("No active render pass to end."); } GLuint program = MG_State::GetCurrentProgram(); 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]; 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, mode ); 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) { MG_Util::Debug::LogE("No current VAO found. A VAO must be bound before drawing."); return; } for (uint32_t attribIndex = 0; attribIndex < MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS; ++attribIndex) { const auto& attrib = pVAO->attribs[attribIndex]; if (!attrib.enabled || attrib.buffer == 0) continue; GLuint buffer = attrib.buffer; auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); Diligent::IBuffer *&pBuffer = MG_Diligent::g_BufferMap[buffer]; if (bufferObj.isDynamic && (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()))) { if (pBuffer) { pBuffer->Release(); pBuffer = nullptr; } Diligent::BufferDesc BuffDesc; std::string bufferName = "Dynamic VBO " + std::to_string(buffer); BuffDesc.Name = bufferName.c_str(); BuffDesc.Size = bufferObj.data.size(); BuffDesc.Usage = Diligent::USAGE_DYNAMIC; BuffDesc.BindFlags = Diligent::BIND_VERTEX_BUFFER | Diligent::BIND_INDEX_BUFFER | Diligent::BIND_UNIFORM_BUFFER; BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, nullptr, &pBuffer); if (!pBuffer) { MG_Util::Debug::LogE("Failed to create dynamic vertex buffer %u", buffer); continue; } } } if (mode == GL_TRIANGLE_FAN) { if (*pCount < 3) return; const void* pOriginalIndices = nullptr; if (pVAO->elementBuffer != 0) { auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject( pVAO->elementBuffer); pOriginalIndices = bufferObj.data.data() + reinterpret_cast(pIndices); } else { pOriginalIndices = pIndices; } std::vector newIndexData; switch(type) { case GL_UNSIGNED_BYTE: generate_triangle_fan_indices(newIndexData, pOriginalIndices, *pCount); break; case GL_UNSIGNED_SHORT: generate_triangle_fan_indices(newIndexData, pOriginalIndices, *pCount); break; case GL_UNSIGNED_INT: generate_triangle_fan_indices(newIndexData, pOriginalIndices, *pCount); break; default: MG_Util::Debug::LogE("Unsupported index type for triangle fan conversion: %X", type); return; } *pCount = (static_cast(*pCount) - 2) * 3; pIndices = nullptr; if (!MG_Diligent::g_TriangleFanIndexBuffer || MG_Diligent::g_TriangleFanIndexBuffer->GetDesc().Size < newIndexData.size()) { if (MG_Diligent::g_TriangleFanIndexBuffer) { MG_Diligent::g_TriangleFanIndexBuffer->Release(); MG_Diligent::g_TriangleFanIndexBuffer = nullptr; } Diligent::BufferDesc BuffDesc; BuffDesc.Name = "Triangle Fan Temp Index Buffer"; BuffDesc.Size = newIndexData.size(); BuffDesc.Usage = Diligent::USAGE_DYNAMIC; BuffDesc.BindFlags = Diligent::BIND_INDEX_BUFFER; BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, nullptr, &MG_Diligent::g_TriangleFanIndexBuffer); } if (MG_Diligent::g_TriangleFanIndexBuffer) { void* pMappedData = nullptr; MG_Diligent::g_pContext->MapBuffer(MG_Diligent::g_TriangleFanIndexBuffer, Diligent::MAP_WRITE, Diligent::MAP_FLAG_DISCARD, pMappedData); if (pMappedData) { memcpy(pMappedData, newIndexData.data(), newIndexData.size()); MG_Diligent::g_pContext->UnmapBuffer(MG_Diligent::g_TriangleFanIndexBuffer, Diligent::MAP_WRITE); } MG_Diligent::g_pContext->SetIndexBuffer(MG_Diligent::g_TriangleFanIndexBuffer, 0, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); } } else if (pVAO->elementBuffer != 0) { GLuint buffer = pVAO->elementBuffer; auto& bufferObj = *MG_State_T::bufferState->GetOrCreateBufferObject(buffer); Diligent::IBuffer*& pBuffer = MG_Diligent::g_BufferMap[buffer]; if (bufferObj.isDynamic || (!pBuffer || (pBuffer && pBuffer->GetDesc().Size != bufferObj.data.size()))) { if (pBuffer) { pBuffer->Release(); pBuffer = nullptr; } Diligent::BufferDesc BuffDesc; std::string bufferName = "Dynamic IBO " + std::to_string(buffer); BuffDesc.Name = bufferName.c_str(); BuffDesc.Size = bufferObj.data.size(); BuffDesc.Usage = Diligent::USAGE_DYNAMIC; BuffDesc.BindFlags = Diligent::BIND_VERTEX_BUFFER | Diligent::BIND_INDEX_BUFFER | Diligent::BIND_UNIFORM_BUFFER; BuffDesc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; MG_Diligent::g_pDevice->CreateBuffer(BuffDesc, nullptr, &pBuffer); if (!pBuffer) { MG_Util::Debug::LogE("Failed to create dynamic index buffer %u", buffer); } } if (pBuffer) { MG_Diligent::g_pContext->SetIndexBuffer(pBuffer, 0, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); } } // Update data for all dynamic buffers for (auto& [bufferID, pBuffer] : MG_Diligent::g_BufferMap) { auto* pBufferObject = MG_State_T::bufferState->GetOrCreateBufferObject(bufferID); if (!pBufferObject) { MG_Util::Debug::LogW("Buffer ID %u not found in bufferState. Skipping update.", bufferID); continue; } auto& bufferObj = *pBufferObject; if (pBuffer && bufferObj.isDynamic) { void* pMappedData = nullptr; MG_Util::Debug::LogD("Mapping dynamic buffer %u for data update.", bufferID); MG_Diligent::g_pContext->MapBuffer( pBuffer, Diligent::MAP_WRITE, Diligent::MAP_FLAG_DISCARD, pMappedData); if (pMappedData) { memcpy(pMappedData, bufferObj.data.data(), bufferObj.data.size()); MG_Diligent::g_pContext->UnmapBuffer(pBuffer, Diligent::MAP_WRITE); bufferObj.dirty = false; MG_Util::Debug::LogD("Successfully updated data for dynamic buffer %u.", bufferID); } else { MG_Util::Debug::LogE("Failed to map dynamic buffer %u for data update.", bufferID); } } } std::vector vertexBuffers; std::vector offsets; for (uint32_t attribIndex = 0; attribIndex < MG_Constants::VertexArray::MAX_VERTEX_ATTRIBS; ++attribIndex) { const auto& attrib = pVAO->attribs[attribIndex]; if (!attrib.enabled || attrib.buffer == 0) continue; GLuint buffer = attrib.buffer; auto it = MG_Diligent::g_BufferMap.find(buffer); if (it == MG_Diligent::g_BufferMap.end() || !it->second) continue; vertexBuffers.push_back(it->second); offsets.push_back(static_cast(reinterpret_cast(attrib.pointer))); } if (!vertexBuffers.empty()) { MG_Util::Debug::LogD("Setting Vertex Buffers:"); MG_Util::Debug::LogD(" NumBuffers: %u", static_cast(vertexBuffers.size())); for (size_t i = 0; i < vertexBuffers.size(); ++i) { MG_Util::Debug::LogD(" Buffer %zu:", i); if (vertexBuffers[i]) { const auto& desc = vertexBuffers[i]->GetDesc(); MG_Util::Debug::LogD(" Name: %s", desc.Name ? desc.Name : "N/A"); MG_Util::Debug::LogD(" Size: %llu", desc.Size); MG_Util::Debug::LogD(" Usage: %d", desc.Usage); MG_Util::Debug::LogD(" BindFlags: %u", desc.BindFlags); MG_Util::Debug::LogD(" CPUAccessFlags: %u", desc.CPUAccessFlags); } else { MG_Util::Debug::LogD(" "); } MG_Util::Debug::LogD(" Offset: %llu", offsets[i]); } MG_Diligent::g_pContext->SetVertexBuffers( 0, static_cast(vertexBuffers.size()), vertexBuffers.data(), offsets.data(), Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, Diligent::SET_VERTEX_BUFFERS_FLAG_NONE ); } MG_Util::Debug::LogD("Updating uniforms for program %u", program); UpdateUniformsToDefaultUBO(program, *programInfo.pResourceBinding); UpdateSamplerAndTextureUniforms(program, *programInfo.pResourceBinding, programInfo.pPipelineState->GetDesc().ResourceLayout); MG_Util::Debug::LogD("Committing shader resources for program %u", program); MG_Diligent::g_pContext->CommitShaderResources( programInfo.pResourceBinding, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); } void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { const void* pIndices = indices; PrepareForDraw(mode, &count, type, pIndices); Diligent::DrawIndexedAttribs drawAttrs; drawAttrs.NumIndices = count; drawAttrs.Flags = Diligent::DRAW_FLAG_VERIFY_ALL; drawAttrs.IndexType = ConvertGLTypeToDiligent(type); auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); if (pIndices != nullptr && pVAO != nullptr && pVAO->elementBuffer != 0) { size_t indexSize = 1; if (drawAttrs.IndexType == Diligent::VT_UINT16) indexSize = 2; else if (drawAttrs.IndexType == Diligent::VT_UINT32) indexSize = 4; drawAttrs.FirstIndexLocation = static_cast(reinterpret_cast(pIndices) / indexSize); } MG_Util::Debug::LogD("DrawIndexedAttribs Dump:"); MG_Util::Debug::LogD(" NumIndices: %u", drawAttrs.NumIndices); MG_Util::Debug::LogD(" IndexType: %d", drawAttrs.IndexType); MG_Util::Debug::LogD(" Flags: %u", drawAttrs.Flags); MG_Util::Debug::LogD(" NumInstances: %u", drawAttrs.NumInstances); MG_Util::Debug::LogD(" BaseVertex: %u", drawAttrs.BaseVertex); MG_Util::Debug::LogD(" FirstIndexLocation: %u", drawAttrs.FirstIndexLocation); MG_Util::Debug::LogD(" FirstInstanceLocation: %u", drawAttrs.FirstInstanceLocation); 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) { auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); if (pVAO->elementBuffer != 0) { GLuint buffer = pVAO->elementBuffer; auto it = MG_Diligent::g_BufferMap.find(buffer); if (it != MG_Diligent::g_BufferMap.end() && it->second) { auto offset = reinterpret_cast(indices); MG_Diligent::g_pContext->SetIndexBuffer( it->second, offset, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); } } Diligent::DrawIndexedAttribs drawAttrs; drawAttrs.NumIndices = count; drawAttrs.Flags = Diligent::DRAW_FLAG_VERIFY_ALL; drawAttrs.IndexType = ConvertGLTypeToDiligent(type); drawAttrs.BaseVertex = basevertex; // Apply basevertex MG_Util::Debug::LogD("DrawIndexedAttribs Dump (BaseVertex):"); MG_Util::Debug::LogD(" NumIndices: %u", drawAttrs.NumIndices); MG_Util::Debug::LogD(" IndexType: %d", drawAttrs.IndexType); MG_Util::Debug::LogD(" Flags: %u", drawAttrs.Flags); MG_Util::Debug::LogD(" NumInstances: %u", drawAttrs.NumInstances); MG_Util::Debug::LogD(" BaseVertex: %u", drawAttrs.BaseVertex); MG_Util::Debug::LogD(" FirstIndexLocation: %u", drawAttrs.FirstIndexLocation); MG_Util::Debug::LogD(" FirstInstanceLocation: %u", drawAttrs.FirstInstanceLocation); EnsureRenderPassActive(); MG_Diligent::g_pContext->DrawIndexed(drawAttrs); MG_Diligent::g_pContext->EndRenderPass(); MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("DrawIndexed (BaseVertex) completed."); } struct DrawIndexedArguments { Diligent::Uint32 IndexCount; Diligent::Uint32 InstanceCount; Diligent::Uint32 FirstIndex; Diligent::Uint32 BaseVertex; Diligent::Uint32 FirstInstance; }; void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) { return; // PrepareForDraw(); /* if (MG_Diligent::IsInRenderPass) { MG_Util::Debug::LogD("Ending current render pass."); MG_Diligent::g_pContext->EndRenderPass(); MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("Current render pass ended."); } else { MG_Util::Debug::LogD("No active render pass to end."); } auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); Diligent::IBuffer* pIndexBuffer = nullptr; if (pVAO->elementBuffer != 0) { auto it = MG_Diligent::g_BufferMap.find(pVAO->elementBuffer); if (it != MG_Diligent::g_BufferMap.end()) pIndexBuffer = it->second; } if (!pIndexBuffer) { MG_Util::Debug::LogE("No valid index buffer bound for multi-draw"); return; } MG_Diligent::g_pContext->SetIndexBuffer( pIndexBuffer, 0, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); Diligent::VALUE_TYPE indexType = ConvertGLTypeToDiligent(type); Diligent::Uint32 indexSize = 0; switch (indexType) { case Diligent::VT_UINT16: indexSize = 2; break; case Diligent::VT_UINT32: indexSize = 4; break; default: MG_Util::Debug::LogE("Unsupported index type for multi-draw: %d", type); return; } std::vector indirectCmds; indirectCmds.reserve(drawcount); indirectCmds.clear(); for (GLsizei i = 0; i < drawcount; ++i) { if (count[i] <= 0) continue; DrawIndexedArguments cmd{}; cmd.IndexCount = static_cast(count[i]); cmd.InstanceCount = 1; cmd.FirstIndex = static_cast(reinterpret_cast(indices[i]) / indexSize); cmd.BaseVertex = 0; cmd.FirstInstance = 0; indirectCmds.push_back(cmd); } if (indirectCmds.empty()) { MG_Util::Debug::LogW("No valid draw items in multi-draw"); return; } static GLuint indirectBufId = 0; Diligent::IBuffer* pIndirectBuffer = nullptr; if (indirectBufId == 0) { bool isIdFree = false; while (!isIdFree) { MG_Diligent::g_NextResourceId++; bool isIdAlreadyExist = false; for (auto& [id, bufferObj] : MG_State_T::bufferState->buffers_) { if (MG_Diligent::g_NextResourceId == id) { isIdAlreadyExist = true; break; } } isIdFree = !isIdAlreadyExist; } indirectBufId = MG_Diligent::g_NextResourceId; MG_Diligent::g_NextResourceId++; } auto& bufEntry = MG_Diligent::g_BufferMap[indirectBufId]; const auto requiredSize = indirectCmds.size() * sizeof(DrawIndexedArguments); bool recreateBuffer = !bufEntry || bufEntry->GetDesc().Size != requiredSize; if (recreateBuffer) { if (bufEntry) { bufEntry->Release(); bufEntry = nullptr; } Diligent::BufferDesc desc; desc.Name = "MultiDrawIndirectArgs"; desc.Usage = Diligent::USAGE_DYNAMIC; desc.BindFlags = Diligent::BIND_INDIRECT_DRAW_ARGS; desc.Size = static_cast(requiredSize); desc.CPUAccessFlags = Diligent::CPU_ACCESS_WRITE; MG_Diligent::g_pDevice->CreateBuffer(desc, nullptr, &bufEntry); } pIndirectBuffer = bufEntry; void* pMappedData = nullptr; MG_Util::Debug::LogD("Mapping indirect draw buffer for multi-draw."); MG_Diligent::g_pContext->MapBuffer( pIndirectBuffer, Diligent::MAP_WRITE, Diligent::MAP_FLAG_DISCARD, pMappedData ); if (pMappedData) { memcpy(pMappedData, indirectCmds.data(), requiredSize); MG_Diligent::g_pContext->UnmapBuffer(pIndirectBuffer, Diligent::MAP_WRITE); MG_Util::Debug::LogD("Successfully updated indirect draw buffer."); } else { MG_Util::Debug::LogE("Failed to map indirect draw buffer for multi-draw."); return; } // Execute multi-draw indirect! EnsureRenderPassActive(); Diligent::DrawIndexedIndirectAttribs mdAttribs; mdAttribs.IndexType = indexType; mdAttribs.pAttribsBuffer = pIndirectBuffer; mdAttribs.DrawCount = static_cast(indirectCmds.size()); MG_Diligent::g_pContext->DrawIndexedIndirect(mdAttribs); MG_Diligent::g_pContext->EndRenderPass(); MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("MultiDrawElements completed with %d draws.", indirectCmds.size()); */ } void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) { PrepareForDraw(mode, (GLsizei *)count, type, (const void*&)indices[0]); auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO(); Diligent::IBuffer* pIndexBuffer = nullptr; if (pVAO->elementBuffer != 0) { auto it = MG_Diligent::g_BufferMap.find(pVAO->elementBuffer); if (it != MG_Diligent::g_BufferMap.end() && it->second) { pIndexBuffer = it->second; } } if (!pIndexBuffer) { MG_Util::Debug::LogE("No valid index buffer bound for multi-draw"); return; } MG_Diligent::g_pContext->SetIndexBuffer( pIndexBuffer, 0, Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); std::vector drawItems; drawItems.reserve(drawcount); Diligent::VALUE_TYPE indexType = ConvertGLTypeToDiligent(type); Diligent::Uint32 indexSize = 0; switch (indexType) { case Diligent::VT_UINT8: indexSize = 1; break; case Diligent::VT_UINT16: indexSize = 2; break; case Diligent::VT_UINT32: indexSize = 4; break; default: MG_Util::Debug::LogE("Unsupported index type for multi-draw: %d", type); return; } for (GLsizei i = 0; i < drawcount; i++) { if (count[i] <= 0) continue; Diligent::MultiDrawIndexedItem item; item.NumIndices = static_cast(count[i]); auto byteOffset = reinterpret_cast(indices[i]); item.FirstIndexLocation = static_cast(byteOffset / indexSize); item.BaseVertex = static_cast(basevertex[i]); drawItems.push_back(item); } if (drawItems.empty()) { MG_Util::Debug::LogW("No valid draw items in multi-draw"); return; } Diligent::MultiDrawIndexedAttribs drawAttrs; drawAttrs.DrawCount = static_cast(drawItems.size()); drawAttrs.pDrawItems = drawItems.data(); drawAttrs.IndexType = indexType; drawAttrs.Flags = Diligent::DRAW_FLAG_VERIFY_ALL; drawAttrs.NumInstances = 1; drawAttrs.FirstInstanceLocation = 0; MG_Util::Debug::LogD("MultiDrawIndexedAttribs Dump:"); MG_Util::Debug::LogD(" DrawCount: %u", drawAttrs.DrawCount); MG_Util::Debug::LogD(" IndexType: %d", drawAttrs.IndexType); MG_Util::Debug::LogD(" Flags: %u", drawAttrs.Flags); MG_Util::Debug::LogD(" NumInstances: %u", drawAttrs.NumInstances); MG_Util::Debug::LogD(" FirstInstanceLocation: %u", drawAttrs.FirstInstanceLocation); for (Diligent::Uint32 i = 0; i < drawAttrs.DrawCount; i++) { const auto& item = drawAttrs.pDrawItems[i]; MG_Util::Debug::LogD(" DrawItem[%u]:", i); MG_Util::Debug::LogD(" NumIndices: %u", item.NumIndices); MG_Util::Debug::LogD(" FirstIndexLocation: %u", item.FirstIndexLocation); MG_Util::Debug::LogD(" BaseVertex: %d", item.BaseVertex); } EnsureRenderPassActive(); MG_Diligent::g_pContext->MultiDrawIndexed(drawAttrs); MG_Diligent::g_pContext->EndRenderPass(); MG_Diligent::IsInRenderPass = false; MG_Util::Debug::LogD("MultiDrawIndexed completed."); } void DrawBuffer(GLenum buf) { // TODO } }