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