From 3d922f5db63c1cb4a0aab88bf014a2f59e359f3b Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 15 Jun 2017 14:17:43 -0700 Subject: [PATCH] works, sorta, but blinks like crazy, cursor gets f-ed up... --- .../resources/qml/hifi/SpectatorCamera.qml | 4 ++ interface/src/ui/ResourceImageItem.cpp | 55 +++++++++++++++++-- interface/src/ui/ResourceImageItem.h | 26 ++++++++- .../display-plugins/OpenGLDisplayPlugin.cpp | 32 ++++++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 6 +- libraries/plugins/src/plugins/DisplayPlugin.h | 12 ++-- 6 files changed, 116 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 37e8fdee01..44d4759cdf 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -190,6 +190,7 @@ Rectangle { boxSize: 24; onClicked: { sendToScript({method: (checked ? 'spectatorCameraOn' : 'spectatorCameraOff')}); + spectatorCameraPreviewItem.ready = checked; } } @@ -202,7 +203,10 @@ Rectangle { anchors.topMargin: 20; anchors.right: parent.right; Hifi.ResourceImageItem { + id: spectatorCameraPreviewItem; anchors.fill: parent; + url: "resource://spectatorCameraFrame"; + ready: false; } } diff --git a/interface/src/ui/ResourceImageItem.cpp b/interface/src/ui/ResourceImageItem.cpp index b1869d5ed2..f1ffae06b5 100644 --- a/interface/src/ui/ResourceImageItem.cpp +++ b/interface/src/ui/ResourceImageItem.cpp @@ -8,11 +8,55 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Application.h" #include "ResourceImageItem.h" #include #include #include + +ResourceImageItem::ResourceImageItem(QQuickItem* parent) : QQuickFramebufferObject(parent) { + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(update())); +} + +void ResourceImageItem::setUrl(const QString& url) { + if (url != m_url) { + m_url = url; + update(); + } +} + +void ResourceImageItem::setReady(bool ready) { + if (ready != m_ready) { + m_ready = ready; + if (m_ready) { + m_updateTimer.start(1000); + } else { + m_updateTimer.stop(); + } + update(); + } +} + +void ResourceImageItemRenderer::synchronize(QQuickFramebufferObject* item) { + ResourceImageItem* resourceImageItem = static_cast(item); + bool urlChanged = false; + if( _url != resourceImageItem->getUrl()) { + _url = resourceImageItem->getUrl(); + urlChanged = true; + } + bool readyChanged = false; + if (_ready != resourceImageItem->getReady()) { + _ready = resourceImageItem->getReady(); + readyChanged = true; + } + _window = resourceImageItem->window(); + qDebug() << "synchronize called!!!!!!!"; + if (_ready && !_url.isNull() && !_url.isEmpty() && (readyChanged || urlChanged)) { + _networkTexture = DependencyManager::get()->getTexture(_url); + } +} + QOpenGLFramebufferObject* ResourceImageItemRenderer::createFramebufferObject(const QSize& size) { QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); @@ -20,9 +64,12 @@ QOpenGLFramebufferObject* ResourceImageItemRenderer::createFramebufferObject(con } void ResourceImageItemRenderer::render() { - auto texture = DependencyManager::get()->getTexture(QUrl("resource://spectatorCameraFrame")); - if (texture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->getGPUTexture(), 0); + qDebug() << "render called!!!!!!!!!!!!!!"; + if (_networkTexture && _ready) { + auto texture = _networkTexture->getGPUTexture(); + if (texture) { + qApp->getActiveDisplayPlugin()->copyTextureToQuickFramebuffer(texture, framebufferObject()); + _window->resetOpenGLState(); + } } - } diff --git a/interface/src/ui/ResourceImageItem.h b/interface/src/ui/ResourceImageItem.h index 6d8b33ae64..a1f332a817 100644 --- a/interface/src/ui/ResourceImageItem.h +++ b/interface/src/ui/ResourceImageItem.h @@ -13,15 +13,37 @@ #define hifi_ResourceImageItem_h #include -#include +#include +#include -class ResourceImageItemRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions { +class ResourceImageItemRenderer : public QQuickFramebufferObject::Renderer { +public: QOpenGLFramebufferObject* createFramebufferObject(const QSize& size); + void synchronize(QQuickFramebufferObject* item); void render(); +private: + bool _ready; + QString _url; + NetworkTexturePointer _networkTexture; + QQuickWindow* _window; }; class ResourceImageItem : public QQuickFramebufferObject { + Q_OBJECT + Q_PROPERTY(QString url READ getUrl WRITE setUrl) + Q_PROPERTY(bool ready READ getReady WRITE setReady) + +public: + ResourceImageItem(QQuickItem* parent = Q_NULLPTR); + QString getUrl() const { return m_url; } + void setUrl(const QString& url); + bool getReady() const { return m_ready; } + void setReady(bool ready); QQuickFramebufferObject::Renderer* createRenderer() const { return new ResourceImageItemRenderer; } +private: + QString m_url; + bool m_ready { false }; + QTimer m_updateTimer; // TODO: something more clever }; #endif // hifi_ResourceImageItem_h diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index ba8842c2ec..c331d1a233 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -16,6 +16,7 @@ #include #include +#include #if defined(Q_OS_MAC) #include #endif @@ -55,7 +56,7 @@ out vec4 outFragColor; float sRGBFloatToLinear(float value) { const float SRGB_ELBOW = 0.04045; - + return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4); } @@ -121,10 +122,10 @@ public: PROFILE_SET_THREAD_NAME("Present Thread"); // FIXME determine the best priority balance between this and the main thread... - // It may be dependent on the display plugin being used, since VR plugins should + // It may be dependent on the display plugin being used, since VR plugins should // have higher priority on rendering (although we could say that the Oculus plugin // doesn't need that since it has async timewarp). - // A higher priority here + // A higher priority here setPriority(QThread::HighPriority); OpenGLDisplayPlugin* currentPlugin{ nullptr }; Q_ASSERT(_context); @@ -233,7 +234,7 @@ public: // Move the context back to the presentation thread _context->moveToThread(this); - // restore control of the context to the presentation thread and signal + // restore control of the context to the presentation thread and signal // the end of the operation _finishedMainThreadOperation = true; lock.unlock(); @@ -291,7 +292,7 @@ bool OpenGLDisplayPlugin::activate() { if (!RENDER_THREAD) { RENDER_THREAD = _presentThread; } - + // Child classes may override this in order to do things like initialize // libraries, etc if (!internalActivate()) { @@ -411,7 +412,7 @@ void OpenGLDisplayPlugin::customizeContext() { gpu::Shader::makeProgram(*program); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _overlayPipeline = gpu::Pipeline::create(program, state); @@ -686,7 +687,7 @@ void OpenGLDisplayPlugin::resetPresentRate() { // _presentRate = RateCounter<100>(); } -float OpenGLDisplayPlugin::renderRate() const { +float OpenGLDisplayPlugin::renderRate() const { return _renderRate.rate(); } @@ -820,3 +821,20 @@ void OpenGLDisplayPlugin::updateCompositeFramebuffer() { _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32, renderSize.x, renderSize.y)); } } + +void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(gpu::TexturePointer source, QOpenGLFramebufferObject* target) { + auto glBackend = const_cast(*this).getGLBackend(); + withMainThreadContext([&] { + GLuint sourceTexture = glBackend->getTextureID(source); + GLuint targetTexture = target->texture(); + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 0); + glCopyTextureSubImage2D(targetTexture, 0, 0, 0, 0, 0, target->width(), target->height()); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &fbo); + }); +} + diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index cf874fb721..7e7fcd1116 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -38,7 +38,7 @@ protected: using Condition = std::condition_variable; public: ~OpenGLDisplayPlugin(); - // These must be final to ensure proper ordering of operations + // These must be final to ensure proper ordering of operations // between the main thread and the presentation thread bool activate() override final; void deactivate() override final; @@ -78,6 +78,8 @@ public: // Three threads, one for rendering, one for texture transfers, one reserved for the GL driver int getRequiredThreadCount() const override { return 3; } + void copyTextureToQuickFramebuffer(gpu::TexturePointer source, QOpenGLFramebufferObject* target); + protected: friend class PresentThread; @@ -102,7 +104,7 @@ protected: // Returns true on successful activation virtual bool internalActivate() { return true; } virtual void internalDeactivate() {} - + // Returns true on successful activation of standby session virtual bool activateStandBySession() { return true; } virtual void deactivateSession() {} diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 7bfdbddbc5..d45320ec9a 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -25,6 +25,8 @@ #include "Plugin.h" +class QOpenGLFramebufferObject; + class QImage; enum Eye { @@ -61,7 +63,7 @@ namespace gpu { } // Stereo display functionality -// TODO move out of this file don't derive DisplayPlugin from this. Instead use dynamic casting when +// TODO move out of this file don't derive DisplayPlugin from this. Instead use dynamic casting when // displayPlugin->isStereo returns true class StereoDisplay { public: @@ -78,7 +80,7 @@ public: }; // HMD display functionality -// TODO move out of this file don't derive DisplayPlugin from this. Instead use dynamic casting when +// TODO move out of this file don't derive DisplayPlugin from this. Instead use dynamic casting when // displayPlugin->isHmd returns true class HmdDisplay : public StereoDisplay { public: @@ -142,7 +144,7 @@ public: virtual float getTargetFrameRate() const { return 1.0f; } virtual bool hasAsyncReprojection() const { return false; } - /// Returns a boolean value indicating whether the display is currently visible + /// Returns a boolean value indicating whether the display is currently visible /// to the user. For monitor displays, false might indicate that a screensaver, /// or power-save mode is active. For HMDs it may reflect a sensor indicating /// whether the HMD is being worn @@ -204,10 +206,12 @@ public: // Rate at which rendered frames are being skipped virtual float droppedFrameRate() const { return -1.0f; } virtual bool getSupportsAutoSwitch() { return false; } - + // Hardware specific stats virtual QJsonObject getHardwareStats() const { return QJsonObject(); } + virtual void copyTextureToQuickFramebuffer(gpu::TexturePointer source, QOpenGLFramebufferObject* target) = 0; + uint32_t presentCount() const { return _presentedFrameIndex; } // Time since last call to incrementPresentCount (only valid if DEBUG_PAINT_DELAY is defined) int64_t getPaintDelayUsecs() const;