[Feat] (Diligent/PSO, MG_State/Buffer): implement GL_TRIANGLE_FAN emulation, fixing sky

This commit is contained in:
2025-06-27 10:14:05 +08:00
parent 229b5f292e
commit d056acf0af
4 changed files with 135 additions and 31 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;
Diligent::IBuffer* g_TriangleFanIndexBuffer = nullptr;
GLuint g_NextResourceId = 0;
bool IsInRenderPass = false;
bool initialized = false;
@@ -101,7 +102,8 @@ namespace MG_Diligent {
uint64_t PipelineStateManager::CalculateStateHash(
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo) {
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology) {
size_t hash = 0;
auto& capabilities = commonState.capabilities;
@@ -121,6 +123,7 @@ namespace MG_Diligent {
hash_combine(hash, commonState.depthMask);
hash_combine(hash, capabilities[GL_DEPTH_TEST]);
hash_combine(hash, primitiveTopology);
hash_combine(hash, 0); // TODO: Cull Face Mode
hash_combine(hash, capabilities[GL_CULL_FACE]);
hash_combine(hash, capabilities[GL_STENCIL_TEST]);
@@ -168,7 +171,8 @@ namespace MG_Diligent {
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo) {
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology) {
PSOCreateInfo.PSODesc.Name = "Program_PSO";
PSOCreateInfo.PSODesc.PipelineType = Diligent::PIPELINE_TYPE_GRAPHICS;
@@ -199,7 +203,7 @@ namespace MG_Diligent {
PSOCreateInfo.GraphicsPipeline.pRenderPass = g_FramebufferMap[0].pRenderPass; // Default render pass
}
PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = GLPrimitiveTopologyToDiligent(primitiveTopology);
if (fbInfo.pRenderPass) {
PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 0;
@@ -314,8 +318,9 @@ namespace MG_Diligent {
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo) {
uint64_t currentStateHash = CalculateStateHash(commonState, vaState, fbInfo);
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology) {
uint64_t currentStateHash = CalculateStateHash(commonState, vaState, fbInfo, primitiveTopology);
if (programInfo.pPipelineState &&
programInfo.psoStateHash == currentStateHash &&
@@ -360,7 +365,7 @@ namespace MG_Diligent {
MG_Diligent::BuildInputLayout(program, vaState, programInfo.inputLayout);
Diligent::GraphicsPipelineStateCreateInfo PSOCreateInfo;
ConfigurePSO(PSOCreateInfo, programInfo, commonState, vaState, fbInfo);
ConfigurePSO(PSOCreateInfo, programInfo, commonState, vaState, fbInfo, primitiveTopology);
MG_Util::Debug::LogD("Dumping PSOCreateInfo for program %u:", program);
MG_Util::Debug::LogD(" PSODesc.Name: %s", PSOCreateInfo.PSODesc.Name);
@@ -56,6 +56,23 @@ namespace MG_Diligent {
extern MG_Global::unordered_map<GLuint, Diligent::ISampler*> g_SamplerMap;
extern MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_UniformBufferMap;
extern Diligent::IBuffer* g_TriangleFanIndexBuffer;
inline Diligent::PRIMITIVE_TOPOLOGY GLPrimitiveTopologyToDiligent(GLenum Topology)
{
switch (Topology)
{
case GL_TRIANGLE_STRIP:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
case GL_TRIANGLES:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case GL_TRIANGLE_FAN:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
// TODO: Handle other topologies
default:
return Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
}
}
class PipelineStateManager {
private:
@@ -83,7 +100,8 @@ namespace MG_Diligent {
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo);
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void MarkPSODirty(GLuint program);
@@ -191,14 +209,16 @@ namespace MG_Diligent {
uint64_t CalculateStateHash(
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo);
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void ConfigurePSO(
Diligent::GraphicsPipelineStateCreateInfo &PSOCreateInfo,
GLProgramInfo &programInfo,
CommonState &commonState,
VertexArrayState &vaState,
GLFramebufferInfo& fbInfo);
GLFramebufferInfo& fbInfo,
GLenum primitiveTopology);
void ConfigureResourceLayout(
Diligent::GraphicsPipelineStateCreateInfo& PSOCreateInfo,
@@ -411,7 +411,22 @@ namespace MG_GL::GL {
}
}
void PrepareForDraw() {
template<typename T>
void generate_triangle_fan_indices(std::vector<uint8_t>& out_data, const void* in_indices, size_t count) {
const auto* pIn = static_cast<const T*>(in_indices);
std::vector<T> 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();
@@ -444,7 +459,8 @@ namespace MG_GL::GL {
programInfo,
*MG_State_T::commonState,
*MG_State_T::vertexArrayState,
fbInfo
fbInfo,
mode
);
if (!programInfo.pPipelineState) {
@@ -473,7 +489,6 @@ namespace MG_GL::GL {
return;
}
// for (const auto& [attribIndex, attrib] : pVAO->attribs) {
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;
@@ -507,7 +522,67 @@ namespace MG_GL::GL {
}
}
if (pVAO->elementBuffer != 0) {
if (mode == GL_TRIANGLE_FAN)
{
if (*pCount < 3) return;
const void* pOriginalIndices = nullptr;
if (pVAO->elementBuffer != 0)
{
auto& bufferObj = MG_State_T::bufferState->buffers_[pVAO->elementBuffer];
pOriginalIndices = bufferObj.data.data() + reinterpret_cast<uintptr_t>(pIndices);
}
else
{
pOriginalIndices = pIndices;
}
std::vector<uint8_t> newIndexData;
switch(type) {
case GL_UNSIGNED_BYTE:
generate_triangle_fan_indices<uint8_t>(newIndexData, pOriginalIndices, *pCount);
break;
case GL_UNSIGNED_SHORT:
generate_triangle_fan_indices<uint16_t>(newIndexData, pOriginalIndices, *pCount);
break;
case GL_UNSIGNED_INT:
generate_triangle_fan_indices<uint32_t>(newIndexData, pOriginalIndices, *pCount);
break;
default:
MG_Util::Debug::LogE("Unsupported index type for triangle fan conversion: %X", type);
return;
}
*pCount = (static_cast<GLsizei>(*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();
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->buffers_[buffer];
@@ -534,6 +609,10 @@ namespace MG_GL::GL {
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
@@ -621,26 +700,22 @@ namespace MG_GL::GL {
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
PrepareForDraw();
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<uintptr_t>(indices);
MG_Diligent::g_pContext->SetIndexBuffer(
it->second,
offset,
Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
);
}
}
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<Diligent::Uint32>(reinterpret_cast<uintptr_t>(pIndices) / indexSize);
}
MG_Util::Debug::LogD("DrawIndexedAttribs Dump:");
MG_Util::Debug::LogD(" NumIndices: %u", drawAttrs.NumIndices);
MG_Util::Debug::LogD(" IndexType: %d", drawAttrs.IndexType);
@@ -708,8 +783,9 @@ namespace MG_GL::GL {
};
void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) {
PrepareForDraw();
return;
// PrepareForDraw();
if (MG_Diligent::IsInRenderPass) {
MG_Util::Debug::LogD("Ending current render pass.");
MG_Diligent::g_pContext->EndRenderPass();
@@ -843,7 +919,8 @@ namespace MG_GL::GL {
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) {
PrepareForDraw();
return;
// PrepareForDraw();
auto* pVAO = MG_State_T::vertexArrayState->GetCurrentVAO();
Diligent::IBuffer* pIndexBuffer = nullptr;
@@ -8,6 +8,8 @@
namespace MG_GL::GL {
bool IsSamplerType(GLenum type);
Diligent::VALUE_TYPE ConvertGLTypeToDiligent(GLenum type);
void PrepareForDraw(GLenum mode, GLsizei* pCount, GLenum type, const void*& pIndices);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count);