Merge remote-tracking branch 'highfidelity/master' into marketplaces_html

This commit is contained in:
elisa-lj11 2016-08-30 10:45:26 -07:00
commit 37cc50a14a
45 changed files with 1110 additions and 389 deletions

View file

@ -121,9 +121,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
if (_type != NonMetaverse) { if (_type != NonMetaverse) {
// if we have a metaverse domain, we'll use an access token for API calls // if we have a metaverse domain, we'll use an access token for API calls
resetAccountManagerAccessToken(); resetAccountManagerAccessToken();
}
setupAutomaticNetworking(); setupAutomaticNetworking();
}
if (!getID().isNull() && _type != NonMetaverse) { if (!getID().isNull() && _type != NonMetaverse) {
// setup periodic heartbeats to metaverse API // setup periodic heartbeats to metaverse API

View file

@ -778,8 +778,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// enable mouse tracking; otherwise, we only get drag events // enable mouse tracking; otherwise, we only get drag events
_glWidget->setMouseTracking(true); _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->makeCurrent();
_glWidget->initializeGL();
initializeGL(); initializeGL();
// Make sure we don't time out during slow operations at startup // Make sure we don't time out during slow operations at startup
@ -1483,7 +1485,8 @@ void Application::initializeGL() {
_glWidget->makeCurrent(); _glWidget->makeCurrent();
_chromiumShareContext = new OffscreenGLCanvas(); _chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->create(_glWidget->context()->contextHandle()); _chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent(); _chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext()); qt_gl_set_global_share_context(_chromiumShareContext->getContext());
@ -1529,7 +1532,8 @@ void Application::initializeGL() {
_idleLoopStdev.reset(); _idleLoopStdev.reset();
_offscreenContext = new OffscreenGLCanvas(); _offscreenContext = new OffscreenGLCanvas();
_offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
// update before the first render // update before the first render
@ -1551,7 +1555,7 @@ void Application::initializeUi() {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->context()->contextHandle()); offscreenUi->create(_glWidget->qglContext());
auto rootContext = offscreenUi->getRootContext(); auto rootContext = offscreenUi->getRootContext();
@ -5673,7 +5677,7 @@ MainWindow* Application::getPrimaryWindow() {
} }
QOpenGLContext* Application::getPrimaryContext() { QOpenGLContext* Application::getPrimaryContext() {
return _glWidget->context()->contextHandle(); return _glWidget->qglContext();
} }
bool Application::makeRenderingContextCurrent() { bool Application::makeRenderingContextCurrent() {

View file

@ -111,7 +111,7 @@ void DiscoverabilityManager::updateLocation() {
} }
// Update Steam // Update Steam
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress()); SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingShareableAddress());
} }
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) { void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) {

View file

@ -22,7 +22,7 @@ class AddressBarDialog : public OffscreenQmlDialog {
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged) Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged) Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged) Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl) Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl NOTIFY metaverseServerUrlChanged)
public: public:
AddressBarDialog(QQuickItem* parent = nullptr); AddressBarDialog(QQuickItem* parent = nullptr);
@ -37,6 +37,7 @@ signals:
void forwardEnabledChanged(); void forwardEnabledChanged();
void useFeedChanged(); void useFeedChanged();
void receivedHifiSchemeURL(const QString& url); void receivedHifiSchemeURL(const QString& url);
void metaverseServerUrlChanged(); // While it is a constant, qml will complain about not seeing a change signal.
protected: protected:
void displayAddressOfflineMessage(); void displayAddressOfflineMessage();

View file

@ -29,6 +29,7 @@
#include <gl/GLWidget.h> #include <gl/GLWidget.h>
#include <gl/Config.h> #include <gl/Config.h>
#include <gl/GLEscrow.h> #include <gl/GLEscrow.h>
#include <gl/Context.h>
#include <gpu/Texture.h> #include <gpu/Texture.h>
#include <gpu/StandardShaderLib.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 // Move the OpenGL context to the present thread
// Extra code because of the widget 'wrapper' context // Extra code because of the widget 'wrapper' context
_context = context; _context = context;
@ -126,7 +127,6 @@ public:
OpenGLDisplayPlugin* currentPlugin{ nullptr }; OpenGLDisplayPlugin* currentPlugin{ nullptr };
Q_ASSERT(_context); Q_ASSERT(_context);
_context->makeCurrent(); _context->makeCurrent();
Q_ASSERT(isCurrentContext(_context->contextHandle()));
while (!_shutdown) { while (!_shutdown) {
if (_pendingMainThreadOperation) { if (_pendingMainThreadOperation) {
PROFILE_RANGE("MainThreadOp") PROFILE_RANGE("MainThreadOp")
@ -250,7 +250,7 @@ private:
bool _finishedMainThreadOperation { false }; bool _finishedMainThreadOperation { false };
QThread* _mainThread { nullptr }; QThread* _mainThread { nullptr };
std::queue<OpenGLDisplayPlugin*> _newPluginQueue; std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
QGLContext* _context { nullptr }; gl::Context* _context { nullptr };
}; };
bool OpenGLDisplayPlugin::activate() { bool OpenGLDisplayPlugin::activate() {
@ -649,8 +649,8 @@ float OpenGLDisplayPlugin::presentRate() const {
} }
void OpenGLDisplayPlugin::swapBuffers() { void OpenGLDisplayPlugin::swapBuffers() {
static auto widget = _container->getPrimaryWidget(); static auto context = _container->getPrimaryWidget()->context();
widget->swapBuffers(); context->swapBuffers();
} }
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const { 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.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
setGLFormatVersion(format); setGLFormatVersion(format);
if (GLDebug::enabled()) {
qDebug() << "Enabling debug context";
format.setOption(QSurfaceFormat::DebugContext);
}
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
}); });
return 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) { int glVersionToInteger(QString glVersion) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt(); int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt(); int minorNumber = versionParts[1].toInt();
return majorNumber * 100 + minorNumber * 10; return (majorNumber << 16) | minorNumber;
} }
QJsonObject getGLContextData() { QJsonObject getGLContextData() {
if (!QOpenGLContext::currentContext()) {
return QJsonObject();
}
QString glVersion = QString((const char*)glGetString(GL_VERSION)); QString glVersion = QString((const char*)glGetString(GL_VERSION));
QString glslVersion = QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); QString glslVersion = QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
QString glVendor = QString((const char*) glGetString(GL_VENDOR)); QString glVendor = QString((const char*) glGetString(GL_VENDOR));
@ -77,30 +53,3 @@ QThread* RENDER_THREAD = nullptr;
bool isRenderThread() { bool isRenderThread() {
return QThread::currentThread() == RENDER_THREAD; 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);
});
}
}

View file

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

View file

