Added support for Instancing

Former-commit-id: 62f5f3186423b01f7a0ac2762969dca12bea1327
This commit is contained in:
Lynix
2013-02-26 01:40:57 +01:00
parent 9b2eb8ce3f
commit 3b0751fb88
6 changed files with 337 additions and 24 deletions

View File

@@ -60,9 +60,8 @@ namespace
std::map<VAO_Key, unsigned int> s_vaos;
std::vector<TextureUnit> s_textureUnits;
NzBuffer* s_instancingBuffer = nullptr;
NzMatrix4f s_matrix[totalMatrixCount];
int s_matrixLocation[totalMatrixCount];
bool s_matrixUpdated[totalMatrixCount];
nzBlendFunc s_srcBlend;
nzBlendFunc s_dstBlend;
nzFaceCulling s_faceCulling;
@@ -79,12 +78,15 @@ namespace
const NzShader* s_shader;
const NzVertexBuffer* s_vertexBuffer;
const NzVertexDeclaration* s_vertexDeclaration;
bool s_vaoUpdated;
bool s_capabilities[nzRendererCap_Max+1];
bool s_instancingEnabled;
bool s_matrixUpdated[totalMatrixCount];
bool s_stencilFuncUpdated;
bool s_stencilOpUpdated;
bool s_useSamplerObjects;
bool s_useVertexArrayObjects;
bool s_vaoUpdated;
int s_matrixLocation[totalMatrixCount];
unsigned int s_maxRenderTarget;
unsigned int s_maxTextureUnit;
unsigned int s_stencilReference;
@@ -147,6 +149,12 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f
return;
}
if (s_instancingEnabled)
{
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]+8);
s_instancingEnabled = false;
}
if (s_indexBuffer->IsSequential())
glDrawArrays(NzOpenGL::PrimitiveType[primitive], s_indexBuffer->GetStartIndex(), s_indexBuffer->GetIndexCount());
else
@@ -168,6 +176,81 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f
}
}
void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPrimitiveType primitive, unsigned int firstIndex, unsigned int indexCount)
{
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
if (primitive > nzPrimitiveType_Max)
{
NazaraError("Primitive type out of enum");
return;
}
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return;
}
if (!s_indexBuffer)
{
NazaraError("No index buffer");
return;
}
if (instanceCount == 0)
{
NazaraError("Instance count must be over 0");
return;
}
if (instanceCount > NAZARA_RENDERER_INSTANCING_MAX)
{
NazaraError("Instance count is over maximum instance count (" + NzString::Number(instanceCount) + " >= " + NzString::Number(NAZARA_RENDERER_INSTANCING_MAX) + ')');
return;
}
#endif
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
}
if (!s_instancingEnabled)
{
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]+8);
s_instancingEnabled = true;
}
if (s_indexBuffer->IsSequential())
glDrawArraysInstanced(NzOpenGL::PrimitiveType[primitive], s_indexBuffer->GetStartIndex(), s_indexBuffer->GetIndexCount(), instanceCount);
else
{
GLenum type;
const nzUInt8* ptr = reinterpret_cast<const nzUInt8*>(s_indexBuffer->GetPointer());
if (s_indexBuffer->HasLargeIndices())
{
ptr += firstIndex*sizeof(nzUInt32);
type = GL_UNSIGNED_INT;
}
else
{
ptr += firstIndex*sizeof(nzUInt16);
type = GL_UNSIGNED_SHORT;
}
glDrawElementsInstanced(NzOpenGL::PrimitiveType[primitive], indexCount, type, ptr, instanceCount);
}
}
void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount)
{
#ifdef NAZARA_DEBUG
@@ -190,9 +273,66 @@ void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVer
return;
}
if (s_instancingEnabled)
{
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]+8);
s_instancingEnabled = false;
}
glDrawArrays(NzOpenGL::PrimitiveType[primitive], firstVertex, vertexCount);
}
void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount)
{
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
if (primitive > nzPrimitiveType_Max)
{
NazaraError("Primitive type out of enum");
return;
}
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return;
}
if (instanceCount == 0)
{
NazaraError("Instance count must be over 0");
return;
}
if (instanceCount > NAZARA_RENDERER_INSTANCING_MAX)
{
NazaraError("Instance count is over maximum instance count (" + NzString::Number(instanceCount) + " >= " + NzString::Number(NAZARA_RENDERER_INSTANCING_MAX) + ')');
return;
}
#endif
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
}
if (!s_instancingEnabled)
{
glEnableVertexAttribArray(NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]+8);
s_instancingEnabled = true;
}
glDrawArraysInstanced(NzOpenGL::PrimitiveType[primitive], firstVertex, vertexCount, instanceCount);
}
void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
{
#ifdef NAZARA_DEBUG
@@ -229,6 +369,43 @@ void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
}
}
void NzRenderer::FillInstancingBuffer(const NzRenderer::InstancingData* instancingData, unsigned int instanceCount)
{
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return;
}
if (!instancingData)
{
NazaraError("Instancing data must be valid");
return;
}
if (instanceCount == 0)
{
NazaraError("Instance count must be over 0");
return;
}
if (instanceCount > NAZARA_RENDERER_INSTANCING_MAX)
{
NazaraError("Instance count is over maximum instance count (" + NzString::Number(instanceCount) + " >= " + NzString::Number(NAZARA_RENDERER_INSTANCING_MAX) + ')');
return;
}
#endif
if (!s_instancingBuffer->Fill(instancingData, 0, instanceCount))
NazaraError("Failed to fill instancing buffer");
}
void NzRenderer::Flush()
{
glFlush();
}
float NzRenderer::GetLineWidth()
{
#ifdef NAZARA_DEBUG
@@ -387,6 +564,8 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer)
NzContext::EnsureContext();
NzBuffer::SetBufferFunction(nzBufferStorage_Hardware, HardwareBufferFunction);
for (unsigned int i = 0; i < totalMatrixCount; ++i)
{
s_matrix[i].MakeIdentity();
@@ -398,8 +577,8 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer)
s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter);
s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64);
s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5
// MultipleRenderTargets (Techniquement natif depuis OpenGL 2.0 mais inutile sans glBindFragDataLocation)
s_capabilities[nzRendererCap_MultipleRenderTargets] = (glBindFragDataLocation != nullptr);
s_capabilities[nzRendererCap_Instancing] = NzOpenGL::IsSupported(nzOpenGLExtension_DrawInstanced) && NzOpenGL::IsSupported(nzOpenGLExtension_InstancedArray);
s_capabilities[nzRendererCap_MultipleRenderTargets] = (glBindFragDataLocation != nullptr); // Natif depuis OpenGL 2.0 mais inutile sans glBindFragDataLocation
s_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5
s_capabilities[nzRendererCap_PixelBufferObject] = NzOpenGL::IsSupported(nzOpenGLExtension_PixelBufferObject);
s_capabilities[nzRendererCap_RenderTexture] = NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject);
@@ -418,6 +597,35 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer)
else
s_maxAnisotropyLevel = 1;
if (s_capabilities[nzRendererCap_Instancing])
{
s_instancingBuffer = new NzBuffer(nzBufferType_Vertex);
if (s_instancingBuffer->Create(NAZARA_RENDERER_INSTANCING_MAX, sizeof(InstancingData), nzBufferStorage_Hardware, nzBufferUsage_Dynamic))
{
static_cast<NzHardwareBuffer*>(s_instancingBuffer->GetImpl())->Bind();
unsigned int instanceMatrixIndex = NzOpenGL::AttributeIndex[nzElementUsage_TexCoord] + 8;
for (unsigned int i = 0; i < 4; ++i)
{
glVertexAttribPointer(instanceMatrixIndex, 4, GL_FLOAT, GL_FALSE, sizeof(InstancingData), reinterpret_cast<GLvoid*>(offsetof(InstancingData, worldMatrix) + sizeof(float)*4*i));
glVertexAttribDivisor(instanceMatrixIndex, 1);
instanceMatrixIndex++;
}
s_instancingEnabled = false;
}
else
{
s_capabilities[nzRendererCap_Instancing] = false;
delete s_instancingBuffer;
s_instancingBuffer = nullptr;
NazaraWarning("Failed to create instancing buffer, disabled instancing.");
}
}
if (s_capabilities[nzRendererCap_MultipleRenderTargets])
{
GLint maxDrawBuffers;
@@ -467,8 +675,6 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer)
s_vertexBuffer = nullptr;
s_vertexDeclaration = nullptr;
NzBuffer::SetBufferFunction(nzBufferStorage_Hardware, HardwareBufferFunction);
if (initializeDebugDrawer && !NzDebugDrawer::Initialize())
NazaraWarning("Failed to initialize debug drawer"); // Non-critique
@@ -1040,6 +1246,13 @@ void NzRenderer::Uninitialize()
NzContext::EnsureContext();
// Libération du buffer d'instancing
if (s_instancingBuffer)
{
delete s_instancingBuffer;
s_instancingBuffer = nullptr;
}
// Libération des VAOs
for (auto it = s_vaos.begin(); it != s_vaos.end(); ++it)
{