Add new Renderer architecture (far from complete)
Former-commit-id: 52226793d7a087dfe0523315d3303934daffee49 [formerly 9de1c04df6b371f861a2eee8bba38902ee5041cd] [formerly ecd3099df5498722f6390447f40bd3907b8e40c4 [formerly 3076df585565fc9759ab3e718270f2e5ef620840]] Former-commit-id: 92d52f967d0b088d1271afef26069e08cacd6b0f [formerly 5fe27e2ead104278951c772c2121a7b677f88d4d] Former-commit-id: fb6c2456d8edd3ec022d5d953f79fecdd4f2b8f4
This commit is contained in:
@@ -1,376 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_GLX)
|
||||
#include <Nazara/Renderer/GLX/ContextImpl.hpp>
|
||||
#define CALLBACK
|
||||
#else
|
||||
#error Lack of implementation: Context
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
thread_local const Context* s_currentContext = nullptr;
|
||||
thread_local const Context* s_threadContext = nullptr;
|
||||
|
||||
void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, const void* userParam)
|
||||
{
|
||||
NazaraUnused(length);
|
||||
|
||||
StringStream ss;
|
||||
ss << "OpenGL debug message (ID: 0x" << String::Number(id, 16) << "):\n";
|
||||
ss << "Sent by context: " << userParam;
|
||||
ss << "\n-Source: ";
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API:
|
||||
ss << "OpenGL API";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
|
||||
ss << "Operating system";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER:
|
||||
ss << "Shader compiler";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY:
|
||||
ss << "Third party";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_APPLICATION:
|
||||
ss << "Application";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_OTHER:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Type: ";
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR:
|
||||
ss << "Error";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
|
||||
ss << "Deprecated behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
|
||||
ss << "Undefined behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PORTABILITY:
|
||||
ss << "Portability";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PERFORMANCE:
|
||||
ss << "Performance";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_OTHER:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Severity: ";
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
ss << "High";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
ss << "Medium";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
ss << "Low";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "Message: " << message << '\n';
|
||||
|
||||
NazaraNotice(ss);
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
OnContextRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool Context::Create(const ContextParameters& parameters)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_parameters = parameters;
|
||||
if (m_parameters.shared && !m_parameters.shareContext)
|
||||
m_parameters.shareContext = s_reference.get();
|
||||
|
||||
std::unique_ptr<ContextImpl> impl(new ContextImpl);
|
||||
if (!impl->Create(m_parameters))
|
||||
{
|
||||
NazaraError("Failed to create context implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
|
||||
CallOnExit onExit([this] () { Destroy(); });
|
||||
|
||||
if (!SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_parameters.antialiasingLevel > 0)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
if (m_parameters.debugMode && OpenGL::IsSupported(OpenGLExtension_DebugOutput))
|
||||
{
|
||||
glDebugMessageCallback(&DebugCallback, this);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
#endif
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
OnContextDestroy(this);
|
||||
|
||||
OpenGL::OnContextDestruction(this);
|
||||
SetActive(false);
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Context::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->EnableVerticalSync(enabled);
|
||||
}
|
||||
|
||||
const ContextParameters& Context::GetParameters() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
NazaraError("No context has been created");
|
||||
#endif
|
||||
|
||||
return m_parameters;
|
||||
}
|
||||
|
||||
bool Context::IsActive() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return s_currentContext == this;
|
||||
}
|
||||
|
||||
bool Context::SetActive(bool active) const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Si le contexte est déjà activé/désactivé
|
||||
if ((s_currentContext == this) == active)
|
||||
return true;
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (!m_impl->Activate())
|
||||
return false;
|
||||
|
||||
s_currentContext = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ContextImpl::Desactivate())
|
||||
return false;
|
||||
|
||||
s_currentContext = nullptr;
|
||||
}
|
||||
|
||||
OpenGL::OnContextChanged(s_currentContext);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::SwapBuffers()
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_parameters.doubleBuffered)
|
||||
{
|
||||
NazaraError("Context is not double buffered");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SwapBuffers();
|
||||
}
|
||||
|
||||
bool Context::EnsureContext()
|
||||
{
|
||||
if (!s_currentContext)
|
||||
{
|
||||
if (!s_threadContext)
|
||||
{
|
||||
std::unique_ptr<Context> context(new Context);
|
||||
if (!context->Create())
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_threadContext = context.get();
|
||||
|
||||
s_contexts.emplace_back(std::move(context));
|
||||
}
|
||||
|
||||
if (!s_threadContext->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to active thread context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Context* Context::GetCurrent()
|
||||
{
|
||||
return s_currentContext;
|
||||
}
|
||||
|
||||
const Context* Context::GetReference()
|
||||
{
|
||||
return s_reference.get();
|
||||
}
|
||||
|
||||
const Context* Context::GetThreadContext()
|
||||
{
|
||||
EnsureContext();
|
||||
|
||||
return s_threadContext;
|
||||
}
|
||||
|
||||
bool Context::Initialize()
|
||||
{
|
||||
if (!ContextLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
ContextParameters parameters;
|
||||
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
|
||||
|
||||
std::unique_ptr<Context> reference(new Context);
|
||||
if (!reference->Create(parameters))
|
||||
{
|
||||
NazaraError("Failed to create reference context");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le contexte de référence doit rester désactivé pour le partage
|
||||
if (!reference->SetActive(false))
|
||||
{
|
||||
NazaraError("Failed to desactive reference context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_reference = std::move(reference);
|
||||
|
||||
// Le contexte de référence est partagé par défaut avec les autres contextes
|
||||
ContextParameters::defaultShareContext = s_reference.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::Uninitialize()
|
||||
{
|
||||
ContextLibrary::Uninitialize();
|
||||
s_contexts.clear(); // On supprime tous les contextes créés
|
||||
s_reference.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> Context::s_reference;
|
||||
std::vector<std::unique_ptr<Context>> Context::s_contexts;
|
||||
ContextLibrary::LibraryMap Context::s_library;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ContextParameters.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
|
||||
UInt8 ContextParameters::defaultMajorVersion;
|
||||
|
||||
// Version majeure d'OpenGL, initialisé par OpenGL::Initialize()
|
||||
UInt8 ContextParameters::defaultMinorVersion;
|
||||
|
||||
// Contexte de partage par défaut, initialisé par OpenGL::Initialize()
|
||||
const Context* ContextParameters::defaultShareContext = nullptr;
|
||||
|
||||
// Si possible, garder la compatibilité avec les fonctionnalités dépréciées
|
||||
bool ContextParameters::defaultCompatibilityProfile = false;
|
||||
|
||||
// Mode debug d'OpenGL par défaut
|
||||
#if NAZARA_RENDERER_OPENGL_DEBUG || defined(NAZARA_DEBUG)
|
||||
bool ContextParameters::defaultDebugMode = true;
|
||||
#else
|
||||
bool ContextParameters::defaultDebugMode = false;
|
||||
#endif
|
||||
|
||||
// Active le double-buffering sur les contextes
|
||||
bool ContextParameters::defaultDoubleBuffered = false;
|
||||
|
||||
// Active le partage des ressources entre contextes (Via le defaultShareContext)
|
||||
bool ContextParameters::defaultShared = true;
|
||||
}
|
||||
@@ -1,741 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/DebugDrawer.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
#include <Nazara/Utility/VertexDeclaration.hpp>
|
||||
#include <Nazara/Utility/VertexStruct.hpp>
|
||||
#include <memory>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
///TODO: Améliorer
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static Shader* s_shader = nullptr;
|
||||
static Color s_primaryColor;
|
||||
static Color s_secondaryColor;
|
||||
static RenderStates s_renderStates;
|
||||
static VertexBuffer s_vertexBuffer;
|
||||
static bool s_initialized = false;
|
||||
static int s_colorLocation = -1;
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const BoundingVolumef& volume)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!volume.IsFinite())
|
||||
return;
|
||||
|
||||
Color oldPrimaryColor = s_primaryColor;
|
||||
|
||||
Draw(volume.aabb);
|
||||
|
||||
s_primaryColor = s_secondaryColor;
|
||||
Draw(volume.obb);
|
||||
|
||||
s_primaryColor = oldPrimaryColor;
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxi& box)
|
||||
{
|
||||
Draw(Boxf(box));
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxf& box)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
Vector3f max, min;
|
||||
max = box.GetMaximum();
|
||||
min = box.GetMinimum();
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, max.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, min.y, max.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(min.x, max.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(min.x, max.y, max.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, max.y, min.z);
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(max.x, min.y, min.z);
|
||||
vertex++;
|
||||
vertex->position.Set(max.x, min.y, max.z);
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Boxui& box)
|
||||
{
|
||||
Draw(Boxf(box));
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Frustumf& frustum)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(frustum.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const OrientedBoxf& orientedBox)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 24);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearLeftTop));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarLeftTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightTop));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_NearRightBottom));
|
||||
vertex++;
|
||||
vertex->position.Set(orientedBox.GetCorner(BoxCorner_FarRightBottom));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 24);
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Skeleton* skeleton)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int jointCount = skeleton->GetJointCount();
|
||||
if (s_vertexBuffer.GetVertexCount() < jointCount*2)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, jointCount*2);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
unsigned int vertexCount = 0;
|
||||
for (unsigned int i = 0; i < jointCount; ++i)
|
||||
{
|
||||
const Node* joint = skeleton->GetJoint(i);
|
||||
const Node* parent = joint->GetParent();
|
||||
if (parent)
|
||||
{
|
||||
vertex->position = joint->GetPosition();
|
||||
vertex++;
|
||||
|
||||
vertex->position = parent->GetPosition();
|
||||
vertex++;
|
||||
|
||||
vertexCount += 2;
|
||||
}
|
||||
}
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_secondaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_PointList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::Draw(const Vector3f& position, float size)
|
||||
{
|
||||
Draw(Boxf(position.x - size*0.5f, position.y - size*0.5f, position.z - size*0.5f, size, size, size));
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawAxes(const Vector3f& position, float size)
|
||||
{
|
||||
Color oldPrimaryColor = s_primaryColor;
|
||||
s_primaryColor = Color::Red;
|
||||
DrawLine(position, position + Vector3f::UnitX() * 3.f * size / 4.f);
|
||||
s_primaryColor = Color::Green;
|
||||
DrawLine(position, position + Vector3f::UnitY() * 3.f * size / 4.f);
|
||||
s_primaryColor = Color::Blue;
|
||||
DrawLine(position, position + Vector3f::UnitZ() * 3.f * size / 4.f);
|
||||
|
||||
s_primaryColor = Color::Red;
|
||||
DrawCone(position + Vector3f::UnitX() * size, EulerAnglesf(0.f, 90.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = Color::Green;
|
||||
DrawCone(position + Vector3f::UnitY() * size, EulerAnglesf(-90.f, 0.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = Color::Blue;
|
||||
DrawCone(position + Vector3f::UnitZ() * size, EulerAnglesf(0.f, 0.f, 0.f), 15, size / 4.f);
|
||||
s_primaryColor = oldPrimaryColor;
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawBinormals(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normalCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = normalCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < normalCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + Vector3f::CrossProduct(inputVertex->normal, inputVertex->tangent)*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawCone(const Vector3f& origin, const Quaternionf& rotation, float angle, float length)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4f transformMatrix;
|
||||
transformMatrix.MakeIdentity();
|
||||
transformMatrix.SetRotation(rotation);
|
||||
transformMatrix.SetTranslation(origin);
|
||||
|
||||
BufferMapper<VertexBuffer> mapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, 16);
|
||||
VertexStruct_XYZ* vertex = static_cast<VertexStruct_XYZ*>(mapper.GetPointer());
|
||||
|
||||
// On calcule le reste des points
|
||||
Vector3f base(Vector3f::Forward()*length);
|
||||
|
||||
// Il nous faut maintenant le rayon du cercle projeté à cette distance
|
||||
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
|
||||
float radius = length*std::tan(DegreeToRadian(angle));
|
||||
Vector3f lExtend = Vector3f::Left()*radius;
|
||||
Vector3f uExtend = Vector3f::Up()*radius;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base + lExtend - uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * Vector3f::Zero());
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base - lExtend - uExtend));
|
||||
vertex++;
|
||||
|
||||
vertex->position.Set(transformMatrix * (base - lExtend + uExtend));
|
||||
vertex++;
|
||||
vertex->position.Set(transformMatrix * (base + lExtend + uExtend));
|
||||
vertex++;
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 16);
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawLine(const Vector3f& p1, const Vector3f& p2)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
VertexStruct_XYZ buffer[2];
|
||||
buffer[0].position = p1;
|
||||
buffer[1].position = p2;
|
||||
|
||||
s_vertexBuffer.Fill(&buffer[0], 0, 2);
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, 2);
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawPoints(const Vector3f* ptr, unsigned int pointCount)
|
||||
{
|
||||
static_assert(sizeof(VertexStruct_XYZ) == sizeof(Vector3f), "VertexStruct_XYZ is no longer equal to Vector3f, please rewrite this");
|
||||
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pointCount > 0)
|
||||
{
|
||||
s_vertexBuffer.Fill(ptr, 0, pointCount);
|
||||
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_PointList, 0, pointCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawNormals(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int normalCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = normalCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < normalCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + inputVertex->normal*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::DrawTangents(const StaticMesh* subMesh)
|
||||
{
|
||||
if (!s_initialized && !Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Debug Drawer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int tangentCount = subMesh->GetVertexCount();
|
||||
unsigned int vertexCount = tangentCount*2;
|
||||
if (s_vertexBuffer.GetVertexCount() < vertexCount)
|
||||
{
|
||||
NazaraError("Debug buffer not large enougth to draw object");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferMapper<VertexBuffer> inputMapper(subMesh->GetVertexBuffer(), BufferAccess_ReadOnly);
|
||||
BufferMapper<VertexBuffer> outputMapper(s_vertexBuffer, BufferAccess_DiscardAndWrite, 0, vertexCount);
|
||||
|
||||
MeshVertex* inputVertex = static_cast<MeshVertex*>(inputMapper.GetPointer());
|
||||
VertexStruct_XYZ* outputVertex = static_cast<VertexStruct_XYZ*>(outputMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < tangentCount; ++i)
|
||||
{
|
||||
outputVertex->position = inputVertex->position;
|
||||
outputVertex++;
|
||||
|
||||
outputVertex->position = inputVertex->position + inputVertex->tangent*0.01f;
|
||||
outputVertex++;
|
||||
|
||||
inputVertex++;
|
||||
}
|
||||
|
||||
inputMapper.Unmap();
|
||||
outputMapper.Unmap();
|
||||
|
||||
if (vertexCount > 0)
|
||||
{
|
||||
Renderer::SetRenderStates(s_renderStates);
|
||||
Renderer::SetShader(s_shader);
|
||||
Renderer::SetVertexBuffer(&s_vertexBuffer);
|
||||
|
||||
s_shader->SendColor(s_colorLocation, s_primaryColor);
|
||||
Renderer::DrawPrimitives(PrimitiveMode_LineList, 0, vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDrawer::EnableDepthBuffer(bool depthBuffer)
|
||||
{
|
||||
s_renderStates.depthBuffer = depthBuffer;
|
||||
}
|
||||
|
||||
float DebugDrawer::GetLineWidth()
|
||||
{
|
||||
return s_renderStates.lineWidth;
|
||||
}
|
||||
|
||||
float DebugDrawer::GetPointSize()
|
||||
{
|
||||
return s_renderStates.pointSize;
|
||||
}
|
||||
|
||||
Color DebugDrawer::GetPrimaryColor()
|
||||
{
|
||||
return s_primaryColor;
|
||||
}
|
||||
|
||||
Color DebugDrawer::GetSecondaryColor()
|
||||
{
|
||||
return s_secondaryColor;
|
||||
}
|
||||
|
||||
bool DebugDrawer::Initialize()
|
||||
{
|
||||
if (!s_initialized)
|
||||
{
|
||||
// s_shader
|
||||
s_shader = ShaderLibrary::Get("DebugSimple");
|
||||
s_colorLocation = s_shader->GetUniformLocation("Color");
|
||||
|
||||
// s_vertexBuffer
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
s_vertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ), 65365, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError("Failed to create buffer: " + String(e.what()));
|
||||
|
||||
Uninitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
s_primaryColor = Color::Red;
|
||||
s_renderStates.depthBuffer = true;
|
||||
s_secondaryColor = Color::Green;
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugDrawer::IsDepthBufferEnabled()
|
||||
{
|
||||
return s_renderStates.depthBuffer;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetLineWidth(float width)
|
||||
{
|
||||
s_renderStates.lineWidth = width;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetPointSize(float size)
|
||||
{
|
||||
s_renderStates.pointSize = size;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetPrimaryColor(const Color& color)
|
||||
{
|
||||
s_primaryColor = color;
|
||||
}
|
||||
|
||||
void DebugDrawer::SetSecondaryColor(const Color& color)
|
||||
{
|
||||
s_secondaryColor = color;
|
||||
}
|
||||
|
||||
void DebugDrawer::Uninitialize()
|
||||
{
|
||||
s_shader = nullptr;
|
||||
s_vertexBuffer.Reset();
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/GLX/ContextImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
using namespace GLX;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
Display* m_display;
|
||||
int m_sharedDisplay = 0;
|
||||
|
||||
bool ctxErrorOccurred = false;
|
||||
int ctxErrorHandler( Display* /*dpy*/, XErrorEvent* /*ev*/ )
|
||||
{
|
||||
ctxErrorOccurred = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ContextImpl::ContextImpl() :
|
||||
m_colormap(0),
|
||||
m_context(0),
|
||||
m_window(0),
|
||||
m_ownsWindow(false)
|
||||
{
|
||||
if (m_sharedDisplay == 0)
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
|
||||
++m_sharedDisplay;
|
||||
}
|
||||
|
||||
ContextImpl::~ContextImpl()
|
||||
{
|
||||
Destroy();
|
||||
|
||||
if (--m_sharedDisplay == 0)
|
||||
{
|
||||
XCloseDisplay(m_display);
|
||||
m_display = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextImpl::Activate()
|
||||
{
|
||||
return glXMakeCurrent(m_display, m_window, m_context) == true;
|
||||
}
|
||||
|
||||
bool ContextImpl::Create(ContextParameters& parameters)
|
||||
{
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
// Get a matching FB config
|
||||
static int visual_attribs[] =
|
||||
{
|
||||
GLX_X_RENDERABLE, True,
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||
GLX_BUFFER_SIZE, parameters.bitsPerPixel,
|
||||
GLX_ALPHA_SIZE, (parameters.bitsPerPixel == 32) ? 8 : 0,
|
||||
GLX_DEPTH_SIZE, parameters.depthBits,
|
||||
GLX_STENCIL_SIZE, parameters.stencilBits,
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
GLX_SAMPLE_BUFFERS, (parameters.antialiasingLevel > 0) ? True : False,
|
||||
GLX_SAMPLES, parameters.antialiasingLevel,
|
||||
None
|
||||
};
|
||||
|
||||
int glx_major = 0;
|
||||
int glx_minor = 0;
|
||||
// FBConfigs were added in GLX version 1.3.
|
||||
if (!glXQueryVersion(m_display, &glx_major, &glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1))
|
||||
{
|
||||
NazaraError("Invalid GLX version, version > 1.3 is required.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(m_display, XDefaultScreen(m_display), visual_attribs, &fbcount);
|
||||
if (!fbc)
|
||||
{
|
||||
NazaraError("Failed to retrieve a framebuffer config");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pick the FB config/visual with the most samples per pixel
|
||||
int best_fbc = -1;
|
||||
int worst_fbc = -1;
|
||||
int best_num_samp = -1;
|
||||
int worst_num_samp = 999;
|
||||
|
||||
for (int i = 0; i < fbcount; ++i)
|
||||
{
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, fbc[i]);
|
||||
|
||||
if (vi)
|
||||
{
|
||||
int samp_buf = 0, samples = 0;
|
||||
glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
|
||||
glXGetFBConfigAttrib(m_display, fbc[i], GLX_SAMPLES , &samples );
|
||||
|
||||
if ((best_fbc < 0) || (samp_buf && (samples > best_num_samp)))
|
||||
{
|
||||
best_fbc = i;
|
||||
best_num_samp = samples;
|
||||
}
|
||||
if ((worst_fbc < 0) || !samp_buf || (samples < worst_num_samp))
|
||||
{
|
||||
worst_fbc = i;
|
||||
worst_num_samp = samples;
|
||||
}
|
||||
}
|
||||
XFree(vi);
|
||||
}
|
||||
|
||||
GLXFBConfig bestFbc = fbc[best_fbc];
|
||||
|
||||
// Be sure to free the FBConfig list allocated by glXChooseFBConfig()
|
||||
XFree(fbc);
|
||||
|
||||
// Get a visual
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, bestFbc);
|
||||
if (!vi)
|
||||
{
|
||||
NazaraError("Failed to get best VisualInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If context is shared by multiple windows
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = parameters.window;
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = m_colormap = XCreateColormap(
|
||||
m_display,
|
||||
XRootWindow(
|
||||
m_display,
|
||||
vi->screen),
|
||||
vi->visual,
|
||||
AllocNone
|
||||
);
|
||||
|
||||
swa.background_pixmap = None;
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = StructureNotifyMask;
|
||||
|
||||
if (!m_colormap)
|
||||
{
|
||||
NazaraError("Failed to create colormap for context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window = XCreateWindow(
|
||||
m_display,
|
||||
XRootWindow(
|
||||
m_display,
|
||||
vi->screen),
|
||||
0, 0, // X, Y
|
||||
1, 1, // W H
|
||||
0,
|
||||
vi->depth,
|
||||
InputOutput,
|
||||
vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask,
|
||||
&swa
|
||||
);
|
||||
|
||||
m_ownsWindow = true;
|
||||
}
|
||||
|
||||
if (!m_window)
|
||||
{
|
||||
NazaraError("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Done with the visual info data
|
||||
XFree(vi);
|
||||
|
||||
// Install an X error handler so the application won't exit if GL 3.0
|
||||
// context allocation fails.
|
||||
//
|
||||
// Note this error handler is global. All display connections in all threads
|
||||
// of a process use the same error handler, so be sure to guard against other
|
||||
// threads issuing X commands while this code is running.
|
||||
ctxErrorOccurred = false;
|
||||
int (*oldHandler)(Display*, XErrorEvent*) =
|
||||
XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
// Check for the GLX_ARB_create_context extension string and the function.
|
||||
// If either is not present, use GLX 1.3 context creation method.
|
||||
if (!glXCreateContextAttribs)
|
||||
{
|
||||
NazaraWarning("glXCreateContextAttribs() not found. Using old-style GLX context");
|
||||
m_context = glXCreateNewContext(m_display, bestFbc, GLX_RGBA_TYPE, parameters.shared ? parameters.shareContext->m_impl->m_context : 0, True);
|
||||
}
|
||||
// If it does, try to get a GL 3.0 context!
|
||||
else
|
||||
{
|
||||
int profile = parameters.compatibilityProfile ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
int debug = parameters.debugMode ? GLX_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
|
||||
int major = 3;//parameters.majorVersion;
|
||||
int minor = 3;//parameters.minorVersion;
|
||||
|
||||
int context_attribs[] =
|
||||
{
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, minor,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, profile,
|
||||
GLX_CONTEXT_FLAGS_ARB, debug,
|
||||
None, None
|
||||
};
|
||||
|
||||
m_context = glXCreateContextAttribs(
|
||||
m_display,
|
||||
bestFbc,
|
||||
parameters.shared ? parameters.shareContext->m_impl->m_context : 0,
|
||||
True,
|
||||
context_attribs
|
||||
);
|
||||
}
|
||||
|
||||
// Sync to ensure any errors generated are processed.
|
||||
XSync(m_display, False);
|
||||
XSetErrorHandler(oldHandler);
|
||||
if (ctxErrorOccurred || !m_context)
|
||||
{
|
||||
NazaraError("Failed to create context, check the version");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextImpl::Destroy()
|
||||
{
|
||||
// Destroy the context
|
||||
if (m_context)
|
||||
{
|
||||
if (glXGetCurrentContext() == m_context)
|
||||
glXMakeCurrent(m_display, None, nullptr);
|
||||
glXDestroyContext(m_display, m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
// Destroy the window if we own it
|
||||
if (m_ownsWindow && m_window)
|
||||
{
|
||||
XFreeColormap(m_display, m_colormap);
|
||||
XDestroyWindow(m_display, m_window);
|
||||
m_ownsWindow = false;
|
||||
m_window = 0;
|
||||
XFlush(m_display);
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImpl::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
if (glXSwapIntervalEXT)
|
||||
glXSwapIntervalEXT(m_display, glXGetCurrentDrawable(), enabled ? 1 : 0);
|
||||
else if (NzglXSwapIntervalMESA)
|
||||
NzglXSwapIntervalMESA(enabled ? 1 : 0);
|
||||
else if (glXSwapIntervalSGI)
|
||||
glXSwapIntervalSGI(enabled ? 1 : 0);
|
||||
else
|
||||
NazaraError("Vertical sync not supported");
|
||||
}
|
||||
|
||||
void ContextImpl::SwapBuffers()
|
||||
{
|
||||
if (m_window)
|
||||
glXSwapBuffers(m_display, m_window);
|
||||
}
|
||||
|
||||
bool ContextImpl::Desactivate()
|
||||
{
|
||||
return glXMakeCurrent(m_display, None, nullptr) == true;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine".
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CONTEXTIMPL_HPP
|
||||
#define NAZARA_CONTEXTIMPL_HPP
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ContextParameters;
|
||||
|
||||
class ContextImpl
|
||||
{
|
||||
public:
|
||||
ContextImpl();
|
||||
~ContextImpl();
|
||||
|
||||
bool Activate();
|
||||
|
||||
bool Create(ContextParameters& parameters);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableVerticalSync(bool enabled);
|
||||
|
||||
void SwapBuffers();
|
||||
|
||||
static bool Desactivate();
|
||||
|
||||
private:
|
||||
GLX::Colormap m_colormap;
|
||||
GLX::GLXContext m_context;
|
||||
GLX::Window m_window;
|
||||
bool m_ownsWindow;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONTEXTIMPL_HPP
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/GpuQuery.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
GpuQuery::GpuQuery() :
|
||||
m_id(0)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
m_id = 0;
|
||||
glGenQueries(1, static_cast<GLuint*>(&m_id));
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Failed to create occlusion query");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GpuQuery::~GpuQuery()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
GLuint query = static_cast<GLuint>(m_id);
|
||||
glDeleteQueries(1, &query);
|
||||
}
|
||||
}
|
||||
|
||||
void GpuQuery::Begin(GpuQueryMode mode)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!IsModeSupported(mode))
|
||||
{
|
||||
NazaraError("Mode (0x" + String::Number(mode, 16) + ") not supported");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_mode = mode;
|
||||
glBeginQuery(OpenGL::QueryMode[mode], m_id);
|
||||
}
|
||||
|
||||
void GpuQuery::End()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glEndQuery(OpenGL::QueryMode[m_mode]);
|
||||
}
|
||||
|
||||
unsigned int GpuQuery::GetResult() const
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
GLuint result;
|
||||
glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GpuQuery::IsResultAvailable() const
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
GLint available;
|
||||
glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
|
||||
return available == GL_TRUE;
|
||||
}
|
||||
|
||||
unsigned int GpuQuery::GetOpenGLID() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
bool GpuQuery::IsModeSupported(GpuQueryMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case GpuQueryMode_AnySamplesPassedConservative:
|
||||
return OpenGL::GetVersion() >= 430;
|
||||
|
||||
case GpuQueryMode_AnySamplesPassed:
|
||||
case GpuQueryMode_PrimitiveGenerated:
|
||||
case GpuQueryMode_SamplesPassed:
|
||||
case GpuQueryMode_TimeElapsed:
|
||||
case GpuQueryMode_TransformFeedbackPrimitivesWritten:
|
||||
return true;
|
||||
}
|
||||
|
||||
NazaraError("Gpu Query mode not handled (0x" + String::Number(mode, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/HardwareBuffer.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
HardwareBuffer::HardwareBuffer(Buffer* parent, BufferType type) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
HardwareBuffer::~HardwareBuffer() = default;
|
||||
|
||||
bool HardwareBuffer::Create(unsigned int size, BufferUsage usage)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
m_buffer = 0;
|
||||
glGenBuffers(1, &m_buffer);
|
||||
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
|
||||
glBufferData(OpenGL::BufferTarget[m_type], size, nullptr, OpenGL::BufferUsage[usage]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HardwareBuffer::Destroy()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
OpenGL::DeleteBuffer(m_type, m_buffer);
|
||||
}
|
||||
|
||||
bool HardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
unsigned int totalSize = m_parent->GetSize();
|
||||
|
||||
if (!forceDiscard)
|
||||
forceDiscard = (size == totalSize);
|
||||
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
|
||||
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
|
||||
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
|
||||
if (size < 32*1024)
|
||||
{
|
||||
// http://www.opengl.org/wiki/Buffer_Object_Streaming
|
||||
if (forceDiscard)
|
||||
glBufferData(OpenGL::BufferTarget[m_type], totalSize, nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
||||
|
||||
glBufferSubData(OpenGL::BufferTarget[m_type], offset, size, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* ptr = Map((forceDiscard) ? BufferAccess_DiscardAndWrite : BufferAccess_WriteOnly, offset, size);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(ptr, data, size);
|
||||
|
||||
Unmap();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HardwareBuffer::IsHardware() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* HardwareBuffer::Map(BufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
|
||||
if (glMapBufferRange)
|
||||
return glMapBufferRange(OpenGL::BufferTarget[m_type], offset, size, OpenGL::BufferLockRange[access]);
|
||||
else
|
||||
{
|
||||
// http://www.opengl.org/wiki/Buffer_Object_Streaming
|
||||
if (access == BufferAccess_DiscardAndWrite)
|
||||
glBufferData(OpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
||||
|
||||
UInt8* ptr = static_cast<UInt8*>(glMapBuffer(OpenGL::BufferTarget[m_type], OpenGL::BufferLock[access]));
|
||||
if (ptr)
|
||||
ptr += offset;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool HardwareBuffer::Unmap()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
|
||||
if (glUnmapBuffer(OpenGL::BufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
glBufferData(OpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, OpenGL::BufferUsage[m_parent->GetUsage()]);
|
||||
|
||||
// Une erreur rare est survenue, nous devons réinitialiser le buffer
|
||||
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + String::Number(glGetError(), 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HardwareBuffer::Bind() const
|
||||
{
|
||||
OpenGL::BindBuffer(m_type, m_buffer);
|
||||
}
|
||||
|
||||
unsigned int HardwareBuffer::GetOpenGLID() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_HARDWAREBUFFER_HPP
|
||||
#define NAZARA_HARDWAREBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Utility/AbstractBuffer.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class HardwareBuffer : public AbstractBuffer
|
||||
{
|
||||
public:
|
||||
HardwareBuffer(Buffer* parent, BufferType type);
|
||||
~HardwareBuffer();
|
||||
|
||||
bool Create(unsigned int size, BufferUsage usage = BufferUsage_Static);
|
||||
void Destroy();
|
||||
|
||||
bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard);
|
||||
|
||||
bool IsHardware() const;
|
||||
|
||||
void* Map(BufferAccess access, unsigned int offset = 0, unsigned int size = 0);
|
||||
bool Unmap();
|
||||
|
||||
// Fonctions OpenGL
|
||||
void Bind() const;
|
||||
unsigned int GetOpenGLID() const;
|
||||
|
||||
private:
|
||||
GLuint m_buffer;
|
||||
BufferType m_type;
|
||||
Buffer* m_parent;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_HARDWAREBUFFER_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,133 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderBuffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderBuffer::RenderBuffer() :
|
||||
m_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
RenderBuffer::~RenderBuffer()
|
||||
{
|
||||
OnRenderBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool RenderBuffer::Create(PixelFormatType format, unsigned int width, unsigned int height)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
NazaraError("Invalid size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PixelFormat::IsValid(format))
|
||||
{
|
||||
NazaraError("Invalid pixel format");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
OpenGL::Format openglFormat;
|
||||
if (!OpenGL::TranslateFormat(format, &openglFormat, OpenGL::FormatType_RenderBuffer))
|
||||
{
|
||||
NazaraError("Failed to translate pixel format \"" + PixelFormat::GetName(format) + "\" into OpenGL format");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint renderBuffer = 0;
|
||||
|
||||
glGenRenderbuffers(1, &renderBuffer);
|
||||
if (!renderBuffer)
|
||||
{
|
||||
NazaraError("Failed to create renderbuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, width, height);
|
||||
|
||||
if (previous != 0)
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, previous);
|
||||
|
||||
m_pixelFormat = format;
|
||||
m_height = height;
|
||||
m_id = renderBuffer;
|
||||
m_width = width;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderBuffer::Destroy()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
OnRenderBufferDestroy(this);
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
GLuint renderBuffer = m_id;
|
||||
glDeleteRenderbuffers(1, &renderBuffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème
|
||||
m_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int RenderBuffer::GetHeight() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
PixelFormatType RenderBuffer::GetFormat() const
|
||||
{
|
||||
return m_pixelFormat;
|
||||
}
|
||||
|
||||
unsigned int RenderBuffer::GetWidth() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
unsigned int RenderBuffer::GetOpenGLID() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
bool RenderBuffer::IsValid() const
|
||||
{
|
||||
return m_id != 0;
|
||||
}
|
||||
|
||||
bool RenderBuffer::Initialize()
|
||||
{
|
||||
if (!RenderBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderBuffer::Uninitialize()
|
||||
{
|
||||
RenderBufferLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
RenderBufferLibrary::LibraryMap RenderBuffer::s_library;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
OnRenderTargetRelease(this);
|
||||
}
|
||||
|
||||
bool RenderTarget::IsActive() const
|
||||
{
|
||||
return Renderer::GetTarget() == this;
|
||||
}
|
||||
|
||||
bool RenderTarget::SetActive(bool active)
|
||||
{
|
||||
if (active)
|
||||
return Renderer::SetTarget(this);
|
||||
else if (Renderer::GetTarget() == this)
|
||||
return Renderer::SetTarget(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTarget::Desactivate() const
|
||||
{
|
||||
// Seuls les target sans contextes (ex: RenderTexture) nécessitent une désactivation
|
||||
}
|
||||
}
|
||||
@@ -1,854 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderBuffer.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct Attachment
|
||||
{
|
||||
NazaraSlot(RenderBuffer, OnRenderBufferDestroy, renderBufferDestroySlot);
|
||||
NazaraSlot(Texture, OnTextureDestroy, textureDestroySlot);
|
||||
|
||||
RenderBufferRef buffer;
|
||||
TextureRef texture;
|
||||
|
||||
AttachmentPoint attachmentPoint;
|
||||
bool isBuffer;
|
||||
bool isUsed = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
unsigned int attachmentIndex[AttachmentPoint_Max+1] =
|
||||
{
|
||||
3, // AttachmentPoint_Color
|
||||
0, // AttachmentPoint_Depth
|
||||
1, // AttachmentPoint_DepthStencil
|
||||
2 // AttachmentPoint_Stencil
|
||||
};
|
||||
|
||||
AttachmentPoint FormatTypeToAttachment(PixelFormatType format)
|
||||
{
|
||||
const PixelFormatInfo& info = PixelFormat::GetInfo(format);
|
||||
switch (info.content)
|
||||
{
|
||||
case PixelFormatContent_ColorRGBA:
|
||||
return AttachmentPoint_Color;
|
||||
|
||||
case PixelFormatContent_DepthStencil:
|
||||
return (!info.greenMask.TestAny()) ? AttachmentPoint_Depth : AttachmentPoint_DepthStencil;
|
||||
|
||||
case PixelFormatContent_Stencil:
|
||||
return AttachmentPoint_Stencil;
|
||||
|
||||
case PixelFormatContent_Undefined:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraInternalError("Unexpected pixel format content: 0x" + String::Number(info.content, 16));
|
||||
return AttachmentPoint_Max;
|
||||
}
|
||||
|
||||
GLuint lockedPrevious = 0;
|
||||
UInt8 lockedLevel = 0;
|
||||
}
|
||||
|
||||
struct RenderTextureImpl
|
||||
{
|
||||
NazaraSlot(Context, OnContextDestroy, contextDestroySlot);
|
||||
|
||||
GLuint fbo;
|
||||
std::vector<Attachment> attachments;
|
||||
std::vector<UInt8> colorTargets;
|
||||
mutable std::vector<GLenum> drawBuffers;
|
||||
const Context* context;
|
||||
bool complete = false;
|
||||
bool userDefinedTargets = false;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, RenderBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer || !buffer->IsValid())
|
||||
{
|
||||
NazaraError("Invalid render buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
if (attachmentPoint == AttachmentPoint_Depth)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
else if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(buffer->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, buffer->GetOpenGLID());
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.buffer = buffer;
|
||||
attachment.renderBufferDestroySlot.Connect(buffer->OnRenderBufferDestroy, std::bind(&RenderTexture::OnRenderBufferDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = buffer->GetHeight();
|
||||
attachment.width = buffer->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachBuffer(AttachmentPoint attachmentPoint, UInt8 index, PixelFormatType format, unsigned int width, unsigned int height)
|
||||
{
|
||||
RenderBufferRef renderBuffer = RenderBuffer::New();
|
||||
if (!renderBuffer->Create(format, width, height))
|
||||
{
|
||||
NazaraError("Failed to create RenderBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AttachBuffer(attachmentPoint, index, renderBuffer))
|
||||
{
|
||||
NazaraError("Failed to attach buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::AttachTexture(AttachmentPoint attachmentPoint, UInt8 index, Texture* texture, unsigned int z)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= Renderer::GetMaxColorAttachments())
|
||||
{
|
||||
NazaraError("Color index is over max color attachments (" + String::Number(index) + " >= " + String::Number(Renderer::GetMaxColorAttachments()) + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentPoint == AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Targeting stencil-only textures is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == AttachmentPoint_Depth && m_impl->attachments.size() > depthStencilIndex &&
|
||||
m_impl->attachments[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Depth target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture || !texture->IsValid())
|
||||
{
|
||||
NazaraError("Invalid texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depth = (texture->GetType() == ImageType_Cubemap) ? 6 : texture->GetDepth();
|
||||
if (z >= depth)
|
||||
{
|
||||
NazaraError("Z value exceeds depth (" + String::Number(z) + " >= (" + String::Number(depth) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachmentPoint targetAttachmentPoint = FormatTypeToAttachment(texture->GetFormat());
|
||||
if (targetAttachmentPoint != attachmentPoint && targetAttachmentPoint != AttachmentPoint_DepthStencil &&
|
||||
attachmentPoint != AttachmentPoint_Depth && attachmentPoint != AttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
switch (texture->GetType())
|
||||
{
|
||||
case ImageType_1D:
|
||||
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_1D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_1D_Array:
|
||||
case ImageType_2D_Array:
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_2D:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_2D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case ImageType_3D:
|
||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_3D, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case ImageType_Cubemap:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, OpenGL::CubemapFace[z], texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
m_impl->attachments.resize(attachIndex+1);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachIndex];
|
||||
attachment.attachmentPoint = attachmentPoint;
|
||||
attachment.isBuffer = false;
|
||||
attachment.isUsed = true;
|
||||
attachment.height = texture->GetHeight();
|
||||
attachment.texture = texture;
|
||||
attachment.textureDestroySlot.Connect(texture->OnTextureDestroy, std::bind(&RenderTexture::OnTextureDestroy, this, std::placeholders::_1, attachIndex));
|
||||
attachment.width = texture->GetWidth();
|
||||
|
||||
InvalidateSize();
|
||||
InvalidateTargets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderTexture::Create(bool lock)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<RenderTextureImpl> impl(new RenderTextureImpl);
|
||||
|
||||
impl->fbo = 0;
|
||||
glGenFramebuffers(1, &impl->fbo);
|
||||
|
||||
if (!impl->fbo)
|
||||
{
|
||||
NazaraError("Failed to create framebuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
m_impl->context = Context::GetCurrent();
|
||||
m_impl->contextDestroySlot.Connect(m_impl->context->OnContextDestroy, this, &RenderTexture::OnContextDestroy);
|
||||
|
||||
m_checked = false;
|
||||
m_drawBuffersUpdated = true;
|
||||
m_sizeUpdated = false;
|
||||
m_targetsUpdated = true;
|
||||
|
||||
if (lock)
|
||||
{
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
}
|
||||
|
||||
OnRenderTargetParametersChange(this);
|
||||
OnRenderTargetSizeChange(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
if (IsActive())
|
||||
Renderer::SetTarget(nullptr);
|
||||
|
||||
// Le FBO devant être supprimé dans son contexte d'origine, nous déléguons sa suppression à la classe OpenGL
|
||||
// Celle-ci va libérer le FBO dès que possible (la prochaine fois que son contexte d'origine sera actif)
|
||||
OpenGL::DeleteFrameBuffer(m_impl->context, m_impl->fbo);
|
||||
|
||||
delete m_impl; // Enlève également une références sur les Texture/RenderBuffer
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::Detach(AttachmentPoint attachmentPoint, UInt8 index)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachmentPoint != AttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint] + index;
|
||||
if (attachIndex >= m_impl->attachments.size())
|
||||
return;
|
||||
|
||||
Attachment& attachement = m_impl->attachments[attachIndex];
|
||||
if (!attachement.isUsed)
|
||||
return;
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return;
|
||||
}
|
||||
|
||||
attachement.isUsed = false;
|
||||
|
||||
if (attachement.isBuffer)
|
||||
{
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
|
||||
|
||||
attachement.buffer = nullptr;
|
||||
attachement.renderBufferDestroySlot.Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glFramebufferTexture)
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0);
|
||||
else
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, OpenGL::Attachment[attachmentPoint]+index, 0, 0, 0);
|
||||
|
||||
attachement.texture = nullptr;
|
||||
attachement.textureDestroySlot.Disconnect();
|
||||
}
|
||||
|
||||
InvalidateSize();
|
||||
|
||||
if (attachement.attachmentPoint == AttachmentPoint_Color)
|
||||
InvalidateTargets();
|
||||
|
||||
Unlock();
|
||||
|
||||
m_checked = false;
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetHeight() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->height;
|
||||
}
|
||||
|
||||
RenderTargetParameters RenderTexture::GetParameters() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
///TODO
|
||||
return RenderTargetParameters();
|
||||
}
|
||||
|
||||
Vector2ui RenderTexture::GetSize() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return Vector2ui(m_impl->width, m_impl->height);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetWidth() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_sizeUpdated)
|
||||
UpdateSize();
|
||||
|
||||
return m_impl->width;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsComplete() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
if (!m_checked)
|
||||
{
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
Unlock();
|
||||
|
||||
m_impl->complete = false;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
m_impl->complete = true;
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
NazaraError("Incomplete attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
NazaraInternalError("Incomplete draw buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
NazaraInternalError("Incomplete read buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
NazaraError("Incomplete missing attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
NazaraError("Incomplete multisample");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
NazaraError("Incomplete layer targets");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
NazaraError("Render texture has unsupported attachments");
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Unknown error");
|
||||
}
|
||||
|
||||
m_checked = true;
|
||||
}
|
||||
|
||||
return m_impl->complete;
|
||||
}
|
||||
|
||||
bool RenderTexture::IsRenderable() const
|
||||
{
|
||||
return IsComplete() && !m_impl->attachments.empty();
|
||||
}
|
||||
|
||||
bool RenderTexture::Lock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lockedLevel++ == 0)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous);
|
||||
|
||||
lockedPrevious = previous;
|
||||
|
||||
if (lockedPrevious != m_impl->fbo)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const UInt8* targets, unsigned int targetCount) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (unsigned int i = 0; i < targetCount; ++i)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + targets[i];
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(targets[i]) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targetCount);
|
||||
std::memcpy(&m_impl->colorTargets[0], targets, targetCount*sizeof(UInt8));
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::SetColorTargets(const std::initializer_list<UInt8>& targets) const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
for (UInt8 target : targets)
|
||||
{
|
||||
unsigned int index = attachmentIndex[AttachmentPoint_Color] + target;
|
||||
if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed)
|
||||
{
|
||||
NazaraError("Target " + String::Number(target) + " not attached");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->colorTargets.resize(targets.size());
|
||||
|
||||
UInt8* ptr = &m_impl->colorTargets[0];
|
||||
for (UInt8 index : targets)
|
||||
*ptr++ = index;
|
||||
|
||||
m_impl->userDefinedTargets = true;
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::Unlock() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockedLevel == 0)
|
||||
{
|
||||
NazaraWarning("Unlock called on non-locked texture");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--lockedLevel == 0 && lockedPrevious != m_impl->fbo) // Ici, il est important qu'un FBO soit débindé si l'ancien était 0
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
|
||||
}
|
||||
|
||||
unsigned int RenderTexture::GetOpenGLID() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->fbo;
|
||||
}
|
||||
|
||||
bool RenderTexture::HasContext() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderTexture::Blit(RenderTexture* src, Rectui srcRect, RenderTexture* dst, Rectui dstRect, UInt32 buffers, bool bilinearFilter)
|
||||
{
|
||||
NazaraAssert(src && src->IsValid(), "Invalid source render texture");
|
||||
NazaraAssert(dst && dst->IsValid(), "Invalid destination render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (srcRect.x+srcRect.width > src->GetWidth() || srcRect.y+srcRect.height > src->GetHeight())
|
||||
{
|
||||
NazaraError("Source rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstRect.x+dstRect.width > dst->GetWidth() || dstRect.y+dstRect.height > dst->GetHeight())
|
||||
{
|
||||
NazaraError("Destination rectangle dimensions are out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bilinearFilter && (buffers & RendererBuffer_Depth || buffers & RendererBuffer_Stencil))
|
||||
{
|
||||
NazaraError("Filter cannot be bilinear when blitting depth/stencil buffers");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GLbitfield mask = 0;
|
||||
if (buffers & RendererBuffer_Color)
|
||||
mask |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Depth)
|
||||
mask |= GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if (buffers & RendererBuffer_Stencil)
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
GLint previousDrawBuffer, previousReadBuffer;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousDrawBuffer);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previousReadBuffer);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->GetOpenGLID());
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetOpenGLID());
|
||||
|
||||
glBlitFramebuffer(srcRect.x, srcRect.y, srcRect.x + srcRect.width, srcRect.y + srcRect.height,
|
||||
dstRect.x, dstRect.y, dstRect.x + dstRect.width, dstRect.y + dstRect.height,
|
||||
mask, (bilinearFilter) ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previousDrawBuffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, previousReadBuffer);
|
||||
}
|
||||
|
||||
bool RenderTexture::Activate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
|
||||
m_drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTexture::Desactivate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid render texture");
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (Context::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glFlush();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void RenderTexture::EnsureTargetUpdated() const
|
||||
{
|
||||
if (!m_drawBuffersUpdated)
|
||||
UpdateDrawBuffers();
|
||||
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
{
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex[AttachmentPoint_Color] + index];
|
||||
if (!attachment.isBuffer)
|
||||
attachment.texture->InvalidateMipmaps();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::OnContextDestroy(const Context* context)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraUnused(context);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (m_impl->context != context)
|
||||
{
|
||||
NazaraInternalError("Not listening to " + String::Pointer(context));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void RenderTexture::OnRenderBufferDestroy(const RenderBuffer* renderBuffer, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(renderBuffer);
|
||||
|
||||
Attachment& attachment = m_impl->attachments[attachmentIndex];
|
||||
attachment.buffer = nullptr;
|
||||
attachment.isUsed = false;
|
||||
attachment.renderBufferDestroySlot.Disconnect();
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::OnTextureDestroy(const Texture* texture, unsigned int attachmentIndex)
|
||||
{
|
||||
NazaraAssert(m_impl, "Invalid internal state");
|
||||
NazaraAssert(attachmentIndex < m_impl->attachments.size(), "Invalid attachment index");
|
||||
NazaraAssert(!m_impl->attachments[attachmentIndex].isBuffer, "Invalid attachment state");
|
||||
NazaraUnused(texture);
|
||||
|
||||
InvalidateTargets();
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateDrawBuffers() const
|
||||
{
|
||||
if (!m_targetsUpdated)
|
||||
UpdateTargets();
|
||||
|
||||
glDrawBuffers(m_impl->drawBuffers.size(), &m_impl->drawBuffers[0]);
|
||||
|
||||
m_drawBuffersUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateSize() const
|
||||
{
|
||||
m_impl->width = 0;
|
||||
m_impl->height = 0;
|
||||
for (Attachment& attachment : m_impl->attachments)
|
||||
{
|
||||
if (attachment.isUsed)
|
||||
{
|
||||
m_impl->height = std::max(m_impl->height, attachment.height);
|
||||
m_impl->width = std::max(m_impl->width, attachment.width);
|
||||
}
|
||||
}
|
||||
|
||||
m_sizeUpdated = true;
|
||||
}
|
||||
|
||||
void RenderTexture::UpdateTargets() const
|
||||
{
|
||||
if (!m_impl->userDefinedTargets)
|
||||
{
|
||||
m_impl->colorTargets.clear();
|
||||
|
||||
unsigned int colorIndex = 0;
|
||||
for (unsigned int index = attachmentIndex[AttachmentPoint_Color]; index < m_impl->attachments.size(); ++index)
|
||||
m_impl->colorTargets.push_back(colorIndex++);
|
||||
}
|
||||
|
||||
if (m_impl->colorTargets.empty())
|
||||
{
|
||||
m_impl->drawBuffers.resize(1);
|
||||
m_impl->drawBuffers[0] = GL_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_impl->drawBuffers.resize(m_impl->colorTargets.size());
|
||||
GLenum* ptr = &m_impl->drawBuffers[0];
|
||||
for (UInt8 index : m_impl->colorTargets)
|
||||
*ptr++ = GL_COLOR_ATTACHMENT0 + index;
|
||||
}
|
||||
|
||||
m_targetsUpdated = true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
/*
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
@@ -289,3 +289,4 @@ namespace Nz
|
||||
OnRenderTargetSizeChange(this);
|
||||
}
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
11
src/Nazara/Renderer/RendererImpl.cpp
Normal file
11
src/Nazara/Renderer/RendererImpl.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RendererImpl.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RendererImpl::~RendererImpl() = default;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#version 140
|
||||
|
||||
/********************Sortant********************/
|
||||
out vec4 RenderTarget0;
|
||||
|
||||
/********************Uniformes********************/
|
||||
uniform vec4 Color;
|
||||
|
||||
/********************Fonctions********************/
|
||||
void main()
|
||||
{
|
||||
RenderTarget0 = Color;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
35,118,101,114,115,105,111,110,32,49,52,48,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,118,101,99,52,32,67,111,108,111,114,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,67,111,108,111,114,59,13,10,125,
|
||||
@@ -1,13 +0,0 @@
|
||||
#version 140
|
||||
|
||||
/********************Entrant********************/
|
||||
in vec3 VertexPosition;
|
||||
|
||||
/********************Uniformes********************/
|
||||
uniform mat4 WorldViewProjMatrix;
|
||||
|
||||
/********************Fonctions********************/
|
||||
void main()
|
||||
{
|
||||
gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
35,118,101,114,115,105,111,110,32,49,52,48,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,105,110,32,118,101,99,51,32,86,101,114,116,101,120,80,111,115,105,116,105,111,110,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,117,110,105,102,111,114,109,32,109,97,116,52,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,59,13,10,13,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,13,10,118,111,105,100,32,109,97,105,110,40,41,13,10,123,13,10,9,103,108,95,80,111,115,105,116,105,111,110,32,61,32,87,111,114,108,100,86,105,101,119,80,114,111,106,77,97,116,114,105,120,32,42,32,118,101,99,52,40,86,101,114,116,101,120,80,111,115,105,116,105,111,110,44,32,49,46,48,41,59,13,10,125,13,10,
|
||||
@@ -1,841 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/ShaderStage.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
Shader::Shader() :
|
||||
m_linked(false),
|
||||
m_program(0)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
OnShaderRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Shader::AttachStage(ShaderStageType stage, const ShaderStage& shaderStage)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Invalid program");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Invalid shader stage");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shaderStage.IsCompiled())
|
||||
{
|
||||
NazaraError("Shader stage must be compiled");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int shader = shaderStage.GetOpenGLID();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (std::find(m_attachedShaders[stage].begin(), m_attachedShaders[stage].end(), shader) != m_attachedShaders[stage].end())
|
||||
{
|
||||
NazaraError("Shader stage is already attached");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glAttachShader(m_program, shader);
|
||||
m_attachedShaders[stage].push_back(shader);
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromFile(ShaderStageType stage, const String& filePath)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSourceFromFile(filePath);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromSource(ShaderStageType stage, const char* source, unsigned int length)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSource(source, length);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::AttachStageFromSource(ShaderStageType stage, const String& source)
|
||||
{
|
||||
ShaderStage shaderStage(stage);
|
||||
if (!shaderStage.IsValid())
|
||||
{
|
||||
NazaraError("Failed to create shader stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderStage.SetSource(source);
|
||||
|
||||
if (!shaderStage.Compile())
|
||||
{
|
||||
NazaraError("Failed to compile stage: " + shaderStage.GetLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
AttachStage(stage, shaderStage);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Bind() const
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
}
|
||||
|
||||
bool Shader::Create()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
m_program = glCreateProgram();
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Failed to create program");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_linked = false;
|
||||
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData0], "InstanceData0");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData1], "InstanceData1");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData2], "InstanceData2");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData3], "InstanceData3");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData4], "InstanceData4");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_InstanceData5], "InstanceData5");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Color], "VertexColor");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Normal], "VertexNormal");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Position], "VertexPosition");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Tangent], "VertexTangent");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_TexCoord], "VertexTexCoord");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata0], "VertexUserdata0");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata1], "VertexUserdata1");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata2], "VertexUserdata2");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata3], "VertexUserdata3");
|
||||
glBindAttribLocation(m_program, OpenGL::VertexComponentIndex[VertexComponent_Userdata4], "VertexUserdata4");
|
||||
|
||||
String uniform;
|
||||
uniform = "RenderTarget";
|
||||
|
||||
unsigned int maxRenderTargets = Renderer::GetMaxRenderTargets();
|
||||
for (unsigned int i = 0; i < maxRenderTargets; ++i)
|
||||
{
|
||||
String uniformName = uniform + String::Number(i);
|
||||
glBindFragDataLocation(m_program, i, uniformName.GetConstBuffer());
|
||||
}
|
||||
|
||||
if (OpenGL::IsSupported(OpenGLExtension_GetProgramBinary))
|
||||
glProgramParameteri(m_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Destroy()
|
||||
{
|
||||
if (m_program)
|
||||
{
|
||||
OnShaderDestroy(this);
|
||||
|
||||
Context::EnsureContext();
|
||||
OpenGL::DeleteProgram(m_program);
|
||||
m_program = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ByteArray Shader::GetBinary() const
|
||||
{
|
||||
ByteArray byteArray;
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
GLint binaryLength = 0;
|
||||
glGetProgramiv(m_program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||
|
||||
if (binaryLength > 0)
|
||||
{
|
||||
byteArray.Reserve(sizeof(UInt64) + binaryLength);
|
||||
|
||||
UInt8* buffer = byteArray.GetBuffer();
|
||||
|
||||
GLenum binaryFormat;
|
||||
glGetProgramBinary(m_program, binaryLength, nullptr, &binaryFormat, &buffer[sizeof(UInt64)]);
|
||||
|
||||
// On stocke le format au début du binaire
|
||||
*reinterpret_cast<UInt64*>(&buffer[0]) = binaryFormat;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
String Shader::GetLog() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Shader is not initialized");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
String log;
|
||||
|
||||
GLint length = 0;
|
||||
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &length);
|
||||
if (length > 1) // Le caractère de fin faisant partie du compte
|
||||
{
|
||||
log.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
|
||||
glGetProgramInfoLog(m_program, length, nullptr, &log[0]);
|
||||
}
|
||||
else
|
||||
log = "No log.";
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
String Shader::GetSourceCode(ShaderStageType stage) const
|
||||
{
|
||||
if (!HasStage(stage))
|
||||
return String();
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
static const char sep[] = "\n////////////////////////////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
unsigned int totalLength = 0;
|
||||
for (unsigned int shader : m_attachedShaders[stage])
|
||||
{
|
||||
GLint length;
|
||||
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &length);
|
||||
|
||||
totalLength += length - 1;
|
||||
}
|
||||
|
||||
totalLength += (m_attachedShaders[stage].size()-1) * (sizeof(sep)/sizeof(char));
|
||||
|
||||
String source(totalLength, '\0');
|
||||
|
||||
unsigned int offset = 0;
|
||||
for (unsigned int shader : m_attachedShaders[stage])
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
std::memcpy(&source[offset], sep, sizeof(sep));
|
||||
offset += sizeof(sep)/sizeof(char);
|
||||
}
|
||||
|
||||
GLint length;
|
||||
glGetShaderSource(shader, totalLength, &length, &source[offset]);
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
int Shader::GetUniformLocation(const String& name) const
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
return glGetUniformLocation(m_program, name.GetConstBuffer());
|
||||
}
|
||||
|
||||
int Shader::GetUniformLocation(ShaderUniform shaderUniform) const
|
||||
{
|
||||
return m_uniformLocations[shaderUniform];
|
||||
}
|
||||
|
||||
bool Shader::HasStage(ShaderStageType stage) const
|
||||
{
|
||||
return !m_attachedShaders[stage].empty();
|
||||
}
|
||||
|
||||
bool Shader::IsBinaryRetrievable() const
|
||||
{
|
||||
return OpenGL::IsSupported(OpenGLExtension_GetProgramBinary);
|
||||
}
|
||||
|
||||
bool Shader::IsLinked() const
|
||||
{
|
||||
return m_linked;
|
||||
}
|
||||
|
||||
bool Shader::IsValid() const
|
||||
{
|
||||
return m_program != 0;
|
||||
}
|
||||
|
||||
bool Shader::Link()
|
||||
{
|
||||
Context::EnsureContext();
|
||||
|
||||
glLinkProgram(m_program);
|
||||
|
||||
return PostLinkage();
|
||||
}
|
||||
|
||||
bool Shader::LoadFromBinary(const void* buffer, unsigned int size)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!glProgramBinary)
|
||||
{
|
||||
NazaraError("GL_ARB_get_program_binary not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer || size < sizeof(UInt64))
|
||||
{
|
||||
NazaraError("Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Context::EnsureContext();
|
||||
|
||||
const UInt8* ptr = reinterpret_cast<const UInt8*>(buffer);
|
||||
|
||||
// On récupère le format au début du binaire
|
||||
///TODO: ByteStream ?
|
||||
GLenum binaryFormat = static_cast<GLenum>(*reinterpret_cast<const UInt64*>(&ptr[0]));
|
||||
ptr += sizeof(UInt64);
|
||||
|
||||
glProgramBinary(m_program, binaryFormat, ptr, size - sizeof(UInt64));
|
||||
|
||||
return PostLinkage();
|
||||
}
|
||||
|
||||
bool Shader::LoadFromBinary(const ByteArray& byteArray)
|
||||
{
|
||||
return LoadFromBinary(byteArray.GetConstBuffer(), byteArray.GetSize());
|
||||
}
|
||||
|
||||
void Shader::SendBoolean(int location, bool value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1i)
|
||||
glProgramUniform1i(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendColor(int location, const Color& color) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
Vector4f vecColor(color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f);
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, 1, vecColor);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, 1, vecColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendDouble(int location, double value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1d)
|
||||
glProgramUniform1d(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1d(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendDoubleArray(int location, const double* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1dv)
|
||||
glProgramUniform1dv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1dv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendFloat(int location, float value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1f)
|
||||
glProgramUniform1f(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1f(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendFloatArray(int location, const float* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1fv)
|
||||
glProgramUniform1fv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1fv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendInteger(int location, int value) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1i)
|
||||
glProgramUniform1i(m_program, location, value);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendIntegerArray(int location, const int* values, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform1iv)
|
||||
glProgramUniform1iv(m_program, location, count, values);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform1iv(location, count, values);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendMatrix(int location, const Matrix4d& matrix) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniformMatrix4dv)
|
||||
glProgramUniformMatrix4dv(m_program, location, 1, GL_FALSE, matrix);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniformMatrix4dv(location, 1, GL_FALSE, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendMatrix(int location, const Matrix4f& matrix) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniformMatrix4fv)
|
||||
glProgramUniformMatrix4fv(m_program, location, 1, GL_FALSE, matrix);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2dv)
|
||||
glProgramUniform2dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector2i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3dv)
|
||||
glProgramUniform3dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3fv)
|
||||
glProgramUniform3fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector3i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3iv)
|
||||
glProgramUniform3iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4d& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4dv)
|
||||
glProgramUniform4dv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4dv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4f& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVector(int location, const Vector4i& vector) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4iv)
|
||||
glProgramUniform4iv(m_program, location, 1, vector);
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4iv(location, 1, vector);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2dv)
|
||||
glProgramUniform2dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2fv)
|
||||
glProgramUniform2fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector2i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform2iv)
|
||||
glProgramUniform2iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform2iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3dv)
|
||||
glProgramUniform3dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3fv)
|
||||
glProgramUniform3fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector3i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform3iv)
|
||||
glProgramUniform3iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform3iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4d* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4dv)
|
||||
glProgramUniform4dv(m_program, location, count, reinterpret_cast<const double*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4dv(location, count, reinterpret_cast<const double*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4f* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4fv)
|
||||
glProgramUniform4fv(m_program, location, count, reinterpret_cast<const float*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4fv(location, count, reinterpret_cast<const float*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::SendVectorArray(int location, const Vector4i* vectors, unsigned int count) const
|
||||
{
|
||||
if (location == -1)
|
||||
return;
|
||||
|
||||
if (glProgramUniform4iv)
|
||||
glProgramUniform4iv(m_program, location, count, reinterpret_cast<const int*>(vectors));
|
||||
else
|
||||
{
|
||||
OpenGL::BindProgram(m_program);
|
||||
glUniform4iv(location, count, reinterpret_cast<const int*>(vectors));
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::Validate() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_program)
|
||||
{
|
||||
NazaraError("Shader is not initialized");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glValidateProgram(m_program);
|
||||
|
||||
GLint success;
|
||||
glGetProgramiv(m_program, GL_VALIDATE_STATUS, &success);
|
||||
|
||||
if (success == GL_TRUE)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to validate shader: " + GetLog());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int Shader::GetOpenGLID() const
|
||||
{
|
||||
return m_program;
|
||||
}
|
||||
|
||||
bool Shader::IsStageSupported(ShaderStageType stage)
|
||||
{
|
||||
return ShaderStage::IsSupported(stage);
|
||||
}
|
||||
|
||||
bool Shader::PostLinkage()
|
||||
{
|
||||
GLint success;
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
|
||||
|
||||
m_linked = (success == GL_TRUE);
|
||||
if (m_linked)
|
||||
{
|
||||
// Pour éviter de se tromper entre le nom et la constante
|
||||
#define CacheUniform(name) m_uniformLocations[ShaderUniform_##name] = glGetUniformLocation(m_program, #name)
|
||||
|
||||
CacheUniform(InvProjMatrix);
|
||||
CacheUniform(InvTargetSize);
|
||||
CacheUniform(InvViewMatrix);
|
||||
CacheUniform(InvViewProjMatrix);
|
||||
CacheUniform(InvWorldMatrix);
|
||||
CacheUniform(InvWorldViewMatrix);
|
||||
CacheUniform(InvWorldViewProjMatrix);
|
||||
CacheUniform(ProjMatrix);
|
||||
CacheUniform(TargetSize);
|
||||
CacheUniform(ViewMatrix);
|
||||
CacheUniform(ViewProjMatrix);
|
||||
CacheUniform(WorldMatrix);
|
||||
CacheUniform(WorldViewMatrix);
|
||||
CacheUniform(WorldViewProjMatrix);
|
||||
|
||||
#undef CacheUniform
|
||||
|
||||
OnShaderUniformInvalidated(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to link shader: " + GetLog());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::Initialize()
|
||||
{
|
||||
if (!ShaderLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shader::Uninitialize()
|
||||
{
|
||||
ShaderLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
ShaderLibrary::LibraryMap Shader::s_library;
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderStage.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ShaderStage::ShaderStage() :
|
||||
m_compiled(false),
|
||||
m_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderStage::ShaderStage(ShaderStageType stage) :
|
||||
ShaderStage()
|
||||
{
|
||||
Create(stage);
|
||||
}
|
||||
|
||||
ShaderStage::ShaderStage(ShaderStage&& stage) :
|
||||
m_stage(stage.m_stage),
|
||||
m_compiled(stage.m_compiled),
|
||||
m_id(stage.m_id)
|
||||
{
|
||||
stage.m_id = 0;
|
||||
}
|
||||
|
||||
ShaderStage::~ShaderStage()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool ShaderStage::Compile()
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glCompileShader(m_id);
|
||||
|
||||
GLint success;
|
||||
glGetShaderiv(m_id, GL_COMPILE_STATUS, &success);
|
||||
|
||||
m_compiled = (success == GL_TRUE);
|
||||
if (m_compiled)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to compile shader stage: " + GetLog());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShaderStage::Create(ShaderStageType stage)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_id = glCreateShader(OpenGL::ShaderStage[stage]);
|
||||
m_stage = stage;
|
||||
|
||||
return (m_id != 0);
|
||||
}
|
||||
|
||||
void ShaderStage::Destroy()
|
||||
{
|
||||
m_compiled = false;
|
||||
if (m_id)
|
||||
{
|
||||
glDeleteShader(m_id);
|
||||
m_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
String ShaderStage::GetLog() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
String log;
|
||||
|
||||
GLint length = 0;
|
||||
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length);
|
||||
if (length > 1) // Le caractère de fin faisant partie du compte
|
||||
{
|
||||
log.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
|
||||
glGetShaderInfoLog(m_id, length, nullptr, &log[0]);
|
||||
}
|
||||
else
|
||||
log = "No log.";
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
String ShaderStage::GetSource() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
String source;
|
||||
|
||||
GLint length = 0;
|
||||
glGetShaderiv(m_id, GL_SHADER_SOURCE_LENGTH, &length);
|
||||
if (length > 1) // Le caractère de fin compte
|
||||
{
|
||||
source.Set(length - 1, '\0'); // La taille retournée est celle du buffer (Avec caractère de fin)
|
||||
glGetShaderSource(m_id, length, nullptr, &source[0]);
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
bool ShaderStage::IsCompiled() const
|
||||
{
|
||||
return m_compiled;
|
||||
}
|
||||
|
||||
bool ShaderStage::IsValid() const
|
||||
{
|
||||
return m_id != 0;
|
||||
}
|
||||
|
||||
void ShaderStage::SetSource(const char* source, unsigned int length)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glShaderSource(m_id, 1, &source, reinterpret_cast<const GLint*>(&length));
|
||||
}
|
||||
|
||||
void ShaderStage::SetSource(const String& source)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* tmp = source.GetConstBuffer();
|
||||
GLint length = source.GetSize();
|
||||
glShaderSource(m_id, 1, &tmp, &length);
|
||||
}
|
||||
|
||||
bool ShaderStage::SetSourceFromFile(const String& filePath)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Shader stage is not initialized");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
File file(filePath);
|
||||
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
|
||||
{
|
||||
NazaraError("Failed to open \"" + filePath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int length = static_cast<unsigned int>(file.GetSize());
|
||||
|
||||
String source(length, '\0');
|
||||
|
||||
if (file.Read(&source[0], length) != length)
|
||||
{
|
||||
NazaraError("Failed to read program file");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.Close();
|
||||
|
||||
SetSource(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
ShaderStage& ShaderStage::operator=(ShaderStage&& shader)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_compiled = shader.m_compiled;
|
||||
m_id = shader.m_id;
|
||||
m_stage = shader.m_stage;
|
||||
|
||||
shader.m_id = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Fonctions OpenGL
|
||||
unsigned int ShaderStage::GetOpenGLID() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
bool ShaderStage::IsSupported(ShaderStageType stage)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStageType_Fragment:
|
||||
case ShaderStageType_Geometry:
|
||||
case ShaderStageType_Vertex:
|
||||
return true;
|
||||
|
||||
default:
|
||||
NazaraError("Shader stage not handled (0x" + String::Number(stage, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,393 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/TextureSampler.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <unordered_map>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<UInt32, GLuint> s_samplers;
|
||||
UInt8 s_maxAnisotropyLevel;
|
||||
bool s_useAnisotropicFilter;
|
||||
}
|
||||
|
||||
TextureSampler::TextureSampler() :
|
||||
m_filterMode(SamplerFilter_Default),
|
||||
m_wrapMode(SamplerWrap_Default),
|
||||
m_anisotropicLevel(0),
|
||||
m_mipmaps(true),
|
||||
m_samplerId(0)
|
||||
{
|
||||
}
|
||||
|
||||
UInt8 TextureSampler::GetAnisotropicLevel() const
|
||||
{
|
||||
return m_anisotropicLevel;
|
||||
}
|
||||
|
||||
SamplerFilter TextureSampler::GetFilterMode() const
|
||||
{
|
||||
return m_filterMode;
|
||||
}
|
||||
|
||||
SamplerWrap TextureSampler::GetWrapMode() const
|
||||
{
|
||||
return m_wrapMode;
|
||||
}
|
||||
|
||||
void TextureSampler::SetAnisotropyLevel(UInt8 anisotropyLevel)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Renderer::IsInitialized())
|
||||
{
|
||||
NazaraError("Renderer module must be initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_anisotropicLevel != anisotropyLevel)
|
||||
{
|
||||
if (anisotropyLevel > s_maxAnisotropyLevel)
|
||||
{
|
||||
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + String::Number(anisotropyLevel) + " > " + String::Number(s_maxAnisotropyLevel) + ')');
|
||||
anisotropyLevel = s_maxAnisotropyLevel;
|
||||
}
|
||||
|
||||
m_anisotropicLevel = anisotropyLevel;
|
||||
m_samplerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::SetFilterMode(SamplerFilter filterMode)
|
||||
{
|
||||
if (m_filterMode != filterMode)
|
||||
{
|
||||
m_filterMode = filterMode;
|
||||
m_samplerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::SetWrapMode(SamplerWrap wrapMode)
|
||||
{
|
||||
if (m_wrapMode != wrapMode)
|
||||
{
|
||||
m_wrapMode = wrapMode;
|
||||
m_samplerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt8 TextureSampler::GetDefaultAnisotropicLevel()
|
||||
{
|
||||
return s_defaultAnisotropyLevel;
|
||||
}
|
||||
|
||||
SamplerFilter TextureSampler::GetDefaultFilterMode()
|
||||
{
|
||||
return s_defaultFilterMode;
|
||||
}
|
||||
|
||||
SamplerWrap TextureSampler::GetDefaultWrapMode()
|
||||
{
|
||||
return s_defaultWrapMode;
|
||||
}
|
||||
|
||||
void TextureSampler::SetDefaultAnisotropyLevel(UInt8 anisotropyLevel)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (anisotropyLevel == 0)
|
||||
{
|
||||
NazaraError("Default anisotropy level mode cannot be set to default value (0)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Renderer::IsInitialized())
|
||||
{
|
||||
NazaraError("Renderer module must be initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (anisotropyLevel > s_maxAnisotropyLevel)
|
||||
{
|
||||
NazaraWarning("Anisotropy level is over maximum anisotropy level (" + String::Number(anisotropyLevel) + " > " + String::Number(s_maxAnisotropyLevel));
|
||||
anisotropyLevel = s_maxAnisotropyLevel;
|
||||
}
|
||||
|
||||
s_defaultAnisotropyLevel = anisotropyLevel;
|
||||
|
||||
if (s_useAnisotropicFilter)
|
||||
{
|
||||
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
|
||||
{
|
||||
if (((pair.first >> 5) & 0xFF) == 0)
|
||||
glSamplerParameterf(pair.second, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::SetDefaultFilterMode(SamplerFilter filterMode)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (filterMode == SamplerFilter_Default)
|
||||
{
|
||||
NazaraError("Default filter mode cannot be set to default enum value (SamplerFilter_Default)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_defaultFilterMode = filterMode;
|
||||
|
||||
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
|
||||
{
|
||||
if (((pair.first >> 1) & 0x3) == SamplerFilter_Default)
|
||||
{
|
||||
bool mipmaps = pair.first & 0x1;
|
||||
switch (filterMode)
|
||||
{
|
||||
case SamplerFilter_Bilinear:
|
||||
if (mipmaps)
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
else
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Nearest:
|
||||
if (mipmaps)
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
else
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Trilinear:
|
||||
if (mipmaps)
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
else
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
|
||||
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::SetDefaultWrapMode(SamplerWrap wrapMode)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (wrapMode == SamplerWrap_Default)
|
||||
{
|
||||
NazaraError("Default wrap mode cannot be set to default enum value (SamplerWrap_Default)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_defaultWrapMode = wrapMode;
|
||||
|
||||
GLenum wrapEnum = OpenGL::SamplerWrapMode[wrapMode];
|
||||
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
|
||||
{
|
||||
if (((pair.first >> 3) & 0x3) == SamplerWrap_Default)
|
||||
{
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_R, wrapEnum);
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_T, wrapEnum);
|
||||
glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_S, wrapEnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::Apply(const Texture* texture) const
|
||||
{
|
||||
ImageType type = texture->GetType();
|
||||
GLenum target = OpenGL::TextureTarget[type];
|
||||
|
||||
OpenGL::BindTexture(type, texture->GetOpenGLID());
|
||||
|
||||
if (s_useAnisotropicFilter)
|
||||
{
|
||||
UInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
|
||||
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
|
||||
}
|
||||
|
||||
SamplerFilter filterMode = (m_filterMode == SamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
|
||||
switch (filterMode)
|
||||
{
|
||||
case SamplerFilter_Bilinear:
|
||||
if (m_mipmaps)
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
else
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Nearest:
|
||||
if (m_mipmaps)
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
else
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Trilinear:
|
||||
if (m_mipmaps)
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
else
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
GLenum wrapMode = OpenGL::SamplerWrapMode[(m_wrapMode == SamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
|
||||
switch (type)
|
||||
{
|
||||
// Notez l'absence de "break" ici
|
||||
case ImageType_3D:
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode);
|
||||
case ImageType_2D:
|
||||
case ImageType_2D_Array:
|
||||
case ImageType_Cubemap:
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode);
|
||||
case ImageType_1D:
|
||||
case ImageType_1D_Array:
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSampler::Bind(unsigned int unit) const
|
||||
{
|
||||
static_assert(SamplerFilter_Max < 0x4, "Maximum sampler filter mode takes more than 2 bits");
|
||||
static_assert(SamplerWrap_Max < 0x4, "Maximum sampler wrap mode takes more than 2 bits");
|
||||
|
||||
if (!m_samplerId)
|
||||
UpdateSamplerId();
|
||||
|
||||
OpenGL::BindSampler(unit, m_samplerId);
|
||||
}
|
||||
|
||||
unsigned int TextureSampler::GetOpenGLID() const
|
||||
{
|
||||
if (!m_samplerId)
|
||||
UpdateSamplerId();
|
||||
|
||||
return m_samplerId;
|
||||
}
|
||||
|
||||
void TextureSampler::UpdateSamplerId() const
|
||||
{
|
||||
UInt32 key = (((m_mipmaps) ? 1 : 0) << 0) | // 1 bit
|
||||
(m_filterMode << 1) | // 2 bits
|
||||
(m_wrapMode << 3) | // 2 bits
|
||||
(m_anisotropicLevel << 5); // 8 bits
|
||||
|
||||
auto it = s_samplers.find(key);
|
||||
if (it == s_samplers.end())
|
||||
{
|
||||
GLuint sampler;
|
||||
glGenSamplers(1, &sampler);
|
||||
|
||||
if (s_useAnisotropicFilter)
|
||||
{
|
||||
UInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel;
|
||||
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast<float>(anisotropyLevel));
|
||||
}
|
||||
|
||||
SamplerFilter filterMode = (m_filterMode == SamplerFilter_Default) ? s_defaultFilterMode : m_filterMode;
|
||||
switch (filterMode)
|
||||
{
|
||||
case SamplerFilter_Bilinear:
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Nearest:
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
break;
|
||||
|
||||
case SamplerFilter_Trilinear:
|
||||
// Équivalent au filtrage bilinéaire si les mipmaps sont absentes
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, (m_mipmaps) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraError("Texture filter not handled (0x" + String::Number(filterMode, 16) + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
GLenum wrapMode = OpenGL::SamplerWrapMode[(m_wrapMode == SamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode];
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, wrapMode);
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, wrapMode);
|
||||
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, wrapMode);
|
||||
|
||||
s_samplers[key] = sampler;
|
||||
m_samplerId = sampler;
|
||||
}
|
||||
else
|
||||
m_samplerId = it->second;
|
||||
}
|
||||
|
||||
bool TextureSampler::UseMipmaps(bool mipmaps)
|
||||
{
|
||||
if (m_mipmaps != mipmaps)
|
||||
{
|
||||
m_mipmaps = mipmaps;
|
||||
m_samplerId = 0;
|
||||
|
||||
return true; // Renvoie true si la valeur a été changée (Donc s'il faut réappliquer le sampler)
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextureSampler::Initialize()
|
||||
{
|
||||
s_maxAnisotropyLevel = Renderer::GetMaxAnisotropyLevel();
|
||||
s_useAnisotropicFilter = OpenGL::IsSupported(OpenGLExtension_AnisotropicFilter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureSampler::Uninitialize()
|
||||
{
|
||||
if (!s_samplers.empty())
|
||||
{
|
||||
Context::EnsureContext();
|
||||
for (const std::pair<UInt32, GLuint>& pair : s_samplers)
|
||||
OpenGL::DeleteSampler(pair.second);
|
||||
|
||||
s_samplers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
UInt8 TextureSampler::s_defaultAnisotropyLevel = 1;
|
||||
SamplerFilter TextureSampler::s_defaultFilterMode = SamplerFilter_Trilinear;
|
||||
SamplerWrap TextureSampler::s_defaultWrapMode = SamplerWrap_Repeat;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShader.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShader::~UberShader()
|
||||
{
|
||||
OnUberShaderRelease(this);
|
||||
}
|
||||
|
||||
bool UberShader::Initialize()
|
||||
{
|
||||
if (!UberShaderLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UberShader::Uninitialize()
|
||||
{
|
||||
UberShaderLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
UberShaderLibrary::LibraryMap UberShader::s_library;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderInstance.hpp>
|
||||
#include <algorithm>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderInstance::UberShaderInstance(const Shader* shader) :
|
||||
m_shader(shader)
|
||||
{
|
||||
}
|
||||
|
||||
UberShaderInstance::~UberShaderInstance() = default;
|
||||
|
||||
const Shader* UberShaderInstance::GetShader() const
|
||||
{
|
||||
return m_shader;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderInstancePreprocessor.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderInstancePreprocessor::UberShaderInstancePreprocessor(const Shader* shader) :
|
||||
UberShaderInstance(shader)
|
||||
{
|
||||
}
|
||||
|
||||
UberShaderInstancePreprocessor::~UberShaderInstancePreprocessor() = default;
|
||||
|
||||
bool UberShaderInstancePreprocessor::Activate() const
|
||||
{
|
||||
Renderer::SetShader(m_shader);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShaderPreprocessor::~UberShaderPreprocessor()
|
||||
{
|
||||
OnUberShaderPreprocessorRelease(this);
|
||||
}
|
||||
|
||||
UberShaderInstance* UberShaderPreprocessor::Get(const ParameterList& parameters) const
|
||||
{
|
||||
// Première étape, transformer les paramètres en un flag
|
||||
UInt32 flags = 0;
|
||||
for (auto it = m_flags.begin(); it != m_flags.end(); ++it)
|
||||
{
|
||||
if (parameters.HasParameter(it->first))
|
||||
{
|
||||
bool value;
|
||||
if (parameters.GetBooleanParameter(it->first, &value) && value)
|
||||
flags |= it->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Le shader fait-il partie du cache ?
|
||||
auto shaderIt = m_cache.find(flags);
|
||||
|
||||
// Si non, il nous faut le construire
|
||||
if (shaderIt == m_cache.end())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Une exception sera lancée à la moindre erreur et celle-ci ne sera pas enregistrée dans le log (car traitée dans le bloc catch)
|
||||
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowException, true);
|
||||
|
||||
ShaderRef shader = Shader::New();
|
||||
shader->Create();
|
||||
|
||||
for (unsigned int i = 0; i <= ShaderStageType_Max; ++i)
|
||||
{
|
||||
const CachedShader& shaderStage = m_shaders[i];
|
||||
|
||||
// Le shader stage est-il activé dans cette version du shader ?
|
||||
if (shaderStage.present && (flags & shaderStage.requiredFlags) == shaderStage.requiredFlags)
|
||||
{
|
||||
UInt32 stageFlags = 0;
|
||||
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
|
||||
{
|
||||
if (parameters.HasParameter(it->first))
|
||||
{
|
||||
bool value;
|
||||
if (parameters.GetBooleanParameter(it->first, &value) && value)
|
||||
stageFlags |= it->second;
|
||||
}
|
||||
}
|
||||
|
||||
auto stageIt = shaderStage.cache.find(stageFlags);
|
||||
if (stageIt == shaderStage.cache.end())
|
||||
{
|
||||
ShaderStage stage;
|
||||
stage.Create(static_cast<ShaderStageType>(i));
|
||||
|
||||
unsigned int glslVersion = OpenGL::GetGLSLVersion();
|
||||
|
||||
StringStream code;
|
||||
code << "#version " << glslVersion << "\n\n";
|
||||
|
||||
code << "#define GLSL_VERSION " << glslVersion << "\n\n";
|
||||
|
||||
code << "#define EARLY_FRAGMENT_TEST " << (glslVersion >= 420 || OpenGL::IsSupported(OpenGLExtension_Shader_ImageLoadStore)) << "\n\n";
|
||||
|
||||
for (auto it = shaderStage.flags.begin(); it != shaderStage.flags.end(); ++it)
|
||||
code << "#define " << it->first << ' ' << ((stageFlags & it->second) ? '1' : '0') << '\n';
|
||||
|
||||
code << "\n#line 1\n"; // Pour que les éventuelles erreurs du shader se réfèrent à la bonne ligne
|
||||
code << shaderStage.source;
|
||||
|
||||
stage.SetSource(code);
|
||||
stage.Compile();
|
||||
|
||||
stageIt = shaderStage.cache.emplace(flags, std::move(stage)).first;
|
||||
}
|
||||
|
||||
shader->AttachStage(static_cast<ShaderStageType>(i), stageIt->second);
|
||||
}
|
||||
}
|
||||
|
||||
shader->Link();
|
||||
|
||||
// On construit l'instant
|
||||
shaderIt = m_cache.emplace(flags, shader.Get()).first;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
ErrorFlags errFlags(ErrorFlag_ThrowExceptionDisabled);
|
||||
|
||||
NazaraError("Failed to build UberShader instance: " + Error::GetLastError());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return &shaderIt->second;
|
||||
}
|
||||
|
||||
void UberShaderPreprocessor::SetShader(ShaderStageType stage, const String& source, const String& shaderFlags, const String& requiredFlags)
|
||||
{
|
||||
CachedShader& shader = m_shaders[stage];
|
||||
shader.present = true;
|
||||
shader.source = source;
|
||||
|
||||
// On extrait les flags de la chaîne
|
||||
std::vector<String> flags;
|
||||
shaderFlags.Split(flags, ' ');
|
||||
|
||||
for (String& flag : flags)
|
||||
{
|
||||
auto it = m_flags.find(flag);
|
||||
if (it == m_flags.end())
|
||||
m_flags[flag] = 1U << m_flags.size();
|
||||
|
||||
auto it2 = shader.flags.find(flag);
|
||||
if (it2 == shader.flags.end())
|
||||
shader.flags[flag] = 1U << shader.flags.size();
|
||||
}
|
||||
|
||||
// On construit les flags requis pour l'activation du shader
|
||||
shader.requiredFlags = 0;
|
||||
|
||||
flags.clear();
|
||||
requiredFlags.Split(flags, ' ');
|
||||
|
||||
for (String& flag : flags)
|
||||
{
|
||||
UInt32 flagVal;
|
||||
|
||||
auto it = m_flags.find(flag);
|
||||
if (it == m_flags.end())
|
||||
{
|
||||
flagVal = 1U << m_flags.size();
|
||||
m_flags[flag] = flagVal;
|
||||
}
|
||||
else
|
||||
flagVal = it->second;
|
||||
|
||||
shader.requiredFlags |= flagVal;
|
||||
}
|
||||
}
|
||||
|
||||
bool UberShaderPreprocessor::SetShaderFromFile(ShaderStageType stage, const String& filePath, const String& shaderFlags, const String& requiredFlags)
|
||||
{
|
||||
File file(filePath);
|
||||
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
|
||||
{
|
||||
NazaraError("Failed to open \"" + filePath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int length = static_cast<unsigned int>(file.GetSize());
|
||||
|
||||
String source(length, '\0');
|
||||
|
||||
if (file.Read(&source[0], length) != length)
|
||||
{
|
||||
NazaraError("Failed to read program file");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.Close();
|
||||
|
||||
SetShader(stage, source, shaderFlags, requiredFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UberShaderPreprocessor::IsSupported()
|
||||
{
|
||||
return true; // Forcément supporté
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/LockGuard.hpp>
|
||||
#include <Nazara/Core/Mutex.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ContextImpl::ContextImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool ContextImpl::Activate()
|
||||
{
|
||||
return wglMakeCurrent(m_deviceContext, m_context) == TRUE;
|
||||
}
|
||||
|
||||
bool ContextImpl::Create(ContextParameters& parameters)
|
||||
{
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = static_cast<HWND>(parameters.window);
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
if (!m_window)
|
||||
{
|
||||
NazaraError("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
m_ownsWindow = true;
|
||||
}
|
||||
|
||||
// En cas d'exception, la ressource sera quand même libérée
|
||||
CallOnExit onExit([this] ()
|
||||
{
|
||||
Destroy();
|
||||
});
|
||||
|
||||
m_deviceContext = GetDC(m_window);
|
||||
if (!m_deviceContext)
|
||||
{
|
||||
NazaraError("Failed to get device context");
|
||||
return false;
|
||||
}
|
||||
|
||||
int pixelFormat = 0;
|
||||
if (parameters.antialiasingLevel > 0)
|
||||
{
|
||||
if (wglChoosePixelFormat)
|
||||
{
|
||||
bool valid;
|
||||
UINT numFormats;
|
||||
|
||||
int attributes[] = {
|
||||
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
||||
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
|
||||
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
|
||||
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
|
||||
WGL_DEPTH_BITS_ARB, parameters.depthBits,
|
||||
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
|
||||
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
|
||||
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
|
||||
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
|
||||
0, 0
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
valid = (wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats) == TRUE);
|
||||
}
|
||||
while ((!valid || numFormats == 0) && --attributes[19] > 0);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
|
||||
pixelFormat = 0;
|
||||
}
|
||||
|
||||
parameters.antialiasingLevel = attributes[19];
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraWarning("Antialiasing is not supported");
|
||||
parameters.antialiasingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR descriptor;
|
||||
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
descriptor.nVersion = 1;
|
||||
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
descriptor.cColorBits = parameters.bitsPerPixel;
|
||||
descriptor.cDepthBits = parameters.depthBits;
|
||||
descriptor.cStencilBits = parameters.stencilBits;
|
||||
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||
descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||
|
||||
if (parameters.bitsPerPixel == 32)
|
||||
descriptor.cAlphaBits = 8;
|
||||
|
||||
if (parameters.doubleBuffered)
|
||||
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
|
||||
|
||||
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
NazaraError("Failed to choose pixel format");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
|
||||
{
|
||||
NazaraError("Failed to set pixel format");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte
|
||||
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
|
||||
{
|
||||
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
|
||||
parameters.depthBits = descriptor.cDepthBits;
|
||||
parameters.stencilBits = descriptor.cDepthBits;
|
||||
}
|
||||
else
|
||||
NazaraWarning("Failed to get context's parameters");
|
||||
|
||||
HGLRC shareContext = (parameters.shared) ? static_cast<ContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
|
||||
|
||||
m_context = nullptr;
|
||||
if (wglCreateContextAttribs)
|
||||
{
|
||||
int attributes[4*2+1];
|
||||
int* attrib = attributes;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
||||
*attrib++ = parameters.majorVersion;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
|
||||
*attrib++ = parameters.minorVersion;
|
||||
|
||||
if (parameters.majorVersion >= 3)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
|
||||
*attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
|
||||
// Les contextes forward-compatible ne sont plus utilisés pour cette raison :
|
||||
// http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile
|
||||
}
|
||||
|
||||
if (parameters.debugMode)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
|
||||
*attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
}
|
||||
|
||||
*attrib++ = 0;
|
||||
|
||||
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
m_context = wglCreateContext(m_deviceContext);
|
||||
|
||||
if (shareContext)
|
||||
{
|
||||
// wglShareLists n'est pas thread-safe (source: SFML)
|
||||
static Mutex mutex;
|
||||
LockGuard lock(mutex);
|
||||
|
||||
if (!wglShareLists(shareContext, m_context))
|
||||
NazaraWarning("Failed to share the context: " + Error::GetLastSystemError());
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextImpl::Destroy()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
if (wglGetCurrentContext() == m_context)
|
||||
wglMakeCurrent(nullptr, nullptr);
|
||||
|
||||
wglDeleteContext(m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
if (m_deviceContext)
|
||||
{
|
||||
ReleaseDC(m_window, m_deviceContext);
|
||||
m_deviceContext = nullptr;
|
||||
}
|
||||
|
||||
if (m_ownsWindow)
|
||||
{
|
||||
DestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImpl::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
if (wglSwapInterval)
|
||||
wglSwapInterval(enabled ? 1 : 0);
|
||||
else
|
||||
NazaraError("Vertical sync not supported");
|
||||
}
|
||||
|
||||
void ContextImpl::SwapBuffers()
|
||||
{
|
||||
::SwapBuffers(m_deviceContext);
|
||||
}
|
||||
|
||||
bool ContextImpl::Desactivate()
|
||||
{
|
||||
return wglMakeCurrent(nullptr, nullptr) == TRUE;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine".
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CONTEXTIMPL_HPP
|
||||
#define NAZARA_CONTEXTIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Renderer/ContextParameters.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class ContextImpl
|
||||
{
|
||||
public:
|
||||
ContextImpl();
|
||||
|
||||
bool Activate();
|
||||
|
||||
bool Create(ContextParameters& parameters);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void EnableVerticalSync(bool enabled);
|
||||
|
||||
void SwapBuffers();
|
||||
|
||||
static bool Desactivate();
|
||||
|
||||
private:
|
||||
HDC m_deviceContext;
|
||||
HGLRC m_context;
|
||||
HWND m_window;
|
||||
bool m_ownsWindow;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONTEXTIMPL_HPP
|
||||
31
src/Nazara/VulkanRenderer/Debug/NewOverload.cpp
Normal file
31
src/Nazara/VulkanRenderer/Debug/NewOverload.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2014 AUTHORS
|
||||
// This file is part of the "Nazara Engine - Module name"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#if NAZARA_VULKANRENDERER_MANAGE_MEMORY
|
||||
|
||||
#include <Nazara/Core/MemoryManager.hpp>
|
||||
#include <new> // Nécessaire ?
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, false);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return Nz::MemoryManager::Allocate(size, true);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* pointer) noexcept
|
||||
{
|
||||
Nz::MemoryManager::Free(pointer, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_VULKANRENDERER_MANAGE_MEMORY
|
||||
15
src/Nazara/VulkanRenderer/Export.cpp
Normal file
15
src/Nazara/VulkanRenderer/Export.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderer.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
NAZARA_EXPORT Nz::RendererImpl* NazaraRenderer_Instantiate()
|
||||
{
|
||||
std::unique_ptr<Nz::VulkanRenderer> renderer(new Nz::VulkanRenderer);
|
||||
return renderer.release();
|
||||
}
|
||||
}
|
||||
14
src/Nazara/VulkanRenderer/RenderTarget.cpp
Normal file
14
src/Nazara/VulkanRenderer/RenderTarget.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/RenderTarget.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
OnRenderTargetRelease(this);
|
||||
}
|
||||
}
|
||||
530
src/Nazara/VulkanRenderer/RenderWindow.cpp
Normal file
530
src/Nazara/VulkanRenderer/RenderWindow.cpp
Normal file
@@ -0,0 +1,530 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderWindow::RenderWindow() :
|
||||
RenderTarget(), Window(),
|
||||
m_surface(Nz::Vulkan::GetInstance()),
|
||||
m_forcedPhysicalDevice(nullptr),
|
||||
m_depthStencilFormat(VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
}
|
||||
|
||||
RenderWindow::RenderWindow(VideoMode mode, const String& title, UInt32 style) :
|
||||
RenderWindow()
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
Create(mode, title, style);
|
||||
}
|
||||
|
||||
RenderWindow::RenderWindow(WindowHandle handle) :
|
||||
RenderWindow()
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
Create(handle);
|
||||
}
|
||||
|
||||
RenderWindow::~RenderWindow()
|
||||
{
|
||||
// Nécessaire si Window::Destroy est appelé par son destructeur
|
||||
OnWindowDestroy();
|
||||
}
|
||||
|
||||
bool RenderWindow::Acquire(UInt32* imageIndex) const
|
||||
{
|
||||
if (!m_swapchain.AcquireNextImage(std::numeric_limits<UInt64>::max(), m_imageReadySemaphore, VK_NULL_HANDLE, imageIndex))
|
||||
{
|
||||
NazaraError("Failed to acquire next image");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::BuildPreRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer)
|
||||
{
|
||||
//commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
// Temporary
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
VkImageSubresourceRange imageRange = {
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageAspectFlags aspectMask
|
||||
0, // uint32_t baseMipLevel
|
||||
1, // uint32_t levelCount
|
||||
0, // uint32_t baseArrayLayer
|
||||
1 // uint32_t layerCount
|
||||
};
|
||||
|
||||
commandBuffer.SetImageLayout(m_depthBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, imageRange);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWindow::BuildPostRenderCommands(UInt32 imageIndex, Vk::CommandBuffer& commandBuffer)
|
||||
{
|
||||
//commandBuffer.SetImageLayout(m_swapchain.GetBuffer(imageIndex).image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
const Vk::Framebuffer& RenderWindow::GetFrameBuffer(UInt32 imageIndex) const
|
||||
{
|
||||
return m_frameBuffers[imageIndex];
|
||||
}
|
||||
|
||||
UInt32 RenderWindow::GetFramebufferCount() const
|
||||
{
|
||||
return static_cast<UInt32>(m_frameBuffers.size());
|
||||
}
|
||||
|
||||
bool RenderWindow::Create(VideoMode mode, const String& title, UInt32 style)
|
||||
{
|
||||
return Window::Create(mode, title, style);
|
||||
}
|
||||
|
||||
bool RenderWindow::Create(WindowHandle handle)
|
||||
{
|
||||
return Window::Create(handle);
|
||||
}
|
||||
|
||||
const Vk::DeviceHandle& RenderWindow::GetDevice() const
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
UInt32 RenderWindow::GetPresentableFamilyQueue() const
|
||||
{
|
||||
return m_presentableFamilyQueue;
|
||||
}
|
||||
|
||||
const Vk::Surface& RenderWindow::GetSurface() const
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
const Vk::Swapchain& RenderWindow::GetSwapchain() const
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
void RenderWindow::Present(UInt32 imageIndex)
|
||||
{
|
||||
NazaraAssert(imageIndex < m_frameBuffers.size(), "Invalid image index");
|
||||
|
||||
m_presentQueue.Present(m_swapchain, imageIndex);
|
||||
}
|
||||
|
||||
bool RenderWindow::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void RenderWindow::SetDepthStencilFormats(std::vector<PixelFormatType> pixelFormat)
|
||||
{
|
||||
m_wantedDepthStencilFormats = std::move(pixelFormat);
|
||||
}
|
||||
|
||||
void RenderWindow::SetPhysicalDevice(VkPhysicalDevice device)
|
||||
{
|
||||
m_forcedPhysicalDevice = device;
|
||||
}
|
||||
|
||||
bool RenderWindow::OnWindowCreated()
|
||||
{
|
||||
OnRenderTargetSizeChange(this);
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
HWND handle = reinterpret_cast<HWND>(GetHandle());
|
||||
HINSTANCE instance = reinterpret_cast<HINSTANCE>(GetWindowLongPtrW(handle, GWLP_HINSTANCE));
|
||||
bool success = m_surface.Create(instance, handle);
|
||||
#else
|
||||
#error This OS is not supported by Vulkan
|
||||
#endif
|
||||
|
||||
if (!success)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device = Vulkan::SelectDevice(m_forcedPhysicalDevice, m_surface, &m_presentableFamilyQueue);
|
||||
if (!m_device)
|
||||
{
|
||||
NazaraError("Failed to get compatible Vulkan device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_presentQueue = m_device->GetQueue(m_presentableFamilyQueue, 0);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
||||
if (!m_surface.GetFormats(m_forcedPhysicalDevice, &surfaceFormats))
|
||||
{
|
||||
NazaraError("Failed to query supported surface formats");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surfaceFormats.size() == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
|
||||
m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
else
|
||||
m_colorFormat = surfaceFormats[0].format;
|
||||
|
||||
m_colorSpace = surfaceFormats[0].colorSpace;
|
||||
|
||||
if (!m_wantedDepthStencilFormats.empty())
|
||||
{
|
||||
const Vk::PhysicalDevice& deviceInfo = Vulkan::GetPhysicalDeviceInfo(m_forcedPhysicalDevice);
|
||||
|
||||
for (PixelFormatType format : m_wantedDepthStencilFormats)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormatType_Depth16:
|
||||
m_depthStencilFormat = VK_FORMAT_D16_UNORM;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Depth24:
|
||||
case PixelFormatType_Depth24Stencil8:
|
||||
m_depthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Depth32:
|
||||
m_depthStencilFormat = VK_FORMAT_D32_SFLOAT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Stencil1:
|
||||
case PixelFormatType_Stencil4:
|
||||
case PixelFormatType_Stencil8:
|
||||
m_depthStencilFormat = VK_FORMAT_S8_UINT;
|
||||
break;
|
||||
|
||||
case PixelFormatType_Stencil16:
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
PixelFormatContent formatContent = PixelFormat::GetContent(format);
|
||||
if (formatContent != PixelFormatContent_DepthStencil && formatContent != PixelFormatContent_Stencil)
|
||||
NazaraWarning("Invalid format " + PixelFormat::GetName(format) + " for depth-stencil attachment");
|
||||
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM)
|
||||
{
|
||||
VkFormatProperties formatProperties = m_device->GetInstance().GetPhysicalDeviceFormatProperties(m_forcedPhysicalDevice, m_depthStencilFormat);
|
||||
if (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
break; //< Found it
|
||||
|
||||
m_depthStencilFormat = VK_FORMAT_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetupSwapchain())
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer())
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetupRenderPass())
|
||||
{
|
||||
NazaraError("Failed to create render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt32 imageCount = m_swapchain.GetBufferCount();
|
||||
|
||||
// Framebuffers
|
||||
m_frameBuffers.resize(imageCount);
|
||||
for (UInt32 i = 0; i < imageCount; ++i)
|
||||
{
|
||||
std::array<VkImageView, 2> attachments = {m_swapchain.GetBuffer(i).view, m_depthBufferView};
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreate = {
|
||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkFramebufferCreateFlags flags;
|
||||
m_renderPass, // VkRenderPass renderPass;
|
||||
(attachments[1] != VK_NULL_HANDLE) ? 2U : 1U, // uint32_t attachmentCount;
|
||||
attachments.data(), // const VkImageView* pAttachments;
|
||||
GetWidth(), // uint32_t width;
|
||||
GetHeight(), // uint32_t height;
|
||||
1U // uint32_t layers;
|
||||
};
|
||||
|
||||
if (!m_frameBuffers[i].Create(m_device, frameBufferCreate))
|
||||
{
|
||||
NazaraError("Failed to create framebuffer for image #" + String::Number(i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_imageReadySemaphore.Create(m_device);
|
||||
|
||||
m_clock.Restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::OnWindowDestroy()
|
||||
{
|
||||
m_device->WaitForIdle();
|
||||
m_frameBuffers.clear();
|
||||
m_renderPass.Destroy();
|
||||
|
||||
m_swapchain.Destroy();
|
||||
m_surface.Destroy();
|
||||
}
|
||||
|
||||
void RenderWindow::OnWindowResized()
|
||||
{
|
||||
OnRenderTargetSizeChange(this);
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupDepthBuffer()
|
||||
{
|
||||
VkImageCreateInfo imageCreateInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0U, // VkImageCreateFlags flags;
|
||||
VK_IMAGE_TYPE_2D, // VkImageType imageType;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
{GetWidth(), GetHeight(), 1U}, // VkExtent3D extent;
|
||||
1U, // uint32_t mipLevels;
|
||||
1U, // uint32_t arrayLayers;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
|
||||
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
|
||||
0U, // uint32_t queueFamilyIndexCount;
|
||||
nullptr, // const uint32_t* pQueueFamilyIndices;
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
|
||||
};
|
||||
|
||||
if (!m_depthBuffer.Create(m_device, imageCreateInfo))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memoryReq = m_depthBuffer.GetMemoryRequirements();
|
||||
if (!m_depthBufferMemory.Create(m_device, memoryReq.size, memoryReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
|
||||
{
|
||||
NazaraError("Failed to allocate depth buffer memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_depthBuffer.BindImageMemory(m_depthBufferMemory))
|
||||
{
|
||||
NazaraError("Failed to bind depth buffer to buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo imageViewCreateInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkImageViewCreateFlags flags;
|
||||
m_depthBuffer, // VkImage image;
|
||||
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
{ // VkComponentMapping components;
|
||||
VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle .r;
|
||||
VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle .g;
|
||||
VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle .b;
|
||||
VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a;
|
||||
},
|
||||
{ // VkImageSubresourceRange subresourceRange;
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags .aspectMask;
|
||||
0, // uint32_t .baseMipLevel;
|
||||
1, // uint32_t .levelCount;
|
||||
0, // uint32_t .baseArrayLayer;
|
||||
1 // uint32_t .layerCount;
|
||||
}
|
||||
};
|
||||
|
||||
if (!m_depthBufferView.Create(m_device, imageViewCreateInfo))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer view");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupRenderPass()
|
||||
{
|
||||
std::array<VkAttachmentDescription, 2> attachments = {
|
||||
{
|
||||
{
|
||||
0, // VkAttachmentDescriptionFlags flags;
|
||||
m_colorFormat, // VkFormat format;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
|
||||
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // VkImageLayout finalLayout;
|
||||
},
|
||||
{
|
||||
0, // VkAttachmentDescriptionFlags flags;
|
||||
m_depthStencilFormat, // VkFormat format;
|
||||
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
VkAttachmentReference colorReference = {
|
||||
0, // uint32_t attachment;
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
|
||||
};
|
||||
|
||||
VkAttachmentReference depthReference = {
|
||||
1, // uint32_t attachment;
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout;
|
||||
};
|
||||
|
||||
VkSubpassDescription subpass = {
|
||||
0, // VkSubpassDescriptionFlags flags;
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
|
||||
0U, // uint32_t inputAttachmentCount;
|
||||
nullptr, // const VkAttachmentReference* pInputAttachments;
|
||||
1U, // uint32_t colorAttachmentCount;
|
||||
&colorReference, // const VkAttachmentReference* pColorAttachments;
|
||||
nullptr, // const VkAttachmentReference* pResolveAttachments;
|
||||
(m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? &depthReference : nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
|
||||
0U, // uint32_t preserveAttachmentCount;
|
||||
nullptr // const uint32_t* pPreserveAttachments;
|
||||
};
|
||||
|
||||
std::array<VkSubpassDependency, 2> dependencies;
|
||||
// First dependency at the start of the renderpass
|
||||
// Does the transition from final to initial layout
|
||||
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
|
||||
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
|
||||
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
// Second dependency at the end the renderpass
|
||||
// Does the transition from the initial to the final layout
|
||||
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
|
||||
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
|
||||
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
VkRenderPassCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkRenderPassCreateFlags flags;
|
||||
(m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? 2U : 1U, // uint32_t attachmentCount;
|
||||
attachments.data(), // const VkAttachmentDescription* pAttachments;
|
||||
1U, // uint32_t subpassCount;
|
||||
&subpass, // const VkSubpassDescription* pSubpasses;
|
||||
dependencies.size(), // uint32_t dependencyCount;
|
||||
dependencies.data() // const VkSubpassDependency* pDependencies;
|
||||
};
|
||||
|
||||
return m_renderPass.Create(m_device, createInfo);
|
||||
}
|
||||
|
||||
bool RenderWindow::SetupSwapchain()
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR surfaceCapabilities;
|
||||
if (!m_surface.GetCapabilities(m_forcedPhysicalDevice, &surfaceCapabilities))
|
||||
{
|
||||
NazaraError("Failed to query surface capabilities");
|
||||
return false;
|
||||
}
|
||||
|
||||
Nz::UInt32 imageCount = surfaceCapabilities.minImageCount + 1;
|
||||
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
|
||||
imageCount = surfaceCapabilities.maxImageCount;
|
||||
|
||||
VkExtent2D extent;
|
||||
if (surfaceCapabilities.currentExtent.width == -1)
|
||||
{
|
||||
extent.width = Nz::Clamp<Nz::UInt32>(GetWidth(), surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
|
||||
extent.height = Nz::Clamp<Nz::UInt32>(GetHeight(), surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);
|
||||
}
|
||||
else
|
||||
extent = surfaceCapabilities.currentExtent;
|
||||
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
if (!m_surface.GetPresentModes(m_forcedPhysicalDevice, &presentModes))
|
||||
{
|
||||
NazaraError("Failed to query supported present modes");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
for (VkPresentModeKHR presentMode : presentModes)
|
||||
{
|
||||
if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
{
|
||||
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchainInfo = {
|
||||
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
nullptr,
|
||||
0,
|
||||
m_surface,
|
||||
imageCount,
|
||||
m_colorFormat,
|
||||
m_colorSpace,
|
||||
extent,
|
||||
1,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
VK_SHARING_MODE_EXCLUSIVE,
|
||||
0, nullptr,
|
||||
surfaceCapabilities.currentTransform,
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
swapchainPresentMode,
|
||||
VK_TRUE,
|
||||
0
|
||||
};
|
||||
|
||||
if (!m_swapchain.Create(m_device, swapchainInfo))
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
53
src/Nazara/VulkanRenderer/VkCommandPool.cpp
Normal file
53
src/Nazara/VulkanRenderer/VkCommandPool.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VkCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkCommandBuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
CommandBuffer CommandPool::AllocateCommandBuffer(VkCommandBufferLevel level)
|
||||
{
|
||||
VkCommandBufferAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
nullptr,
|
||||
m_handle,
|
||||
level,
|
||||
1U
|
||||
};
|
||||
|
||||
VkCommandBuffer handle = VK_NULL_HANDLE;
|
||||
m_lastErrorCode = m_device->vkAllocateCommandBuffers(*m_device, &createInfo, &handle);
|
||||
|
||||
return CommandBuffer(*this, handle);
|
||||
}
|
||||
|
||||
std::vector<CommandBuffer> CommandPool::AllocateCommandBuffers(UInt32 commandBufferCount, VkCommandBufferLevel level)
|
||||
{
|
||||
VkCommandBufferAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
nullptr,
|
||||
m_handle,
|
||||
level,
|
||||
commandBufferCount
|
||||
};
|
||||
|
||||
std::vector<VkCommandBuffer> handles(commandBufferCount, VK_NULL_HANDLE);
|
||||
m_lastErrorCode = m_device->vkAllocateCommandBuffers(*m_device, &createInfo, handles.data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
return std::vector<CommandBuffer>();
|
||||
|
||||
std::vector<CommandBuffer> commandBuffers;
|
||||
for (UInt32 i = 0; i < commandBufferCount; ++i)
|
||||
commandBuffers.emplace_back(CommandBuffer(*this, handles[i]));
|
||||
|
||||
return commandBuffers;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/Nazara/VulkanRenderer/VkDescriptorPool.cpp
Normal file
53
src/Nazara/VulkanRenderer/VkDescriptorPool.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VkDescriptorPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkDescriptorSet.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
DescriptorSet DescriptorPool::AllocateDescriptorSet(const VkDescriptorSetLayout& setLayouts)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
m_handle, // VkDescriptorPool descriptorPool;
|
||||
1U, // uint32_t descriptorSetCount;
|
||||
&setLayouts // const VkDescriptorSetLayout* pSetLayouts;
|
||||
};
|
||||
|
||||
VkDescriptorSet handle = VK_NULL_HANDLE;
|
||||
m_lastErrorCode = m_device->vkAllocateDescriptorSets(*m_device, &createInfo, &handle);
|
||||
|
||||
return DescriptorSet(*this, handle);
|
||||
}
|
||||
|
||||
std::vector<DescriptorSet> DescriptorPool::AllocateDescriptorSets(UInt32 descriptorSetCount, const VkDescriptorSetLayout* setLayouts)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo createInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
m_handle, // VkDescriptorPool descriptorPool;
|
||||
descriptorSetCount, // uint32_t descriptorSetCount;
|
||||
setLayouts // const VkDescriptorSetLayout* pSetLayouts;
|
||||
};
|
||||
|
||||
std::vector<VkDescriptorSet> handles(descriptorSetCount, VK_NULL_HANDLE);
|
||||
m_lastErrorCode = m_device->vkAllocateDescriptorSets(*m_device, &createInfo, handles.data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
return std::vector<DescriptorSet>();
|
||||
|
||||
std::vector<DescriptorSet> descriptorSets;
|
||||
for (UInt32 i = 0; i < descriptorSetCount; ++i)
|
||||
descriptorSets.emplace_back(DescriptorSet(*this, handles[i]));
|
||||
|
||||
return descriptorSets;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
src/Nazara/VulkanRenderer/VkDevice.cpp
Normal file
222
src/Nazara/VulkanRenderer/VkDevice.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VkDevice.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Device::Create(VkPhysicalDevice device, const VkDeviceCreateInfo& createInfo, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
std::vector<VkQueueFamilyProperties> queuesProperties;
|
||||
if (!m_instance.GetPhysicalDeviceQueueFamilyProperties(device, &queuesProperties))
|
||||
{
|
||||
NazaraError("Failed to query queue family properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lastErrorCode = m_instance.vkCreateDevice(device, &createInfo, allocator, &m_device);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_physicalDevice = device;
|
||||
|
||||
// Store the allocator to access them when needed
|
||||
if (allocator)
|
||||
m_allocator = *allocator;
|
||||
else
|
||||
m_allocator.pfnAllocation = nullptr;
|
||||
|
||||
// Parse extensions and layers
|
||||
for (UInt32 i = 0; i < createInfo.enabledExtensionCount; ++i)
|
||||
m_loadedExtensions.insert(createInfo.ppEnabledExtensionNames[i]);
|
||||
|
||||
for (UInt32 i = 0; i < createInfo.enabledLayerCount; ++i)
|
||||
m_loadedLayers.insert(createInfo.ppEnabledLayerNames[i]);
|
||||
|
||||
// Load all device-related functions
|
||||
#define NAZARA_VULKANRENDERER_LOAD_DEVICE(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func))
|
||||
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateCommandBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAllocateMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBeginCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBindBufferMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkBindImageMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBeginQuery);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBeginRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindIndexBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindPipeline);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBindVertexBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdBlitImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearAttachments);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearColorImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdClearDepthStencilImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyBufferToImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyImageToBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdCopyQueryPoolResults);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDispatch);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDispatchIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDraw);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndexed);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndexedIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdDrawIndirect);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdEndQuery);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdEndRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdExecuteCommands);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdFillBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdNextSubpass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdPipelineBarrier);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdPushConstants);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResetQueryPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdResolveImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetBlendConstants);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetDepthBias);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetDepthBounds);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetLineWidth);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetScissor);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilCompareMask);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilReference);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetStencilWriteMask);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdSetViewport);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdUpdateBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdWaitEvents);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCmdWriteTimestamp);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateBufferView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateComputePipelines);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateDescriptorSetLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateFramebuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateGraphicsPipelines);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateImageView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreatePipelineCache);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreatePipelineLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSampler);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSemaphore);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateShaderModule);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyBufferView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDescriptorSetLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyDevice);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyFramebuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyImage);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyImageView);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipeline);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipelineCache);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyPipelineLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyRenderPass);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySampler);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySemaphore);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroyShaderModule);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDeviceWaitIdle);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkEndCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeCommandBuffers);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFreeMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkFlushMappedMemoryRanges);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetBufferMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetDeviceMemoryCommitment);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetDeviceQueue);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetEventStatus);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetFenceStatus);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageSparseMemoryRequirements);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetImageSubresourceLayout);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetRenderAreaGranularity);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkInvalidateMappedMemoryRanges);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkMapMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkMergePipelineCaches);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueueSubmit);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueueWaitIdle);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetCommandBuffer);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetCommandPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetDescriptorPool);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetFences);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkResetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkSetEvent);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkUnmapMemory);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkUpdateDescriptorSets);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkWaitForFences);
|
||||
|
||||
// VK_KHR_display_swapchain
|
||||
if (IsExtensionLoaded("VK_KHR_display_swapchain"))
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSharedSwapchainsKHR);
|
||||
|
||||
// VK_KHR_swapchain
|
||||
if (IsExtensionLoaded("VK_KHR_swapchain"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkAcquireNextImageKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkCreateSwapchainKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkDestroySwapchainKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkGetSwapchainImagesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_DEVICE(vkQueuePresentKHR);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError(String("Failed to query device function: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_DEVICE
|
||||
|
||||
// And retains informations about queues
|
||||
UInt32 maxFamilyIndex = 0;
|
||||
m_enabledQueuesInfos.resize(createInfo.queueCreateInfoCount);
|
||||
for (UInt32 i = 0; i < createInfo.queueCreateInfoCount; ++i)
|
||||
{
|
||||
const VkDeviceQueueCreateInfo& queueCreateInfo = createInfo.pQueueCreateInfos[i];
|
||||
QueueFamilyInfo& info = m_enabledQueuesInfos[i];
|
||||
|
||||
info.familyIndex = queueCreateInfo.queueFamilyIndex;
|
||||
if (info.familyIndex > maxFamilyIndex)
|
||||
maxFamilyIndex = info.familyIndex;
|
||||
|
||||
const VkQueueFamilyProperties& queueProperties = queuesProperties[info.familyIndex];
|
||||
info.flags = queueProperties.queueFlags;
|
||||
info.minImageTransferGranularity = queueProperties.minImageTransferGranularity;
|
||||
info.timestampValidBits = queueProperties.timestampValidBits;
|
||||
|
||||
info.queues.resize(queueCreateInfo.queueCount);
|
||||
for (UInt32 queueIndex = 0; queueIndex < queueCreateInfo.queueCount; ++queueIndex)
|
||||
{
|
||||
QueueInfo& queueInfo = info.queues[queueIndex];
|
||||
queueInfo.familyInfo = &info;
|
||||
queueInfo.priority = queueCreateInfo.pQueuePriorities[queueIndex];
|
||||
vkGetDeviceQueue(m_device, info.familyIndex, queueIndex, &queueInfo.queue);
|
||||
}
|
||||
}
|
||||
|
||||
m_queuesByFamily.resize(maxFamilyIndex + 1);
|
||||
for (const QueueFamilyInfo& familyInfo : m_enabledQueuesInfos)
|
||||
m_queuesByFamily[familyInfo.familyIndex] = &familyInfo.queues;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
193
src/Nazara/VulkanRenderer/VkInstance.cpp
Normal file
193
src/Nazara/VulkanRenderer/VkInstance.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VkInstance.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Instance::Create(const VkInstanceCreateInfo& createInfo, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
m_lastErrorCode = Loader::vkCreateInstance(&createInfo, allocator, &m_instance);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to create Vulkan instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the allocator to access them when needed
|
||||
if (allocator)
|
||||
m_allocator = *allocator;
|
||||
else
|
||||
m_allocator.pfnAllocation = nullptr;
|
||||
|
||||
// Parse extensions and layers
|
||||
for (UInt32 i = 0; i < createInfo.enabledExtensionCount; ++i)
|
||||
m_loadedExtensions.insert(createInfo.ppEnabledExtensionNames[i]);
|
||||
|
||||
for (UInt32 i = 0; i < createInfo.enabledLayerCount; ++i)
|
||||
m_loadedLayers.insert(createInfo.ppEnabledLayerNames[i]);
|
||||
|
||||
// And now load everything
|
||||
#define NAZARA_VULKANRENDERER_LOAD_INSTANCE(func) func = reinterpret_cast<PFN_##func>(GetProcAddr(#func))
|
||||
|
||||
try
|
||||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
// Vulkan core
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDevice);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroyInstance);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkEnumeratePhysicalDevices);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDeviceProcAddr);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceFeatures);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceFormatProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceImageFormatProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceMemoryProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
|
||||
// VK_KHR_display
|
||||
if (IsExtensionLoaded("VK_KHR_display"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDisplayModeKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDisplayPlaneSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayModePropertiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayPlaneCapabilitiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetDisplayPlaneSupportedDisplaysKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceDisplayPropertiesKHR);
|
||||
}
|
||||
|
||||
// VK_KHR_surface
|
||||
if (IsExtensionLoaded("VK_KHR_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroySurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
}
|
||||
|
||||
// VK_EXT_debug_report
|
||||
if (IsExtensionLoaded("VK_EXT_debug_report"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateDebugReportCallbackEXT);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDestroyDebugReportCallbackEXT);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkDebugReportMessageEXT);
|
||||
}
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
// VK_KHR_android_surface
|
||||
if (IsExtensionLoaded("VK_KHR_android_surface"))
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateAndroidSurfaceKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
// VK_KHR_mir_surface
|
||||
if (IsExtensionLoaded("VK_KHR_mir_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateMirSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceMirPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
// VK_KHR_xcb_surface
|
||||
if (IsExtensionLoaded("VK_KHR_xcb_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateXcbSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceXcbPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
// VK_KHR_xlib_surface
|
||||
if (IsExtensionLoaded("VK_KHR_xlib_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateXlibSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceXlibPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
// VK_KHR_wayland_surface
|
||||
if (IsExtensionLoaded("VK_KHR_wayland_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateWaylandSurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
// VK_KHR_win32_surface
|
||||
if (IsExtensionLoaded("VK_KHR_win32_surface"))
|
||||
{
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkCreateWin32SurfaceKHR);
|
||||
NAZARA_VULKANRENDERER_LOAD_INSTANCE(vkGetPhysicalDeviceWin32PresentationSupportKHR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError(String("Failed to query instance function: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_INSTANCE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::EnumeratePhysicalDevices(std::vector<VkPhysicalDevice>* devices)
|
||||
{
|
||||
NazaraAssert(devices, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 deviceCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
m_lastErrorCode = vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS || deviceCount == 0)
|
||||
{
|
||||
NazaraError("Failed to query physical device count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
devices->resize(deviceCount);
|
||||
m_lastErrorCode = vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices->data());
|
||||
if (m_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to query physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice device, std::vector<VkQueueFamilyProperties>* queueFamilyProperties)
|
||||
{
|
||||
NazaraAssert(queueFamilyProperties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 queueFamiliesCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, nullptr);
|
||||
if (queueFamiliesCount == 0)
|
||||
{
|
||||
NazaraError("Failed to query physical device count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
queueFamilyProperties->resize(queueFamiliesCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamiliesCount, queueFamilyProperties->data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
117
src/Nazara/VulkanRenderer/VkLoader.cpp
Normal file
117
src/Nazara/VulkanRenderer/VkLoader.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VkLoader.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Vk
|
||||
{
|
||||
bool Loader::EnumerateInstanceExtensionProperties(std::vector<VkExtensionProperties>* properties, const char* layerName)
|
||||
{
|
||||
NazaraAssert(properties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 propertyCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
s_lastErrorCode = vkEnumerateInstanceExtensionProperties(layerName, &propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to get instance extension properties count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
properties->resize(propertyCount);
|
||||
s_lastErrorCode = vkEnumerateInstanceExtensionProperties(layerName, &propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to enumerate instance extension properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loader::EnumerateInstanceLayerProperties(std::vector<VkLayerProperties>* properties)
|
||||
{
|
||||
NazaraAssert(properties, "Invalid device vector");
|
||||
|
||||
// First, query physical device count
|
||||
UInt32 propertyCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t
|
||||
s_lastErrorCode = vkEnumerateInstanceLayerProperties(&propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to get instance layer properties count");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we can get the list of the available physical device
|
||||
properties->resize(propertyCount);
|
||||
s_lastErrorCode = vkEnumerateInstanceLayerProperties(&propertyCount, properties->data());
|
||||
if (s_lastErrorCode != VkResult::VK_SUCCESS)
|
||||
{
|
||||
NazaraError("Failed to enumerate instance layer properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loader::Initialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
s_vulkanLib.Load("vulkan-1.dll");
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
s_vulkanLib.Load("libvulkan.so");
|
||||
#else
|
||||
#error Unhandled platform
|
||||
#endif
|
||||
|
||||
if (!s_vulkanLib.IsLoaded())
|
||||
{
|
||||
NazaraError("Failed to open vulkan library: " + s_vulkanLib.GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// vkGetInstanceProcAddr is the only function that's garantee to be exported
|
||||
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(s_vulkanLib.GetSymbol("vkGetInstanceProcAddr"));
|
||||
if (!vkGetInstanceProcAddr)
|
||||
{
|
||||
NazaraError("Failed to get symbol \"vkGetInstanceProcAddr\": " + s_vulkanLib.GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// all other functions should be loaded using vkGetInstanceProcAddr
|
||||
#define NAZARA_VULKANRENDERER_LOAD_GLOBAL(func) func = reinterpret_cast<PFN_##func>(vkGetInstanceProcAddr(nullptr, #func))
|
||||
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkCreateInstance);
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceExtensionProperties);
|
||||
NAZARA_VULKANRENDERER_LOAD_GLOBAL(vkEnumerateInstanceLayerProperties);
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_LOAD_GLOBAL
|
||||
|
||||
s_lastErrorCode = VkResult::VK_SUCCESS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(func) PFN_##func Loader::func = nullptr
|
||||
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkCreateInstance);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceExtensionProperties);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkEnumerateInstanceLayerProperties);
|
||||
NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL(vkGetInstanceProcAddr);
|
||||
|
||||
#undef NAZARA_VULKANRENDERER_GLOBAL_FUNCTION_IMPL
|
||||
|
||||
DynLib Loader::s_vulkanLib;
|
||||
VkResult Loader::s_lastErrorCode;
|
||||
|
||||
void Loader::Uninitialize()
|
||||
{
|
||||
s_vulkanLib.Unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
451
src/Nazara/VulkanRenderer/Vulkan.cpp
Normal file
451
src/Nazara/VulkanRenderer/Vulkan.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <Nazara/VulkanRenderer/Config.hpp>
|
||||
#include <array>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
Vk::Instance& Vulkan::GetInstance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const std::vector<Vk::PhysicalDevice>& Vulkan::GetPhysicalDevices()
|
||||
{
|
||||
return s_physDevices;
|
||||
}
|
||||
|
||||
const Vk::PhysicalDevice& Vulkan::GetPhysicalDeviceInfo(VkPhysicalDevice physDevice)
|
||||
{
|
||||
for (const Vk::PhysicalDevice& info : s_physDevices)
|
||||
{
|
||||
if (info.device == physDevice)
|
||||
return info;
|
||||
}
|
||||
|
||||
// This cannot happen if physDevice is valid, as we retrieved every physical device
|
||||
NazaraInternalError("Invalid physical device: " + String::Pointer(physDevice));
|
||||
|
||||
static Vk::PhysicalDevice dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
bool Vulkan::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Already initialized
|
||||
}
|
||||
|
||||
// Initialize module dependencies
|
||||
if (!Utility::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize utility module");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
CallOnExit onExit(Vulkan::Uninitialize);
|
||||
|
||||
// Initialize module here
|
||||
if (!Vk::Loader::Initialize())
|
||||
{
|
||||
NazaraError("Failed to load Vulkan API, it may be not installed on your system");
|
||||
return false;
|
||||
}
|
||||
|
||||
String appName = "Another application made with Nazara Engine";
|
||||
String engineName = "Nazara Engine - Vulkan Renderer";
|
||||
UInt32 apiVersion = VK_MAKE_VERSION(1, 0, 8);
|
||||
UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
s_initializationParameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName);
|
||||
s_initializationParameters.GetStringParameter("VkAppInfo_OverrideEngineName", &engineName);
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion", &iParam))
|
||||
apiVersion = iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion", &iParam))
|
||||
appVersion = iParam;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion", &iParam))
|
||||
engineVersion = iParam;
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
nullptr,
|
||||
appName.GetConstBuffer(),
|
||||
appVersion,
|
||||
engineName.GetConstBuffer(),
|
||||
engineVersion,
|
||||
apiVersion
|
||||
};
|
||||
|
||||
VkInstanceCreateFlags createFlags = 0;
|
||||
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags", &iParam))
|
||||
createFlags = static_cast<VkInstanceCreateFlags>(iParam);
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
{
|
||||
enabledExtensions.push_back("VK_KHR_surface");
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
enabledExtensions.push_back("VK_KHR_android_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
enabledExtensions.push_back("VK_KHR_mir_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xcb_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xlib_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
enabledExtensions.push_back("VK_KHR_wayland_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
enabledExtensions.push_back("VK_KHR_win32_surface");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkInstanceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
additionalExtensions.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkInstanceCreateInfo instanceInfo = {
|
||||
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
nullptr,
|
||||
createFlags,
|
||||
&appInfo,
|
||||
UInt32(enabledLayers.size()),
|
||||
enabledLayers.data(),
|
||||
UInt32(enabledExtensions.size()),
|
||||
enabledExtensions.data()
|
||||
};
|
||||
|
||||
if (!s_instance.Create(instanceInfo))
|
||||
{
|
||||
NazaraError("Failed to create instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> physDevices;
|
||||
if (!s_instance.EnumeratePhysicalDevices(&physDevices))
|
||||
{
|
||||
NazaraError("Failed to enumerate physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_physDevices.reserve(physDevices.size());
|
||||
|
||||
for (std::size_t i = 0; i < physDevices.size(); ++i)
|
||||
{
|
||||
VkPhysicalDevice physDevice = physDevices[i];
|
||||
|
||||
Vk::PhysicalDevice deviceInfo;
|
||||
if (!s_instance.GetPhysicalDeviceQueueFamilyProperties(physDevice, &deviceInfo.queues))
|
||||
{
|
||||
NazaraWarning("Failed to query physical device queue family properties");
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.device = physDevice;
|
||||
|
||||
deviceInfo.features = s_instance.GetPhysicalDeviceFeatures(physDevice);
|
||||
deviceInfo.memoryProperties = s_instance.GetPhysicalDeviceMemoryProperties(physDevice);
|
||||
deviceInfo.properties = s_instance.GetPhysicalDeviceProperties(physDevice);
|
||||
|
||||
s_physDevices.emplace_back(std::move(deviceInfo));
|
||||
}
|
||||
|
||||
if (s_physDevices.empty())
|
||||
{
|
||||
NazaraError("No valid physical device found");
|
||||
return false;
|
||||
}
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Vulkan module");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vulkan::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
Vk::DeviceHandle Vulkan::CreateDevice(VkPhysicalDevice gpu, const Vk::Surface& surface, UInt32* presentableFamilyQueue)
|
||||
{
|
||||
Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies;
|
||||
s_instance.GetPhysicalDeviceQueueFamilyProperties(gpu, &queueFamilies);
|
||||
|
||||
// Find a queue that supports graphics operations
|
||||
UInt32 graphicsQueueNodeIndex = UINT32_MAX;
|
||||
UInt32 presentQueueNodeIndex = UINT32_MAX;
|
||||
UInt32 transfertQueueNodeFamily = UINT32_MAX;
|
||||
for (UInt32 i = 0; i < queueFamilies.size(); i++)
|
||||
{
|
||||
bool supportPresentation = false;
|
||||
if (!surface.GetSupportPresentation(gpu, i, &supportPresentation))
|
||||
NazaraWarning("Failed to get presentation support of queue family #" + String::Number(i));
|
||||
|
||||
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
if (graphicsQueueNodeIndex == UINT32_MAX)
|
||||
graphicsQueueNodeIndex = i;
|
||||
|
||||
if (supportPresentation)
|
||||
{
|
||||
graphicsQueueNodeIndex = i;
|
||||
presentQueueNodeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (supportPresentation)
|
||||
presentQueueNodeIndex = i;
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i < queueFamilies.size(); i++)
|
||||
{
|
||||
if (queueFamilies[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
||||
{
|
||||
transfertQueueNodeFamily = i;
|
||||
if (transfertQueueNodeFamily != graphicsQueueNodeIndex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<UInt32, 3> usedQueueFamilies = {graphicsQueueNodeIndex, presentQueueNodeIndex, transfertQueueNodeFamily};
|
||||
std::array<float, 3> priorities = {1.f, 1.f, 1.f};
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
for (UInt32 queueFamily : usedQueueFamilies)
|
||||
{
|
||||
auto it = std::find_if(queueCreateInfos.begin(), queueCreateInfos.end(), [queueFamily] (const VkDeviceQueueCreateInfo& createInfo)
|
||||
{
|
||||
return createInfo.queueFamilyIndex == queueFamily;
|
||||
});
|
||||
|
||||
if (it == queueCreateInfos.end())
|
||||
{
|
||||
VkDeviceQueueCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
0, // VkDeviceQueueCreateFlags flags;
|
||||
queueFamily, // uint32_t queueFamilyIndex;
|
||||
1, // uint32_t queueCount;
|
||||
priorities.data() // const float* pQueuePriorities;
|
||||
};
|
||||
|
||||
queueCreateInfos.emplace_back(createInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkDeviceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkDeviceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkDeviceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_initializationParameters.GetBooleanParameter("VkDeviceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (s_initializationParameters.GetIntegerParameter("VkDeviceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkDeviceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (s_initializationParameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
UInt32(queueCreateInfos.size()),
|
||||
queueCreateInfos.data(),
|
||||
UInt32(enabledLayers.size()),
|
||||
enabledLayers.data(),
|
||||
UInt32(enabledExtensions.size()),
|
||||
enabledExtensions.data(),
|
||||
nullptr
|
||||
};
|
||||
|
||||
///TODO: First create then move
|
||||
s_devices.emplace_back(s_instance);
|
||||
|
||||
Vk::Device& device = s_devices.back();
|
||||
device.Create(gpu, createInfo);
|
||||
|
||||
*presentableFamilyQueue = presentQueueNodeIndex;
|
||||
|
||||
return device.CreateHandle();
|
||||
}
|
||||
|
||||
Vk::DeviceHandle Vulkan::SelectDevice(VkPhysicalDevice gpu, const Vk::Surface& surface, UInt32* presentableFamilyQueue)
|
||||
{
|
||||
// First, try to find a device compatible with that surface
|
||||
for (Vk::Device& device : s_devices)
|
||||
{
|
||||
if (device.GetPhysicalDevice() == gpu)
|
||||
{
|
||||
const std::vector<Vk::Device::QueueFamilyInfo>& queueFamilyInfo = device.GetEnabledQueues();
|
||||
UInt32 presentableQueueFamilyIndex = UINT32_MAX;
|
||||
for (Vk::Device::QueueFamilyInfo queueInfo : queueFamilyInfo)
|
||||
{
|
||||
bool supported = false;
|
||||
if (surface.GetSupportPresentation(gpu, queueInfo.familyIndex, &supported) && supported)
|
||||
{
|
||||
if (presentableQueueFamilyIndex == UINT32_MAX || queueInfo.flags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
presentableQueueFamilyIndex = queueInfo.familyIndex;
|
||||
if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (presentableQueueFamilyIndex != UINT32_MAX)
|
||||
*presentableFamilyQueue = presentableQueueFamilyIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// No device had support for that surface, create one
|
||||
return CreateDevice(gpu, surface, presentableFamilyQueue);
|
||||
}
|
||||
|
||||
void Vulkan::SetParameters(const ParameterList& parameters)
|
||||
{
|
||||
s_initializationParameters = parameters;
|
||||
}
|
||||
|
||||
void Vulkan::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Either the module is not initialized, either it was initialized multiple times
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
// Uninitialize module here
|
||||
s_devices.clear();
|
||||
s_instance.Destroy();
|
||||
|
||||
Vk::Loader::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Vulkan module");
|
||||
|
||||
// Free module dependencies
|
||||
Utility::Uninitialize();
|
||||
}
|
||||
|
||||
std::list<Vk::Device> Vulkan::s_devices;
|
||||
std::vector<Vk::PhysicalDevice> Vulkan::s_physDevices;
|
||||
Vk::Instance Vulkan::s_instance;
|
||||
ParameterList Vulkan::s_initializationParameters;
|
||||
unsigned int Vulkan::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
252
src/Nazara/VulkanRenderer/VulkanRenderer.cpp
Normal file
252
src/Nazara/VulkanRenderer/VulkanRenderer.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Vulkan Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VkLoader.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool VulkanRenderer::IsBetterThan(const RendererImpl* other) const
|
||||
{
|
||||
if (other->QueryAPI() == RenderAPI_Vulkan && QueryAPIVersion() < other->QueryAPIVersion())
|
||||
return false;
|
||||
|
||||
return true; //< Vulkan FTW
|
||||
}
|
||||
|
||||
bool VulkanRenderer::Prepare(const ParameterList& parameters)
|
||||
{
|
||||
if (!Vk::Loader::Initialize())
|
||||
{
|
||||
NazaraError("Failed to load Vulkan API, it may be not installed on your system");
|
||||
return false;
|
||||
}
|
||||
|
||||
String appName = "Another application made with Nazara Engine";
|
||||
String engineName = "Nazara Engine - Vulkan Renderer";
|
||||
|
||||
UInt32 apiVersion = APIVersion;
|
||||
UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
parameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName);
|
||||
parameters.GetStringParameter("VkAppInfo_OverrideEngineName", &engineName);
|
||||
|
||||
bool bParam;
|
||||
int iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion", &iParam))
|
||||
apiVersion = iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion", &iParam))
|
||||
appVersion = iParam;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion", &iParam))
|
||||
engineVersion = iParam;
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
nullptr,
|
||||
appName.GetConstBuffer(),
|
||||
appVersion,
|
||||
engineName.GetConstBuffer(),
|
||||
engineVersion,
|
||||
apiVersion
|
||||
};
|
||||
|
||||
VkInstanceCreateFlags createFlags = 0;
|
||||
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags", &iParam))
|
||||
createFlags = static_cast<VkInstanceCreateFlags>(iParam);
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
std::vector<const char*> enabledExtensions;
|
||||
|
||||
if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledLayers", &bParam) || !bParam)
|
||||
{
|
||||
//< Nazara default layers goes here
|
||||
}
|
||||
|
||||
std::vector<String> additionalLayers; // Just to keep the String alive
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_EnabledLayerCount", &iParam))
|
||||
{
|
||||
additionalLayers.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledLayer" + String::Number(i);
|
||||
Nz::String layer;
|
||||
if (parameters.GetStringParameter(parameterName, &layer))
|
||||
{
|
||||
additionalLayers.emplace_back(std::move(layer));
|
||||
enabledLayers.push_back(additionalLayers.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!parameters.GetBooleanParameter("VkInstanceInfo_OverrideEnabledExtensions", &bParam) || !bParam)
|
||||
{
|
||||
enabledExtensions.push_back("VK_KHR_surface");
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
enabledExtensions.push_back("VK_KHR_android_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
enabledExtensions.push_back("VK_KHR_mir_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xcb_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
enabledExtensions.push_back("VK_KHR_xlib_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
enabledExtensions.push_back("VK_KHR_wayland_surface");
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
enabledExtensions.push_back("VK_KHR_win32_surface");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<String> additionalExtensions; // Just to keep the String alive
|
||||
if (parameters.GetIntegerParameter("VkInstanceInfo_EnabledExtensionCount", &iParam))
|
||||
{
|
||||
additionalExtensions.reserve(iParam);
|
||||
for (int i = 0; i < iParam; ++i)
|
||||
{
|
||||
Nz::String parameterName = "VkInstanceInfo_EnabledExtension" + String::Number(i);
|
||||
Nz::String extension;
|
||||
if (parameters.GetStringParameter(parameterName, &extension))
|
||||
{
|
||||
additionalExtensions.emplace_back(std::move(extension));
|
||||
enabledExtensions.push_back(additionalExtensions.back().GetConstBuffer());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Parameter " + parameterName + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
VkInstanceCreateInfo instanceInfo =
|
||||
{
|
||||
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType;
|
||||
nullptr, // const void* pNext;
|
||||
createFlags, // VkInstanceCreateFlags flags;
|
||||
&appInfo, // const VkApplicationInfo* pApplicationInfo;
|
||||
UInt32(enabledLayers.size()), // uint32_t enabledLayerCount;
|
||||
enabledLayers.data(), // const char* const* ppEnabledLayerNames;
|
||||
UInt32(enabledExtensions.size()), // uint32_t enabledExtensionCount;
|
||||
enabledExtensions.data() // const char* const* ppEnabledExtensionNames;
|
||||
};
|
||||
|
||||
if (!m_instance.Create(instanceInfo))
|
||||
{
|
||||
NazaraError("Failed to create instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_apiVersion = apiVersion;
|
||||
|
||||
std::vector<VkPhysicalDevice> physDevices;
|
||||
if (!m_instance.EnumeratePhysicalDevices(&physDevices))
|
||||
{
|
||||
NazaraError("Failed to enumerate physical devices");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_physDevices.reserve(physDevices.size());
|
||||
for (std::size_t i = 0; i < physDevices.size(); ++i)
|
||||
{
|
||||
VkPhysicalDevice physDevice = physDevices[i];
|
||||
|
||||
Vk::PhysicalDevice deviceInfo;
|
||||
if (!m_instance.GetPhysicalDeviceQueueFamilyProperties(physDevice, &deviceInfo.queues))
|
||||
{
|
||||
NazaraWarning("Failed to query physical device queue family properties for " + String(deviceInfo.properties.deviceName) + " (0x" + String::Number(deviceInfo.properties.deviceID, 16) + ')');
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.device = physDevice;
|
||||
|
||||
deviceInfo.features = m_instance.GetPhysicalDeviceFeatures(physDevice);
|
||||
deviceInfo.memoryProperties = m_instance.GetPhysicalDeviceMemoryProperties(physDevice);
|
||||
deviceInfo.properties = m_instance.GetPhysicalDeviceProperties(physDevice);
|
||||
|
||||
m_physDevices.emplace_back(std::move(deviceInfo));
|
||||
}
|
||||
|
||||
if (m_physDevices.empty())
|
||||
{
|
||||
NazaraError("No valid physical device found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderAPI VulkanRenderer::QueryAPI() const
|
||||
{
|
||||
return RenderAPI_Vulkan;
|
||||
}
|
||||
|
||||
String VulkanRenderer::QueryAPIString() const
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Vulkan renderer " << VK_VERSION_MAJOR(m_apiVersion) << '.' << VK_VERSION_MINOR(m_apiVersion) << '.' << VK_VERSION_PATCH(m_apiVersion);
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
UInt32 VulkanRenderer::QueryAPIVersion() const
|
||||
{
|
||||
return m_apiVersion;
|
||||
}
|
||||
|
||||
std::vector<RenderDevice> VulkanRenderer::QueryRenderDevices() const
|
||||
{
|
||||
std::vector<RenderDevice> devices;
|
||||
devices.reserve(m_physDevices.size());
|
||||
|
||||
for (const Vk::PhysicalDevice& physDevice : m_physDevices)
|
||||
{
|
||||
RenderDevice device;
|
||||
device.name = physDevice.properties.deviceName;
|
||||
|
||||
switch (physDevice.properties.deviceType)
|
||||
{
|
||||
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
||||
device.type = RenderDeviceType_Software;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
||||
device.type = RenderDeviceType_Dedicated;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
device.type = RenderDeviceType_Integrated;
|
||||
break;
|
||||
|
||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
||||
device.type = RenderDeviceType_Virtual;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraWarning("Device " + device.name + " has handled device type (0x" + String::Number(physDevice.properties.deviceType, 16) + ')');
|
||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
||||
device.type = RenderDeviceType_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
devices.emplace_back(device);
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user