Added support for double and integer attribute (VertexDeclaration)

Improved Renderer error handling


Former-commit-id: 8cded7c0a7d1ba7c8583ef3e7b74b1d9604088e3
This commit is contained in:
Lynix 2014-04-25 21:11:14 +02:00
parent 4898018396
commit beb1879aca
4 changed files with 195 additions and 72 deletions

View File

@ -26,8 +26,12 @@ enum nzAttributeType
nzAttributeType_Float2,
nzAttributeType_Float3,
nzAttributeType_Float4,
nzAttributeType_Int1,
nzAttributeType_Int2,
nzAttributeType_Int3,
nzAttributeType_Int4,
nzAttributeType_Max = nzAttributeType_Float4
nzAttributeType_Max = nzAttributeType_Int4
};
enum nzAttributeUsage

View File

@ -1886,10 +1886,14 @@ GLenum NzOpenGL::AttributeType[] =
GL_FLOAT, // nzAttributeType_Float1
GL_FLOAT, // nzAttributeType_Float2
GL_FLOAT, // nzAttributeType_Float3
GL_FLOAT // nzAttributeType_Float4
GL_FLOAT, // nzAttributeType_Float4
GL_INT, // nzAttributeType_Int1
GL_INT, // nzAttributeType_Int2
GL_INT, // nzAttributeType_Int3
GL_INT // nzAttributeType_Int4
};
static_assert(nzAttributeType_Max+1 == 9, "Attribute type array is incomplete");
static_assert(nzAttributeType_Max+1 == 13, "Attribute type array is incomplete");
GLenum NzOpenGL::BlendFunc[] =
{

View File

@ -282,7 +282,7 @@ void NzRenderer::DrawFullscreenQuad()
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
NazaraError("Failed to update states: " + NzError::GetLastError());
return;
}
@ -320,7 +320,7 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode mode, unsigned int firstI
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
NazaraError("Failed to update states: " + NzError::GetLastError());
return;
}
@ -391,7 +391,7 @@ void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPr
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
NazaraError("Failed to update states: " + NzError::GetLastError());
return;
}
@ -435,7 +435,7 @@ void NzRenderer::DrawPrimitives(nzPrimitiveMode mode, unsigned int firstVertex,
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
NazaraError("Failed to update states: " + NzError::GetLastError());
return;
}
@ -486,7 +486,7 @@ void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitive
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
NazaraError("Failed to update states: " + NzError::GetLastError());
return;
}
@ -915,6 +915,34 @@ bool NzRenderer::IsInitialized()
return s_moduleReferenceCounter != 0;
}
bool NzRenderer::IsVertexAttributeSupported(nzAttributeType attributeType)
{
switch (attributeType)
{
case nzAttributeType_Color:
case nzAttributeType_Float1:
case nzAttributeType_Float2:
case nzAttributeType_Float3:
case nzAttributeType_Float4:
return true; // Supportés nativement
case nzAttributeType_Double1:
case nzAttributeType_Double2:
case nzAttributeType_Double3:
case nzAttributeType_Double4:
return glVertexAttribLPointer != nullptr; // Fonction requise pour envoyer des doubles
case nzAttributeType_Int1:
case nzAttributeType_Int2:
case nzAttributeType_Int3:
case nzAttributeType_Int4:
return glVertexAttribIPointer != nullptr; // Fonction requise pour envoyer des entiers
}
NazaraError("Attribute type out of enum");
return false;
}
void NzRenderer::SetBlendFunc(nzBlendFunc srcBlend, nzBlendFunc dstBlend)
{
#ifdef NAZARA_DEBUG
@ -1532,6 +1560,9 @@ void NzRenderer::EnableInstancing(bool instancing)
bool NzRenderer::EnsureStateUpdate()
{
// Toutes les erreurs sont silencieuses car l'erreur est gérée par la fonction appelante
NzErrorFlags flags(nzErrorFlag_Silent);
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
@ -1664,6 +1695,7 @@ bool NzRenderer::EnsureStateUpdate()
#endif
bool update;
VAO_Map::iterator vaoIt;
// Si les VAOs sont supportés, on entoure nos appels par ceux-ci
if (s_useVertexArrayObjects)
@ -1672,15 +1704,15 @@ bool NzRenderer::EnsureStateUpdate()
const NzContext* context = NzContext::GetCurrent();
VAO_Map* vaos;
auto vaoIt = s_vaos.find(context);
if (vaoIt == s_vaos.end())
auto it = s_vaos.find(context);
if (it == s_vaos.end())
{
context->AddResourceListener(&s_listener, ResourceType_Context);
auto pair = s_vaos.insert(std::make_pair(context, Context_Map::mapped_type()));
vaos = &pair.first->second;
}
else
vaos = &vaoIt->second;
vaos = &it->second;
// Notre clé est composée de ce qui définit un VAO
const NzVertexDeclaration* vertexDeclaration = s_vertexBuffer->GetVertexDeclaration();
@ -1688,15 +1720,15 @@ bool NzRenderer::EnsureStateUpdate()
VAO_Key key(s_indexBuffer, s_vertexBuffer, vertexDeclaration, instancingDeclaration);
// On recherche un VAO existant avec notre configuration
auto it = vaos->find(key);
if (it == vaos->end())
vaoIt = vaos->find(key);
if (vaoIt == vaos->end())
{
// On créé notre VAO
glGenVertexArrays(1, &s_currentVAO);
glBindVertexArray(s_currentVAO);
// On l'ajoute à notre liste
vaos->insert(std::make_pair(key, s_currentVAO));
vaoIt = vaos->insert(std::make_pair(key, s_currentVAO)).first;
if (s_indexBuffer)
s_indexBuffer->AddResourceListener(&s_listener, ResourceType_IndexBuffer);
@ -1712,7 +1744,7 @@ bool NzRenderer::EnsureStateUpdate()
else
{
// Notre VAO existe déjà, il est donc inutile de le reprogrammer
s_currentVAO = it->second;
s_currentVAO = vaoIt->second;
update = false;
}
@ -1720,6 +1752,8 @@ bool NzRenderer::EnsureStateUpdate()
else
update = true; // Fallback si les VAOs ne sont pas supportés
bool updateFailed = false;
if (update)
{
const NzVertexDeclaration* vertexDeclaration;
@ -1739,79 +1773,144 @@ bool NzRenderer::EnsureStateUpdate()
unsigned int offset;
vertexDeclaration->GetAttribute(static_cast<nzAttributeUsage>(i), &enabled, &type, &offset);
if (!IsVertexAttributeSupported(type))
{
NazaraError("Invalid declaration: Vertex attribute 0x" + NzString::Number(i, 16) + " (0x" + NzString::Number(type, 16) + ") is not supported");
updateFailed = true;
break;
}
if (enabled)
{
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
glVertexAttribPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
(type == nzAttributeType_Color) ? GL_TRUE : GL_FALSE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
else
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
if (s_instancing)
{
NzHardwareBuffer* instanceBufferImpl = static_cast<NzHardwareBuffer*>(s_instanceBuffer.GetBuffer()->GetImpl());
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Vertex], instanceBufferImpl->GetOpenGLID());
bufferOffset = s_instanceBuffer.GetStartOffset();
vertexDeclaration = s_instanceBuffer.GetVertexDeclaration();
stride = vertexDeclaration->GetStride();
for (unsigned int i = nzAttributeUsage_FirstInstanceData; i <= nzAttributeUsage_LastInstanceData; ++i)
{
nzAttributeType type;
bool enabled;
unsigned int offset;
vertexDeclaration->GetAttribute(static_cast<nzAttributeUsage>(i), &enabled, &type, &offset);
if (enabled)
if (type <= nzAttributeType_Double1 && type >= nzAttributeType_Double4)
{
glVertexAttribLPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
else if (type <= nzAttributeType_Int1 && type >= nzAttributeType_Int4)
{
glVertexAttribIPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
else
{
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
glVertexAttribPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
(type == nzAttributeType_Color) ? GL_TRUE : GL_FALSE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
glVertexAttribDivisor(NzOpenGL::AttributeIndex[i], 1);
}
else
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
}
else
{
for (unsigned int i = nzAttributeUsage_FirstInstanceData; i <= nzAttributeUsage_LastInstanceData; ++i)
else
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
// Et on active l'index buffer (Un seul index buffer par VAO)
if (s_indexBuffer)
if (!updateFailed)
{
NzHardwareBuffer* indexBufferImpl = static_cast<NzHardwareBuffer*>(s_indexBuffer->GetBuffer()->GetImpl());
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Index], indexBufferImpl->GetOpenGLID());
if (s_instancing)
{
NzHardwareBuffer* instanceBufferImpl = static_cast<NzHardwareBuffer*>(s_instanceBuffer.GetBuffer()->GetImpl());
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Vertex], instanceBufferImpl->GetOpenGLID());
bufferOffset = s_instanceBuffer.GetStartOffset();
vertexDeclaration = s_instanceBuffer.GetVertexDeclaration();
stride = vertexDeclaration->GetStride();
for (unsigned int i = nzAttributeUsage_FirstInstanceData; i <= nzAttributeUsage_LastInstanceData; ++i)
{
nzAttributeType type;
bool enabled;
unsigned int offset;
vertexDeclaration->GetAttribute(static_cast<nzAttributeUsage>(i), &enabled, &type, &offset);
if (!IsVertexAttributeSupported(type))
{
NazaraError("Invalid declaration: Vertex attribute 0x" + NzString::Number(i, 16) + " (0x" + NzString::Number(type, 16) + ") is not supported");
updateFailed = true;
break;
}
if (enabled)
{
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
if (type <= nzAttributeType_Double1 && type >= nzAttributeType_Double4)
{
glVertexAttribLPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
else if (type <= nzAttributeType_Int1 && type >= nzAttributeType_Int4)
{
glVertexAttribIPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
else
{
glVertexAttribPointer(NzOpenGL::AttributeIndex[i],
NzVertexDeclaration::GetAttributeSize(type),
NzOpenGL::AttributeType[type],
(type == nzAttributeType_Color) ? GL_TRUE : GL_FALSE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
}
glVertexAttribDivisor(NzOpenGL::AttributeIndex[i], 1);
}
else
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
}
else
{
for (unsigned int i = nzAttributeUsage_FirstInstanceData; i <= nzAttributeUsage_LastInstanceData; ++i)
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
// Et on active l'index buffer (Un seul index buffer par VAO)
if (s_indexBuffer)
{
NzHardwareBuffer* indexBufferImpl = static_cast<NzHardwareBuffer*>(s_indexBuffer->GetBuffer()->GetImpl());
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Index], indexBufferImpl->GetOpenGLID());
}
else
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Index], 0);
}
else
glBindBuffer(NzOpenGL::BufferTarget[nzBufferType_Index], 0);
// On invalide les bindings des buffers (car nous les avons défini manuellement)
NzOpenGL::SetBuffer(nzBufferType_Index, 0);
NzOpenGL::SetBuffer(nzBufferType_Vertex, 0);
}
if (s_useVertexArrayObjects)
{
// Si nous venons de définir notre VAO, nous devons le débinder pour indiquer la fin de sa construction
if (update)
glBindVertexArray(0);
{
if (updateFailed)
{
// La création de notre VAO a échoué, libérons-le et marquons-le comme problématique
glDeleteVertexArrays(1, &vaoIt->second);
vaoIt->second = 0;
s_currentVAO = 0;
}
else
glBindVertexArray(0); // On marque la fin de la construction du VAO en le débindant
}
// En cas de non-support des VAOs, les attributs doivent être respécifiés à chaque frame
s_updateFlags &= ~Update_VAO;
}
// On invalide les bindings des buffers (pour éviter des bugs)
NzOpenGL::SetBuffer(nzBufferType_Index, 0);
NzOpenGL::SetBuffer(nzBufferType_Vertex, 0);
}
#ifdef NAZARA_DEBUG
@ -1822,7 +1921,15 @@ bool NzRenderer::EnsureStateUpdate()
// On bind notre VAO
if (s_useVertexArrayObjects)
{
if (!s_currentVAO)
{
NazaraError("Failed to create VAO");
return false;
}
glBindVertexArray(s_currentVAO);
}
// On vérifie que les textures actuellement bindées sont bien nos textures
// Ceci à cause du fait qu'il est possible que des opérations sur les textures aient eu lieu

View File

@ -20,22 +20,30 @@ namespace
1, // nzAttributeType_Float1
2, // nzAttributeType_Float2
3, // nzAttributeType_Float3
4 // nzAttributeType_Float4
4, // nzAttributeType_Float4
1, // nzAttributeType_Int1
2, // nzAttributeType_Int2
3, // nzAttributeType_Int3
4 // nzAttributeType_Int4
};
static_assert(sizeof(attributeSize)/sizeof(unsigned int) == nzAttributeType_Max+1, "Attribute size array is incomplete");
unsigned int attributeStride[] =
{
4*sizeof(nzUInt8), // nzAttributeType_Color
1*sizeof(double), // nzAttributeType_Double1
2*sizeof(double), // nzAttributeType_Double2
3*sizeof(double), // nzAttributeType_Double3
4*sizeof(double), // nzAttributeType_Double4
1*sizeof(float), // nzAttributeType_Float1
2*sizeof(float), // nzAttributeType_Float2
3*sizeof(float), // nzAttributeType_Float3
4*sizeof(float) // nzAttributeType_Float4
4*sizeof(nzUInt8), // nzAttributeType_Color
1*sizeof(double), // nzAttributeType_Double1
2*sizeof(double), // nzAttributeType_Double2
3*sizeof(double), // nzAttributeType_Double3
4*sizeof(double), // nzAttributeType_Double4
1*sizeof(float), // nzAttributeType_Float1
2*sizeof(float), // nzAttributeType_Float2
3*sizeof(float), // nzAttributeType_Float3
4*sizeof(float), // nzAttributeType_Float4
1*sizeof(nzUInt32), // nzAttributeType_Int1
2*sizeof(nzUInt32), // nzAttributeType_Int2
3*sizeof(nzUInt32), // nzAttributeType_Int3
4*sizeof(nzUInt32) // nzAttributeType_Int4
};
static_assert(sizeof(attributeStride)/sizeof(unsigned int) == nzAttributeType_Max+1, "Attribute stride array is incomplete");