Merge branch 'vulkan' into shader-nodes
This commit is contained in:
302
src/Nazara/Renderer/GLX/ContextImpl.cpp
Normal file
302
src/Nazara/Renderer/GLX/ContextImpl.cpp
Normal file
@@ -0,0 +1,302 @@
|
||||
// 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() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
NazaraAssert(parameters.window.type == WindowManager::X11, "Cannot create a context for a non-x11 window");
|
||||
|
||||
m_window = static_cast<GLX::Window>(parameters.window.x11.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;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Nz
|
||||
{
|
||||
if (m_framerateLimit > 0)
|
||||
{
|
||||
int remainingTime = 1000/static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetMilliseconds());
|
||||
int remainingTime = 1000 / static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetMilliseconds());
|
||||
if (remainingTime > 0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(remainingTime));
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace Nz
|
||||
|
||||
bool RenderWindow::OnWindowCreated()
|
||||
{
|
||||
RendererImpl* rendererImpl = Renderer::GetRendererImpl();
|
||||
RendererImpl *rendererImpl = Renderer::GetRendererImpl();
|
||||
auto surface = rendererImpl->CreateRenderSurfaceImpl();
|
||||
if (!surface->Create(GetHandle()))
|
||||
if (!surface->Create(GetSystemHandle()))
|
||||
{
|
||||
NazaraError("Failed to create render surface: " + Error::GetLastError());
|
||||
return false;
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
#define NazaraRendererPattern "Nazara?*Renderer-d" NAZARA_DYNLIB_EXTENSION
|
||||
#define NazaraRendererDebugSuffix "-d"
|
||||
#else
|
||||
#define NazaraRendererPattern "Nazara?*Renderer" NAZARA_DYNLIB_EXTENSION
|
||||
#define NazaraRendererDebugSuffix ""
|
||||
#endif
|
||||
|
||||
namespace Nz
|
||||
@@ -48,26 +48,45 @@ namespace Nz
|
||||
|
||||
CallOnExit onExit(Renderer::Uninitialize);
|
||||
|
||||
struct RendererImplementations
|
||||
{
|
||||
std::filesystem::path fileName;
|
||||
int score;
|
||||
};
|
||||
std::vector<RendererImplementations> implementations;
|
||||
|
||||
auto RegisterImpl = [&](std::filesystem::path fileName, auto ComputeScore)
|
||||
{
|
||||
fileName.replace_extension(NAZARA_DYNLIB_EXTENSION);
|
||||
|
||||
int score = ComputeScore();
|
||||
if (score >= 0)
|
||||
{
|
||||
auto& impl = implementations.emplace_back();
|
||||
impl.fileName = std::move(fileName);
|
||||
impl.score = score;
|
||||
}
|
||||
};
|
||||
|
||||
RegisterImpl("NazaraOpenGLRenderer" NazaraRendererDebugSuffix, [] { return 50; });
|
||||
RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; });
|
||||
|
||||
std::sort(implementations.begin(), implementations.end(), [](const auto& lhs, const auto& rhs) { return lhs.score > rhs.score; });
|
||||
|
||||
NazaraDebug("Searching for renderer implementation");
|
||||
|
||||
DynLib chosenLib;
|
||||
std::unique_ptr<RendererImpl> chosenImpl;
|
||||
|
||||
for (auto&& entry : std::filesystem::directory_iterator("."))
|
||||
for (auto&& rendererImpl : implementations)
|
||||
{
|
||||
if (!entry.is_regular_file())
|
||||
if (!std::filesystem::exists(rendererImpl.fileName))
|
||||
continue;
|
||||
|
||||
const std::filesystem::path& entryPath = entry.path();
|
||||
std::filesystem::path fileName = entryPath.filename();
|
||||
std::string fileNameStr = fileName.generic_u8string();
|
||||
if (!MatchPattern(fileNameStr, NazaraRendererPattern))
|
||||
continue;
|
||||
|
||||
NazaraDebug("Trying to load " + fileNameStr);
|
||||
std::string fileNameStr = rendererImpl.fileName.generic_u8string();
|
||||
|
||||
DynLib implLib;
|
||||
if (!implLib.Load(entryPath))
|
||||
if (!implLib.Load(rendererImpl.fileName))
|
||||
{
|
||||
NazaraWarning("Failed to load " + fileNameStr + ": " + implLib.GetLastError());
|
||||
continue;
|
||||
@@ -87,16 +106,11 @@ namespace Nz
|
||||
continue;
|
||||
}
|
||||
|
||||
NazaraDebug("Loaded " + impl->QueryAPIString());
|
||||
NazaraDebug("Loaded " + fileNameStr);
|
||||
|
||||
if (!chosenImpl || impl->IsBetterThan(chosenImpl.get()))
|
||||
{
|
||||
if (chosenImpl)
|
||||
NazaraDebug("Choose " + impl->QueryAPIString() + " over " + chosenImpl->QueryAPIString());
|
||||
|
||||
chosenImpl = std::move(impl); //< Move (and delete previous) implementation before unloading library
|
||||
chosenLib = std::move(implLib);
|
||||
}
|
||||
chosenImpl = std::move(impl); //< Move (and delete previous) implementation before unloading library
|
||||
chosenLib = std::move(implLib);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!chosenImpl)
|
||||
|
||||
Reference in New Issue
Block a user