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 we have a metaverse domain, we'll use an access token for API calls
resetAccountManagerAccessToken();
}
setupAutomaticNetworking();
setupAutomaticNetworking();
}
if (!getID().isNull() && _type != NonMetaverse) {
// 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
_glWidget->setMouseTracking(true);
// Make sure the window is set to the correct size by processing the pending events
QCoreApplication::processEvents();
_glWidget->createContext();
_glWidget->makeCurrent();
_glWidget->initializeGL();
initializeGL();
// Make sure we don't time out during slow operations at startup
@ -1483,7 +1485,8 @@ void Application::initializeGL() {
_glWidget->makeCurrent();
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->create(_glWidget->context()->contextHandle());
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
@ -1529,7 +1532,8 @@ void Application::initializeGL() {
_idleLoopStdev.reset();
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->create(_glWidget->context()->contextHandle());
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
_offscreenContext->makeCurrent();
// update before the first render
@ -1551,7 +1555,7 @@ void Application::initializeUi() {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->context()->contextHandle());
offscreenUi->create(_glWidget->qglContext());
auto rootContext = offscreenUi->getRootContext();
@ -5673,7 +5677,7 @@ MainWindow* Application::getPrimaryWindow() {
}
QOpenGLContext* Application::getPrimaryContext() {
return _glWidget->context()->contextHandle();
return _glWidget->qglContext();
}
bool Application::makeRenderingContextCurrent() {

View file

@ -111,7 +111,7 @@ void DiscoverabilityManager::updateLocation() {
}
// Update Steam
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingAddress());
SteamClient::updateLocation(domainHandler.getHostname(), addressManager->currentFacingShareableAddress());
}
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 forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
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:
AddressBarDialog(QQuickItem* parent = nullptr);
@ -37,6 +37,7 @@ signals:
void forwardEnabledChanged();
void useFeedChanged();
void receivedHifiSchemeURL(const QString& url);
void metaverseServerUrlChanged(); // While it is a constant, qml will complain about not seeing a change signal.
protected:
void displayAddressOfflineMessage();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -582,7 +582,7 @@ void GLBackend::releaseShader(GLuint id) const {
void GLBackend::releaseProgram(GLuint id) const {
Lock lock(_trashMutex);
_shadersTrash.push_back(id);
_programsTrash.push_back(id);
}
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 (!availableTextureMemory) {
auto totalGpuMemory = gpu::gl::getDedicatedMemory();
auto totalGpuMemory = getDedicatedMemory();
// If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB
@ -118,7 +118,7 @@ float GLTexture::getMemoryPressure() {
return (float)consumedGpuMemory / (float)availableTextureMemory;
}
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<gl::GLBackend>& backend, GLTexture* oldTexture) :
GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr<GLBackend>& backend, GLTexture* oldTexture) :
_backend(backend),
_size(oldTexture ? oldTexture->_size : 0),
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
@ -161,7 +161,7 @@ GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture
// Create the texture and allocate storage
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id, bool transferrable) :
GLTexture(backend, texture, id, nullptr, transferrable)
{
// FIXME, do during allocation
@ -170,7 +170,7 @@ GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture&
}
// Create the texture and copy from the original higher resolution version
GLTexture::GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable)
{
Q_ASSERT(_minMip >= originalTexture->_minMip);
@ -243,15 +243,8 @@ bool GLTexture::isReady() const {
return false;
}
// If we're out of date, but the transfer is in progress, report ready
// as a special case
auto syncState = _syncState.load();
if (isOutdated()) {
return Idle != syncState;
}
if (Idle != syncState) {
if (isOutdated() || Idle != syncState) {
return false;
}

View file

@ -21,6 +21,9 @@ struct GLFilterMode {
class GLTexture : public GLObject<Texture> {
public:
static const uint16_t INVALID_MIP { (uint16_t)-1 };
static const uint8_t INVALID_FACE { (uint8_t)-1 };
static void initTextureTransferHelper();
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 (GLSyncState::Transferred == object->getSyncState()) {
object->postTransfer();
return object;
}
if (object->isReady()) {
// 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()) {
if (object->isOutdated()) {
// Object might be outdated, if so, start the transfer
// (outdated objects that are already in transfer will have reported 'true' for ready()
_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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -38,7 +38,7 @@ void GL45Backend::transferTransformState(const Batch& batch) const {
}
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()) {

View file

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

View file

@ -35,7 +35,7 @@ public:
void setCubemap(const gpu::TexturePointer& 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();
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_CONSTANTS_SLOT { 0 };
gpu::TexturePointer _cubemap;
class Schema {
public:
glm::vec3 color { 0.0f, 0.0f, 0.0f };
float blend { 0.0f };
};
mutable gpu::BufferView _schemaBuffer;
void updateSchemaBuffer() const;
mutable gpu::BufferView _schemaBuffer;
gpu::TexturePointer _cubemap;
bool _empty{ true };
};
typedef std::shared_ptr<Skybox> SkyboxPointer;

View file

@ -63,15 +63,31 @@ QUrl AddressManager::currentAddress() const {
}
QUrl AddressManager::currentFacingAddress() const {
QUrl hifiURL;
auto hifiURL = currentAddress();
hifiURL.setPath(currentFacingPath());
hifiURL.setScheme(HIFI_URL_SCHEME);
hifiURL.setHost(_host);
return hifiURL;
}
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());
return hifiURL;
@ -360,6 +376,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
LookupTrigger trigger = (LookupTrigger) reply.property(LOOKUP_TRIGGER_KEY).toInt();
// set our current root place id to the ID that came back
const QString PLACE_ID_KEY = "id";
_rootPlaceID = rootMap[PLACE_ID_KEY].toUuid();
@ -368,6 +385,18 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
const QString PLACE_NAME_KEY = "name";
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 (setHost(placeName, trigger)) {
trigger = LookupTrigger::Internal;
@ -651,6 +680,9 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
_port = port;
// any host change should clear the shareable place name
_shareablePlaceName.clear();
if (host != _host) {
_host = host;
emit hostChanged(_host);
@ -701,13 +733,67 @@ void AddressManager::refreshPreviousLookup() {
}
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() {
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) {
// 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 currentFacingAddress() const;
QUrl currentShareableAddress() const;
QUrl currentFacingShareableAddress() const;
QString currentPath(bool withOrientation = true) const;
QString currentFacingPath() const;
@ -102,6 +104,8 @@ public slots:
void copyAddress();
void copyPath();
void lookupShareableNameForDomainID(const QUuid& domainID);
signals:
void lookupResultsFinished();
void lookupResultIsOffline();
@ -125,6 +129,8 @@ private slots:
void handleAPIResponse(QNetworkReply& requestReply);
void handleAPIError(QNetworkReply& errorReply);
void handleShareableNameAPIResponse(QNetworkReply& requestReply);
private:
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
@ -155,6 +161,8 @@ private:
PositionGetter _positionGetter;
OrientationGetter _orientationGetter;
QString _shareablePlaceName;
QStack<QUrl> _backStack;
QStack<QUrl> _forwardStack;
quint64 _lastBackPush = 0;

View file

@ -539,6 +539,10 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
if (!_domainHandler.isConnected()) {
_domainHandler.setUUID(domainUUID);
_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) {
// Recieved packet from different domain.
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);
obj.setProperty("pos3D", direction);
bool isPrimaryButton = false;
bool isSecondaryButton = false;
bool isTertiaryButton = false;
switch (event._button) {
case NoButtons:
obj.setProperty("button", "None");
break;
case PrimaryButton:
obj.setProperty("button", "Primary");
isPrimaryButton = true;
break;
case SecondaryButton:
obj.setProperty("button", "Secondary");
isSecondaryButton = true;
break;
case TertiaryButton:
obj.setProperty("button", "Tertiary");
isTertiaryButton = true;
break;
}
obj.setProperty("isLeftButton", areFlagsSet(event._buttons, PrimaryButton));
obj.setProperty("isRightButton", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isMiddleButton", areFlagsSet(event._buttons, TertiaryButton));
if (isPrimaryButton) {
obj.setProperty("isPrimaryButton", isPrimaryButton);
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("isSecondaryButton", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isTertiaryButton", areFlagsSet(event._buttons, TertiaryButton));
obj.setProperty("isPrimaryHeld", areFlagsSet(event._buttons, PrimaryButton));
obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton));
return obj;
}
@ -146,9 +161,9 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
event._button = NoButtons;
}
bool primary = object.property("isPrimary").toBool() || object.property("isLeftButton").toBool();
bool secondary = object.property("isSecondary").toBool() || object.property("isRightButton").toBool();
bool tertiary = object.property("isTertiary").toBool() || object.property("isMiddleButton").toBool();
bool primary = object.property("isPrimaryHeld").toBool();
bool secondary = object.property("isSecondaryHeld").toBool();
bool tertiary = object.property("isTertiaryHeld").toBool();
event._buttons = 0;
if (primary) {
event._buttons |= PrimaryButton;

View file

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

View file

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

View file

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

View file

@ -803,7 +803,7 @@ function setupModelMenus() {
menuName: "Edit",
menuItemName: "Delete",
shortcutKeyEvent: {
text: "backspace"
text: "delete"
},
afterItem: "Entities",
grouping: "Advanced"
@ -1215,7 +1215,7 @@ Controller.keyReleaseEvent.connect(function (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
if (event.text === "BACKSPACE" || event.text === "DELETE") {
if (event.text === "DELETE") {
deleteSelectedEntities();
} else if (event.text === "ESC") {
selectionManager.clearSelections();

View file

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

View file

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

View file

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

View file

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

View file

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