Moving to custom context creation

This commit is contained in:
Brad Davis 2016-08-22 11:50:32 -07:00
parent c3e345150b
commit 617633b85c
31 changed files with 803 additions and 296 deletions

View file

@ -778,8 +778,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// enable mouse tracking; otherwise, we only get drag events
_glWidget->setMouseTracking(true);
// Make sure the window is set to the correct size by processing the pending events
QCoreApplication::processEvents();
_glWidget->createContext();
_glWidget->makeCurrent();
_glWidget->initializeGL();
initializeGL();
// Make sure we don't time out during slow operations at startup
@ -1484,7 +1486,7 @@ void Application::initializeGL() {
_glWidget->makeCurrent();
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->context()->contextHandle());
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
@ -1531,7 +1533,7 @@ void Application::initializeGL() {
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->context()->contextHandle());
_offscreenContext->create(_glWidget->qglContext());
_offscreenContext->makeCurrent();
// update before the first render
@ -1553,7 +1555,7 @@ void Application::initializeUi() {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->context()->contextHandle());
offscreenUi->create(_glWidget->qglContext());
auto rootContext = offscreenUi->getRootContext();
@ -5675,7 +5677,7 @@ MainWindow* Application::getPrimaryWindow() {
}
QOpenGLContext* Application::getPrimaryContext() {
return _glWidget->context()->contextHandle();
return _glWidget->qglContext();
}
bool Application::makeRenderingContextCurrent() {

View file

@ -29,6 +29,7 @@
#include <gl/GLWidget.h>
#include <gl/Config.h>
#include <gl/GLEscrow.h>
#include <gl/Context.h>
#include <gpu/Texture.h>
#include <gpu/StandardShaderLib.h>
@ -108,7 +109,7 @@ public:
}
}
void setContext(QGLContext * context) {
void setContext(gl::Context* context) {
// Move the OpenGL context to the present thread
// Extra code because of the widget 'wrapper' context
_context = context;
@ -126,7 +127,6 @@ public:
OpenGLDisplayPlugin* currentPlugin{ nullptr };
Q_ASSERT(_context);
_context->makeCurrent();
Q_ASSERT(isCurrentContext(_context->contextHandle()));
while (!_shutdown) {
if (_pendingMainThreadOperation) {
PROFILE_RANGE("MainThreadOp")
@ -250,7 +250,7 @@ private:
bool _finishedMainThreadOperation { false };
QThread* _mainThread { nullptr };
std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
QGLContext* _context { nullptr };
gl::Context* _context { nullptr };
};
bool OpenGLDisplayPlugin::activate() {
@ -649,8 +649,8 @@ float OpenGLDisplayPlugin::presentRate() const {
}
void OpenGLDisplayPlugin::swapBuffers() {
static auto widget = _container->getPrimaryWidget();
widget->swapBuffers();
static auto context = _container->getPrimaryWidget()->context();
context->swapBuffers();
}
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {

View file

@ -0,0 +1,279 @@
//
// Created by Bradley Austin Davis on 2016/08/21
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Context.h"
#include <assert.h>
#include <mutex>
#include <QtCore/QDebug>
#include <QtCore/QProcessEnvironment>
#include <QtCore/QThread>
#include <QtGui/QWindow>
#include <QtGui/QGuiApplication>
#include <GLMHelpers.h>
#ifdef Q_OS_WIN
#ifdef DEBUG
static bool enableDebugLogger = true;
#else
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
#endif
#endif
#include "Config.h"
#include "GLHelpers.h"
using namespace gl;
Context* Context::PRIMARY = nullptr;
Context::Context() {}
Context::Context(QWindow* window) {
setWindow(window);
}
#ifdef Q_OS_WIN
void Context::destroyWin32Context(HGLRC hglrc) {
wglDeleteContext(hglrc);
}
#endif
void Context::release() {
doneCurrent();
#ifdef Q_OS_WIN
if (_wrappedContext) {
destroyContext(_wrappedContext);
_wrappedContext = nullptr;
}
if (_hglrc) {
destroyWin32Context(_hglrc);
_hglrc = 0;
}
if (_hdc) {
ReleaseDC(_hwnd, _hdc);
_hdc = 0;
}
_hwnd = 0;
#else
destroyContext(_context);
_context = nullptr;
#endif
_window = nullptr;
if (PRIMARY == this) {
PRIMARY = nullptr;
}
}
Context::~Context() {
release();
}
void Context::setWindow(QWindow* window) {
release();
_window = window;
#ifdef Q_OS_WIN
_hwnd = (HWND)window->winId();
#endif
}
#ifdef Q_OS_WIN
static const char* PRIMARY_CONTEXT_PROPERTY_NAME = "com.highfidelity.gl.primaryContext";
bool Context::makeCurrent() {
BOOL result = wglMakeCurrent(_hdc, _hglrc);
assert(result);
return result;
}
void Context::swapBuffers() {
SwapBuffers(_hdc);
}
void Context::doneCurrent() {
wglMakeCurrent(0, 0);
}
void GLAPIENTRY debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
if (GL_DEBUG_SEVERITY_NOTIFICATION == severity) {
return;
}
qDebug() << "QQQ " << message;
}
// FIXME build the PFD based on the
static const PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
24, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
1, // Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
24, // 24 Bit Z-Buffer (Depth Buffer)
8, // 8 Bit Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
void setupPixelFormatSimple(HDC hdc) {
auto pixelFormat = ChoosePixelFormat(hdc, &pfd);
if (pixelFormat == 0) {
throw std::runtime_error("Unable to create initial context");
}
if (SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE) {
throw std::runtime_error("Unable to create initial context");
}
}
void Context::create() {
if (!PRIMARY) {
PRIMARY = static_cast<Context*>(qApp->property(PRIMARY_CONTEXT_PROPERTY_NAME).value<void*>());
}
if (PRIMARY) {
_version = PRIMARY->_version;
}
assert(0 != _hwnd);
assert(0 == _hdc);
auto hwnd = _hwnd;
// Create a temporary context to initialize glew
static std::once_flag once;
std::call_once(once, [&] {
auto hdc = GetDC(hwnd);
setupPixelFormatSimple(hdc);
auto glrc = wglCreateContext(hdc);
BOOL makeCurrentResult;
makeCurrentResult = wglMakeCurrent(hdc, glrc);
if (!makeCurrentResult) {
throw std::runtime_error("Unable to create initial context");
}
glewExperimental = true;
glewInit();
if (glewIsSupported("GL_VERSION_4_5")) {
_version = 0x0405;
} else if (glewIsSupported("GL_VERSION_4_3")) {
_version = 0x0403;
}
glGetError();
wglMakeCurrent(0, 0);
wglDeleteContext(glrc);
ReleaseDC(hwnd, hdc);
});
_hdc = GetDC(_hwnd);
static int pixelFormat = 0;
static PIXELFORMATDESCRIPTOR pfd;
if (!pixelFormat) {
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
std::vector<int> formatAttribs;
formatAttribs.push_back(WGL_DRAW_TO_WINDOW_ARB);
formatAttribs.push_back(GL_TRUE);
formatAttribs.push_back(WGL_SUPPORT_OPENGL_ARB);
formatAttribs.push_back(GL_TRUE);
formatAttribs.push_back(WGL_DOUBLE_BUFFER_ARB);
formatAttribs.push_back(GL_TRUE);
formatAttribs.push_back(WGL_PIXEL_TYPE_ARB);
formatAttribs.push_back(WGL_TYPE_RGBA_ARB);
formatAttribs.push_back(WGL_COLOR_BITS_ARB);
formatAttribs.push_back(32);
formatAttribs.push_back(WGL_DEPTH_BITS_ARB);
formatAttribs.push_back(24);
formatAttribs.push_back(WGL_STENCIL_BITS_ARB);
formatAttribs.push_back(8);
formatAttribs.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
formatAttribs.push_back(GL_TRUE);
// terminate the list
formatAttribs.push_back(0);
UINT numFormats;
wglChoosePixelFormatARB(_hdc, &formatAttribs[0], NULL, 1, &pixelFormat, &numFormats);
DescribePixelFormat(_hdc, pixelFormat, sizeof(pfd), &pfd);
}
SetPixelFormat(_hdc, pixelFormat, &pfd);
{
std::vector<int> contextAttribs;
uint32_t majorVersion = _version >> 8;
uint32_t minorVersion = _version & 0xFF;
contextAttribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
contextAttribs.push_back(majorVersion);
contextAttribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
contextAttribs.push_back(minorVersion);
contextAttribs.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
contextAttribs.push_back(WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
contextAttribs.push_back(WGL_CONTEXT_FLAGS_ARB);
if (enableDebugLogger) {
contextAttribs.push_back(WGL_CONTEXT_DEBUG_BIT_ARB);
} else {
contextAttribs.push_back(0);
}
contextAttribs.push_back(0);
auto shareHglrc = PRIMARY ? PRIMARY->_hglrc : 0;
_hglrc = wglCreateContextAttribsARB(_hdc, shareHglrc, &contextAttribs[0]);
}
if (_hglrc == 0) {
throw std::runtime_error("Could not create GL context");
}
if (!PRIMARY) {
PRIMARY = this;
qApp->setProperty(PRIMARY_CONTEXT_PROPERTY_NAME, QVariant::fromValue((void*)PRIMARY));
}
if (enableDebugLogger) {
makeCurrent();
glDebugMessageCallback(debugMessageCallback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
doneCurrent();
}
}
#endif
void Context::clear() {
glClearColor(0, 0, 0, 1);
QSize windowSize = _window->size() * _window->devicePixelRatio();
glViewport(0, 0, windowSize.width(), windowSize.height());
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
swapBuffers();
}
OffscreenContext::~OffscreenContext() {
_window->deleteLater();
}
void OffscreenContext::create() {
if (!_window) {
_window = new QWindow();
_window->setFlags(Qt::MSWindowsOwnDC);
_window->setSurfaceType(QSurface::OpenGLSurface);
_window->create();
setWindow(_window);
QGuiApplication::processEvents();
}
Parent::create();
}

View file

@ -0,0 +1,72 @@
//
// Created by Bradley Austin Davis on 2016/08/21
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gl_context_h
#define hifi_gl_context_h
#include <stdint.h>
#include <QtGlobal>
#if defined(Q_OS_WIN)
#include <Windows.h>
#endif
class QSurface;
class QWindow;
class QOpenGLContext;
class QThread;
namespace gl {
class Context {
protected:
QWindow* _window { nullptr };
static Context* PRIMARY;
static void destroyContext(QOpenGLContext* context);
#if defined(Q_OS_WIN)
uint32_t _version { 0x0401 };
HWND _hwnd { 0 };
HDC _hdc { 0 };
HGLRC _hglrc { 0 };
static void destroyWin32Context(HGLRC hglrc);
QOpenGLContext* _wrappedContext { nullptr };
#else
QOpenGLContext* _context { nullptr };
#endif
private:
Context(const Context& other);
public:
Context();
Context(QWindow* window);
void release();
virtual ~Context();
void clear();
void setWindow(QWindow* window);
bool makeCurrent();
static void makeCurrent(QOpenGLContext* context, QSurface* surface);
void swapBuffers();
void doneCurrent();
virtual void create();
QOpenGLContext* qglContext();
void moveToThread(QThread* thread);
};
class OffscreenContext : public Context {
using Parent = Context;
protected:
QWindow* _window { nullptr };
public:
virtual ~OffscreenContext();
virtual void create();
};
}
#endif // hifi_gpu_GPUConfig_h

View file

@ -0,0 +1,75 @@
//
// Created by Bradley Austin Davis on 2016/08/21
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Context.h"
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/QWGLNativeContext>
#endif
using namespace gl;
void Context::destroyContext(QOpenGLContext* context) {
delete context;
}
void Context::makeCurrent(QOpenGLContext* context, QSurface* surface) {
context->makeCurrent(surface);
}
QOpenGLContext* Context::qglContext() {
#ifdef Q_OS_WIN
if (!_wrappedContext) {
_wrappedContext = new QOpenGLContext();
_wrappedContext->setNativeHandle(QVariant::fromValue(QWGLNativeContext(_hglrc, _hwnd)));
_wrappedContext->create();
}
return _wrappedContext;
#else
return _context;
#endif
}
void Context::moveToThread(QThread* thread) {
qglContext()->moveToThread(thread);
}
#ifndef Q_OS_WIN
bool Context::makeCurrent() {
return _context->makeCurrent(_window);
}
void Context::swapBuffers() {
_context->swapBuffers(_window);
}
void Context::doneCurrent() {
if (_context) {
_context->doneCurrent();
}
}
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
void Context::create() {
_context = new QOpenGLContext();
if (PRIMARY) {
_context->setShareContext(PRIMARY->qglContext());
} else {
PRIMARY = this;
}
_context->setFormat(getDefaultOpenGLSurfaceFormat());
_context->create();
}
#endif

View file

@ -21,44 +21,20 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
setGLFormatVersion(format);
if (GLDebug::enabled()) {
qDebug() << "Enabling debug context";
format.setOption(QSurfaceFormat::DebugContext);
}
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
});
return format;
}
const QGLFormat& getDefaultGLFormat() {
// Specify an OpenGL 3.3 format using the Core profile.
// That is, no old-school fixed pipeline functionality
static QGLFormat glFormat;
static std::once_flag once;
std::call_once(once, [] {
setGLFormatVersion(glFormat);
glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0
glFormat.setSampleBuffers(false);
glFormat.setDepth(false);
glFormat.setStencil(false);
QGLFormat::setDefaultFormat(glFormat);
});
return glFormat;
}
int glVersionToInteger(QString glVersion) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt();
return majorNumber * 100 + minorNumber * 10;
return (majorNumber << 16) | minorNumber;
}
QJsonObject getGLContextData() {
if (!QOpenGLContext::currentContext()) {
return QJsonObject();
}
QString glVersion = QString((const char*)glGetString(GL_VERSION));
QString glslVersion = QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
QString glVendor = QString((const char*) glGetString(GL_VENDOR));
@ -77,31 +53,3 @@ QThread* RENDER_THREAD = nullptr;
bool isRenderThread() {
return QThread::currentThread() == RENDER_THREAD;
}
#ifdef DEBUG
static bool enableDebugLogger = true;
#else
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
#endif
bool GLDebug::enabled() {
return enableDebugLogger;
}
void GLDebug::log(const QOpenGLDebugMessage & debugMessage) {
qDebug() << debugMessage;
}
void GLDebug::setupLogger(QObject* window) {
if (enabled()) {
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window);
logger->initialize(); // initializes in the current context, i.e. ctx
logger->enableMessages();
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) {
GLDebug::log(debugMessage);
});
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
}
}