@ -7,30 +7,52 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QtGlobal>
#include "GLWidget.h" #include "GLWidget.h"
#include "Config.h"
#include <mutex> #include <mutex>
#include <QtGlobal>
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QKeyEvent> #include <QtGui/QKeyEvent>
#include <QtGui/QPaintEngine>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include "Context.h"
#include "GLHelpers.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 #ifdef Q_OS_LINUX
// Cause GLWidget::eventFilter to be called. // 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. // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux.
qApp->installEventFilter(this); qApp->installEventFilter(this);
#endif #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 { int GLWidget::getDeviceWidth() const {
@ -41,31 +63,25 @@ int GLWidget::getDeviceHeight() const {
return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f);
} }
void GLWidget::initializeGL() { void GLWidget::createContext() {
setAttribute(Qt::WA_AcceptTouchEvents); _context = new gl::Context();
grabGesture(Qt::PinchGesture); _context->setWindow(windowHandle());
setAcceptDrops(true); _context->create();
// 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. _context->clear();
setAutoBufferSwap(false); _context->makeCurrent();
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::paintEvent(QPaintEvent* event) { bool GLWidget::makeCurrent() {
QWidget::paintEvent(event); gl::Context::makeCurrent(_context->qglContext(), windowHandle());
return _context->makeCurrent();
} }
void GLWidget::resizeEvent(QResizeEvent* event) { QOpenGLContext* GLWidget::qglContext() {
QWidget::resizeEvent(event); return _context->qglContext();
}
void GLWidget::doneCurrent() {
_context->doneCurrent();
} }
bool GLWidget::event(QEvent* event) { bool GLWidget::event(QEvent* event) {
@ -94,10 +110,9 @@ bool GLWidget::event(QEvent* event) {
default: default:
break; break;
} }
return QGLWidget::event(event); return QWidget::event(event);
} }
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // 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 // SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
// receive keyPress events for the Alt (and Meta) key in a reliable manner. // 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) { } else if (event->type() == QEvent::KeyRelease) {
keyReleaseEvent(keyEvent); keyReleaseEvent(keyEvent);
} else { } else {
QGLWidget::event(event); QWidget::event(event);
} }
return true; return true;
} }
@ -130,7 +145,22 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
return false; 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 #ifndef hifi_GLWidget_h
#define 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 /// customized canvas that simply forwards requests/events to the singleton application
class GLWidget : public QGLWidget { class GLWidget : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
GLWidget(); GLWidget();
~GLWidget();
int getDeviceWidth() const; int getDeviceWidth() const;
int getDeviceHeight() const; int getDeviceHeight() const;
QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); }
bool isVsyncSupported() const; QPaintEngine* paintEngine() const override;
virtual void initializeGL() override; void createContext();
bool makeCurrent();
void doneCurrent();
gl::Context* context() { return _context; }
QOpenGLContext* qglContext();
protected: protected:
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
virtual bool event(QEvent* event) override; virtual bool event(QEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override; gl::Context* _context { nullptr };
virtual void resizeEvent(QResizeEvent* event) override;
private slots: private slots:
virtual bool eventFilter(QObject*, QEvent* event) override; virtual bool eventFilter(QObject*, QEvent* event) override;
private: private:
QPaintEngine* _paintEngine { nullptr };
bool _vsyncSupported { false }; bool _vsyncSupported { false };
}; };
#endif // hifi_GLCanvas_h #endif // hifi_GLCanvas_h

View file

@ -23,7 +23,8 @@ OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscree
} }
OffscreenGLCanvas::~OffscreenGLCanvas() { OffscreenGLCanvas::~OffscreenGLCanvas() {
_context->doneCurrent(); // A context with logging enabled needs to be current when it's destroyed
_context->makeCurrent(_offscreenSurface);
delete _context; delete _context;
_context = nullptr; _context = nullptr;
@ -59,7 +60,6 @@ bool OffscreenGLCanvas::makeCurrent() {
qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); qDebug() << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); qDebug() << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
GLDebug::setupLogger(this);
}); });
return result; return result;

View file

