Merge branch 'OpenGL3-upgrade' into NDK

Conflicts:
	src/Nazara/Graphics/SkyboxBackground.cpp
	src/Nazara/Renderer/RenderTexture.cpp
	src/Nazara/Renderer/Renderer.cpp

Former-commit-id: e8914d4e32a689b7df365dca15a438f10722530c
This commit is contained in:
Lynix
2015-09-24 21:35:43 +02:00
30 changed files with 185 additions and 1136 deletions

View File

@@ -33,6 +33,8 @@
#include <vector>
#include <Nazara/Renderer/Debug.hpp>
///TODO: Manager les VAO (permettre plusieurs draw calls sans rebinder le VAO)
namespace
{
const nzUInt8 r_coreFragmentShader[] = {
@@ -43,14 +45,6 @@ namespace
#include <Nazara/Renderer/Resources/Shaders/Debug/core.vert.h>
};
const nzUInt8 r_compatibilityFragmentShader[] = {
#include <Nazara/Renderer/Resources/Shaders/Debug/compatibility.frag.h>
};
const nzUInt8 r_compatibilityVertexShader[] = {
#include <Nazara/Renderer/Resources/Shaders/Debug/compatibility.vert.h>
};
enum ObjectType
{
ObjectType_Context,
@@ -122,8 +116,6 @@ namespace
const NzVertexBuffer* s_vertexBuffer;
bool s_capabilities[nzRendererCap_Max+1];
bool s_instancing;
bool s_useSamplerObjects;
bool s_useVertexArrayObjects;
unsigned int s_maxColorAttachments;
unsigned int s_maxRenderTarget;
unsigned int s_maxTextureSize;
@@ -141,14 +133,6 @@ void NzRenderer::BeginCondition(const NzGpuQuery& query, nzGpuQueryCondition con
}
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_ConditionalRendering])
{
NazaraError("Conditional rendering is not supported");
return;
}
#endif
glBeginConditionalRender(query.GetOpenGLID(), NzOpenGL::QueryCondition[condition]);
}
@@ -205,9 +189,7 @@ void NzRenderer::DrawFullscreenQuad()
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (s_useVertexArrayObjects)
glBindVertexArray(0);
glBindVertexArray(0);
}
void NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode mode, unsigned int firstIndex, unsigned int indexCount)
@@ -257,9 +239,7 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode mode, unsigned int firstI
}
glDrawElements(NzOpenGL::PrimitiveMode[mode], indexCount, type, offset);
if (s_useVertexArrayObjects)
glBindVertexArray(0);
glBindVertexArray(0);
}
void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPrimitiveMode mode, unsigned int firstIndex, unsigned int indexCount)
@@ -279,12 +259,6 @@ void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPr
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return;
}
if (!s_indexBuffer)
{
NazaraError("No index buffer");
@@ -328,9 +302,7 @@ void NzRenderer::DrawIndexedPrimitivesInstanced(unsigned int instanceCount, nzPr
}
glDrawElementsInstanced(NzOpenGL::PrimitiveMode[mode], indexCount, type, offset, instanceCount);
if (s_useVertexArrayObjects)
glBindVertexArray(0);
glBindVertexArray(0);
}
void NzRenderer::DrawPrimitives(nzPrimitiveMode mode, unsigned int firstVertex, unsigned int vertexCount)
@@ -358,9 +330,7 @@ void NzRenderer::DrawPrimitives(nzPrimitiveMode mode, unsigned int firstVertex,
}
glDrawArrays(NzOpenGL::PrimitiveMode[mode], firstVertex, vertexCount);
if (s_useVertexArrayObjects)
glBindVertexArray(0);
glBindVertexArray(0);
}
void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitiveMode mode, unsigned int firstVertex, unsigned int vertexCount)
@@ -380,12 +350,6 @@ void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitive
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return;
}
if (instanceCount == 0)
{
NazaraError("Instance count must be over zero");
@@ -409,9 +373,7 @@ void NzRenderer::DrawPrimitivesInstanced(unsigned int instanceCount, nzPrimitive
}
glDrawArraysInstanced(NzOpenGL::PrimitiveMode[mode], firstVertex, vertexCount, instanceCount);
if (s_useVertexArrayObjects)
glBindVertexArray(0);
glBindVertexArray(0);
}
void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
@@ -443,14 +405,6 @@ void NzRenderer::EndCondition()
}
#endif
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_ConditionalRendering])
{
NazaraError("Conditional rendering is not supported");
return;
}
#endif
glEndConditionalRender();
}
@@ -474,14 +428,6 @@ nzRendererComparison NzRenderer::GetDepthFunc()
NzVertexBuffer* NzRenderer::GetInstanceBuffer()
{
#if NAZARA_RENDERER_SAFE
if (!s_capabilities[nzRendererCap_Instancing])
{
NazaraError("Instancing not supported");
return nullptr;
}
#endif
s_updateFlags |= Update_VAO;
return &s_instanceBuffer;
}
@@ -629,19 +575,9 @@ bool NzRenderer::Initialize()
}
// Récupération des capacités d'OpenGL
s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter);
s_capabilities[nzRendererCap_ConditionalRendering] = NzOpenGL::IsSupported(nzOpenGLExtension_ConditionalRender);
s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64);
s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5
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);
s_capabilities[nzRendererCap_Texture3D] = true; // Natif depuis OpenGL 1.2
s_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3
s_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3
s_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0
s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter);
s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64);
s_capabilities[nzRendererCap_Instancing] = true; // Supporté par OpenGL 3.3
NzContext::EnsureContext();
@@ -655,39 +591,21 @@ bool NzRenderer::Initialize()
else
s_maxAnisotropyLevel = 1;
if (s_capabilities[nzRendererCap_RenderTexture])
{
GLint maxColorAttachments;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
GLint maxColorAttachments;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
s_maxColorAttachments = static_cast<unsigned int>(maxColorAttachments);
s_maxColorAttachments = static_cast<unsigned int>(maxColorAttachments);
}
else
s_maxColorAttachments = 1;
GLint maxDrawBuffers;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
s_maxRenderTarget = static_cast<unsigned int>(maxDrawBuffers);
if (s_capabilities[nzRendererCap_MultipleRenderTargets])
{
GLint maxDrawBuffers;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
s_maxRenderTarget = static_cast<unsigned int>(maxDrawBuffers);
}
else
s_maxRenderTarget = 1;
if (s_capabilities[nzRendererCap_TextureMulti])
{
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
s_maxTextureUnit = static_cast<unsigned int>(maxTextureUnits);
}
else
s_maxTextureUnit = 1;
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
s_maxTextureUnit = static_cast<unsigned int>(maxTextureUnits);
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
s_maxTextureSize = maxTextureSize;
s_maxTextureSize = static_cast<unsigned int>(maxTextureSize);
GLint maxVertexAttribs;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
@@ -700,8 +618,6 @@ bool NzRenderer::Initialize()
s_target = nullptr;
s_targetSize.Set(0U);
s_textureUnits.resize(s_maxTextureUnit);
s_useSamplerObjects = NzOpenGL::IsSupported(nzOpenGLExtension_SamplerObjects);
s_useVertexArrayObjects = NzOpenGL::IsSupported(nzOpenGLExtension_VertexArrayObjects);
s_updateFlags = Update_Matrices | Update_Shader | Update_VAO;
s_vertexBuffer = nullptr;
@@ -775,32 +691,13 @@ bool NzRenderer::Initialize()
return false;
}
const char* fragmentShader;
const char* vertexShader;
unsigned int fragmentShaderLength;
unsigned int vertexShaderLength;
if (NzOpenGL::GetGLSLVersion() >= 140)
{
fragmentShader = reinterpret_cast<const char*>(r_coreFragmentShader);
fragmentShaderLength = sizeof(r_coreFragmentShader);
vertexShader = reinterpret_cast<const char*>(r_coreVertexShader);
vertexShaderLength = sizeof(r_coreVertexShader);
}
else
{
fragmentShader = reinterpret_cast<const char*>(r_compatibilityFragmentShader);
fragmentShaderLength = sizeof(r_compatibilityFragmentShader);
vertexShader = reinterpret_cast<const char*>(r_compatibilityVertexShader);
vertexShaderLength = sizeof(r_compatibilityVertexShader);
}
if (!debugShader->AttachStageFromSource(nzShaderStage_Fragment, fragmentShader, fragmentShaderLength))
if (!debugShader->AttachStageFromSource(nzShaderStage_Fragment, reinterpret_cast<const char*>(r_coreFragmentShader), sizeof(r_coreFragmentShader)))
{
NazaraError("Failed to attach fragment stage");
return false;
}
if (!debugShader->AttachStageFromSource(nzShaderStage_Vertex, vertexShader, vertexShaderLength))
if (!debugShader->AttachStageFromSource(nzShaderStage_Vertex, reinterpret_cast<const char*>(r_coreVertexShader), sizeof(r_coreVertexShader)))
{
NazaraError("Failed to attach vertex stage");
return false;
@@ -1549,31 +1446,14 @@ bool NzRenderer::EnsureStateUpdate()
{
if (s_updateFlags & Update_Textures)
{
if (s_useSamplerObjects)
for (unsigned int i : s_dirtyTextureUnits)
{
for (unsigned int i : s_dirtyTextureUnits)
{
TextureUnit& unit = s_textureUnits[i];
TextureUnit& unit = s_textureUnits[i];
if (unit.texture && !unit.samplerUpdated)
{
unit.sampler.Bind(i);
unit.samplerUpdated = true;
}
}
}
else
{
for (unsigned int i : s_dirtyTextureUnits)
if (unit.texture && !unit.samplerUpdated)
{
TextureUnit& unit = s_textureUnits[i];
if (unit.texture && !unit.samplerUpdated)
{
NzOpenGL::BindTextureUnit(i);
unit.sampler.Apply(unit.texture);
unit.samplerUpdated = true;
}
unit.sampler.Bind(i);
unit.samplerUpdated = true;
}
}
@@ -1608,73 +1488,52 @@ bool NzRenderer::EnsureStateUpdate()
}
#endif
bool update;
VAO_Map::iterator vaoIt;
// Note: Les VAOs ne sont pas partagés entre les contextes, nous avons donc un tableau de VAOs par contexte
const NzContext* context = NzContext::GetCurrent();
// Si les VAOs sont supportés, on entoure nos appels par ceux-ci
if (s_useVertexArrayObjects)
auto it = s_vaos.find(context);
if (it == s_vaos.end())
{
// Note: Les VAOs ne sont pas partagés entre les contextes, nous avons donc un tableau de VAOs par contexte
const NzContext* context = NzContext::GetCurrent();
Context_Entry entry;
entry.onReleaseSlot.Connect(context->OnContextRelease, OnContextRelease);
auto it = s_vaos.find(context);
if (it == s_vaos.end())
{
Context_Entry entry;
entry.onReleaseSlot.Connect(context->OnContextRelease, OnContextRelease);
it = s_vaos.insert(std::make_pair(context, std::move(entry))).first;
}
VAO_Map& vaoMap = it->second.vaoMap;
// Notre clé est composée de ce qui définit un VAO
const NzVertexDeclaration* vertexDeclaration = s_vertexBuffer->GetVertexDeclaration();
const NzVertexDeclaration* instancingDeclaration = (s_instancing) ? s_instanceBuffer.GetVertexDeclaration() : nullptr;
VAO_Key key(s_indexBuffer, s_vertexBuffer, vertexDeclaration, instancingDeclaration);
// On recherche un VAO existant avec notre configuration
vaoIt = vaoMap.find(key);
if (vaoIt == vaoMap.end())
{
// On créé notre VAO
glGenVertexArrays(1, &s_currentVAO);
glBindVertexArray(s_currentVAO);
// On l'ajoute à notre liste
VAO_Entry entry;
entry.vao = s_currentVAO;
// Connect the slots
if (s_indexBuffer)
entry.onIndexBufferReleaseSlot.Connect(s_indexBuffer->OnIndexBufferRelease, OnIndexBufferRelease);
if (instancingDeclaration)
entry.onInstancingDeclarationReleaseSlot.Connect(instancingDeclaration->OnVertexDeclarationRelease, OnVertexDeclarationRelease);
entry.onVertexBufferReleaseSlot.Connect(s_vertexBuffer->OnVertexBufferRelease, OnVertexBufferRelease);
entry.onVertexDeclarationReleaseSlot.Connect(vertexDeclaration->OnVertexDeclarationRelease, OnVertexDeclarationRelease);
vaoIt = vaoMap.insert(std::make_pair(key, std::move(entry))).first;
// Et on indique qu'on veut le programmer
update = true;
}
else
{
// Notre VAO existe déjà, il est donc inutile de le reprogrammer
s_currentVAO = vaoIt->second.vao;
update = false;
}
it = s_vaos.insert(std::make_pair(context, std::move(entry))).first;
}
else
update = true; // Fallback si les VAOs ne sont pas supportés
bool updateFailed = false;
VAO_Map& vaoMap = it->second.vaoMap;
if (update)
// Notre clé est composée de ce qui définit un VAO
const NzVertexDeclaration* vertexDeclaration = s_vertexBuffer->GetVertexDeclaration();
const NzVertexDeclaration* instancingDeclaration = (s_instancing) ? s_instanceBuffer.GetVertexDeclaration() : nullptr;
VAO_Key key(s_indexBuffer, s_vertexBuffer, vertexDeclaration, instancingDeclaration);
// On recherche un VAO existant avec notre configuration
auto vaoIt = vaoMap.find(key);
if (vaoIt == vaoMap.end())
{
// On créé notre VAO
glGenVertexArrays(1, &s_currentVAO);
glBindVertexArray(s_currentVAO);
// On l'ajoute à notre liste
VAO_Entry entry;
entry.vao = s_currentVAO;
// Connect the slots
if (s_indexBuffer)
entry.onIndexBufferReleaseSlot.Connect(s_indexBuffer->OnIndexBufferRelease, OnIndexBufferRelease);
if (instancingDeclaration)
entry.onInstancingDeclarationReleaseSlot.Connect(instancingDeclaration->OnVertexDeclarationRelease, OnVertexDeclarationRelease);
entry.onVertexBufferReleaseSlot.Connect(s_vertexBuffer->OnVertexBufferRelease, OnVertexBufferRelease);
entry.onVertexDeclarationReleaseSlot.Connect(vertexDeclaration->OnVertexDeclarationRelease, OnVertexDeclarationRelease);
vaoIt = vaoMap.insert(std::make_pair(key, std::move(entry))).first;
// And begin to program it
bool updateFailed = false;
// Pour éviter la duplication de code, on va utiliser une astuce via une boucle for
for (unsigned int i = 0; i < (s_instancing ? 2U : 1U); ++i)
{
@@ -1714,11 +1573,11 @@ bool NzRenderer::EnsureStateUpdate()
case nzComponentType_Color:
{
glVertexAttribPointer(NzOpenGL::VertexComponentIndex[j],
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
GL_TRUE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
GL_TRUE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
break;
}
@@ -1729,10 +1588,10 @@ bool NzRenderer::EnsureStateUpdate()
case nzComponentType_Double4:
{
glVertexAttribLPointer(NzOpenGL::VertexComponentIndex[j],
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
break;
}
@@ -1743,11 +1602,11 @@ bool NzRenderer::EnsureStateUpdate()
case nzComponentType_Float4:
{
glVertexAttribPointer(NzOpenGL::VertexComponentIndex[j],
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
GL_FALSE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
GL_FALSE,
stride,
reinterpret_cast<void*>(bufferOffset + offset));
break;
}
@@ -1758,10 +1617,10 @@ bool NzRenderer::EnsureStateUpdate()
case nzComponentType_Int4:
{
glVertexAttribIPointer(NzOpenGL::VertexComponentIndex[j],
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
NzUtility::ComponentCount[type],
NzOpenGL::ComponentType[type],
stride,
reinterpret_cast<void*>(bufferOffset + offset));
break;
}
@@ -1772,6 +1631,7 @@ bool NzRenderer::EnsureStateUpdate()
break;
}
}
// Les attributs d'instancing ont un diviseur spécifique (pour dépendre de l'instance en cours)
if (i == 1)
glVertexAttribDivisor(NzOpenGL::VertexComponentIndex[j], 1);
@@ -1801,46 +1661,40 @@ bool NzRenderer::EnsureStateUpdate()
// 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)
{
if (update)
if (updateFailed)
{
if (updateFailed)
{
// La création de notre VAO a échoué, libérons-le et marquons-le comme problématique
glDeleteVertexArrays(1, &vaoIt->second.vao);
vaoIt->second.vao = 0;
s_currentVAO = 0;
}
else
glBindVertexArray(0); // On marque la fin de la construction du VAO en le débindant
// La création de notre VAO a échoué, libérons-le et marquons-le comme problématique
glDeleteVertexArrays(1, &vaoIt->second.vao);
vaoIt->second.vao = 0;
s_currentVAO = 0;
}
// En cas de non-support des VAOs, les attributs doivent être respécifiés à chaque frame
s_updateFlags &= ~Update_VAO;
else
glBindVertexArray(0); // On marque la fin de la construction du VAO en le débindant
}
else
// Notre VAO existe déjà, il est donc inutile de le reprogrammer
s_currentVAO = vaoIt->second.vao;
// En cas de non-support des VAOs, les attributs doivent être respécifiés à chaque frame
s_updateFlags &= ~Update_VAO;
}
#ifdef NAZARA_DEBUG
if (s_updateFlags != Update_None && !s_useVertexArrayObjects && s_updateFlags != Update_VAO)
if (s_updateFlags != Update_None && s_updateFlags != Update_VAO)
NazaraWarning("Update flags not fully cleared");
#endif
}
// On bind notre VAO
if (s_useVertexArrayObjects)
if (!s_currentVAO)
{
if (!s_currentVAO)
{
NazaraError("Failed to create VAO");
return false;
}
glBindVertexArray(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
// entre le dernier rendu et maintenant