View file

@ -27,19 +27,9 @@ template<class F>
void setGLFormatVersion(F& format, int major = 4, int minor = 5) { format.setVersion(major, minor); }
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
const QGLFormat& getDefaultGLFormat();
QJsonObject getGLContextData();
int glVersionToInteger(QString glVersion);
bool isRenderThread();
class GLDebug {
public:
static bool enabled();
static void log(const QOpenGLDebugMessage& debugMessage);
static void setupLogger(QObject* window = nullptr);
};
#endif

View file

@ -7,30 +7,52 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtGlobal>
#include "GLWidget.h"
#include "Config.h"
#include <mutex>
#include <QtGlobal>
#include <QtCore/QMimeData>
#include <QtCore/QUrl>
#include <QtCore/QCoreApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QKeyEvent>
#include <QtGui/QPaintEngine>
#include <QtGui/QWindow>
#include "Context.h"
#include "GLHelpers.h"
class GLPaintEngine : public QPaintEngine {
bool begin(QPaintDevice *pdev) override { return true; }
bool end() override { return true; }
void updateState(const QPaintEngineState &state) override { }
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override { }
Type type() const override { return OpenGL2; }
};
GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) {
GLWidget::GLWidget() {
#ifdef Q_OS_LINUX
// Cause GLWidget::eventFilter to be called.
// It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux.
qApp->installEventFilter(this);
#endif
setAttribute(Qt::WA_AcceptTouchEvents);
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAutoFillBackground(false);
grabGesture(Qt::PinchGesture);
setAcceptDrops(true);
_paintEngine = new GLPaintEngine();
}
GLWidget::~GLWidget() {
delete _paintEngine;
_paintEngine = nullptr;
}
int GLWidget::getDeviceWidth() const {
@ -41,31 +63,25 @@ int GLWidget::getDeviceHeight() const {
return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
}
void GLWidget::initializeGL() {
setAttribute(Qt::WA_AcceptTouchEvents);
grabGesture(Qt::PinchGesture);
setAcceptDrops(true);
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
setAutoBufferSwap(false);
makeCurrent();
if (isValid() && context() && context()->contextHandle()) {
#if defined(Q_OS_WIN)
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");
#elif defined(Q_OS_MAC)
_vsyncSupported = true;
#else
// TODO: write the proper code for linux
#endif
}
void GLWidget::createContext() {
_context = new gl::Context();
_context->setWindow(windowHandle());
_context->create();
_context->clear();
_context->makeCurrent();
}
void GLWidget::paintEvent(QPaintEvent* event) {
QWidget::paintEvent(event);
bool GLWidget::makeCurrent() {
gl::Context::makeCurrent(_context->qglContext(), windowHandle());
return _context->makeCurrent();
}
void GLWidget::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
QOpenGLContext* GLWidget::qglContext() {
return _context->qglContext();
}
void GLWidget::doneCurrent() {
_context->doneCurrent();
}
bool GLWidget::event(QEvent* event) {
@ -94,10 +110,9 @@ bool GLWidget::event(QEvent* event) {
default:
break;
}
return QGLWidget::event(event);
return QWidget::event(event);
}
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
// receive keyPress events for the Alt (and Meta) key in a reliable manner.
@ -119,7 +134,7 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
} else if (event->type() == QEvent::KeyRelease) {
keyReleaseEvent(keyEvent);
} else {
QGLWidget::event(event);
QWidget::event(event);
}
return true;
}
@ -130,7 +145,22 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
return false;
}
bool GLWidget::isVsyncSupported() const {
return _vsyncSupported;
bool GLWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) {
#ifdef Q_OS_WIN32
MSG* win32message = static_cast<MSG*>(message);
switch (win32message->message) {
case WM_ERASEBKGND:
*result = 1L;
return TRUE;
default:
break;
}
#endif
return QWidget::nativeEvent(eventType, message, result);
}
QPaintEngine* GLWidget::paintEngine() const {
return _paintEngine;
}

View file

@ -10,31 +10,43 @@
#ifndef hifi_GLWidget_h
#define hifi_GLWidget_h
#include <QGLWidget>
#include <QtWidgets/QWidget>
namespace gl {
class Context;
}
class QOpenGLContext;
/// customized canvas that simply forwards requests/events to the singleton application
class GLWidget : public QGLWidget {
class GLWidget : public QWidget {
Q_OBJECT
public:
GLWidget();
~GLWidget();
int getDeviceWidth() const;
int getDeviceHeight() const;
QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); }
bool isVsyncSupported() const;
virtual void initializeGL() override;
QPaintEngine* paintEngine() const override;
void createContext();
bool makeCurrent();
void doneCurrent();
gl::Context* context() { return _context; }
QOpenGLContext* qglContext();
protected:
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
virtual bool event(QEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
gl::Context* _context { nullptr };
private slots:
virtual bool eventFilter(QObject*, QEvent* event) override;
private:
QPaintEngine* _paintEngine { nullptr };
bool _vsyncSupported { false };
};
#endif // hifi_GLCanvas_h

View file

@ -60,7 +60,6 @@ bool OffscreenGLCanvas::makeCurrent() {
qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
GLDebug::setupLogger(this);
});
return result;