@ -195,6 +195,7 @@ QEvent* OffscreenQmlRenderThread::Queue::take() {
} }
OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) { OffscreenQmlRenderThread::OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) {
_canvas.setObjectName("OffscreenQmlRenderCanvas");
qDebug() << "Building QML Renderer"; qDebug() << "Building QML Renderer";
if (!_canvas.create(shareContext)) { if (!_canvas.create(shareContext)) {
qWarning("Failed to create OffscreenGLCanvas"); qWarning("Failed to create OffscreenGLCanvas");

View file

@ -10,27 +10,46 @@
// //
#include "OpenGLVersionChecker.h" #include "OpenGLVersionChecker.h"
#include <QMessageBox>
#include <QRegularExpression>
#include <QJsonObject>
#include "Config.h" #include "Config.h"
#include "GLWidget.h"
#include <mutex>
#include <QtCore/QRegularExpression>
#include <QtCore/QJsonObject>
#include <QtWidgets/QMessageBox>
#include <QtOpenGL/QGLWidget>
#include "GLHelpers.h" #include "GLHelpers.h"
#define MINIMUM_GL_VERSION 410 #define MINIMUM_GL_VERSION 0x0401
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) : OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
QApplication(argc, 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) { QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
valid = true; valid = true;
override = false; override = false;
GLWidget* glWidget = new GLWidget(); QGLWidget* glWidget = new QGLWidget();
valid = glWidget->isValid(); valid = glWidget->isValid();
// Inform user if no OpenGL support // Inform user if no OpenGL support
if (!valid) { if (!valid) {
@ -46,7 +65,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
} }
// Retrieve OpenGL version // Retrieve OpenGL version
glWidget->initializeGL(); // glWidget->initializeGL();
glWidget->makeCurrent();
QJsonObject glData = getGLContextData(); QJsonObject glData = getGLContextData();
delete glWidget; delete glWidget;
@ -60,8 +80,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt(); int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt(); int minorNumber = versionParts[1].toInt();
int minimumMajorNumber = MINIMUM_GL_VERSION / 100; int minimumMajorNumber = (MINIMUM_GL_VERSION >> 16);
int minimumMinorNumber = (MINIMUM_GL_VERSION - minimumMajorNumber * 100) / 10; int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF);
valid = (majorNumber > minimumMajorNumber valid = (majorNumber > minimumMajorNumber
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber)); || (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));

View file

@ -582,7 +582,7 @@ void GLBackend::releaseShader(GLuint id) const {
void GLBackend::releaseProgram(GLuint id) const { void GLBackend::releaseProgram(GLuint id) const {
Lock lock(_trashMutex); Lock lock(_trashMutex);
_shadersTrash.push_back(id); _programsTrash.push_back(id);
} }
void GLBackend::releaseQuery(GLuint id) const { void GLBackend::releaseQuery(GLuint id) const {

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 no memory limit has been set, use a percentage of the total dedicated memory
if (!availableTextureMemory) { 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, // If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB // just use a fallback fixed value of 256 MB
@ -118,7 +118,7 @@ float GLTexture::getMemoryPressure() {
return (float)consumedGpuMemory / (float)availableTextureMemory; 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), _backend(backend),
_size(oldTexture ? oldTexture->_size : 0), _size(oldTexture ? oldTexture->_size : 0),
_texture(oldTexture ? oldTexture->takeOwnership() : 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 // 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) GLTexture(backend, texture, id, nullptr, transferrable)
{ {
// FIXME, do during allocation // 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 // 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) GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
{ {
Q_ASSERT(_minMip >= originalTexture->_minMip); Q_ASSERT(_minMip >= originalTexture->_minMip);
@ -243,15 +243,8 @@ bool GLTexture::isReady() const {
return false; return false;
} }
// If we're out of date, but the transfer is in progress, report ready
// as a special case
auto syncState = _syncState.load(); auto syncState = _syncState.load();
if (isOutdated() || Idle != syncState) {
if (isOutdated()) {
return Idle != syncState;
}
if (Idle != syncState) {
return false; return false;
} }

View file

@ -21,6 +21,9 @@ struct GLFilterMode {
class GLTexture : public GLObject<Texture> { class GLTexture : public GLObject<Texture> {
public: public:
static const uint16_t INVALID_MIP { (uint16_t)-1 };
static const uint8_t INVALID_FACE { (uint8_t)-1 };
static void initTextureTransferHelper(); static void initTextureTransferHelper();
static std::shared_ptr<GLTextureTransferHelper> _textureTransferHelper; static std::shared_ptr<GLTextureTransferHelper> _textureTransferHelper;
@ -55,21 +58,26 @@ public:
// If we just did a transfer, return the object after doing post-transfer work // If we just did a transfer, return the object after doing post-transfer work
if (GLSyncState::Transferred == object->getSyncState()) { if (GLSyncState::Transferred == object->getSyncState()) {
object->postTransfer(); object->postTransfer();
return object;
} }
if (object->isReady()) { if (object->isOutdated()) {
// Do we need to reduce texture memory usage?
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
// WARNING, this code path will essentially `delete this`,
// so no dereferencing of this instance should be done past this point
object = new GLTextureType(backend.shared_from_this(), texture, object);
_textureTransferHelper->transferTexture(texturePointer);
}
} else if (object->isOutdated()) {
// Object might be outdated, if so, start the transfer // Object might be outdated, if so, start the transfer
// (outdated objects that are already in transfer will have reported 'true' for ready() // (outdated objects that are already in transfer will have reported 'true' for ready()
_textureTransferHelper->transferTexture(texturePointer); _textureTransferHelper->transferTexture(texturePointer);
return nullptr;
}
if (!object->isReady()) {
return nullptr;
}
// Do we need to reduce texture memory usage?
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
// WARNING, this code path will essentially `delete this`,
// so no dereferencing of this instance should be done past this point
object = new GLTextureType(backend.shared_from_this(), texture, object);
_textureTransferHelper->transferTexture(texturePointer);
return nullptr;
} }
return object; return object;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,9 +17,10 @@
#include "../gl/GLTexelFormat.h" #include "../gl/GLTexelFormat.h"
using namespace gpu; using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl41; using namespace gpu::gl41;
using GL41TexelFormat = gl::GLTexelFormat; using GL41TexelFormat = GLTexelFormat;
using GL41Texture = GL41Backend::GL41Texture; using GL41Texture = GL41Backend::GL41Texture;
GLuint GL41Texture::allocate() { GLuint GL41Texture::allocate() {
@ -33,13 +34,13 @@ GLuint GL41Backend::getTextureID(const TexturePointer& texture, bool transfer) {
return GL41Texture::getId<GL41Texture>(*this, texture, 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); 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 { void GL41Backend::GL41Texture::withPreservedTexture(std::function<void()> f) const {
GLint boundTex = -1; GLint boundTex = -1;
@ -71,7 +72,7 @@ void GL41Backend::GL41Texture::generateMips() const {
} }
void GL41Backend::GL41Texture::allocateStorage() 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); glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); 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 // 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 { void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); 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 = getFaceTargets()[face];
GLenum target = _target == GL_TEXTURE_2D ? GL_TEXTURE_2D : CUBE_FACE_LAYOUT[face]; GLenum target = _target == GL_TEXTURE_2D ? GL_TEXTURE_2D : CUBE_FACE_LAYOUT[face];
auto size = _gpuObject.evalMipDimensions(mipLevel); auto size = _gpuObject.evalMipDimensions(mipLevel);
@ -216,7 +217,7 @@ void GL41Backend::GL41Texture::syncSampler() const {
if (sampler.doComparison()) { if (sampler.doComparison()) {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); 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 { } else {
glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
} }

View file

@ -69,7 +69,9 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
#else #else
glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT); glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT);
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); 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 #endif
CHECK_GL_ERROR(); CHECK_GL_ERROR();

View file

@ -16,8 +16,10 @@
namespace gpu { namespace gl45 { namespace gpu { namespace gl45 {
class GL45Backend : public gl::GLBackend { using namespace gpu::gl;
using Parent = gl::GLBackend;
class GL45Backend : public GLBackend {
using Parent = GLBackend;
// Context Backend static interface required // Context Backend static interface required
friend class Context; friend class Context;
@ -25,12 +27,12 @@ public:
explicit GL45Backend(bool syncCache) : Parent(syncCache) {} explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
GL45Backend() : Parent() {} GL45Backend() : Parent() {}
class GL45Texture : public gpu::gl::GLTexture { class GL45Texture : public GLTexture {
using Parent = gpu::gl::GLTexture; using Parent = GLTexture;
GLuint allocate(const Texture& texture); GLuint allocate(const Texture& texture);
public: public:
GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable); GL45Texture(const std::weak_ptr<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, GLTexture* original);
protected: protected:
void transferMip(uint16_t mipLevel, uint8_t face = 0) const; void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
@ -45,16 +47,16 @@ public:
protected: protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; 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; 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; 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; GLuint getQueryID(const QueryPointer& query) override;
gl::GLQuery* syncGPUObject(const Query& query) override; GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage // Draw Stage
void do_draw(const Batch& batch, size_t paramOffset) override; void do_draw(const Batch& batch, size_t paramOffset) override;

View file

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

View file

@ -12,14 +12,15 @@
#include <unordered_set> #include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <QtCore/QThread> #include <QtCore/QThread>
#include "../gl/GLTexelFormat.h" #include "../gl/GLTexelFormat.h"
using namespace gpu; using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl45; using namespace gpu::gl45;
using GLTexelFormat = gl::GLTexelFormat;
using GL45Texture = GL45Backend::GL45Texture; using GL45Texture = GL45Backend::GL45Texture;
GLuint GL45Texture::allocate(const Texture& texture) { 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); 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); return GL45Texture::sync<GL45Texture>(*this, texture, transfer);
} }
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, bool transferrable) GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
: gl::GLTexture(backend, texture, allocate(texture), transferrable) {} : GLTexture(backend, texture, allocate(texture), transferrable) {}
GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLTexture* original) GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLTexture* original)
: gl::GLTexture(backend, texture, allocate(texture), original) {} : GLTexture(backend, texture, allocate(texture), original) {}
void GL45Backend::GL45Texture::withPreservedTexture(std::function<void()> f) const { void GL45Backend::GL45Texture::withPreservedTexture(std::function<void()> f) const {
f(); f();
@ -53,7 +54,7 @@ void GL45Backend::GL45Texture::generateMips() const {
} }
void GL45Backend::GL45Texture::allocateStorage() 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_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
if (_gpuObject.getTexelFormat().isCompressed()) { 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 // 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 { void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); 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); auto size = _gpuObject.evalMipDimensions(mipLevel);
if (GL_TEXTURE_2D == _target) { if (GL_TEXTURE_2D == _target) {
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); 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()) { if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); 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 { } else {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
} }

View file

@ -38,7 +38,7 @@ void GL45Backend::transferTransformState(const Batch& batch) const {
} }
if (!batch._objects.empty()) { if (!batch._objects.empty()) {
glNamedBufferData(_transform._objectBuffer, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_DYNAMIC_DRAW); glNamedBufferData(_transform._objectBuffer, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_STREAM_DRAW);
} }
if (!batch._namedData.empty()) { if (!batch._namedData.empty()) {

View file

@ -26,10 +26,12 @@ Skybox::Skybox() {
} }
void Skybox::setColor(const Color& color) { void Skybox::setColor(const Color& color) {
_empty = false;
_schemaBuffer.edit<Schema>().color = color; _schemaBuffer.edit<Schema>().color = color;
} }
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
_empty = false;
_cubemap = cubemap; _cubemap = cubemap;
} }
@ -50,6 +52,7 @@ void Skybox::updateSchemaBuffer() const {
} }
void Skybox::clear() { void Skybox::clear() {
_empty = true;
_schemaBuffer.edit<Schema>().color = vec3(0); _schemaBuffer.edit<Schema>().color = vec3(0);
setCubemap(nullptr); setCubemap(nullptr);
} }

View file

@ -35,7 +35,7 @@ public:
void setCubemap(const gpu::TexturePointer& cubemap); void setCubemap(const gpu::TexturePointer& cubemap);
const gpu::TexturePointer& getCubemap() const { return _cubemap; } const gpu::TexturePointer& getCubemap() const { return _cubemap; }
virtual bool empty() { return _schemaBuffer.get<Schema>().color == vec3(0) && !_cubemap; } virtual bool empty() { return _empty; }
virtual void clear(); virtual void clear();
void prepare(gpu::Batch& batch, int textureSlot = SKYBOX_SKYMAP_SLOT, int bufferSlot = SKYBOX_CONSTANTS_SLOT) const; void prepare(gpu::Batch& batch, int textureSlot = SKYBOX_SKYMAP_SLOT, int bufferSlot = SKYBOX_CONSTANTS_SLOT) const;
@ -47,17 +47,17 @@ protected:
static const int SKYBOX_SKYMAP_SLOT { 0 }; static const int SKYBOX_SKYMAP_SLOT { 0 };
static const int SKYBOX_CONSTANTS_SLOT { 0 }; static const int SKYBOX_CONSTANTS_SLOT { 0 };
gpu::TexturePointer _cubemap;
class Schema { class Schema {
public: public:
glm::vec3 color { 0.0f, 0.0f, 0.0f }; glm::vec3 color { 0.0f, 0.0f, 0.0f };
float blend { 0.0f }; float blend { 0.0f };
}; };
mutable gpu::BufferView _schemaBuffer;
void updateSchemaBuffer() const; void updateSchemaBuffer() const;
mutable gpu::BufferView _schemaBuffer;
gpu::TexturePointer _cubemap;
bool _empty{ true };
}; };
typedef std::shared_ptr<Skybox> SkyboxPointer; typedef std::shared_ptr<Skybox> SkyboxPointer;

View file

@ -63,15 +63,31 @@ QUrl AddressManager::currentAddress() const {
} }
QUrl AddressManager::currentFacingAddress() const { QUrl AddressManager::currentFacingAddress() const {
QUrl hifiURL; auto hifiURL = currentAddress();
hifiURL.setPath(currentFacingPath());
hifiURL.setScheme(HIFI_URL_SCHEME); return hifiURL;
hifiURL.setHost(_host); }
if (_port != 0 && _port != DEFAULT_DOMAIN_SERVER_PORT) {
hifiURL.setPort(_port); QUrl AddressManager::currentShareableAddress() const {
if (!_shareablePlaceName.isEmpty()) {
// if we have a shareable place name use that instead of whatever the current host is
QUrl hifiURL;
hifiURL.setScheme(HIFI_URL_SCHEME);
hifiURL.setHost(_shareablePlaceName);
hifiURL.setPath(currentPath());
return hifiURL;
} else {
return currentAddress();
} }
}
QUrl AddressManager::currentFacingShareableAddress() const {
auto hifiURL = currentShareableAddress();
hifiURL.setPath(currentFacingPath()); hifiURL.setPath(currentFacingPath());
return hifiURL; return hifiURL;
@ -360,6 +376,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
LookupTrigger trigger = (LookupTrigger) reply.property(LOOKUP_TRIGGER_KEY).toInt(); LookupTrigger trigger = (LookupTrigger) reply.property(LOOKUP_TRIGGER_KEY).toInt();
// set our current root place id to the ID that came back // set our current root place id to the ID that came back
const QString PLACE_ID_KEY = "id"; const QString PLACE_ID_KEY = "id";
_rootPlaceID = rootMap[PLACE_ID_KEY].toUuid(); _rootPlaceID = rootMap[PLACE_ID_KEY].toUuid();
@ -368,6 +385,18 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
const QString PLACE_NAME_KEY = "name"; const QString PLACE_NAME_KEY = "name";
QString placeName = rootMap[PLACE_NAME_KEY].toString(); QString placeName = rootMap[PLACE_NAME_KEY].toString();
if (placeName.isEmpty()) {
// we didn't get a set place name, check if there is a default or temporary domain name to use
const QString TEMPORARY_DOMAIN_NAME_KEY = "name";
const QString DEFAULT_DOMAIN_NAME_KEY = "default_place_name";
if (domainObject.contains(TEMPORARY_DOMAIN_NAME_KEY)) {
placeName = domainObject[TEMPORARY_DOMAIN_NAME_KEY].toString();
} else if (domainObject.contains(DEFAULT_DOMAIN_NAME_KEY)) {
placeName = domainObject[DEFAULT_DOMAIN_NAME_KEY].toString();
}
}
if (!placeName.isEmpty()) { if (!placeName.isEmpty()) {
if (setHost(placeName, trigger)) { if (setHost(placeName, trigger)) {
trigger = LookupTrigger::Internal; trigger = LookupTrigger::Internal;
@ -651,6 +680,9 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
_port = port; _port = port;
// any host change should clear the shareable place name
_shareablePlaceName.clear();
if (host != _host) { if (host != _host) {
_host = host; _host = host;
emit hostChanged(_host); emit hostChanged(_host);
@ -701,13 +733,67 @@ void AddressManager::refreshPreviousLookup() {
} }
void AddressManager::copyAddress() { void AddressManager::copyAddress() {
QApplication::clipboard()->setText(currentAddress().toString()); // assume that the address is being copied because the user wants a shareable address
QApplication::clipboard()->setText(currentShareableAddress().toString());
} }
void AddressManager::copyPath() { void AddressManager::copyPath() {
QApplication::clipboard()->setText(currentPath()); QApplication::clipboard()->setText(currentPath());
} }
void AddressManager::handleShareableNameAPIResponse(QNetworkReply& requestReply) {
// make sure that this response is for the domain we're currently connected to
auto domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
if (requestReply.url().toString().contains(uuidStringWithoutCurlyBraces(domainID))) {
// check for a name or default name in the API response
QJsonObject responseObject = QJsonDocument::fromJson(requestReply.readAll()).object();
QJsonObject domainObject = responseObject["domain"].toObject();
const QString DOMAIN_NAME_KEY = "name";
const QString DOMAIN_DEFAULT_PLACE_NAME_KEY = "default_place_name";
bool shareableNameChanged { false };
if (domainObject[DOMAIN_NAME_KEY].isString()) {
_shareablePlaceName = domainObject[DOMAIN_NAME_KEY].toString();
shareableNameChanged = true;
} else if (domainObject[DOMAIN_DEFAULT_PLACE_NAME_KEY].isString()) {
_shareablePlaceName = domainObject[DOMAIN_DEFAULT_PLACE_NAME_KEY].toString();
shareableNameChanged = true;
}
if (shareableNameChanged) {
qDebug() << "AddressManager shareable name changed to" << _shareablePlaceName;
}
}
}
void AddressManager::lookupShareableNameForDomainID(const QUuid& domainID) {
// if we get to a domain via IP/hostname, often the address is only reachable by this client
// and not by other clients on the LAN or Internet
// to work around this we use the ID to lookup the default place name, and if it exists we
// then use that for Steam join/invite or copiable address
// it only makes sense to lookup a shareable default name if we don't have a place name
if (_placeName.isEmpty()) {
JSONCallbackParameters callbackParams;
// no error callback handling
// in the case of an error we simply assume there is no default place name
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleShareableNameAPIResponse";
DependencyManager::get<AccountManager>()->sendRequest(GET_DOMAIN_ID.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation,
callbackParams);
}
}
void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) { void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
// if we're cold starting and this is called for the first address (from settings) we don't do anything // if we're cold starting and this is called for the first address (from settings) we don't do anything

View file

@ -60,6 +60,8 @@ public:
QUrl currentAddress() const; QUrl currentAddress() const;
QUrl currentFacingAddress() const; QUrl currentFacingAddress() const;
QUrl currentShareableAddress() const;
QUrl currentFacingShareableAddress() const;
QString currentPath(bool withOrientation = true) const; QString currentPath(bool withOrientation = true) const;
QString currentFacingPath() const; QString currentFacingPath() const;
@ -102,6 +104,8 @@ public slots:
void copyAddress(); void copyAddress();
void copyPath(); void copyPath();
void lookupShareableNameForDomainID(const QUuid& domainID);
signals: signals:
void lookupResultsFinished(); void lookupResultsFinished();
void lookupResultIsOffline(); void lookupResultIsOffline();
@ -125,6 +129,8 @@ private slots:
void handleAPIResponse(QNetworkReply& requestReply); void handleAPIResponse(QNetworkReply& requestReply);
void handleAPIError(QNetworkReply& errorReply); void handleAPIError(QNetworkReply& errorReply);
void handleShareableNameAPIResponse(QNetworkReply& requestReply);
private: private:
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply); void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
@ -155,6 +161,8 @@ private:
PositionGetter _positionGetter; PositionGetter _positionGetter;
OrientationGetter _orientationGetter; OrientationGetter _orientationGetter;
QString _shareablePlaceName;
QStack<QUrl> _backStack; QStack<QUrl> _backStack;
QStack<QUrl> _forwardStack; QStack<QUrl> _forwardStack;
quint64 _lastBackPush = 0; quint64 _lastBackPush = 0;

View file

@ -539,6 +539,10 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
if (!_domainHandler.isConnected()) { if (!_domainHandler.isConnected()) {
_domainHandler.setUUID(domainUUID); _domainHandler.setUUID(domainUUID);
_domainHandler.setIsConnected(true); _domainHandler.setIsConnected(true);
// in case we didn't use a place name to get to this domain,
// give the address manager a chance to lookup a default one now
DependencyManager::get<AddressManager>()->lookupShareableNameForDomainID(domainUUID);
} else if (_domainHandler.getUUID() != domainUUID) { } else if (_domainHandler.getUUID() != domainUUID) {
// Recieved packet from different domain. // Recieved packet from different domain.
qWarning() << "IGNORING DomainList packet from" << domainUUID << "while connected to" << _domainHandler.getUUID(); qWarning() << "IGNORING DomainList packet from" << domainUUID << "while connected to" << _domainHandler.getUUID();

View file

@ -81,28 +81,43 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
direction.setProperty("z", event._direction.z); direction.setProperty("z", event._direction.z);
obj.setProperty("pos3D", direction); obj.setProperty("pos3D", direction);
bool isPrimaryButton = false;
bool isSecondaryButton = false;
bool isTertiaryButton = false;
switch (event._button) { switch (event._button) {
case NoButtons: case NoButtons:
obj.setProperty("button", "None"); obj.setProperty("button", "None");
break; break;
case PrimaryButton: case PrimaryButton:
obj.setProperty("button", "Primary"); obj.setProperty("button", "Primary");
isPrimaryButton = true;
break; break;
case SecondaryButton: case SecondaryButton:
obj.setProperty("button", "Secondary"); obj.setProperty("button", "Secondary");
isSecondaryButton = true;
break; break;
case TertiaryButton: case TertiaryButton:
obj.setProperty("button", "Tertiary"); obj.setProperty("button", "Tertiary");
isTertiaryButton = true;
break; break;
} }
obj.setProperty("isLeftButton", areFlagsSet(event._buttons, PrimaryButton)); if (isPrimaryButton) {
obj.setProperty("isRightButton", areFlagsSet(event._buttons, SecondaryButton)); obj.setProperty("isPrimaryButton", isPrimaryButton);
obj.setProperty("isMiddleButton", areFlagsSet(event._buttons, TertiaryButton)); obj.setProperty("isLeftButton", isPrimaryButton);
}
if (isSecondaryButton) {
obj.setProperty("isSecondaryButton", isSecondaryButton);
obj.setProperty("isRightButton", isSecondaryButton);
}
if (isTertiaryButton) {
obj.setProperty("isTertiaryButton", isTertiaryButton);
obj.setProperty("isMiddleButton", isTertiaryButton);
}
obj.setProperty("isPrimaryButton", areFlagsSet(event._buttons, PrimaryButton)); obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton));
obj.setProperty("isSecondaryButton", areFlagsSet(event._buttons, SecondaryButton)); obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isTertiaryButton", areFlagsSet(event._buttons, TertiaryButton)); obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton));
return obj; return obj;
} }
@ -146,9 +161,9 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
event._button = NoButtons; event._button = NoButtons;
} }
bool primary = object.property("isPrimary").toBool() || object.property("isLeftButton").toBool(); bool primary = object.property("isPrimaryHeld").toBool();
bool secondary = object.property("isSecondary").toBool() || object.property("isRightButton").toBool(); bool secondary = object.property("isSecondaryHeld").toBool();
bool tertiary = object.property("isTertiary").toBool() || object.property("isMiddleButton").toBool(); bool tertiary = object.property("isTertiaryHeld").toBool();
event._buttons = 0; event._buttons = 0;
if (primary) { if (primary) {
event._buttons |= PrimaryButton; event._buttons |= PrimaryButton;

View file

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

View file

@ -12,9 +12,12 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <gl/Context.h>
#include <gpu/Frame.h> #include <gpu/Frame.h>
#include <gpu/gl/GLBackend.h> #include <gpu/gl/GLBackend.h>
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <shared/NsightHelpers.h> #include <shared/NsightHelpers.h>
@ -56,7 +59,7 @@ public:
using Condition = std::condition_variable; using Condition = std::condition_variable;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
friend class OpenVrDisplayPlugin; friend class OpenVrDisplayPlugin;
OffscreenGLCanvas _canvas; std::shared_ptr<gl::OffscreenContext> _canvas;
BasicFramebufferWrapperPtr _framebuffer; BasicFramebufferWrapperPtr _framebuffer;
ProgramPtr _program; ProgramPtr _program;
ShapeWrapperPtr _plane; ShapeWrapperPtr _plane;
@ -68,9 +71,7 @@ public:
OpenVrSubmitThread(OpenVrDisplayPlugin& plugin) : _plugin(plugin) { OpenVrSubmitThread(OpenVrDisplayPlugin& plugin) : _plugin(plugin) {
_canvas.create(plugin._container->getPrimaryContext()); setObjectName("OpenVR Submit Thread");
_canvas.doneCurrent();
_canvas.moveToThreadWithContext(this);
} }
void updateReprojectionProgram() { void updateReprojectionProgram() {
@ -131,19 +132,19 @@ public:
void run() override { void run() override {
QThread::currentThread()->setPriority(QThread::Priority::TimeCriticalPriority); QThread::currentThread()->setPriority(QThread::Priority::TimeCriticalPriority);
_canvas.makeCurrent(); _canvas->makeCurrent();
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glViewport(0, 0, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y); glViewport(0, 0, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y);
_framebuffer = std::make_shared<BasicFramebufferWrapper>(); _framebuffer = std::make_shared<BasicFramebufferWrapper>();
_framebuffer->Init(_plugin._renderTargetSize); _framebuffer->Init(_plugin._renderTargetSize);
updateReprojectionProgram(); updateReprojectionProgram();
_plane = loadPlane(_program); _plane = loadPlane(_program);
_canvas.doneCurrent(); _canvas->doneCurrent();
while (!_quit) { while (!_quit) {
_canvas.makeCurrent(); _canvas->makeCurrent();
updateSource(); updateSource();
if (!_current.texture) { if (!_current.texture) {
_canvas.doneCurrent(); _canvas->doneCurrent();
QThread::usleep(1); QThread::usleep(1);
continue; continue;
} }
@ -199,15 +200,14 @@ public:
_presented.notify_one(); _presented.notify_one();
}); });
} }
_canvas.doneCurrent(); _canvas->doneCurrent();
} }
_canvas.makeCurrent(); _canvas->makeCurrent();
_plane.reset(); _plane.reset();
_program.reset(); _program.reset();
_framebuffer.reset(); _framebuffer.reset();
_canvas.doneCurrent(); _canvas->doneCurrent();
} }
void update(const CompositeInfo& newCompositeInfo) { void update(const CompositeInfo& newCompositeInfo) {
@ -307,10 +307,14 @@ bool OpenVrDisplayPlugin::internalActivate() {
} }
#if OPENVR_THREADED_SUBMIT #if OPENVR_THREADED_SUBMIT
withMainThreadContext([&] { _submitThread = std::make_shared<OpenVrSubmitThread>(*this);
_submitThread = std::make_shared<OpenVrSubmitThread>(*this); if (!_submitCanvas) {
}); withMainThreadContext([&] {
_submitThread->setObjectName("OpenVR Submit Thread"); _submitCanvas = std::make_shared<gl::OffscreenContext>();
_submitCanvas->create();
_submitCanvas->doneCurrent();
});
}
#endif #endif
return Parent::internalActivate(); return Parent::internalActivate();
@ -348,6 +352,7 @@ void OpenVrDisplayPlugin::customizeContext() {
} }
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture, false); _compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture, false);
} }
_submitThread->_canvas = _submitCanvas;
_submitThread->start(QThread::HighPriority); _submitThread->start(QThread::HighPriority);
#endif #endif
} }
@ -358,6 +363,7 @@ void OpenVrDisplayPlugin::uncustomizeContext() {
#if OPENVR_THREADED_SUBMIT #if OPENVR_THREADED_SUBMIT
_submitThread->_quit = true; _submitThread->_quit = true;
_submitThread->wait(); _submitThread->wait();
_submitThread.reset();
#endif #endif
} }

