// // ResourceImageItem.cpp // // Created by David Kelly and Howard Stearns on 2017/06/08 // Copyright 2017 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 "ResourceImageItem.h" #include #include #include #include #include static const char* VERTEX_SHADER = R"SHADER( #version 450 core out vec2 vTexCoord; void main(void) { const float depth = 0.0; const vec4 UNIT_QUAD[4] = vec4[4]( vec4(-1.0, -1.0, depth, 1.0), vec4(1.0, -1.0, depth, 1.0), vec4(-1.0, 1.0, depth, 1.0), vec4(1.0, 1.0, depth, 1.0) ); vec4 pos = UNIT_QUAD[gl_VertexID]; gl_Position = pos; vTexCoord = (pos.xy + 1.0) * 0.5; } )SHADER"; static const char* FRAGMENT_SHADER = R"SHADER( #version 450 core uniform sampler2D sampler; in vec2 vTexCoord; out vec4 FragColor; vec3 color_LinearTosRGB(vec3 lrgb) { return mix(vec3(1.055) * pow(vec3(lrgb), vec3(0.41666)) - vec3(0.055), vec3(lrgb) * vec3(12.92), vec3(lessThan(lrgb, vec3(0.0031308)))); } void main() { FragColor = vec4(color_LinearTosRGB(texture(sampler, vTexCoord).rgb), 1.0); } )SHADER"; ResourceImageItem::ResourceImageItem() : QQuickFramebufferObject() { auto textureCache = DependencyManager::get(); connect(textureCache.data(), SIGNAL(spectatorCameraFramebufferReset()), 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; update(); } } void ResourceImageItemRenderer::onUpdateTimer() { if (_ready) { if (_networkTexture && _networkTexture->isLoaded()) { if(_fboMutex.tryLock()) { invalidateFramebufferObject(); qApp->getActiveDisplayPlugin()->copyTextureToQuickFramebuffer(_networkTexture, _copyFbo, &_fenceSync); _fboMutex.unlock(); } else { qDebug() << "couldn't get a lock, using last frame"; } } else { _networkTexture = DependencyManager::get()->getTexture(_url); } } update(); } ResourceImageItemRenderer::ResourceImageItemRenderer() : QQuickFramebufferObject::Renderer() { connect(&_updateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimer())); auto textureCache = DependencyManager::get(); } void ResourceImageItemRenderer::synchronize(QQuickFramebufferObject* item) { ResourceImageItem* resourceImageItem = static_cast(item); resourceImageItem->setFlag(QQuickItem::ItemHasContents); _url = resourceImageItem->getUrl(); _ready = resourceImageItem->getReady(); _visible = resourceImageItem->isVisible(); _window = resourceImageItem->window(); _networkTexture = DependencyManager::get()->getTexture(_url); static const int UPDATE_TIMER_DELAY_IN_MS = 100; // 100 ms = 10 hz for now if (_ready && _visible && !_updateTimer.isActive()) { _updateTimer.start(UPDATE_TIMER_DELAY_IN_MS); } else if (!(_ready && _visible) && _updateTimer.isActive()) { _updateTimer.stop(); } } QOpenGLFramebufferObject* ResourceImageItemRenderer::createFramebufferObject(const QSize& size) { if (_copyFbo) { delete _copyFbo; } QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); _copyFbo = new QOpenGLFramebufferObject(size, format); _copyFbo->bind(); return new QOpenGLFramebufferObject(size, format); } void ResourceImageItemRenderer::render() { if (_fenceSync) { glWaitSync(_fenceSync, 0, GL_TIMEOUT_IGNORED); glDeleteSync(_fenceSync); _fenceSync = 0; } if (_ready) { _fboMutex.lock(); if (!_shader) { _shader = new QOpenGLShaderProgram(); _shader->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, VERTEX_SHADER); _shader->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, FRAGMENT_SHADER); _shader->link(); glGenVertexArrays(1, &_vao); } framebufferObject()->bind(); _shader->bind(); auto sourceTextureId = _copyFbo->takeTexture(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, sourceTextureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindVertexArray(_vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDeleteTextures(1, &sourceTextureId); _copyFbo->bind(); _copyFbo->release(); _fboMutex.unlock(); } glFlush(); _window->resetOpenGLState(); }