Honor input layouts in OpenGL vertex bindings
This commit is contained in:
@@ -13,6 +13,7 @@ class OpenGLBuffer;
|
||||
class OpenGLVertexArray;
|
||||
class OpenGLShader;
|
||||
class OpenGLTexture;
|
||||
class OpenGLPipelineState;
|
||||
|
||||
enum class PrimitiveType {
|
||||
Points,
|
||||
@@ -192,11 +193,17 @@ public:
|
||||
void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) override;
|
||||
|
||||
private:
|
||||
void EnsureInternalVertexArrayBound();
|
||||
void DisableConfiguredVertexAttributes();
|
||||
|
||||
unsigned int m_primitiveType;
|
||||
unsigned int m_currentVAO;
|
||||
unsigned int m_currentProgram;
|
||||
unsigned int m_internalVAO;
|
||||
OpenGLPipelineState* m_currentPipelineState;
|
||||
std::vector<unsigned int> m_enabledVertexAttributes;
|
||||
OpenGLShader* m_currentShader;
|
||||
};
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -11,10 +11,57 @@
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
namespace {
|
||||
|
||||
struct OpenGLVertexAttribFormat {
|
||||
GLint componentCount = 0;
|
||||
GLenum type = GL_FLOAT;
|
||||
GLboolean normalized = GL_FALSE;
|
||||
bool integer = false;
|
||||
};
|
||||
|
||||
bool GetOpenGLVertexAttribFormat(Format format, OpenGLVertexAttribFormat& attributeFormat) {
|
||||
switch (format) {
|
||||
case Format::R8_UNorm:
|
||||
attributeFormat = { 1, GL_UNSIGNED_BYTE, GL_TRUE, false };
|
||||
return true;
|
||||
case Format::R8G8_UNorm:
|
||||
attributeFormat = { 2, GL_UNSIGNED_BYTE, GL_TRUE, false };
|
||||
return true;
|
||||
case Format::R8G8B8A8_UNorm:
|
||||
attributeFormat = { 4, GL_UNSIGNED_BYTE, GL_TRUE, false };
|
||||
return true;
|
||||
case Format::R16_Float:
|
||||
attributeFormat = { 1, GL_HALF_FLOAT, GL_FALSE, false };
|
||||
return true;
|
||||
case Format::R16G16B16A16_Float:
|
||||
attributeFormat = { 4, GL_HALF_FLOAT, GL_FALSE, false };
|
||||
return true;
|
||||
case Format::R32_Float:
|
||||
attributeFormat = { 1, GL_FLOAT, GL_FALSE, false };
|
||||
return true;
|
||||
case Format::R32G32B32A32_Float:
|
||||
attributeFormat = { 4, GL_FLOAT, GL_FALSE, false };
|
||||
return true;
|
||||
case Format::R32_UInt:
|
||||
attributeFormat = { 1, GL_UNSIGNED_INT, GL_FALSE, true };
|
||||
return true;
|
||||
case Format::R32G32B32A32_UInt:
|
||||
attributeFormat = { 4, GL_UNSIGNED_INT, GL_FALSE, true };
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OpenGLCommandList::OpenGLCommandList()
|
||||
: m_primitiveType(GL_TRIANGLES)
|
||||
, m_currentVAO(0)
|
||||
, m_currentProgram(0)
|
||||
, m_internalVAO(0)
|
||||
, m_currentPipelineState(nullptr)
|
||||
, m_currentShader(nullptr) {
|
||||
}
|
||||
|
||||
@@ -407,10 +454,17 @@ void OpenGLCommandList::PopDebugGroup() {
|
||||
}
|
||||
|
||||
void OpenGLCommandList::Shutdown() {
|
||||
DisableConfiguredVertexAttributes();
|
||||
if (m_internalVAO != 0) {
|
||||
glDeleteVertexArrays(1, &m_internalVAO);
|
||||
m_internalVAO = 0;
|
||||
}
|
||||
m_currentPipelineState = nullptr;
|
||||
m_currentShader = nullptr;
|
||||
}
|
||||
|
||||
void OpenGLCommandList::Reset() {
|
||||
m_currentPipelineState = nullptr;
|
||||
}
|
||||
|
||||
void OpenGLCommandList::Close() {
|
||||
@@ -598,7 +652,10 @@ void OpenGLCommandList::ClearDepthStencil(RHIResourceView* depthStencil, float d
|
||||
|
||||
void OpenGLCommandList::SetPipelineState(RHIPipelineState* pipelineState) {
|
||||
if (pipelineState) {
|
||||
m_currentPipelineState = static_cast<OpenGLPipelineState*>(pipelineState);
|
||||
pipelineState->Bind();
|
||||
} else {
|
||||
m_currentPipelineState = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,6 +690,63 @@ void OpenGLCommandList::SetComputeDescriptorSets(
|
||||
}
|
||||
|
||||
void OpenGLCommandList::SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) {
|
||||
EnsureInternalVertexArrayBound();
|
||||
DisableConfiguredVertexAttributes();
|
||||
|
||||
if (m_currentPipelineState != nullptr) {
|
||||
const InputLayoutDesc& inputLayout = m_currentPipelineState->GetInputLayout();
|
||||
if (!inputLayout.elements.empty()) {
|
||||
for (uint32_t attributeIndex = 0; attributeIndex < inputLayout.elements.size(); ++attributeIndex) {
|
||||
const InputElementDesc& element = inputLayout.elements[attributeIndex];
|
||||
if (element.inputSlot < startSlot || element.inputSlot >= startSlot + count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t bindingIndex = element.inputSlot - startSlot;
|
||||
if (buffers[bindingIndex] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(buffers[bindingIndex]);
|
||||
if (!view->IsValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OpenGLVertexAttribFormat attributeFormat = {};
|
||||
if (!GetOpenGLVertexAttribFormat(static_cast<Format>(element.format), attributeFormat)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const GLuint glBuffer = view->GetBuffer();
|
||||
const uint32_t stride = strides[bindingIndex] > 0 ? strides[bindingIndex] : view->GetBufferStride();
|
||||
const uint64_t offset = view->GetBufferOffset() + offsets[bindingIndex] + element.alignedByteOffset;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
|
||||
glEnableVertexAttribArray(attributeIndex);
|
||||
if (attributeFormat.integer) {
|
||||
glVertexAttribIPointer(
|
||||
attributeIndex,
|
||||
attributeFormat.componentCount,
|
||||
attributeFormat.type,
|
||||
static_cast<GLsizei>(stride),
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(offset)));
|
||||
} else {
|
||||
glVertexAttribPointer(
|
||||
attributeIndex,
|
||||
attributeFormat.componentCount,
|
||||
attributeFormat.type,
|
||||
attributeFormat.normalized,
|
||||
static_cast<GLsizei>(stride),
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(offset)));
|
||||
}
|
||||
m_enabledVertexAttributes.push_back(attributeIndex);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!buffers[i]) continue;
|
||||
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(buffers[i]);
|
||||
@@ -644,12 +758,14 @@ void OpenGLCommandList::SetVertexBuffers(uint32_t startSlot, uint32_t count, RHI
|
||||
const uint32_t stride = strides[i] > 0 ? strides[i] : view->GetBufferStride();
|
||||
const uint64_t offset = view->GetBufferOffset() + offsets[i];
|
||||
glVertexAttribPointer(startSlot + i, stride / sizeof(float), GL_FLOAT, GL_FALSE, stride, reinterpret_cast<void*>(static_cast<uintptr_t>(offset)));
|
||||
m_enabledVertexAttributes.push_back(startSlot + i);
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void OpenGLCommandList::SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) {
|
||||
if (!buffer) return;
|
||||
EnsureInternalVertexArrayBound();
|
||||
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(buffer);
|
||||
if (!view->IsValid()) return;
|
||||
|
||||
@@ -694,5 +810,21 @@ void OpenGLCommandList::SetBlendFactor(const float factor[4]) {
|
||||
glBlendColor(factor[0], factor[1], factor[2], factor[3]);
|
||||
}
|
||||
|
||||
void OpenGLCommandList::EnsureInternalVertexArrayBound() {
|
||||
if (m_internalVAO == 0) {
|
||||
glGenVertexArrays(1, &m_internalVAO);
|
||||
}
|
||||
|
||||
m_currentVAO = m_internalVAO;
|
||||
glBindVertexArray(m_internalVAO);
|
||||
}
|
||||
|
||||
void OpenGLCommandList::DisableConfiguredVertexAttributes() {
|
||||
for (unsigned int attributeIndex : m_enabledVertexAttributes) {
|
||||
glDisableVertexAttribArray(attributeIndex);
|
||||
}
|
||||
m_enabledVertexAttributes.clear();
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
|
||||
Reference in New Issue
Block a user