View file

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

View file

@ -1426,10 +1426,7 @@ function MyController(hand) {
pos3D: rayPickInfo.intersection, pos3D: rayPickInfo.intersection,
normal: rayPickInfo.normal, normal: rayPickInfo.normal,
direction: rayPickInfo.searchRay.direction, direction: rayPickInfo.searchRay.direction,
button: "None", button: "None"
isPrimaryButton: false,
isSecondaryButton: false,
isTertiaryButton: false
}; };
this.hoverEntity = entity; this.hoverEntity = entity;
@ -1449,10 +1446,7 @@ function MyController(hand) {
pos3D: rayPickInfo.intersection, pos3D: rayPickInfo.intersection,
normal: rayPickInfo.normal, normal: rayPickInfo.normal,
direction: rayPickInfo.searchRay.direction, direction: rayPickInfo.searchRay.direction,
button: "None", button: "None"
isPrimaryButton: false,
isSecondaryButton: false,
isTertiaryButton: false
}; };
Entities.sendMouseMoveOnEntity(entity, pointerEvent); Entities.sendMouseMoveOnEntity(entity, pointerEvent);
@ -2124,9 +2118,7 @@ function MyController(hand) {
normal: intersectInfo.normal, normal: intersectInfo.normal,
direction: intersectInfo.searchRay.direction, direction: intersectInfo.searchRay.direction,
button: "Primary", button: "Primary",
isPrimaryButton: true, isPrimaryHeld: true
isSecondaryButton: false,
isTertiaryButton: false
}; };
Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent); Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent);
@ -2152,15 +2144,12 @@ function MyController(hand) {
pos3D: intersectInfo.point, pos3D: intersectInfo.point,
normal: intersectInfo.normal, normal: intersectInfo.normal,
direction: intersectInfo.searchRay.direction, direction: intersectInfo.searchRay.direction,
button: "Primary", button: "Primary"
isPrimaryButton: false,
isSecondaryButton: false,
isTertiaryButton: false
}; };
} else { } else {
pointerEvent = this.touchingEnterPointerEvent; pointerEvent = this.touchingEnterPointerEvent;
pointerEvent.button = "Primary"; pointerEvent.button = "Primary";
pointerEvent.isPrimaryButton = false; pointerEvent.isPrimaryHeld = false;
} }
Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent); Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent);
@ -2197,9 +2186,7 @@ function MyController(hand) {
normal: intersectInfo.normal, normal: intersectInfo.normal,
direction: intersectInfo.searchRay.direction, direction: intersectInfo.searchRay.direction,
button: "NoButtons", button: "NoButtons",
isPrimaryButton: true, isPrimaryHeld: true
isSecondaryButton: false,
isTertiaryButton: false
}; };
var POINTER_PRESS_TO_MOVE_DELAY = 0.15; // seconds var POINTER_PRESS_TO_MOVE_DELAY = 0.15; // seconds

