Greatly improved Renderer

Separated Viewport from Scissor rect
Improved performances
Removed Lock/Unlock system from Shader/Texture class


Former-commit-id: f54bca6de58fe9d495d9192dc0d761f92594ee86
This commit is contained in:
Lynix
2013-05-03 02:58:35 +02:00
parent 76c19624d8
commit 4f3060a40d
15 changed files with 389 additions and 561 deletions

View File

@@ -41,13 +41,24 @@ namespace
nzMatrixCombination_Max = nzMatrixCombination_WorldViewProj
};
enum UpdateFlags
{
Update_None = 0,
Update_Matrices = 0x01,
Update_Shader = 0x02,
Update_StencilFunc = 0x04,
Update_StencilOp = 0x08,
Update_Textures = 0x10,
Update_VAO = 0x20,
};
struct TextureUnit
{
NzTextureSampler sampler;
const NzTexture* texture = nullptr;
bool samplerUpdated = false;
bool textureUpdated = true;
bool updated = true;
};
NzBufferImpl* HardwareBufferFunction(NzBuffer* parent, nzBufferType type)
@@ -61,6 +72,7 @@ namespace
std::map<VAO_Key, unsigned int> s_vaos;
std::vector<TextureUnit> s_textureUnits;
std::vector<unsigned int> s_dirtyTextureUnits;
NzBuffer* s_instancingBuffer = nullptr;
NzVertexBuffer* s_quadBuffer = nullptr;
NzMatrix4f s_matrix[totalMatrixCount];
@@ -76,18 +88,17 @@ namespace
nzStencilOperation s_stencilZFail;
nzUInt8 s_maxAnisotropyLevel;
nzUInt32 s_stencilMask;
nzUInt32 s_updateFlags;
const NzIndexBuffer* s_indexBuffer;
const NzRenderTarget* s_target;
const NzShader* s_shader;
const NzVertexBuffer* s_vertexBuffer;
const NzVertexDeclaration* s_vertexDeclaration;
bool s_capabilities[nzRendererCap_Max+1];
bool s_instancing;
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;
@@ -145,7 +156,9 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f
}
#endif
if (!EnsureStateUpdate(false))
EnableInstancing(false);
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
@@ -214,7 +227,9 @@ void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPr
}
#endif
if (!EnsureStateUpdate(true))
EnableInstancing(true);
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
@@ -257,7 +272,9 @@ void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVer
}
#endif
if (!EnsureStateUpdate(false))
EnableInstancing(false);
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
@@ -302,7 +319,9 @@ void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitive
}
#endif
if (!EnsureStateUpdate(true))
EnableInstancing(true);
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
@@ -415,13 +434,13 @@ void NzRenderer::DrawTexture(unsigned int unit, const NzRectf& rect, const NzVec
SetShader(shader);
SetVertexBuffer(s_quadBuffer);
if (!EnsureStateUpdate(true))
if (!EnsureStateUpdate())
{
NazaraError("Failed to update states");
return;
}
shader->SendMatrix(shader->GetUniformLocation("WorldViewProjMatrix"), NzMatrix4f::Ortho(0.f, s_targetSize.x, 0.f, s_targetSize.y, 0.f));
shader->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldViewProj], NzMatrix4f::Ortho(0.f, s_targetSize.x, 0.f, s_targetSize.y, 0.f));
glDrawArrays(NzOpenGL::PrimitiveType[nzPrimitiveType_TriangleStrip], 0, 4);
@@ -429,9 +448,6 @@ void NzRenderer::DrawTexture(unsigned int unit, const NzRectf& rect, const NzVec
Enable(nzRendererParameter_FaceCulling, faceCulling);
SetShader(oldShader);
SetVertexBuffer(oldBuffer);
s_matrixUpdated[nzMatrixCombination_WorldViewProj] = false;
s_vaoUpdated = false;
}
}
@@ -577,6 +593,22 @@ float NzRenderer::GetPointSize()
return pointSize;
}
NzRectui NzRenderer::GetScissorRect()
{
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return NzRectui();
}
#endif
GLint params[4];
glGetIntegerv(GL_SCISSOR_BOX, &params[0]);
return NzRectui(params[0], params[1], params[2], params[3]);
}
const NzShader* NzRenderer::GetShader()
{
return s_shader;
@@ -711,6 +743,7 @@ bool NzRenderer::Initialize()
else
s_maxTextureUnit = 1;
s_dirtyTextureUnits.reserve(s_maxTextureUnit);
s_dstBlend = nzBlendFunc_Zero;
s_faceCulling = nzFaceCulling_Back;
s_faceFilling = nzFaceFilling_Fill;
@@ -719,9 +752,7 @@ bool NzRenderer::Initialize()
s_srcBlend = nzBlendFunc_One;
s_stencilCompare = nzRendererComparison_Always;
s_stencilFail = nzStencilOperation_Keep;
s_stencilFuncUpdated = true;
s_stencilMask = 0xFFFFFFFF;
s_stencilOpUpdated = true;
s_stencilPass = nzStencilOperation_Keep;
s_stencilReference = 0;
s_stencilZFail = nzStencilOperation_Keep;
@@ -729,9 +760,9 @@ bool NzRenderer::Initialize()
s_textureUnits.resize(s_maxTextureUnit);
s_useSamplerObjects = NzOpenGL::IsSupported(nzOpenGLExtension_SamplerObjects);
s_useVertexArrayObjects = NzOpenGL::IsSupported(nzOpenGLExtension_VertexArrayObjects);
s_vaoUpdated = false;
s_vertexBuffer = nullptr;
s_vertexDeclaration = nullptr;
s_updateFlags = (Update_Matrices | Update_Shader | Update_VAO);
NzVertexElement elements[2];
elements[0].offset = 0;
@@ -945,23 +976,21 @@ void NzRenderer::SetFaceFilling(nzFaceFilling fillingMode)
}
}
bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
void NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
{
#if NAZARA_RENDERER_SAFE
if (indexBuffer && !indexBuffer->IsHardware() && !indexBuffer->IsSequential())
{
NazaraError("Buffer must be hardware");
return false;
return;
}
#endif
if (s_indexBuffer != indexBuffer)
{
s_indexBuffer = indexBuffer;
s_vaoUpdated = false;
s_updateFlags |= Update_VAO;
}
return true;
}
void NzRenderer::SetInstancingData(const NzRenderer::InstancingData* instancingData, unsigned int instanceCount)
@@ -1042,6 +1071,8 @@ void NzRenderer::SetMatrix(nzMatrixType type, const NzMatrix4f& matrix)
s_matrixUpdated[nzMatrixCombination_WorldView] = false;
s_matrixUpdated[nzMatrixCombination_WorldViewProj] = false; // Toujours invalidée
s_updateFlags |= Update_Matrices;
}
void NzRenderer::SetPointSize(float size)
@@ -1065,51 +1096,51 @@ void NzRenderer::SetPointSize(float size)
glPointSize(size);
}
bool NzRenderer::SetShader(const NzShader* shader)
void NzRenderer::SetScissorRect(const NzRectui& rect)
{
if (s_shader == shader)
return true;
if (s_shader)
s_shader->m_impl->Unbind();
if (shader)
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
#if NAZARA_RENDERER_SAFE
if (!shader->IsCompiled())
{
NazaraError("Shader is not compiled");
shader = nullptr;
NazaraError("No active context");
return;
}
#endif
return false;
}
#endif
unsigned int height = s_target->GetHeight();
if (!shader->m_impl->Bind())
{
NazaraError("Failed to bind shader");
shader = nullptr;
return false;
}
// Récupération des indices des variables uniformes (-1 si la variable n'existe pas)
s_matrixLocation[nzMatrixType_Projection] = shader->GetUniformLocation("ProjMatrix");
s_matrixLocation[nzMatrixType_View] = shader->GetUniformLocation("ViewMatrix");
s_matrixLocation[nzMatrixType_World] = shader->GetUniformLocation("WorldMatrix");
s_matrixLocation[nzMatrixCombination_ViewProj] = shader->GetUniformLocation("ViewProjMatrix");
s_matrixLocation[nzMatrixCombination_WorldView] = shader->GetUniformLocation("WorldViewMatrix");
s_matrixLocation[nzMatrixCombination_WorldViewProj] = shader->GetUniformLocation("WorldViewProjMatrix");
///FIXME: Peut être optimisé
for (unsigned int i = 0; i < totalMatrixCount; ++i)
s_matrixUpdated[i] = false;
#if NAZARA_RENDERER_SAFE
if (!s_target)
{
NazaraError("Renderer has no target");
return;
}
s_shader = shader;
unsigned int width = s_target->GetWidth();
if (rect.x+rect.width > width || rect.y+rect.height > height)
{
NazaraError("Rectangle dimensions are out of bounds");
return;
}
#endif
return true;
glScissor(rect.x, height-rect.height-rect.y, rect.width, rect.height);
}
void NzRenderer::SetShader(const NzShader* shader)
{
#if NAZARA_RENDERER_SAFE
if (shader && !shader->IsCompiled())
{
NazaraError("Shader is not compiled");
return;
}
#endif
if (s_shader != shader)
{
s_shader = shader;
s_updateFlags |= Update_Shader;
}
}
void NzRenderer::SetStencilCompareFunction(nzRendererComparison compareFunc)
@@ -1125,7 +1156,7 @@ void NzRenderer::SetStencilCompareFunction(nzRendererComparison compareFunc)
if (compareFunc != s_stencilCompare)
{
s_stencilCompare = compareFunc;
s_stencilFuncUpdated = false;
s_updateFlags |= Update_StencilFunc;
}
}
@@ -1142,7 +1173,7 @@ void NzRenderer::SetStencilFailOperation(nzStencilOperation failOperation)
if (failOperation != s_stencilFail)
{
s_stencilFail = failOperation;
s_stencilOpUpdated = false;
s_updateFlags |= Update_StencilOp;
}
}
@@ -1151,7 +1182,7 @@ void NzRenderer::SetStencilMask(nzUInt32 mask)
if (mask != s_stencilMask)
{
s_stencilMask = mask;
s_stencilFuncUpdated = false;
s_updateFlags |= Update_StencilFunc;
}
}
@@ -1168,7 +1199,7 @@ void NzRenderer::SetStencilPassOperation(nzStencilOperation passOperation)
if (passOperation != s_stencilPass)
{
s_stencilPass = passOperation;
s_stencilOpUpdated = false;
s_updateFlags |= Update_StencilOp;
}
}
@@ -1177,7 +1208,7 @@ void NzRenderer::SetStencilReferenceValue(unsigned int refValue)
if (refValue != s_stencilReference)
{
s_stencilReference = refValue;
s_stencilFuncUpdated = false;
s_updateFlags |= Update_StencilFunc;
}
}
@@ -1194,7 +1225,7 @@ void NzRenderer::SetStencilZFailOperation(nzStencilOperation zfailOperation)
if (zfailOperation != s_stencilZFail)
{
s_stencilZFail = zfailOperation;
s_stencilOpUpdated = false;
s_updateFlags |= Update_StencilOp;
}
}
@@ -1253,9 +1284,10 @@ void NzRenderer::SetTexture(nzUInt8 unit, const NzTexture* texture)
{
if (s_textureUnits[unit].sampler.UseMipmaps(texture->HasMipmaps()))
s_textureUnits[unit].samplerUpdated = false;
s_textureUnits[unit].updated = false;
}
s_dirtyTextureUnits.push_back(unit);
s_updateFlags |= Update_Textures;
}
}
@@ -1271,19 +1303,21 @@ void NzRenderer::SetTextureSampler(nzUInt8 unit, const NzTextureSampler& sampler
s_textureUnits[unit].sampler = sampler;
s_textureUnits[unit].samplerUpdated = false;
s_textureUnits[unit].updated = false;
if (s_textureUnits[unit].texture)
s_textureUnits[unit].sampler.UseMipmaps(s_textureUnits[unit].texture->HasMipmaps());
s_dirtyTextureUnits.push_back(unit);
s_updateFlags |= Update_Textures;
}
bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer)
void NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer)
{
#if NAZARA_RENDERER_SAFE
if (vertexBuffer && !vertexBuffer->IsHardware())
{
NazaraError("Buffer must be hardware");
return false;
return;
}
#endif
@@ -1295,10 +1329,8 @@ bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer)
if (s_vertexDeclaration != vertexDeclaration)
s_vertexDeclaration = vertexDeclaration;
s_vaoUpdated = false;
s_updateFlags |= Update_VAO;
}
return true;
}
void NzRenderer::SetViewport(const NzRectui& viewport)
@@ -1329,7 +1361,6 @@ void NzRenderer::SetViewport(const NzRectui& viewport)
#endif
glViewport(viewport.x, height-viewport.height-viewport.y, viewport.width, viewport.height);
glScissor(viewport.x, height-viewport.height-viewport.y, viewport.width, viewport.height);
}
void NzRenderer::Uninitialize()
@@ -1381,8 +1412,20 @@ void NzRenderer::Uninitialize()
NzUtility::Uninitialize();
}
bool NzRenderer::EnsureStateUpdate(bool instancing)
void NzRenderer::EnableInstancing(bool instancing)
{
if (s_instancing != instancing)
{
s_updateFlags |= Update_VAO;
s_instancing = instancing;
}
}
bool NzRenderer::EnsureStateUpdate()
{
if (s_updateFlags == Update_None)
return true;
#ifdef NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
@@ -1391,30 +1434,57 @@ bool NzRenderer::EnsureStateUpdate(bool instancing)
}
#endif
#if NAZARA_RENDERER_SAFE
if (!s_shader)
{
NazaraError("No shader");
return false;
}
#endif
NzShaderImpl* shaderImpl;
// Il est plus rapide d'opérer sur l'implémentation du shader directement
NzShaderImpl* shaderImpl = s_shader->m_impl;
shaderImpl->BindTextures();
if (s_useSamplerObjects)
if (s_updateFlags & Update_Shader)
{
///FIXME: Itère sur toutes les unités (Dont beaucoup inutilisées)
for (unsigned int i = 0; i < s_textureUnits.size(); ++i)
#if NAZARA_RENDERER_SAFE
if (!s_shader)
{
TextureUnit& unit = s_textureUnits[i];
NazaraError("No shader");
return false;
}
#endif
if (!unit.updated)
// Il est plus rapide d'opérer sur l'implémentation du shader directement
shaderImpl = s_shader->m_impl;
shaderImpl->Bind();
shaderImpl->BindTextures();
// Récupération des indices des variables uniformes (-1 si la variable n'existe pas)
s_matrixLocation[nzMatrixType_Projection] = shaderImpl->GetUniformLocation("ProjMatrix");
s_matrixLocation[nzMatrixType_View] = shaderImpl->GetUniformLocation("ViewMatrix");
s_matrixLocation[nzMatrixType_World] = shaderImpl->GetUniformLocation("WorldMatrix");
s_matrixLocation[nzMatrixCombination_ViewProj] = shaderImpl->GetUniformLocation("ViewProjMatrix");
s_matrixLocation[nzMatrixCombination_WorldView] = shaderImpl->GetUniformLocation("WorldViewMatrix");
s_matrixLocation[nzMatrixCombination_WorldViewProj] = shaderImpl->GetUniformLocation("WorldViewProjMatrix");
s_updateFlags |= Update_Matrices;
for (unsigned int i = 0; i < totalMatrixCount; ++i)
{
if (s_matrixLocation[i] != -1)
s_matrixUpdated[i] = false;
else
s_matrixUpdated[i] = false;
}
s_updateFlags &= ~Update_Shader;
}
else
shaderImpl = s_shader->m_impl;
if (s_updateFlags & Update_Textures)
{
if (s_useSamplerObjects)
{
for (unsigned int i : s_dirtyTextureUnits)
{
TextureUnit& unit = s_textureUnits[i];
if (!unit.textureUpdated)
{
glActiveTexture(GL_TEXTURE0 + i);
NzOpenGL::SetTextureUnit(i);
unit.texture->Bind();
unit.textureUpdated = true;
@@ -1425,83 +1495,83 @@ bool NzRenderer::EnsureStateUpdate(bool instancing)
unit.sampler.Bind(i);
unit.samplerUpdated = true;
}
unit.updated = true;
}
}
}
else
{
///FIXME: Itère sur toutes les unités (Dont beaucoup inutilisées)
for (unsigned int i = 0; i < s_textureUnits.size(); ++i)
else
{
TextureUnit& unit = s_textureUnits[i];
if (!unit.updated)
for (unsigned int i : s_dirtyTextureUnits)
{
glActiveTexture(GL_TEXTURE0 + i);
TextureUnit& unit = s_textureUnits[i];
NzOpenGL::SetTextureUnit(i);
unit.texture->Bind();
unit.textureUpdated = true;
unit.sampler.Apply(unit.texture);
unit.samplerUpdated = true;
unit.updated = true;
}
}
s_dirtyTextureUnits.clear(); // Ne change pas la capacité
s_updateFlags &= ~Update_Textures;
}
for (unsigned int i = 0; i <= nzMatrixType_Max; ++i)
if (s_updateFlags & Update_Matrices)
{
if (!s_matrixUpdated[i])
for (unsigned int i = 0; i <= nzMatrixType_Max; ++i)
{
shaderImpl->SendMatrix(s_matrixLocation[i], s_matrix[i]);
s_matrixUpdated[i] = true;
if (!s_matrixUpdated[i])
{
shaderImpl->SendMatrix(s_matrixLocation[i], s_matrix[i]);
s_matrixUpdated[i] = true;
}
}
// Cas spéciaux car il faut recalculer la matrice
if (!s_matrixUpdated[nzMatrixCombination_ViewProj])
{
s_matrix[nzMatrixCombination_ViewProj] = s_matrix[nzMatrixType_View];
s_matrix[nzMatrixCombination_ViewProj].Concatenate(s_matrix[nzMatrixType_Projection]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_ViewProj], s_matrix[nzMatrixCombination_ViewProj]);
s_matrixUpdated[nzMatrixCombination_ViewProj] = true;
}
if (!s_matrixUpdated[nzMatrixCombination_WorldView])
{
s_matrix[nzMatrixCombination_WorldView] = s_matrix[nzMatrixType_World];
s_matrix[nzMatrixCombination_WorldView].ConcatenateAffine(s_matrix[nzMatrixType_View]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldView], s_matrix[nzMatrixCombination_WorldView]);
s_matrixUpdated[nzMatrixCombination_WorldView] = true;
}
if (!s_matrixUpdated[nzMatrixCombination_WorldViewProj])
{
s_matrix[nzMatrixCombination_WorldViewProj] = s_matrix[nzMatrixCombination_WorldView];
s_matrix[nzMatrixCombination_WorldViewProj].Concatenate(s_matrix[nzMatrixType_Projection]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldViewProj], s_matrix[nzMatrixCombination_WorldViewProj]);
s_matrixUpdated[nzMatrixCombination_WorldViewProj] = true;
}
s_updateFlags &= ~Update_Matrices;
}
// Cas spéciaux car il faut recalculer la matrice
if (!s_matrixUpdated[nzMatrixCombination_ViewProj])
{
s_matrix[nzMatrixCombination_ViewProj] = s_matrix[nzMatrixType_View];
s_matrix[nzMatrixCombination_ViewProj].Concatenate(s_matrix[nzMatrixType_Projection]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_ViewProj], s_matrix[nzMatrixCombination_ViewProj]);
s_matrixUpdated[nzMatrixCombination_ViewProj] = true;
}
if (!s_matrixUpdated[nzMatrixCombination_WorldView])
{
s_matrix[nzMatrixCombination_WorldView] = s_matrix[nzMatrixType_World];
s_matrix[nzMatrixCombination_WorldView].ConcatenateAffine(s_matrix[nzMatrixType_View]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldView], s_matrix[nzMatrixCombination_WorldView]);
s_matrixUpdated[nzMatrixCombination_WorldView] = true;
}
if (!s_matrixUpdated[nzMatrixCombination_WorldViewProj])
{
s_matrix[nzMatrixCombination_WorldViewProj] = s_matrix[nzMatrixCombination_WorldView];
s_matrix[nzMatrixCombination_WorldViewProj].Concatenate(s_matrix[nzMatrixType_Projection]);
shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldViewProj], s_matrix[nzMatrixCombination_WorldViewProj]);
s_matrixUpdated[nzMatrixCombination_WorldViewProj] = true;
}
if (!s_stencilFuncUpdated)
if (s_updateFlags & Update_StencilFunc)
{
glStencilFunc(NzOpenGL::RendererComparison[s_stencilCompare], s_stencilReference, s_stencilMask);
s_stencilFuncUpdated = true;
s_updateFlags &= ~Update_StencilFunc;
}
if (!s_stencilOpUpdated)
if (s_updateFlags & Update_StencilOp)
{
glStencilOp(NzOpenGL::StencilOperation[s_stencilFail], NzOpenGL::StencilOperation[s_stencilZFail], NzOpenGL::StencilOperation[s_stencilPass]);
s_stencilOpUpdated = true;
s_updateFlags &= ~Update_StencilOp;
}
if (!s_vaoUpdated)
if (s_updateFlags & Update_VAO)
{
#if NAZARA_RENDERER_SAFE
if (!s_vertexBuffer)
@@ -1526,7 +1596,7 @@ bool NzRenderer::EnsureStateUpdate(bool instancing)
// On recherche si un VAO existe déjà avec notre configuration
// Note: Les VAOs ne sont pas partagés entre les contextes, ces derniers font donc partie de notre configuration
auto key = std::make_tuple(NzContext::GetCurrent(), s_indexBuffer, s_vertexBuffer, s_vertexDeclaration, instancing);
auto key = std::make_tuple(NzContext::GetCurrent(), s_indexBuffer, s_vertexBuffer, s_vertexDeclaration, s_instancing);
auto it = s_vaos.find(key);
if (it == s_vaos.end())
{
@@ -1577,7 +1647,7 @@ bool NzRenderer::EnsureStateUpdate(bool instancing)
glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
}
if (instancing)
if (s_instancing)
{
static_cast<NzHardwareBuffer*>(s_instancingBuffer->GetImpl())->Bind();
@@ -1611,9 +1681,14 @@ bool NzRenderer::EnsureStateUpdate(bool instancing)
glBindVertexArray(vao);
}
s_vaoUpdated = true;
s_updateFlags &= ~Update_VAO;
}
#ifdef NAZARA_DEBUG
if (s_updateFlags != Update_None)
NazaraWarning("Update flags not fully cleared");
#endif
return true;
}