View file

@ -10,27 +10,46 @@
//
#include "OpenGLVersionChecker.h"
#include <QMessageBox>
#include <QRegularExpression>
#include <QJsonObject>
#include "Config.h"
#include "GLWidget.h"
#include <mutex>
#include <QtCore/QRegularExpression>
#include <QtCore/QJsonObject>
#include <QtWidgets/QMessageBox>
#include <QtOpenGL/QGLWidget>
#include "GLHelpers.h"
#define MINIMUM_GL_VERSION 410
#define MINIMUM_GL_VERSION 0x0401
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
QApplication(argc, argv)
{
}
const QGLFormat& getDefaultGLFormat() {
// Specify an OpenGL 3.3 format using the Core profile.
// That is, no old-school fixed pipeline functionality
static QGLFormat glFormat;
static std::once_flag once;
std::call_once(once, [] {
setGLFormatVersion(glFormat);
glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0
glFormat.setSampleBuffers(false);
glFormat.setDepth(false);
glFormat.setStencil(false);
QGLFormat::setDefaultFormat(glFormat);
});
return glFormat;
}
QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
valid = true;
override = false;
GLWidget* glWidget = new GLWidget();
QGLWidget* glWidget = new QGLWidget();
valid = glWidget->isValid();
// Inform user if no OpenGL support
if (!valid) {
@ -46,7 +65,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
}
// Retrieve OpenGL version
glWidget->initializeGL();
// glWidget->initializeGL();
glWidget->makeCurrent();
QJsonObject glData = getGLContextData();
delete glWidget;
@ -60,8 +80,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt();
int minimumMajorNumber = MINIMUM_GL_VERSION / 100;
int minimumMinorNumber = (MINIMUM_GL_VERSION - minimumMajorNumber * 100) / 10;
int minimumMajorNumber = (MINIMUM_GL_VERSION >> 16);
int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF);
valid = (majorNumber > minimumMajorNumber
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));