View file

@ -803,7 +803,7 @@ function setupModelMenus() {
menuName: "Edit", menuName: "Edit",
menuItemName: "Delete", menuItemName: "Delete",
shortcutKeyEvent: { shortcutKeyEvent: {
text: "backspace" text: "delete"
}, },
afterItem: "Entities", afterItem: "Entities",
grouping: "Advanced" grouping: "Advanced"
@ -1215,7 +1215,7 @@ Controller.keyReleaseEvent.connect(function (event) {
cameraManager.keyReleaseEvent(event); cameraManager.keyReleaseEvent(event);
} }
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
if (event.text === "BACKSPACE" || event.text === "DELETE") { if (event.text === "DELETE") {
deleteSelectedEntities(); deleteSelectedEntities();
} else if (event.text === "ESC") { } else if (event.text === "ESC") {
selectionManager.clearSelections(); selectionManager.clearSelections();

View file

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

View file

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

View file

@ -11,6 +11,9 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <gl/Config.h>
#include <gl/Context.h>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QElapsedTimer> #include <QtCore/QElapsedTimer>
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
@ -27,12 +30,13 @@
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <AssetClient.h> #include <AssetClient.h>
#include <gl/OffscreenGLCanvas.h> //#include <gl/OffscreenGLCanvas.h>
#include <gl/GLHelpers.h> //#include <gl/GLHelpers.h>
#include <gl/QOpenGLContextWrapper.h> //#include <gl/QOpenGLContextWrapper.h>
#include <gpu/gl/GLBackend.h> #include <gpu/gl/GLBackend.h>
#include <gpu/gl/GLFramebuffer.h> #include <gpu/gl/GLFramebuffer.h>
@ -61,6 +65,7 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "TextOverlay.hpp" #include "TextOverlay.hpp"
static const QString LAST_SCENE_KEY = "lastSceneFile"; static const QString LAST_SCENE_KEY = "lastSceneFile";
static const QString LAST_LOCATION_KEY = "lastLocation"; 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 { class QWindowCamera : public Camera {
Key forKey(int key) { Key forKey(int key) {
switch (key) { switch (key) {
@ -143,6 +197,7 @@ public:
_lastMouse = mouse; _lastMouse = mouse;
} }
}; };
#endif
static QString toHumanSize(size_t size, size_t maxUnit = std::numeric_limits<size_t>::max()) { 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" } }; static const std::vector<QString> SUFFIXES{ { "B", "KB", "MB", "GB", "TB", "PB" } };
@ -172,11 +227,10 @@ void main(void) {
extern QThread* RENDER_THREAD; extern QThread* RENDER_THREAD;
class RenderThread : public GenericQueueThread<gpu::FramePointer> { class RenderThread : public GenericThread {
using Parent = GenericQueueThread<gpu::FramePointer>; using Parent = GenericThread;
public: public:
QOpenGLContextWrapper* _displayContext{ nullptr }; gl::Context _context;
QSurface* _displaySurface{ nullptr };
gpu::PipelinePointer _presentPipeline; gpu::PipelinePointer _presentPipeline;
gpu::ContextPointer _gpuContext; // initialized during window creation gpu::ContextPointer _gpuContext; // initialized during window creation
std::atomic<size_t> _presentCount; std::atomic<size_t> _presentCount;
@ -187,36 +241,56 @@ public:
std::shared_ptr<gpu::Backend> _backend; std::shared_ptr<gpu::Backend> _backend;
std::vector<uint64_t> _frameTimes; std::vector<uint64_t> _frameTimes;
size_t _frameIndex; size_t _frameIndex;
std::mutex _frameLock;
std::queue<gpu::FramePointer> _pendingFrames;
gpu::FramePointer _activeFrame;
QSize _size;
static const size_t FRAME_TIME_BUFFER_SIZE{ 8192 }; static const size_t FRAME_TIME_BUFFER_SIZE{ 8192 };
void submitFrame(const gpu::FramePointer& frame) {
std::unique_lock<std::mutex> lock(_frameLock);
_pendingFrames.push(frame);
}
void initialize(QOpenGLContextWrapper* displayContext, QWindow* surface) { void initialize(QWindow* window, gl::Context& initContext) {
setObjectName("RenderThread"); setObjectName("RenderThread");
_displayContext = displayContext; _context.setWindow(window);
_displaySurface = surface; _context.create();
_displayContext->makeCurrent(_displaySurface); _context.makeCurrent();
window->setSurfaceType(QSurface::OpenGLSurface);
_context.makeCurrent(_context.qglContext(), window);
#ifdef Q_OS_WIN
wglSwapIntervalEXT(0);
#endif
// GPU library init // GPU library init
gpu::Context::init<gpu::gl::GLBackend>(); gpu::Context::init<gpu::gl::GLBackend>();
_gpuContext = std::make_shared<gpu::Context>(); _gpuContext = std::make_shared<gpu::Context>();
_backend = _gpuContext->getBackend(); _backend = _gpuContext->getBackend();
_displayContext->makeCurrent(_displaySurface); _context.makeCurrent();
DependencyManager::get<DeferredLightingEffect>()->init(); DependencyManager::get<DeferredLightingEffect>()->init();
_displayContext->doneCurrent(); _context.makeCurrent();
initContext.create();
_context.doneCurrent();
std::unique_lock<std::mutex> lock(_mutex);
Parent::initialize(); Parent::initialize();
if (isThreaded()) { _context.moveToThread(_thread);
_displayContext->moveToThread(thread());
}
} }
void setup() override { void setup() override {
RENDER_THREAD = QThread::currentThread(); RENDER_THREAD = QThread::currentThread();
_displayContext->makeCurrent(_displaySurface);
// Wait until the context has been moved to this thread
{
std::unique_lock<std::mutex> lock(_mutex);
}
_context.makeCurrent();
glewExperimental = true; glewExperimental = true;
glewInit(); glewInit();
glGetError(); glGetError();
_frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0);
_frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0);
{ {
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG)); auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG));
@ -229,25 +303,33 @@ public:
//_textOverlay = new TextOverlay(glm::uvec2(800, 600)); //_textOverlay = new TextOverlay(glm::uvec2(800, 600));
glViewport(0, 0, 800, 600); glViewport(0, 0, 800, 600);
(void)CHECK_GL_ERROR();
_elapsed.start(); _elapsed.start();
} }
void shutdown() override { void shutdown() override {
_activeFrame.reset();
while (!_pendingFrames.empty()) {
_gpuContext->consumeFrameUpdates(_pendingFrames.front());
_pendingFrames.pop();
}
_presentPipeline.reset(); _presentPipeline.reset();
_gpuContext.reset(); _gpuContext.reset();
} }
void renderFrame(gpu::FramePointer& frame) { void renderFrame(gpu::FramePointer& frame) {
++_presentCount; ++_presentCount;
_displayContext->makeCurrent(_displaySurface); _context.makeCurrent();
_backend->recycle(); _backend->recycle();
_backend->syncCache(); _backend->syncCache();
if (frame && !frame->batches.empty()) { if (frame && !frame->batches.empty()) {
_gpuContext->executeFrame(frame); _gpuContext->executeFrame(frame);
{ {
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
gpu::Batch presentBatch; gpu::Batch presentBatch;
presentBatch.setViewportTransform({ 0, 0, _size.width(), _size.height() });
presentBatch.enableStereo(false); presentBatch.enableStereo(false);
presentBatch.resetViewTransform(); presentBatch.resetViewTransform();
presentBatch.setFramebuffer(gpu::FramebufferPointer()); presentBatch.setFramebuffer(gpu::FramebufferPointer());
@ -256,11 +338,10 @@ public:
presentBatch.draw(gpu::TRIANGLE_STRIP, 4); presentBatch.draw(gpu::TRIANGLE_STRIP, 4);
_gpuContext->executeBatch(presentBatch); _gpuContext->executeBatch(presentBatch);
} }
(void)CHECK_GL_ERROR();
} }
{ _context.makeCurrent();
//_textOverlay->render(); _context.swapBuffers();
}
_displayContext->swapBuffers(_displaySurface);
_fpsCounter.increment(); _fpsCounter.increment();
static size_t _frameCount{ 0 }; static size_t _frameCount{ 0 };
++_frameCount; ++_frameCount;
@ -269,6 +350,8 @@ public:
_frameCount = 0; _frameCount = 0;
_elapsed.restart(); _elapsed.restart();
} }
(void)CHECK_GL_ERROR();
_context.doneCurrent();
} }
void report() { void report() {
@ -292,10 +375,30 @@ public:
} }
} }
bool processQueueItems(const Queue& items) override {
for (auto frame : items) { bool process() override {
std::queue<gpu::FramePointer> pendingFrames;
{
std::unique_lock<std::mutex> lock(_frameLock);
pendingFrames.swap(_pendingFrames);
}
while (!pendingFrames.empty()) {
_activeFrame = pendingFrames.front();
if (_activeFrame) {
_gpuContext->consumeFrameUpdates(_activeFrame);
}
pendingFrames.pop();
}
if (!_activeFrame) {
QThread::msleep(1);
return true;
}
{
auto start = usecTimestampNow(); auto start = usecTimestampNow();
renderFrame(frame); renderFrame(_activeFrame);
auto duration = usecTimestampNow() - start; auto duration = usecTimestampNow() - start;
auto frameBufferIndex = _frameIndex % FRAME_TIME_BUFFER_SIZE; auto frameBufferIndex = _frameIndex % FRAME_TIME_BUFFER_SIZE;
_frameTimes[frameBufferIndex] = duration; _frameTimes[frameBufferIndex] = duration;
@ -308,7 +411,6 @@ public:
} }
}; };
// Background Render Data & rendering functions // Background Render Data & rendering functions
class BackgroundRenderData { class BackgroundRenderData {
public: public:
@ -354,7 +456,6 @@ namespace render {
// Create a simple OpenGL window that renders text in various ways // Create a simple OpenGL window that renders text in various ways
class QTestWindow : public QWindow, public AbstractViewStateInterface { class QTestWindow : public QWindow, public AbstractViewStateInterface {
Q_OBJECT
protected: protected:
void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { void copyCurrentViewFrustum(ViewFrustum& viewOut) const override {
@ -416,6 +517,7 @@ public:
} }
QTestWindow() { QTestWindow() {
installEventFilter(this);
_camera.movementSpeed = 50.0f; _camera.movementSpeed = 50.0f;
QThreadPool::globalInstance()->setMaxThreadCount(2); QThreadPool::globalInstance()->setMaxThreadCount(2);
QThread::currentThread()->setPriority(QThread::HighestPriority); QThread::currentThread()->setPriority(QThread::HighestPriority);
@ -424,6 +526,7 @@ public:
_octree->init(); _octree->init();
// Prevent web entities from rendering // Prevent web entities from rendering
REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory); REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory);
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, LightEntityItem::factory);
DependencyManager::set<ParentFinder>(_octree->getTree()); DependencyManager::set<ParentFinder>(_octree->getTree());
getEntities()->setViewFrustum(_viewFrustum); getEntities()->setViewFrustum(_viewFrustum);
@ -433,31 +536,51 @@ public:
nodeList->setPermissions(permissions); nodeList->setPermissions(permissions);
ResourceManager::init(); ResourceManager::init();
setSurfaceType(QSurface::OpenGLSurface);
auto format = getDefaultOpenGLSurfaceFormat();
format.setOption(QSurfaceFormat::DebugContext);
setFormat(format);
resize(QSize(800, 600)); setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint);
_size = QSize(800, 600);
_renderThread._size = _size;
setGeometry(QRect(QPoint(), _size));
create();
show(); show();
QCoreApplication::processEvents();
// Create the initial context
_renderThread.initialize(this, _initContext);
_initContext.makeCurrent();
_context.setFormat(format); #if 0
_context.create(); glfwInit();
_context.makeCurrent(this); glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
glewExperimental = true; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glewInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glGetError(); 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); GLDebug::setupLogger(this);
#ifdef Q_OS_WIN
wglSwapIntervalEXT(0);
#endif #endif
_context.doneCurrent();
_initContext.create(_context.getContext()); #ifdef Q_OS_WIN
_renderThread.initialize(&_context, this); //wglSwapIntervalEXT(0);
#endif
// FIXME use a wait condition // FIXME use a wait condition
QThread::msleep(1000); QThread::msleep(1000);
_renderThread.queueItem(gpu::FramePointer()); _renderThread.submitFrame(gpu::FramePointer());
_initContext.makeCurrent(); _initContext.makeCurrent();
// Render engine init // Render engine init
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", _cullFunctor); _renderEngine->addJob<RenderShadowTask>("RenderShadowTask", _cullFunctor);
@ -479,7 +602,6 @@ public:
} }
virtual ~QTestWindow() { virtual ~QTestWindow() {
_renderThread.terminate();
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
_renderEngine.reset(); _renderEngine.reset();
_main3DScene.reset(); _main3DScene.reset();
@ -497,6 +619,15 @@ public:
} }
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override {
if (event->type() == QEvent::Close) {
_renderThread.terminate();
}
return QWindow::eventFilter(obj, event);
}
void keyPressEvent(QKeyEvent* event) override { void keyPressEvent(QKeyEvent* event) override {
switch (event->key()) { switch (event->key()) {
case Qt::Key_F1: case Qt::Key_F1:
@ -508,7 +639,7 @@ protected:
return; return;
case Qt::Key_F4: case Qt::Key_F4:
toggleStereo(); cycleMode();
return; return;
case Qt::Key_F5: case Qt::Key_F5:
@ -575,27 +706,43 @@ private:
0, RenderArgs::DEFAULT_RENDER_MODE, 0, RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
QSize windowSize = _size;
if (_renderMode == NORMAL) {
renderArgs._context->enableStereo(false);
} else {
renderArgs._context->enableStereo(true);
mat4 eyeOffsets[2];
mat4 eyeProjections[2];
if (_renderMode == STEREO) {
for (size_t i = 0; i < 2; ++i) {
eyeProjections[i] = _viewFrustum.getProjection();
}
} else if (_renderMode == HMD) {
eyeOffsets[0][3] = vec4 { -0.0327499993, 0.0, 0.0149999997, 1.0 };
eyeOffsets[1][3] = vec4 { 0.0327499993, 0.0, 0.0149999997, 1.0 };
eyeProjections[0][0] = vec4 { 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
eyeProjections[0][1] = vec4 { 0.000000000, 0.682773232, 0.000000000, 0.000000000 };
eyeProjections[0][2] = vec4 { -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 };
eyeProjections[0][3] = vec4 { 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
eyeProjections[1][0] = vec4 { 0.752847493, 0.000000000, 0.000000000, 0.000000000 };
eyeProjections[1][1] = vec4 { 0.000000000, 0.678060353, 0.000000000, 0.000000000 };
eyeProjections[1][2] = vec4 { 0.0578232110, -0.00669418881, -1.00000489, -1.000000000 };
eyeProjections[1][3] = vec4 { 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
windowSize = { 2048, 2048 };
}
renderArgs._context->setStereoProjections(eyeProjections);
renderArgs._context->setStereoViews(eyeOffsets);
}
auto framebufferCache = DependencyManager::get<FramebufferCache>(); auto framebufferCache = DependencyManager::get<FramebufferCache>();
QSize windowSize = size();
framebufferCache->setFrameBufferSize(windowSize); framebufferCache->setFrameBufferSize(windowSize);
renderArgs._blitFramebuffer = framebufferCache->getFramebuffer(); renderArgs._blitFramebuffer = framebufferCache->getFramebuffer();
// Viewport is assigned to the size of the framebuffer // Viewport is assigned to the size of the framebuffer
renderArgs._viewport = ivec4(0, 0, windowSize.width(), windowSize.height()); renderArgs._viewport = ivec4(0, 0, windowSize.width(), windowSize.height());
renderArgs.setViewFrustum(_viewFrustum); renderArgs.setViewFrustum(_viewFrustum);
renderArgs._context->enableStereo(_stereoEnabled);
if (_stereoEnabled) {
mat4 eyeOffsets[2];
mat4 eyeProjections[2];
for (size_t i = 0; i < 2; ++i) {
eyeProjections[i] = _viewFrustum.getProjection();
}
renderArgs._context->setStereoProjections(eyeProjections);
renderArgs._context->setStereoViews(eyeOffsets);
}
// Final framebuffer that will be handled to the display-plugin // Final framebuffer that will be handled to the display-plugin
render(&renderArgs); render(&renderArgs);
@ -625,11 +772,11 @@ private:
}; };
void updateText() { 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(_fps).arg(_cullingEnabled)
.arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2)) .arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2))
.arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2))); .arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2));
setTitle(title);
#if 0 #if 0
{ {
_textBlocks.erase(TextBlock::Info); _textBlocks.erase(TextBlock::Info);
@ -742,7 +889,7 @@ private:
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){ frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer); DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
}; };
_renderThread.queueItem(frame); _renderThread.submitFrame(frame);
if (!_renderThread.isThreaded()) { if (!_renderThread.isThreaded()) {
_renderThread.process(); _renderThread.process();
} }
@ -750,18 +897,13 @@ private:
} }
bool makeCurrent() {
bool currentResult = _context.makeCurrent(this);
Q_ASSERT(currentResult);
return currentResult;
}
void resizeWindow(const QSize& size) { void resizeWindow(const QSize& size) {
_size = size; _size = size;
_camera.setAspectRatio((float)_size.width() / (float)_size.height()); _camera.setAspectRatio((float)_size.width() / (float)_size.height());
if (!_ready) { if (!_ready) {
return; return;
} }
_renderThread._size = size;
//_textOverlay->resize(toGlm(_size)); //_textOverlay->resize(toGlm(_size));
//glViewport(0, 0, size.width(), size.height()); //glViewport(0, 0, size.width(), size.height());
} }
@ -877,8 +1019,18 @@ private:
_cullingEnabled = !_cullingEnabled; _cullingEnabled = !_cullingEnabled;
} }
void toggleStereo() { void cycleMode() {
_stereoEnabled = !_stereoEnabled; static auto defaultProjection = Camera().matrices.perspective;
_renderMode = (RenderMode)((_renderMode + 1) % RENDER_MODE_COUNT);
if (_renderMode == HMD) {
_camera.matrices.perspective[0] = vec4 { 0.759056330, 0.000000000, 0.000000000, 0.000000000 };
_camera.matrices.perspective[1] = vec4 { 0.000000000, 0.682773232, 0.000000000, 0.000000000 };
_camera.matrices.perspective[2] = vec4 { -0.0580431037, -0.00619550655, -1.00000489, -1.00000000 };
_camera.matrices.perspective[3] = vec4 { 0.000000000, 0.000000000, -0.0800003856, 0.000000000 };
} else {
_camera.matrices.perspective = defaultProjection;
_camera.setAspectRatio((float)_size.width() / (float)_size.height());
}
} }
QSharedPointer<EntityTreeRenderer> getEntities() { QSharedPointer<EntityTreeRenderer> getEntities() {
@ -909,12 +1061,11 @@ private:
render::EnginePointer _renderEngine { new render::Engine() }; render::EnginePointer _renderEngine { new render::Engine() };
render::ScenePointer _main3DScene { new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; render::ScenePointer _main3DScene { new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
QOpenGLContextWrapper _context;
QSize _size; QSize _size;
QSettings _settings; QSettings _settings;
std::atomic<size_t> _renderCount; std::atomic<size_t> _renderCount;
OffscreenGLCanvas _initContext; gl::OffscreenContext _initContext;
RenderThread _renderThread; RenderThread _renderThread;
QWindowCamera _camera; QWindowCamera _camera;
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
@ -924,7 +1075,14 @@ private:
bool _ready { false }; bool _ready { false };
//TextOverlay* _textOverlay; //TextOverlay* _textOverlay;
static bool _cullingEnabled; static bool _cullingEnabled;
bool _stereoEnabled { false };
enum RenderMode {
NORMAL = 0,
STEREO,
HMD,
RENDER_MODE_COUNT
};
RenderMode _renderMode { NORMAL };
QSharedPointer<EntityTreeRenderer> _octree; QSharedPointer<EntityTreeRenderer> _octree;
}; };

View file

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

View file

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