mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 05:09:23 +02:00
Fixing screenshot functionality
This commit is contained in:
parent
b9ace94ff1
commit
d8bb9f8d18
6 changed files with 105 additions and 17 deletions
|
@ -44,6 +44,9 @@
|
||||||
|
|
||||||
#include <QtNetwork/QNetworkDiskCache>
|
#include <QtNetwork/QNetworkDiskCache>
|
||||||
|
|
||||||
|
#include <gl/Config.h>
|
||||||
|
#include <QtGui/QOpenGLContext>
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <AddressManager.h>
|
#include <AddressManager.h>
|
||||||
#include <ApplicationVersion.h>
|
#include <ApplicationVersion.h>
|
||||||
|
@ -150,8 +153,6 @@
|
||||||
#include "InterfaceParentFinder.h"
|
#include "InterfaceParentFinder.h"
|
||||||
|
|
||||||
|
|
||||||
#include <gpu/GLBackend.h>
|
|
||||||
#include <QtGui/QOpenGLContext>
|
|
||||||
|
|
||||||
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||||
// FIXME seems to be broken.
|
// FIXME seems to be broken.
|
||||||
|
@ -1091,7 +1092,6 @@ void Application::paintGL() {
|
||||||
// update fps once a second
|
// update fps once a second
|
||||||
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
|
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
|
||||||
_fps = _framesPerSecond.getAverage();
|
_fps = _framesPerSecond.getAverage();
|
||||||
qDebug() << QString::number(_fps, 'g', 4);
|
|
||||||
_lastFramesPerSecondUpdate = now;
|
_lastFramesPerSecondUpdate = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1344,6 +1344,7 @@ void Application::paintGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlay Composition, needs to occur after screen space effects have completed
|
// Overlay Composition, needs to occur after screen space effects have completed
|
||||||
|
// FIXME migrate composition into the display plugins
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(__FUNCTION__ "/compositor");
|
PROFILE_RANGE(__FUNCTION__ "/compositor");
|
||||||
PerformanceTimer perfTimer("compositor");
|
PerformanceTimer perfTimer("compositor");
|
||||||
|
@ -1372,7 +1373,6 @@ void Application::paintGL() {
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
||||||
PerformanceTimer perfTimer("pluginOutput");
|
PerformanceTimer perfTimer("pluginOutput");
|
||||||
uint64_t displayStart = usecTimestampNow();
|
|
||||||
auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer();
|
auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer();
|
||||||
auto scratchFramebuffer = framebufferCache->getFramebuffer();
|
auto scratchFramebuffer = framebufferCache->getFramebuffer();
|
||||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||||
|
@ -1386,12 +1386,18 @@ void Application::paintGL() {
|
||||||
});
|
});
|
||||||
auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0);
|
auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0);
|
||||||
GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer);
|
GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer);
|
||||||
|
|
||||||
Q_ASSERT(0 != finalTexture);
|
Q_ASSERT(0 != finalTexture);
|
||||||
|
|
||||||
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
|
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
|
||||||
_lockedFramebufferMap[finalTexture] = scratchFramebuffer;
|
_lockedFramebufferMap[finalTexture] = scratchFramebuffer;
|
||||||
|
|
||||||
|
uint64_t displayStart = usecTimestampNow();
|
||||||
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
||||||
displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size));
|
{
|
||||||
|
PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene");
|
||||||
|
PerformanceTimer perfTimer("pluginSubmitScene");
|
||||||
|
displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size));
|
||||||
|
}
|
||||||
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
||||||
|
|
||||||
uint64_t displayEnd = usecTimestampNow();
|
uint64_t displayEnd = usecTimestampNow();
|
||||||
|
@ -4499,13 +4505,12 @@ void Application::toggleLogDialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::takeSnapshot() {
|
void Application::takeSnapshot() {
|
||||||
#if 0
|
|
||||||
QMediaPlayer* player = new QMediaPlayer();
|
QMediaPlayer* player = new QMediaPlayer();
|
||||||
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
||||||
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||||
player->play();
|
player->play();
|
||||||
|
|
||||||
QString fileName = Snapshot::saveSnapshot(_glWidget->grabFrameBuffer());
|
QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot());
|
||||||
|
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
AccountManager& accountManager = AccountManager::getInstance();
|
||||||
if (!accountManager.isLoggedIn()) {
|
if (!accountManager.isLoggedIn()) {
|
||||||
|
@ -4516,7 +4521,6 @@ void Application::takeSnapshot() {
|
||||||
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
|
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
|
||||||
}
|
}
|
||||||
_snapshotShareDialog->show();
|
_snapshotShareDialog->show();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Application::getRenderResolutionScale() const {
|
float Application::getRenderResolutionScale() const {
|
||||||
|
@ -4728,6 +4732,7 @@ void Application::updateDisplayMode() {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
foreach(auto displayPlugin, displayPlugins) {
|
foreach(auto displayPlugin, displayPlugins) {
|
||||||
addDisplayPluginToMenu(displayPlugin, first);
|
addDisplayPluginToMenu(displayPlugin, first);
|
||||||
|
// This must be a queued connection to avoid a deadlock
|
||||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender,
|
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender,
|
||||||
this, &Application::paintGL, Qt::QueuedConnection);
|
this, &Application::paintGL, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
//
|
//
|
||||||
#include "NullDisplayPlugin.h"
|
#include "NullDisplayPlugin.h"
|
||||||
|
|
||||||
|
#include <QtGui/QImage>
|
||||||
#include <plugins/PluginContainer.h>
|
#include <plugins/PluginContainer.h>
|
||||||
|
|
||||||
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
|
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
|
||||||
|
|
||||||
const QString & NullDisplayPlugin::getName() const {
|
const QString & NullDisplayPlugin::getName() const {
|
||||||
|
@ -33,3 +35,7 @@ void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm:
|
||||||
}
|
}
|
||||||
|
|
||||||
void NullDisplayPlugin::stop() {}
|
void NullDisplayPlugin::stop() {}
|
||||||
|
|
||||||
|
QImage NullDisplayPlugin::getScreenshot() const {
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
virtual bool hasFocus() const override;
|
virtual bool hasFocus() const override;
|
||||||
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
||||||
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
||||||
|
virtual QImage getScreenshot() const override;
|
||||||
private:
|
private:
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
//
|
//
|
||||||
#include "OpenGLDisplayPlugin.h"
|
#include "OpenGLDisplayPlugin.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
#include <QtOpenGL/QGLWidget>
|
#include <QtOpenGL/QGLWidget>
|
||||||
#include <QtGui/QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
|
#include <QtGui/QImage>
|
||||||
|
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
@ -23,7 +26,9 @@
|
||||||
|
|
||||||
class PresentThread : public QThread, public Dependency {
|
class PresentThread : public QThread, public Dependency {
|
||||||
using Mutex = std::mutex;
|
using Mutex = std::mutex;
|
||||||
|
using Condition = std::condition_variable;
|
||||||
using Lock = std::unique_lock<Mutex>;
|
using Lock = std::unique_lock<Mutex>;
|
||||||
|
|
||||||
friend class OpenGLDisplayPlugin;
|
friend class OpenGLDisplayPlugin;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -40,6 +45,25 @@ public:
|
||||||
virtual void run() override {
|
virtual void run() override {
|
||||||
Q_ASSERT(_context);
|
Q_ASSERT(_context);
|
||||||
while (!_shutdown) {
|
while (!_shutdown) {
|
||||||
|
if (_pendingMainThreadOperation) {
|
||||||
|
{
|
||||||
|
Lock lock(_mutex);
|
||||||
|
// Move the context to the main thread
|
||||||
|
_context->moveToThread(qApp->thread());
|
||||||
|
_widgetContext->moveToThread(qApp->thread());
|
||||||
|
_pendingMainThreadOperation = false;
|
||||||
|
// Release the main thread to do it's action
|
||||||
|
_condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// Main thread does it's thing while we wait on the lock to release
|
||||||
|
Lock lock(_mutex);
|
||||||
|
_condition.wait(lock, [&] { return _finishedMainThreadOperation; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check before lock
|
// Check before lock
|
||||||
if (_newPlugin != nullptr) {
|
if (_newPlugin != nullptr) {
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
|
@ -69,17 +93,43 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
_context->doneCurrent();
|
_context->doneCurrent();
|
||||||
|
_widgetContext->moveToThread(qApp->thread());
|
||||||
_context->moveToThread(qApp->thread());
|
_context->moveToThread(qApp->thread());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void withMainThreadContext(std::function<void()> f) {
|
||||||
|
// Signal to the thread that there is work to be done on the main thread
|
||||||
|
Lock lock(_mutex);
|
||||||
|
_pendingMainThreadOperation = true;
|
||||||
|
_finishedMainThreadOperation = false;
|
||||||
|
_condition.wait(lock, [&] { return !_pendingMainThreadOperation; });
|
||||||
|
|
||||||
|
_widgetContext->makeCurrent();
|
||||||
|
f();
|
||||||
|
_widgetContext->doneCurrent();
|
||||||
|
|
||||||
|
// restore control of the context to the presentation thread and signal
|
||||||
|
// the end of the operation
|
||||||
|
_widgetContext->moveToThread(this);
|
||||||
|
_context->moveToThread(this);
|
||||||
|
_finishedMainThreadOperation = true;
|
||||||
|
lock.unlock();
|
||||||
|
_condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _shutdown { false };
|
bool _shutdown { false };
|
||||||
Mutex _mutex;
|
Mutex _mutex;
|
||||||
|
// Used to allow the main thread to perform context operations
|
||||||
|
Condition _condition;
|
||||||
|
bool _pendingMainThreadOperation { false };
|
||||||
|
bool _finishedMainThreadOperation { false };
|
||||||
QThread* _mainThread { nullptr };
|
QThread* _mainThread { nullptr };
|
||||||
OpenGLDisplayPlugin* _newPlugin { nullptr };
|
OpenGLDisplayPlugin* _newPlugin { nullptr };
|
||||||
OpenGLDisplayPlugin* _activePlugin { nullptr };
|
OpenGLDisplayPlugin* _activePlugin { nullptr };
|
||||||
QOpenGLContext* _context { nullptr };
|
QOpenGLContext* _context { nullptr };
|
||||||
|
QGLContext* _widgetContext { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
|
OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
|
||||||
|
@ -114,14 +164,16 @@ void OpenGLDisplayPlugin::activate() {
|
||||||
if (!presentThread) {
|
if (!presentThread) {
|
||||||
DependencyManager::set<PresentThread>();
|
DependencyManager::set<PresentThread>();
|
||||||
presentThread = DependencyManager::get<PresentThread>();
|
presentThread = DependencyManager::get<PresentThread>();
|
||||||
|
presentThread->setObjectName("Presentation Thread");
|
||||||
|
|
||||||
auto widget = _container->getPrimaryWidget();
|
auto widget = _container->getPrimaryWidget();
|
||||||
auto glContext = widget->context();
|
|
||||||
auto context = glContext->contextHandle();
|
|
||||||
glContext->moveToThread(presentThread.data());
|
|
||||||
context->moveToThread(presentThread.data());
|
|
||||||
|
|
||||||
// Move the OpenGL context to the present thread
|
// Move the OpenGL context to the present thread
|
||||||
presentThread->_context = context;
|
// Extra code because of the widget 'wrapper' context
|
||||||
|
presentThread->_widgetContext = widget->context();
|
||||||
|
presentThread->_widgetContext->moveToThread(presentThread.data());
|
||||||
|
presentThread->_context = presentThread->_widgetContext->contextHandle();
|
||||||
|
presentThread->_context->moveToThread(presentThread.data());
|
||||||
|
|
||||||
// Start execution
|
// Start execution
|
||||||
presentThread->start();
|
presentThread->start();
|
||||||
|
@ -325,3 +377,18 @@ void OpenGLDisplayPlugin::swapBuffers() {
|
||||||
static auto widget = _container->getPrimaryWidget();
|
static auto widget = _container->getPrimaryWidget();
|
||||||
widget->swapBuffers();
|
widget->swapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
||||||
|
static auto presentThread = DependencyManager::get<PresentThread>();
|
||||||
|
presentThread->withMainThreadContext(f);
|
||||||
|
_container->makeRenderingContextCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage OpenGLDisplayPlugin::getScreenshot() const {
|
||||||
|
QImage result;
|
||||||
|
withMainThreadContext([&] {
|
||||||
|
static auto widget = _container->getPrimaryWidget();
|
||||||
|
result = widget->grabFrameBuffer();
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -31,17 +31,20 @@ public:
|
||||||
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
||||||
virtual float presentRate() override;
|
virtual float presentRate() override;
|
||||||
|
|
||||||
virtual glm::uvec2 getRecommendedRenderSize() const {
|
virtual glm::uvec2 getRecommendedRenderSize() const override {
|
||||||
return getSurfacePixels();
|
return getSurfacePixels();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual glm::uvec2 getRecommendedUiSize() const {
|
virtual glm::uvec2 getRecommendedUiSize() const override {
|
||||||
return getSurfaceSize();
|
return getSurfaceSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual QImage getScreenshot() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class PresentThread;
|
friend class PresentThread;
|
||||||
|
|
||||||
|
|
||||||
virtual glm::uvec2 getSurfaceSize() const = 0;
|
virtual glm::uvec2 getSurfaceSize() const = 0;
|
||||||
virtual glm::uvec2 getSurfacePixels() const = 0;
|
virtual glm::uvec2 getSurfacePixels() const = 0;
|
||||||
|
|
||||||
|
@ -53,6 +56,9 @@ protected:
|
||||||
virtual void customizeContext();
|
virtual void customizeContext();
|
||||||
virtual void uncustomizeContext();
|
virtual void uncustomizeContext();
|
||||||
virtual void cleanupForSceneTexture(uint32_t sceneTexture);
|
virtual void cleanupForSceneTexture(uint32_t sceneTexture);
|
||||||
|
void withMainThreadContext(std::function<void()> f) const;
|
||||||
|
|
||||||
|
|
||||||
void present();
|
void present();
|
||||||
void updateTextures();
|
void updateTextures();
|
||||||
void updateFramerate();
|
void updateFramerate();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <QtCore/QSize>
|
#include <QtCore/QSize>
|
||||||
#include <QtCore/QPoint>
|
#include <QtCore/QPoint>
|
||||||
|
class QImage;
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
@ -96,6 +97,9 @@ public:
|
||||||
return baseProjection;
|
return baseProjection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the most recently displayed image as a QImage
|
||||||
|
virtual QImage getScreenshot() const = 0;
|
||||||
|
|
||||||
// HMD specific methods
|
// HMD specific methods
|
||||||
// TODO move these into another class?
|
// TODO move these into another class?
|
||||||
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
|
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
|
||||||
|
|
Loading…
Reference in a new issue