View file

@ -100,7 +100,7 @@ float GLTexture::getMemoryPressure() {
// If no memory limit has been set, use a percentage of the total dedicated memory
if (!availableTextureMemory) {
auto totalGpuMemory = gpu::gl::getDedicatedMemory();
auto totalGpuMemory = getDedicatedMemory();
// If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB
@ -118,7 +118,7 @@ float GLTexture::getMemoryPressure() {
return (float)consumedGpuMemory / (float)availableTextureMemory;
}
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* oldTexture) :
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<GLBackend>& backend, GLTexture* oldTexture) :
_backend(backend),
_size(oldTexture ? oldTexture->_size : 0),
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
@ -161,7 +161,7 @@ GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture
// Create the texture and allocate storage
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
GLTexture(backend, texture, id, nullptr, transferrable)
{
// FIXME, do during allocation
@ -170,7 +170,7 @@ GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture&
}
// Create the texture and copy from the original higher resolution version
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
{
Q_ASSERT(_minMip >= originalTexture->_minMip);

View file

@ -58,7 +58,6 @@ public:
// If we just did a transfer, return the object after doing post-transfer work
if (GLSyncState::Transferred == object->getSyncState()) {
object->postTransfer();
return object;
}
if (object->isOutdated()) {

View file

@ -7,10 +7,8 @@
//
#include "GLTextureTransfer.h"
#ifdef THREADED_TEXTURE_TRANSFER
#include <gl/OffscreenGLCanvas.h>
#include <gl/QOpenGLContextWrapper.h>
#endif
#include <gl/GLHelpers.h>
#include <gl/Context.h>
#include "GLShared.h"
#include "GLTexture.h"
@ -20,16 +18,9 @@ using namespace gpu::gl;
GLTextureTransferHelper::GLTextureTransferHelper() {
#ifdef THREADED_TEXTURE_TRANSFER
_canvas = QSharedPointer<OffscreenGLCanvas>(new OffscreenGLCanvas(), &QObject::deleteLater);
_canvas->setObjectName("TextureTransferCanvas");
_canvas->create(QOpenGLContextWrapper::currentContext());
if (!_canvas->makeCurrent()) {
qFatal("Unable to create texture transfer context");
}
_canvas->doneCurrent();
setObjectName("TextureTransferThread");
_context.create();
initialize(true, QThread::LowPriority);
_canvas->moveToThreadWithContext(_thread);
// Clean shutdown on UNIX, otherwise _canvas is freed early
connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); });
#endif
@ -64,17 +55,9 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture
}
void GLTextureTransferHelper::setup() {
#ifdef THREADED_TEXTURE_TRANSFER
_canvas->makeCurrent();
#endif
}
void GLTextureTransferHelper::shutdown() {
#ifdef THREADED_TEXTURE_TRANSFER
_canvas->doneCurrent();
_canvas->moveToThreadWithContext(qApp->thread());
_canvas.reset();
#endif
}
void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
@ -85,6 +68,9 @@ void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
}
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
#ifdef THREADED_TEXTURE_TRANSFER
_context.makeCurrent();
#endif
for (auto package : messages) {
TexturePointer texturePointer = package.texture.lock();
// Texture no longer exists, move on to the next
@ -93,21 +79,39 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
}
if (package.fence) {
glClientWaitSync(package.fence, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
auto result = glClientWaitSync(package.fence, 0, 0);
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
// Minimum sleep
QThread::usleep(1);
result = glClientWaitSync(package.fence, 0, 0);
}
assert(GL_CONDITION_SATISFIED == result || GL_ALREADY_SIGNALED == result);
glDeleteSync(package.fence);
package.fence = 0;
}
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
do_transfer(*object);
glBindTexture(object->_target, 0);
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(writeSync);
{
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
assert(fence);
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
// Minimum sleep
QThread::usleep(1);
result = glClientWaitSync(fence, 0, 0);
}
glDeleteSync(package.fence);
}
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLSyncState::Transferred);
}
#ifdef THREADED_TEXTURE_TRANSFER
_context.doneCurrent();
#endif
return true;
}

