[Feat] (Diligent/Drawing): Reimplement glMultiDrawElements through indirect drawing.

This commit is contained in:
BZLZHH
2025-06-21 09:48:08 +08:00
parent 61ae5e2e34
commit 7c3b4e52c3
3 changed files with 96 additions and 27 deletions
@@ -23,6 +23,7 @@ namespace MG_Diligent {
MG_Global::unordered_map<GLuint, GLProgramInfo> g_ProgramMap;
MG_Global::unordered_map<GLuint, Diligent::ISampler*> g_SamplerMap;
MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_UniformBufferMap;
GLuint g_NextResourceId = 0;
bool IsInRenderPass = false;
bool initialized = false;
@@ -173,9 +174,9 @@ namespace MG_Diligent {
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());
MG_Util::Debug::LogD("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);
MG_Util::Debug::LogD("AttachedShader: %p, Type: %d", shader, shader->GetDesc().ShaderType);
switch (shader->GetDesc().ShaderType) {
case Diligent::SHADER_TYPE_VERTEX:
PSOCreateInfo.pVS = shader;
@@ -213,6 +213,7 @@ namespace MG_Diligent {
extern bool initialized;
extern bool IsInRenderPass;
extern GLuint g_NextResourceId;
}
namespace MG_EGL::Diligent {
@@ -684,30 +684,33 @@ namespace MG_GL::GL {
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) {
PrepareForDraw();
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) {
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;
}
std::vector<Diligent::MultiDrawIndexedItem> 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:
@@ -715,34 +718,98 @@ namespace MG_GL::GL {
return;
}
for (GLsizei i = 0; i < drawcount; i++) {
std::vector<DrawIndexedArguments> indirectCmds;
indirectCmds.reserve(drawcount);
for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] <= 0) continue;
Diligent::MultiDrawIndexedItem item;
item.NumIndices = static_cast<Diligent::Uint32>(count[i]);
auto byteOffset = reinterpret_cast<Diligent::Uint64>(indices[i]);
item.FirstIndexLocation = static_cast<Diligent::Uint32>(byteOffset / indexSize);
item.BaseVertex = 0; // No base vertex
drawItems.push_back(item);
DrawIndexedArguments cmd{};
cmd.IndexCount = static_cast<Diligent::Uint32>(count[i]);
cmd.InstanceCount = 1;
cmd.FirstIndex = static_cast<Diligent::Uint32>(reinterpret_cast<uintptr_t>(indices[i]) / indexSize);
cmd.BaseVertex = 0;
cmd.FirstInstance = 0;
indirectCmds.push_back(cmd);
}
if (drawItems.empty()) {
if (indirectCmds.empty()) {
MG_Util::Debug::LogW("No valid draw items in multi-draw");
return;
}
Diligent::MultiDrawIndexedAttribs drawAttrs;
drawAttrs.DrawCount = static_cast<Diligent::Uint32>(drawItems.size());
drawAttrs.pDrawItems = drawItems.data();
drawAttrs.IndexType = indexType;
drawAttrs.Flags = Diligent::DRAW_FLAG_VERIFY_ALL;
drawAttrs.NumInstances = 1;
drawAttrs.FirstInstanceLocation = 0;
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<Diligent::Uint64>(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();
MG_Diligent::g_pContext->MultiDrawIndexed(drawAttrs);
Diligent::DrawIndexedIndirectAttribs mdAttribs;
mdAttribs.IndexType = indexType;
mdAttribs.pAttribsBuffer = pIndirectBuffer;
mdAttribs.DrawCount = static_cast<Diligent::Uint32>(indirectCmds.size());
MG_Diligent::g_pContext->DrawIndexedIndirect(mdAttribs);
MG_Diligent::g_pContext->EndRenderPass();
MG_Diligent::IsInRenderPass = false;
MG_Util::Debug::LogD("MultiDrawElements completed.");
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) {