View file

@ -13,14 +13,14 @@
#include <GenericQueueThread.h>
#include <gl/Context.h>
#include "GLShared.h"
#ifdef Q_OS_WIN
#define THREADED_TEXTURE_TRANSFER
#endif
class OffscreenGLCanvas;
namespace gpu { namespace gl {
struct TextureTransferPackage {
@ -43,7 +43,7 @@ protected:
void do_transfer(GLTexture& texturePointer);
private:
QSharedPointer<OffscreenGLCanvas> _canvas;
::gl::OffscreenContext _context;
};
} }

View file

@ -27,8 +27,10 @@
namespace gpu { namespace gl41 {
class GL41Backend : public gl::GLBackend {
using Parent = gl::GLBackend;
using namespace gpu::gl;
class GL41Backend : public GLBackend {
using Parent = GLBackend;
// Context Backend static interface required
friend class Context;
@ -36,12 +38,12 @@ public:
explicit GL41Backend(bool syncCache) : Parent(syncCache) {}
GL41Backend() : Parent() {}
class GL41Texture : public gpu::gl::GLTexture {
using Parent = gpu::gl::GLTexture;
class GL41Texture : public GLTexture {
using Parent = GLTexture;
GLuint allocate();
public:
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, bool transferrable);
GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& buffer, GL41Texture* original);
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, bool transferrable);
GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& buffer, GL41Texture* original);
protected:
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
@ -56,16 +58,16 @@ public:
protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
GLuint getBufferID(const Buffer& buffer) override;
gl::GLBuffer* syncGPUObject(const Buffer& buffer) override;
GLBuffer* syncGPUObject(const Buffer& buffer) override;
GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override;
gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
GLuint getQueryID(const QueryPointer& query) override;
gl::GLQuery* syncGPUObject(const Query& query) override;
GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage
void do_draw(const Batch& batch, size_t paramOffset) override;

View file

@ -10,7 +10,7 @@
namespace gpu {
namespace gl41 {
class GL41Buffer : public gl::GLBuffer {
class GL41Buffer : public gpu::gl::GLBuffer {
using Parent = gpu::gl::GLBuffer;
static GLuint allocate() {
GLuint result;
@ -55,6 +55,7 @@ namespace gpu {
}
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41;
@ -62,6 +63,6 @@ GLuint GL41Backend::getBufferID(const Buffer& buffer) {
return GL41Buffer::getId<GL41Buffer>(*this, buffer);
}
gl::GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
return GL41Buffer::sync<GL41Buffer>(*this, buffer);
}

View file

@ -13,10 +13,11 @@
#include "../gl/GLQuery.h"
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41;
class GL41Query : public gpu::gl::GLQuery {
using Parent = gpu::gl::GLQuery;
class GL41Query : public GLQuery {
using Parent = GLQuery;
public:
static GLuint allocateQuery() {
GLuint result;
@ -24,11 +25,11 @@ public:
return result;
}
GL41Query(const std::weak_ptr<gl::GLBackend>& backend, const Query& query)
GL41Query(const std::weak_ptr<GLBackend>& backend, const Query& query)
: Parent(backend, query, allocateQuery(), allocateQuery()) { }
};
gl::GLQuery* GL41Backend::syncGPUObject(const Query& query) {
GLQuery* GL41Backend::syncGPUObject(const Query& query) {
return GL41Query::sync<GL41Query>(*this, query);
}

View file

@ -17,9 +17,10 @@
#include "../gl/GLTexelFormat.h"
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41;
using GL41TexelFormat = gl::GLTexelFormat;
using GL41TexelFormat = GLTexelFormat;
using GL41Texture = GL41Backend::GL41Texture;
GLuint GL41Texture::allocate() {
@ -33,13 +34,13 @@ GLuint GL41Backend::getTextureID(const TexturePointer& texture, bool transfer) {
return GL41Texture::getId<GL41Texture>(*this, texture, transfer);
}
gl::GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
return GL41Texture::sync<GL41Texture>(*this, texture, transfer);
}
GL41Texture::GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable) : gl::GLTexture(backend, texture, allocate(), transferrable) {}
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(), transferrable) {}
GL41Texture::GL41Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GL41Texture* original) : gl::GLTexture(backend, texture, allocate(), original) {}
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {}
void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1;
@ -71,7 +72,7 @@ void GL41Backend::GL41Texture::generateMips() const {
}
void GL41Backend::GL41Texture::allocateStorage() const {
gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
(void)CHECK_GL_ERROR();
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
@ -131,7 +132,7 @@ void GL41Backend::GL41Texture::updateSize() const {
// Move content bits from the CPU to the GPU for a given mip / face
void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
//GLenum target = getFaceTargets()[face];
GLenum target = _target == GL_TEXTURE_2D ? GL_TEXTURE_2D : CUBE_FACE_LAYOUT[face];
auto size = _gpuObject.evalMipDimensions(mipLevel);
@ -216,7 +217,7 @@ void GL41Backend::GL41Texture::syncSampler() const {
if (sampler.doComparison()) {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, gl::COMPARISON_TO_GL[sampler.getComparisonFunction()]);
glTexParameteri(_target, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}

View file

@ -69,7 +69,9 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
#else
glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT);
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
if (!batch._objects.empty()) {
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
}
#endif
CHECK_GL_ERROR();

View file

@ -15,9 +15,11 @@
#include "../gl/GLTexture.h"
namespace gpu { namespace gl45 {
using namespace gpu::gl;
class GL45Backend : public gl::GLBackend {
using Parent = gl::GLBackend;
class GL45Backend : public GLBackend {
using Parent = GLBackend;
// Context Backend static interface required
friend class Context;
@ -25,12 +27,12 @@ public:
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
GL45Backend() : Parent() {}
class GL45Texture : public gpu::gl::GLTexture {
using Parent = gpu::gl::GLTexture;
class GL45Texture : public GLTexture {
using Parent = GLTexture;
GLuint allocate(const Texture& texture);
public:
GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable);
GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLTexture* original);
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable);
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original);
protected:
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
@ -45,16 +47,16 @@ public:
protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
GLuint getBufferID(const Buffer& buffer) override;
gl::GLBuffer* syncGPUObject(const Buffer& buffer) override;
GLBuffer* syncGPUObject(const Buffer& buffer) override;
GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override;
gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
GLuint getQueryID(const QueryPointer& query) override;
gl::GLQuery* syncGPUObject(const Query& query) override;
GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage
void do_draw(const Batch& batch, size_t paramOffset) override;

View file

@ -8,41 +8,42 @@
#include "GL45Backend.h"
#include "../gl/GLBuffer.h"
namespace gpu {
namespace gl45 {
class GL45Buffer : public gl::GLBuffer {
using Parent = gpu::gl::GLBuffer;
static GLuint allocate() {
GLuint result;
glCreateBuffers(1, &result);
return result;
}
namespace gpu { namespace gl45 {
using namespace gpu::gl;
public:
GL45Buffer(const std::weak_ptr<gl::GLBackend>& backend, const Buffer& buffer, GLBuffer* original) : Parent(backend, buffer, allocate()) {
glNamedBufferStorage(_buffer, _size == 0 ? 256 : _size, nullptr, GL_DYNAMIC_STORAGE_BIT);
if (original && original->_size) {
glCopyNamedBufferSubData(original->_buffer, _buffer, 0, 0, std::min(original->_size, _size));
}
Backend::setGPUObject(buffer, this);
}
class GL45Buffer : public GLBuffer {
using Parent = GLBuffer;
static GLuint allocate() {
GLuint result;
glCreateBuffers(1, &result);
return result;
}
void transfer() override {
Size offset;
Size size;
Size currentPage { 0 };
auto data = _gpuObject._renderSysmem.readData();
while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) {
glNamedBufferSubData(_buffer, (GLintptr)offset, (GLsizeiptr)size, data + offset);
}
(void)CHECK_GL_ERROR();
_gpuObject._renderPages._flags &= ~PageManager::DIRTY;
public:
GL45Buffer(const std::weak_ptr<GLBackend>& backend, const Buffer& buffer, GLBuffer* original) : Parent(backend, buffer, allocate()) {
glNamedBufferStorage(_buffer, _size == 0 ? 256 : _size, nullptr, GL_DYNAMIC_STORAGE_BIT);
if (original && original->_size) {
glCopyNamedBufferSubData(original->_buffer, _buffer, 0, 0, std::min(original->_size, _size));
}
};
}
}
Backend::setGPUObject(buffer, this);
}
void transfer() override {
Size offset;
Size size;
Size currentPage { 0 };
auto data = _gpuObject._renderSysmem.readData();
while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) {
glNamedBufferSubData(_buffer, (GLintptr)offset, (GLsizeiptr)size, data + offset);
}
(void)CHECK_GL_ERROR();
_gpuObject._renderPages._flags &= ~PageManager::DIRTY;
}
};
} }
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl45;
@ -50,6 +51,6 @@ GLuint GL45Backend::getBufferID(const Buffer& buffer) {
return GL45Buffer::getId<GL45Buffer>(*this, buffer);
}
gl::GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) {
GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) {
return GL45Buffer::sync<GL45Buffer>(*this, buffer);
}

View file

@ -12,14 +12,15 @@
#include <unordered_set>
#include <unordered_map>
#include <QtCore/QThread>
#include "../gl/GLTexelFormat.h"
using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl45;
using GLTexelFormat = gl::GLTexelFormat;
using GL45Texture = GL45Backend::GL45Texture;
GLuint GL45Texture::allocate(const Texture& texture) {
@ -33,15 +34,15 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
return GL45Texture::getId<GL45Texture>(*this, texture, transfer);
}
gl::GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
return GL45Texture::sync<GL45Texture>(*this, texture, transfer);
}
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable)
: gl::GLTexture(backend, texture, allocate(texture), transferrable) {}
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
: GLTexture(backend, texture, allocate(texture), transferrable) {}
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLTexture* original)
: gl::GLTexture(backend, texture, allocate(texture), original) {}
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
: GLTexture(backend, texture, allocate(texture), original) {}
void GL45Backend::GL45Texture::withPreservedTexture(std::function<void()> f) const {
f();
@ -53,7 +54,7 @@ void GL45Backend::GL45Texture::generateMips() const {
}
void GL45Backend::GL45Texture::allocateStorage() const {
gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
if (_gpuObject.getTexelFormat().isCompressed()) {
@ -79,7 +80,7 @@ void GL45Backend::GL45Texture::updateSize() const {
// Move content bits from the CPU to the GPU for a given mip / face
void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
auto size = _gpuObject.evalMipDimensions(mipLevel);
if (GL_TEXTURE_2D == _target) {
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
@ -167,7 +168,7 @@ void GL45Backend::GL45Texture::syncSampler() const {
if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, gl::COMPARISON_TO_GL[sampler.getComparisonFunction()]);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}

View file

@ -30,6 +30,7 @@ MainWindow::MainWindow(QWidget* parent) :
_windowGeometry("WindowGeometry"),
_windowState("WindowState", 0)
{
setAttribute(Qt::WA_NoSystemBackground);
setAcceptDrops(true);
}

View file

@ -12,9 +12,12 @@
#include <GLMHelpers.h>
#include <gl/Context.h>
#include <gpu/Frame.h>
#include <gpu/gl/GLBackend.h>
#include <ViewFrustum.h>
#include <PathUtils.h>
#include <shared/NsightHelpers.h>
@ -56,7 +59,7 @@ public:
using Condition = std::condition_variable;
using Lock = std::unique_lock<Mutex>;
friend class OpenVrDisplayPlugin;
std::shared_ptr<OffscreenGLCanvas> _canvas;
std::shared_ptr<gl::OffscreenContext> _canvas;
BasicFramebufferWrapperPtr _framebuffer;
ProgramPtr _program;
ShapeWrapperPtr _plane;
@ -129,7 +132,6 @@ public:
void run() override {
QThread::currentThread()->setPriority(QThread::Priority::TimeCriticalPriority);
assert(_canvas->thread() == QThread::currentThread());
_canvas->makeCurrent();
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y);
@ -206,7 +208,6 @@ public:
_program.reset();
_framebuffer.reset();
_canvas->doneCurrent();
_canvas->moveToThreadWithContext(qApp->thread());
}
void update(const CompositeInfo& newCompositeInfo) {
@ -309,14 +310,11 @@ bool OpenVrDisplayPlugin::internalActivate() {
_submitThread = std::make_shared<OpenVrSubmitThread>(*this);
if (!_submitCanvas) {
withMainThreadContext([&] {
_submitCanvas = std::make_shared<OffscreenGLCanvas>();
_submitCanvas->setObjectName("OpenVRSubmitContext");
_submitCanvas->create(_container->getPrimaryContext());
_submitCanvas = std::make_shared<gl::OffscreenContext>();
_submitCanvas->create();
_submitCanvas->doneCurrent();
});
}
_submitCanvas->moveToThreadWithContext(_submitThread.get());
assert(_submitCanvas->thread() == _submitThread.get());
#endif
return Parent::internalActivate();
@ -354,7 +352,6 @@ void OpenVrDisplayPlugin::customizeContext() {
}
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture, false);
}
assert(_submitCanvas->thread() == _submitThread.get());
_submitThread->_canvas = _submitCanvas;
_submitThread->start(QThread::HighPriority);
#endif
@ -367,7 +364,6 @@ void OpenVrDisplayPlugin::uncustomizeContext() {
_submitThread->_quit = true;
_submitThread->wait();
_submitThread.reset();
assert(_submitCanvas->thread() == qApp->thread());
#endif
}

View file

@ -18,6 +18,9 @@ const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device p
#define OPENVR_THREADED_SUBMIT 1
#if OPENVR_THREADED_SUBMIT
namespace gl {
class OffscreenContext;
}
class OpenVrSubmitThread;
class OffscreenGLCanvas;
static const size_t COMPOSITING_BUFFER_SIZE = 3;
@ -79,7 +82,7 @@ private:
CompositeInfo::Array _compositeInfos;
size_t _renderingIndex { 0 };
std::shared_ptr<OpenVrSubmitThread> _submitThread;
std::shared_ptr<OffscreenGLCanvas> _submitCanvas;
std::shared_ptr<gl::OffscreenContext> _submitCanvas;
friend class OpenVrSubmitThread;
#endif
};

View file

@ -73,7 +73,6 @@ void TestWindow::initGl() {
DependencyManager::set<DeferredLightingEffect>();
resize(QSize(800, 600));
GLDebug::setupLogger(this);
#ifdef DEFERRED_LIGHTING
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
deferredLightingEffect->init();

View file

@ -32,6 +32,9 @@ public:
DOWN,
BACK,
FORWARD,
MLEFT,
MMIDDLE,
MRIGHT,
KEYS_SIZE,
INVALID = -1,
};

View file

@ -11,6 +11,9 @@
#include <vector>
#include <sstream>
#include <gl/Config.h>
#include <gl/Context.h>
#include <QtCore/QDir>
#include <QtCore/QElapsedTimer>
#include <QtCore/QLoggingCategory>
@ -27,12 +30,13 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QApplication>
#include <shared/RateCounter.h>
#include <AssetClient.h>
#include <gl/OffscreenGLCanvas.h>
#include <gl/GLHelpers.h>
#include <gl/QOpenGLContextWrapper.h>
//#include <gl/OffscreenGLCanvas.h>
//#include <gl/GLHelpers.h>
//#include <gl/QOpenGLContextWrapper.h>
#include <gpu/gl/GLBackend.h>
#include <gpu/gl/GLFramebuffer.h>
@ -61,6 +65,7 @@
#include "Camera.hpp"
#include "TextOverlay.hpp"
static const QString LAST_SCENE_KEY = "lastSceneFile";
static const QString LAST_LOCATION_KEY = "lastLocation";
@ -94,7 +99,56 @@ public:
}
};
#if 0
class GlfwCamera : public Camera {
Key forKey(int key) {
switch (key) {
case GLFW_KEY_W: return FORWARD;
case GLFW_KEY_S: return BACK;
case GLFW_KEY_A: return LEFT;
case GLFW_KEY_D: return RIGHT;
case GLFW_KEY_E: return UP;
case GLFW_KEY_C: return DOWN;
case GLFW_MOUSE_BUTTON_LEFT: return MLEFT;
case GLFW_MOUSE_BUTTON_RIGHT: return MRIGHT;
case GLFW_MOUSE_BUTTON_MIDDLE: return MMIDDLE;
default: break;
}
return INVALID;
}
vec2 _lastMouse;
public:
void keyHandler(int key, int scancode, int action, int mods) {
Key k = forKey(key);
if (k == INVALID) {
return;
}
if (action == GLFW_PRESS) {
keys.set(k);
} else if (action == GLFW_RELEASE) {
keys.reset(k);
}
}
//static void MouseMoveHandler(GLFWwindow* window, double posx, double posy);
//static void MouseScrollHandler(GLFWwindow* window, double xoffset, double yoffset);
void onMouseMove(double posx, double posy) {
vec2 mouse = vec2(posx, posy);
vec2 delta = mouse - _lastMouse;
if (keys.at(Key::MRIGHT)) {
dolly(delta.y * 0.01f);
} else if (keys.at(Key::MLEFT)) {
rotate(delta.x * -0.01f);
} else if (keys.at(Key::MMIDDLE)) {
delta.y *= -1.0f;
translate(delta * -0.01f);
}
_lastMouse = mouse;
}
};
#else
class QWindowCamera : public Camera {
Key forKey(int key) {
switch (key) {
@ -143,6 +197,7 @@ public:
_lastMouse = mouse;
}
};
#endif
static QString toHumanSize(size_t size, size_t maxUnit = std::numeric_limits<size_t>::max()) {
static const std::vector<QString> SUFFIXES{ { "B", "KB", "MB", "GB", "TB", "PB" } };
@ -175,8 +230,7 @@ extern QThread* RENDER_THREAD;
class RenderThread : public GenericThread {
using Parent = GenericThread;
public:
QOpenGLContextWrapper* _displayContext{ nullptr };
QSurface* _displaySurface{ nullptr };
gl::Context _context;
gpu::PipelinePointer _presentPipeline;
gpu::ContextPointer _gpuContext; // initialized during window creation
std::atomic<size_t> _presentCount;
@ -198,38 +252,44 @@ public:
}
void initialize(QOpenGLContextWrapper* displayContext, QWindow* surface) {
void initialize(QWindow* window, gl::Context& initContext) {
setObjectName("RenderThread");
_displayContext = displayContext;
_displaySurface = surface;
_displayContext->makeCurrent(_displaySurface);
_context.setWindow(window);
_context.create();
_context.makeCurrent();
window->setSurfaceType(QSurface::OpenGLSurface);
_context.makeCurrent(_context.qglContext(), window);
#ifdef Q_OS_WIN
wglSwapIntervalEXT(0);
#endif
// GPU library init
gpu::Context::init<gpu::gl::GLBackend>();
_gpuContext = std::make_shared<gpu::Context>();
_backend = _gpuContext->getBackend();
_displayContext->makeCurrent(_displaySurface);
_context.makeCurrent();
DependencyManager::get<DeferredLightingEffect>()->init();
_displayContext->doneCurrent();
_context.makeCurrent();
initContext.create();
_context.doneCurrent();
std::unique_lock<std::mutex> lock(_mutex);
Parent::initialize();
if (isThreaded()) {
_displayContext->moveToThread(thread());
}
_context.moveToThread(_thread);
}
void setup() override {
RENDER_THREAD = QThread::currentThread();
QThread::currentThread()->setPriority(QThread::HighestPriority);
// Wait until the context has been moved to this thread
{
std::unique_lock<std::mutex> lock(_mutex);
}
_displayContext->makeCurrent(_displaySurface);
_context.makeCurrent();
glewExperimental = true;
glewInit();
glGetError();
_frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0);
_frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0);
{
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG));
@ -254,14 +314,11 @@ public:
}
_presentPipeline.reset();
_gpuContext.reset();
if (isThreaded()) {
_displayContext->moveToThread(qApp->thread());
}
}
void renderFrame(gpu::FramePointer& frame) {
++_presentCount;
_displayContext->makeCurrent(_displaySurface);
_context.makeCurrent();
_backend->recycle();
_backend->syncCache();
if (frame && !frame->batches.empty()) {
@ -280,7 +337,8 @@ public:
}
(void)CHECK_GL_ERROR();
}
_displayContext->swapBuffers(_displaySurface);
_context.makeCurrent();
_context.swapBuffers();
_fpsCounter.increment();
static size_t _frameCount{ 0 };
++_frameCount;
@ -290,7 +348,7 @@ public:
_elapsed.restart();
}
(void)CHECK_GL_ERROR();
_displayContext->doneCurrent();
_context.doneCurrent();
}
void report() {
@ -350,7 +408,6 @@ public:
}
};
// Background Render Data & rendering functions
class BackgroundRenderData {
public:
@ -396,7 +453,6 @@ namespace render {
// Create a simple OpenGL window that renders text in various ways
class QTestWindow : public QWindow, public AbstractViewStateInterface {
Q_OBJECT
protected:
void copyCurrentViewFrustum(ViewFrustum& viewOut) const override {
@ -476,28 +532,47 @@ public:
nodeList->setPermissions(permissions);
ResourceManager::init();
setSurfaceType(QSurface::OpenGLSurface);
auto format = getDefaultOpenGLSurfaceFormat();
format.setOption(QSurfaceFormat::DebugContext);
setFormat(format);
resize(QSize(800, 600));
setFlags(Qt::MSWindowsOwnDC);
_size = QSize(800, 600);
setGeometry(QRect(QPoint(), _size));
create();
show();
QCoreApplication::processEvents();
// Create the initial context
_renderThread.initialize(this, _initContext);
_initContext.makeCurrent();
_context.setFormat(format);
_context.create();
_context.makeCurrent(this);
glewExperimental = true;
glewInit();
glGetError();
#if 0
glfwInit();
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
resizeWindow(QSize(800, 600));
_window = glfwCreateWindow(_size.width(), _size.height(), "Window Title", NULL, NULL);
if (!_window) {
throw std::runtime_error("Could not create window");
}
glfwSetWindowUserPointer(_window, this);
glfwSetKeyCallback(_window, KeyboardHandler);
glfwSetMouseButtonCallback(_window, MouseHandler);
glfwSetCursorPosCallback(_window, MouseMoveHandler);
glfwSetWindowCloseCallback(_window, CloseHandler);
glfwSetFramebufferSizeCallback(_window, FramebufferSizeHandler);
glfwSetScrollCallback(_window, MouseScrollHandler);
glfwMakeContextCurrent(_window);
GLDebug::setupLogger(this);
#endif
#ifdef Q_OS_WIN
wglSwapIntervalEXT(0);
#endif
_context.doneCurrent();
_initContext.create(_context.getContext());
_renderThread.initialize(&_context, this);
// FIXME use a wait condition
QThread::msleep(1000);
_renderThread.submitFrame(gpu::FramePointer());
@ -627,7 +702,7 @@ private:
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
auto framebufferCache = DependencyManager::get<FramebufferCache>();
QSize windowSize = size();
QSize windowSize = _size;
framebufferCache->setFrameBufferSize(windowSize);
renderArgs._blitFramebuffer = framebufferCache->getFramebuffer();
@ -676,11 +751,11 @@ private:
};
void updateText() {
setTitle(QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4")
QString title = QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4")
.arg(_fps).arg(_cullingEnabled)
.arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2))
.arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2)));
.arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2));
setTitle(title);
#if 0
{
_textBlocks.erase(TextBlock::Info);
@ -801,12 +876,6 @@ private:
}
bool makeCurrent() {
bool currentResult = _context.makeCurrent(this);
Q_ASSERT(currentResult);
return currentResult;
}
void resizeWindow(const QSize& size) {
_size = size;
_camera.setAspectRatio((float)_size.width() / (float)_size.height());
@ -960,12 +1029,11 @@ private:
render::EnginePointer _renderEngine { new render::Engine() };
render::ScenePointer _main3DScene { new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
QOpenGLContextWrapper _context;
QSize _size;
QSettings _settings;
std::atomic<size_t> _renderCount;
OffscreenGLCanvas _initContext;
gl::OffscreenContext _initContext;
RenderThread _renderThread;
QWindowCamera _camera;
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.

View file

@ -112,8 +112,6 @@ public:
gpu::Context::init<gpu::gl::GLBackend>();
GLDebug::setupLogger(this);
qDebug() << (const char*)glGetString(GL_VERSION);
//_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);

View file

@ -108,9 +108,7 @@ public:
show();
makeCurrent();
gpu::Context::init<gpu::gl::GLBackend>();
GLDebug::setupLogger(this);
makeCurrent();
resize(QSize(800, 600));
}