restructured gamma correction so snapshots look correct

This commit is contained in:
Anna 2019-06-21 11:11:44 -07:00
parent a66bd04810
commit 250d18d7df
6 changed files with 129 additions and 128 deletions

View file

@ -109,11 +109,25 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() {
return Parent::internalActivate(); return Parent::internalActivate();
} }
gpu::PipelinePointer Basic2DWindowOpenGLDisplayPlugin::getRenderTexturePipeline() {
#if defined(Q_OS_ANDROID)
return _linearToSRGBPipeline;
#else
#ifndef USE_GLES
return _SRGBToLinearPipeline;
#else
return _drawTexturePipeline;
#endif
#endif
}
gpu::PipelinePointer Basic2DWindowOpenGLDisplayPlugin::getCompositeScenePipeline() { gpu::PipelinePointer Basic2DWindowOpenGLDisplayPlugin::getCompositeScenePipeline() {
#if defined(Q_OS_ANDROID) #if defined(Q_OS_ANDROID)
return _linearToSRGBPipeline; return _linearToSRGBPipeline;
#else #else
return _SRGBToLinearPipeline; return _drawTexturePipeline;
#endif #endif
} }

View file

@ -37,6 +37,7 @@ public:
virtual void pluginUpdate() override {}; virtual void pluginUpdate() override {};
virtual gpu::PipelinePointer getRenderTexturePipeline() override;
virtual gpu::PipelinePointer getCompositeScenePipeline() override; virtual gpu::PipelinePointer getCompositeScenePipeline() override;
virtual gpu::Element getCompositeFBColorSpace() override; virtual gpu::Element getCompositeFBColorSpace() override;

View file

@ -59,19 +59,14 @@ class PresentThread : public QThread, public Dependency {
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
public: public:
PresentThread() { PresentThread() {
connect(qApp, &QCoreApplication::aboutToQuit, [this] { connect(qApp, &QCoreApplication::aboutToQuit, [this] { shutdown(); });
shutdown();
});
setObjectName("Present"); setObjectName("Present");
_refreshRateController = std::make_shared<RefreshRateController>(); _refreshRateController = std::make_shared<RefreshRateController>();
} }
~PresentThread() { ~PresentThread() { shutdown(); }
shutdown();
}
auto getRefreshRateController() { return _refreshRateController; } auto getRefreshRateController() { return _refreshRateController; }
@ -82,17 +77,16 @@ public:
Lock lock(_mutex); Lock lock(_mutex);
_shutdown = true; _shutdown = true;
_condition.wait(lock, [&] { return !_shutdown; }); _condition.wait(lock, [&] { return !_shutdown; });
qCDebug(displayPlugins) << "Present thread shutdown"; qCDebug(displayPlugins) << "Present thread shutdown";
} }
} }
void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) { void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) {
Lock lock(_mutex); Lock lock(_mutex);
if (isRunning()) { if (isRunning()) {
_newPluginQueue.push(plugin); _newPluginQueue.push(plugin);
_condition.wait(lock, [=]()->bool { return _newPluginQueue.empty(); }); _condition.wait(lock, [=]() -> bool { return _newPluginQueue.empty(); });
} }
} }
@ -104,7 +98,6 @@ public:
_context->moveToThread(this); _context->moveToThread(this);
} }
virtual void run() override { virtual void run() override {
PROFILE_SET_THREAD_NAME("Present Thread"); PROFILE_SET_THREAD_NAME("Present Thread");
@ -120,8 +113,7 @@ public:
CHECK_GL_ERROR(); CHECK_GL_ERROR();
while (!_shutdown) { while (!_shutdown) {
if (_pendingOtherThreadOperation) { if (_pendingOtherThreadOperation) {
PROFILE_RANGE(render, "MainThreadOp") PROFILE_RANGE(render, "MainThreadOp") {
{
Lock lock(_mutex); Lock lock(_mutex);
_context->doneCurrent(); _context->doneCurrent();
// Move the context to the main thread // Move the context to the main thread
@ -131,7 +123,6 @@ public:
_condition.notify_one(); _condition.notify_one();
} }
{ {
// Main thread does it's thing while we wait on the lock to release // Main thread does it's thing while we wait on the lock to release
Lock lock(_mutex); Lock lock(_mutex);
@ -201,7 +192,7 @@ public:
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
_context->doneCurrent(); _context->doneCurrent();
#endif #endif
_refreshRateController->sleepThreadIfNeeded(this, currentPlugin->isHmd()); _refreshRateController->sleepThreadIfNeeded(this, currentPlugin->isHmd());
} }
@ -235,23 +226,21 @@ public:
_condition.notify_one(); _condition.notify_one();
} }
private: private:
void makeCurrent(); void makeCurrent();
void doneCurrent(); void doneCurrent();
bool _shutdown { false }; bool _shutdown{ false };
Mutex _mutex; Mutex _mutex;
// Used to allow the main thread to perform context operations // Used to allow the main thread to perform context operations
Condition _condition; Condition _condition;
QThread* _targetOperationThread{ nullptr };
QThread* _targetOperationThread { nullptr }; bool _pendingOtherThreadOperation{ false };
bool _pendingOtherThreadOperation { false }; bool _finishedOtherThreadOperation{ false };
bool _finishedOtherThreadOperation { false };
std::queue<OpenGLDisplayPlugin*> _newPluginQueue; std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
gl::Context* _context { nullptr }; gl::Context* _context{ nullptr };
std::shared_ptr<RefreshRateController> _refreshRateController { nullptr }; std::shared_ptr<RefreshRateController> _refreshRateController{ nullptr };
}; };
bool OpenGLDisplayPlugin::activate() { bool OpenGLDisplayPlugin::activate() {
@ -302,7 +291,6 @@ bool OpenGLDisplayPlugin::activate() {
return false; return false;
} }
// This should not return until the new context has been customized // This should not return until the new context has been customized
// and the old context (if any) has been uncustomized // and the old context (if any) has been uncustomized
presentThread->setNewDisplayPlugin(this); presentThread->setNewDisplayPlugin(this);
@ -334,7 +322,7 @@ void OpenGLDisplayPlugin::deactivate() {
_container->showDisplayPluginsTools(false); _container->showDisplayPluginsTools(false);
if (!_container->currentDisplayActions().isEmpty()) { if (!_container->currentDisplayActions().isEmpty()) {
foreach(auto itemInfo, _container->currentDisplayActions()) { foreach (auto itemInfo, _container->currentDisplayActions()) {
_container->removeMenuItem(itemInfo.first, itemInfo.second); _container->removeMenuItem(itemInfo.first, itemInfo.second);
} }
_container->currentDisplayActions().clear(); _container->currentDisplayActions().clear();
@ -368,12 +356,9 @@ void OpenGLDisplayPlugin::customizeContext() {
image = image.convertToFormat(QImage::Format_ARGB32); image = image.convertToFormat(QImage::Format_ARGB32);
} }
if ((image.width() > 0) && (image.height() > 0)) { if ((image.width() > 0) && (image.height() > 0)) {
cursorData.texture = gpu::Texture::createStrict(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.width(),
cursorData.texture = gpu::Texture::createStrict( image.height(), gpu::Texture::MAX_NUM_MIPS,
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
image.width(), image.height(),
gpu::Texture::MAX_NUM_MIPS,
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR));
cursorData.texture->setSource("cursor texture"); cursorData.texture->setSource("cursor texture");
auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
cursorData.texture->setUsage(usage.build()); cursorData.texture->setUsage(usage.build());
@ -384,45 +369,39 @@ void OpenGLDisplayPlugin::customizeContext() {
} }
} }
if (!_drawTexturePipeline) { if (!_linearToSRGBPipeline) {
gpu::StatePointer blendState = gpu::StatePointer(new gpu::State()); gpu::StatePointer blendState = gpu::StatePointer(new gpu::State());
blendState->setDepthTest(gpu::State::DepthTest(false)); blendState->setDepthTest(gpu::State::DepthTest(false));
blendState->setBlendFunction(true, blendState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD,
gpu::State::ONE);
gpu::StatePointer scissorState = gpu::StatePointer(new gpu::State()); gpu::StatePointer scissorState = gpu::StatePointer(new gpu::State());
scissorState->setDepthTest(gpu::State::DepthTest(false)); scissorState->setDepthTest(gpu::State::DepthTest(false));
scissorState->setScissorEnable(true); scissorState->setScissorEnable(true);
_drawTexturePipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), scissorState); _drawTexturePipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), scissorState);
_linearToSRGBPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureGammaLinearToSRGB), scissorState); _linearToSRGBPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureGammaLinearToSRGB), scissorState);
_SRGBToLinearPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureGammaSRGBToLinear), scissorState); _SRGBToLinearPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureGammaSRGBToLinear), scissorState);
_hudPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), blendState); _hudPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), blendState);
_mirrorHUDPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureMirroredX), blendState); _mirrorHUDPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureMirroredX), blendState);
_cursorPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTransformedTexture), blendState); _cursorPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTransformedTexture), blendState);
} }
updateCompositeFramebuffer(); updateCompositeFramebuffer();
} }
void OpenGLDisplayPlugin::uncustomizeContext() { void OpenGLDisplayPlugin::uncustomizeContext() {
_drawTexturePipeline.reset(); _drawTexturePipeline.reset();
_linearToSRGBPipeline.reset(); _linearToSRGBPipeline.reset();
_SRGBToLinearPipeline.reset(); _SRGBToLinearPipeline.reset();
_cursorPipeline.reset();
_hudPipeline.reset(); _hudPipeline.reset();
_mirrorHUDPipeline.reset(); _mirrorHUDPipeline.reset();
_cursorPipeline.reset();
_compositeFramebuffer.reset(); _compositeFramebuffer.reset();
withPresentThreadLock([&] { withPresentThreadLock([&] {
_currentFrame.reset(); _currentFrame.reset();
_lastFrame = nullptr; _lastFrame = nullptr;
@ -433,7 +412,6 @@ void OpenGLDisplayPlugin::uncustomizeContext() {
}); });
} }
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // 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 // SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
// receive keyPress events for the Alt (and Meta) key in a reliable manner. // receive keyPress events for the Alt (and Meta) key in a reliable manner.
@ -477,9 +455,7 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
} }
void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) { void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) {
withNonPresentThreadLock([&] { withNonPresentThreadLock([&] { _newFrameQueue.push(newFrame); });
_newFrameQueue.push(newFrame);
});
} }
void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const { void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const {
@ -493,10 +469,10 @@ void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const {
image = QImage{ 1, 1, QImage::Format_ARGB32 }; image = QImage{ 1, 1, QImage::Format_ARGB32 };
auto storedImage = texture->accessStoredMipFace(0, 0); auto storedImage = texture->accessStoredMipFace(0, 0);
memcpy(image.bits(), storedImage->data(), image.sizeInBytes()); memcpy(image.bits(), storedImage->data(), image.sizeInBytes());
//if (texture == textureCache->getWhiteTexture()) { //if (texture == textureCache->getWhiteTexture()) {
//} else if (texture == textureCache->getBlackTexture()) { //} else if (texture == textureCache->getBlackTexture()) {
//} else if (texture == textureCache->getBlueTexture()) { //} else if (texture == textureCache->getBlueTexture()) {
//} else if (texture == textureCache->getGrayTexture()) { //} else if (texture == textureCache->getGrayTexture()) {
} else { } else {
ivec4 rect = { 0, 0, texture->getWidth(), texture->getHeight() }; ivec4 rect = { 0, 0, texture->getWidth(), texture->getHeight() };
framebuffer->setRenderBuffer(0, texture, layer); framebuffer->setRenderBuffer(0, texture, layer);
@ -514,11 +490,18 @@ void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const {
}); });
} }
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor) { void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch,
const gpu::TexturePointer& texture,
const glm::ivec4& viewport,
const glm::ivec4& scissor) {
renderFromTexture(batch, texture, viewport, scissor, nullptr); renderFromTexture(batch, texture, viewport, scissor, nullptr);
} }
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor, const gpu::FramebufferPointer& copyFbo /*=gpu::FramebufferPointer()*/) { void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch,
const gpu::TexturePointer& texture,
const glm::ivec4& viewport,
const glm::ivec4& scissor,
const gpu::FramebufferPointer& copyFbo /*=gpu::FramebufferPointer()*/) {
auto fbo = gpu::FramebufferPointer(); auto fbo = gpu::FramebufferPointer();
batch.enableStereo(false); batch.enableStereo(false);
batch.resetViewTransform(); batch.resetViewTransform();
@ -528,18 +511,18 @@ void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::Textur
batch.setViewportTransform(viewport); batch.setViewportTransform(viewport);
batch.setResourceTexture(0, texture); batch.setResourceTexture(0, texture);
batch.setPipeline(_drawTexturePipeline); batch.setPipeline(getRenderTexturePipeline());
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
if (copyFbo) { if (copyFbo) {
gpu::Vec4i copyFboRect(0, 0, copyFbo->getWidth(), copyFbo->getHeight()); gpu::Vec4i copyFboRect(0, 0, copyFbo->getWidth(), copyFbo->getHeight());
gpu::Vec4i sourceRect(scissor.x, scissor.y, scissor.x + scissor.z, scissor.y + scissor.w); gpu::Vec4i sourceRect(scissor.x, scissor.y, scissor.x + scissor.z, scissor.y + scissor.w);
float aspectRatio = (float)scissor.w / (float) scissor.z; // height/width float aspectRatio = (float)scissor.w / (float)scissor.z; // height/width
// scale width first // scale width first
int xOffset = 0; int xOffset = 0;
int yOffset = 0; int yOffset = 0;
int newWidth = copyFbo->getWidth(); int newWidth = copyFbo->getWidth();
int newHeight = std::round(aspectRatio * (float) copyFbo->getWidth()); int newHeight = std::round(aspectRatio * (float)copyFbo->getWidth());
if (newHeight > copyFbo->getHeight()) { if (newHeight > copyFbo->getHeight()) {
// ok, so now fill height instead // ok, so now fill height instead
newHeight = copyFbo->getHeight(); newHeight = copyFbo->getHeight();
@ -554,7 +537,7 @@ void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::Textur
batch.resetViewTransform(); batch.resetViewTransform();
batch.setViewportTransform(copyFboRect); batch.setViewportTransform(copyFboRect);
batch.setStateScissorRect(copyFboRect); batch.setStateScissorRect(copyFboRect);
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, {0.0f, 0.0f, 0.0f, 1.0f}); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, { 0.0f, 0.0f, 0.0f, 1.0f });
batch.blit(fbo, sourceRect, copyFbo, copyRect); batch.blit(fbo, sourceRect, copyFbo, copyRect);
} }
} }
@ -589,14 +572,11 @@ std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> OpenGL
auto hudStereo = isStereo(); auto hudStereo = isStereo();
auto hudCompositeFramebufferSize = _compositeFramebuffer->getSize(); auto hudCompositeFramebufferSize = _compositeFramebuffer->getSize();
std::array<glm::ivec4, 2> hudEyeViewports; std::array<glm::ivec4, 2> hudEyeViewports;
for_each_eye([&](Eye eye) { for_each_eye([&](Eye eye) { hudEyeViewports[eye] = eyeViewport(eye); });
hudEyeViewports[eye] = eyeViewport(eye);
});
return [=](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) { return [=](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
auto pipeline = mirror ? hudMirrorPipeline : hudPipeline; if (hudPipeline && hudTexture) {
if (pipeline && hudTexture) {
batch.enableStereo(false); batch.enableStereo(false);
batch.setPipeline(pipeline); batch.setPipeline(mirror ? hudMirrorPipeline : hudPipeline);
batch.setResourceTexture(0, hudTexture); batch.setResourceTexture(0, hudTexture);
if (hudStereo) { if (hudStereo) {
for_each_eye([&](Eye eye) { for_each_eye([&](Eye eye) {
@ -635,11 +615,6 @@ void OpenGLDisplayPlugin::compositePointer() {
}); });
} }
// Overridden by Basic2DWindowDisplayPlugin and OculusDisplayPlugin
gpu::PipelinePointer OpenGLDisplayPlugin::getCompositeScenePipeline() {
return _drawTexturePipeline;
}
void OpenGLDisplayPlugin::compositeScene() { void OpenGLDisplayPlugin::compositeScene() {
render([&](gpu::Batch& batch) { render([&](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);
@ -682,9 +657,10 @@ void OpenGLDisplayPlugin::internalPresent() {
render([&](gpu::Batch& batch) { render([&](gpu::Batch& batch) {
// Note: _displayTexture must currently be the same size as the display. // Note: _displayTexture must currently be the same size as the display.
uvec2 dims = _displayTexture ? uvec2(_displayTexture->getDimensions()) : getSurfacePixels(); uvec2 dims = _displayTexture ? uvec2(_displayTexture->getDimensions()) : getSurfacePixels();
auto viewport = ivec4(uvec2(0), dims); auto viewport = ivec4(uvec2(0), dims);
renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport, viewport); renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport,
}); viewport);
});
swapBuffers(); swapBuffers();
_presentRate.increment(); _presentRate.increment();
} }
@ -723,7 +699,7 @@ void OpenGLDisplayPlugin::present(const std::shared_ptr<RefreshRateController>&
compositeLayers(); compositeLayers();
} }
{ // If we have any snapshots this frame, handle them { // If we have any snapshots this frame, handle them
PROFILE_RANGE_EX(render, "snapshotOperators", 0xffff00ff, frameId) PROFILE_RANGE_EX(render, "snapshotOperators", 0xffff00ff, frameId)
while (!_currentFrame->snapshotOperators.empty()) { while (!_currentFrame->snapshotOperators.empty()) {
auto& snapshotOperator = _currentFrame->snapshotOperators.front(); auto& snapshotOperator = _currentFrame->snapshotOperators.front();
@ -765,7 +741,7 @@ float OpenGLDisplayPlugin::presentRate() const {
return _presentRate.rate(); return _presentRate.rate();
} }
std::function<void(int)> OpenGLDisplayPlugin::getRefreshRateOperator() { std::function<void(int)> OpenGLDisplayPlugin::getRefreshRateOperator() {
return [](int targetRefreshRate) { return [](int targetRefreshRate) {
auto refreshRateController = DependencyManager::get<PresentThread>()->getRefreshRateController(); auto refreshRateController = DependencyManager::get<PresentThread>()->getRefreshRateController();
refreshRateController->setRefreshRateLimitPeriod(targetRefreshRate); refreshRateController->setRefreshRateLimitPeriod(targetRefreshRate);
@ -781,7 +757,6 @@ float OpenGLDisplayPlugin::renderRate() const {
return _renderRate.rate(); return _renderRate.rate();
} }
void OpenGLDisplayPlugin::swapBuffers() { void OpenGLDisplayPlugin::swapBuffers() {
static auto context = _container->getPrimaryWidget()->context(); static auto context = _container->getPrimaryWidget()->context();
context->swapBuffers(); context->swapBuffers();
@ -818,7 +793,7 @@ QImage OpenGLDisplayPlugin::getScreenshot(float aspectRatio) {
} }
auto bestSize = size; auto bestSize = size;
uvec2 corner(0); uvec2 corner(0);
if (aspectRatio != 0.0f) { // Pick out the largest piece of the center that produces the requested width/height aspectRatio if (aspectRatio != 0.0f) { // Pick out the largest piece of the center that produces the requested width/height aspectRatio
if (ceil(size.y * aspectRatio) < size.x) { if (ceil(size.y * aspectRatio) < size.x) {
bestSize.x = round(size.y * aspectRatio); bestSize.x = round(size.y * aspectRatio);
} else { } else {
@ -869,9 +844,7 @@ void OpenGLDisplayPlugin::assertIsPresentThread() const {
} }
bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) { bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
withNonPresentThreadLock([&] { withNonPresentThreadLock([&] { _compositeHUDAlpha = _hudAlpha; });
_compositeHUDAlpha = _hudAlpha;
});
return Parent::beginFrameRender(frameIndex); return Parent::beginFrameRender(frameIndex);
} }
@ -909,27 +882,25 @@ void OpenGLDisplayPlugin::render(std::function<void(gpu::Batch& batch)> f) {
OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
} }
// Added this to allow desktop composite framebuffer to be RGBA while mobile is SRGBA
// Overridden by Basic2DWindowDisplayPlugin
// FIXME: Eventually it would be ideal to have both framebuffers be of the same type
gpu::Element OpenGLDisplayPlugin::getCompositeFBColorSpace() {
return gpu::Element::COLOR_RGBA_32;
}
void OpenGLDisplayPlugin::updateCompositeFramebuffer() { void OpenGLDisplayPlugin::updateCompositeFramebuffer() {
auto renderSize = glm::uvec2(getRecommendedRenderSize()); auto renderSize = glm::uvec2(getRecommendedRenderSize());
if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) { if (!_compositeFramebuffer || _compositeFramebuffer->getSize() != renderSize) {
_compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", getCompositeFBColorSpace(), renderSize.x, renderSize.y)); _compositeFramebuffer =
gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_RGBA_32,
renderSize.x, renderSize.y));
// _compositeFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("OpenGLDisplayPlugin::composite", gpu::Element::COLOR_SRGBA_32, renderSize.x, renderSize.y));
} }
} }
void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer networkTexture, QOpenGLFramebufferObject* target, GLsync* fenceSync) { void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer networkTexture,
QOpenGLFramebufferObject* target,
GLsync* fenceSync) {
#if !defined(USE_GLES) #if !defined(USE_GLES)
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend(); auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
withOtherThreadContext([&] { withOtherThreadContext([&] {
GLuint sourceTexture = glBackend->getTextureID(networkTexture->getGPUTexture()); GLuint sourceTexture = glBackend->getTextureID(networkTexture->getGPUTexture());
GLuint targetTexture = target->texture(); GLuint targetTexture = target->texture();
GLuint fbo[2] {0, 0}; GLuint fbo[2]{ 0, 0 };
// need mipmaps for blitting texture // need mipmaps for blitting texture
glGenerateTextureMipmap(sourceTexture); glGenerateTextureMipmap(sourceTexture);
@ -950,14 +921,13 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
// maintain aspect ratio, filling the width first if possible. If that makes the height too // maintain aspect ratio, filling the width first if possible. If that makes the height too
// much, fill height instead. TODO: only do this when texture changes // much, fill height instead. TODO: only do this when texture changes
GLint newX = 0; GLint newX = 0;
GLint newY = 0; GLint newY = 0;
float aspectRatio = (float)texHeight / (float)texWidth; float aspectRatio = (float)texHeight / (float)texWidth;
GLint newWidth = target->width(); GLint newWidth = target->width();
GLint newHeight = std::round(aspectRatio * (float) target->width()); GLint newHeight = std::round(aspectRatio * (float)target->width());
if (newHeight > target->height()) { if (newHeight > target->height()) {
newHeight = target->height(); newHeight = target->height();
newWidth = std::round((float)target->height() / aspectRatio); newWidth = std::round((float)target->height() / aspectRatio);
@ -966,7 +936,8 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
newY = (target->height() - newHeight) / 2; newY = (target->height() - newHeight) / 2;
} }
glBlitNamedFramebuffer(fbo[0], fbo[1], 0, 0, texWidth, texHeight, newX, newY, newX + newWidth, newY + newHeight, GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitNamedFramebuffer(fbo[0], fbo[1], 0, 0, texWidth, texHeight, newX, newY, newX + newWidth, newY + newHeight,
GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, GL_NEAREST);
// don't delete the textures! // don't delete the textures!
glDeleteFramebuffers(2, fbo); glDeleteFramebuffers(2, fbo);
@ -975,3 +946,14 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
#endif #endif
} }
gpu::PipelinePointer OpenGLDisplayPlugin::getRenderTexturePipeline() {
return _drawTexturePipeline;
}
gpu::PipelinePointer OpenGLDisplayPlugin::getCompositeScenePipeline() {
return _drawTexturePipeline;
}
gpu::Element OpenGLDisplayPlugin::getCompositeFBColorSpace() {
return gpu::Element::COLOR_RGBA_32;
}

View file

@ -23,11 +23,9 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
namespace gpu { namespace gpu { namespace gl {
namespace gl { class GLBackend;
class GLBackend; }} // namespace gpu::gl
}
}
class RefreshRateController; class RefreshRateController;
@ -35,10 +33,12 @@ class OpenGLDisplayPlugin : public DisplayPlugin {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float hudAlpha MEMBER _hudAlpha) Q_PROPERTY(float hudAlpha MEMBER _hudAlpha)
using Parent = DisplayPlugin; using Parent = DisplayPlugin;
protected: protected:
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
using Condition = std::condition_variable; using Condition = std::condition_variable;
public: public:
~OpenGLDisplayPlugin(); ~OpenGLDisplayPlugin();
// These must be final to ensure proper ordering of operations // These must be final to ensure proper ordering of operations
@ -55,13 +55,9 @@ public:
void captureFrame(const std::string& outputName) const override; void captureFrame(const std::string& outputName) const override;
void submitFrame(const gpu::FramePointer& newFrame) override; void submitFrame(const gpu::FramePointer& newFrame) override;
glm::uvec2 getRecommendedRenderSize() const override { glm::uvec2 getRecommendedRenderSize() const override { return getSurfacePixels(); }
return getSurfacePixels();
}
glm::uvec2 getRecommendedUiSize() const override { glm::uvec2 getRecommendedUiSize() const override { return getSurfaceSize(); }
return getSurfaceSize();
}
virtual bool setDisplayTexture(const QString& name) override; virtual bool setDisplayTexture(const QString& name) override;
virtual bool onDisplayTextureReset() { return false; }; virtual bool onDisplayTextureReset() { return false; };
@ -84,9 +80,9 @@ public:
// Three threads, one for rendering, one for texture transfers, one reserved for the GL driver // Three threads, one for rendering, one for texture transfers, one reserved for the GL driver
int getRequiredThreadCount() const override { return 3; } int getRequiredThreadCount() const override { return 3; }
void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override; void copyTextureToQuickFramebuffer(NetworkTexturePointer source,
QOpenGLFramebufferObject* target,
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator() override; GLsync* fenceSync) override;
protected: protected:
friend class PresentThread; friend class PresentThread;
@ -104,11 +100,9 @@ protected:
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; } virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
virtual void compositeLayers(); virtual void compositeLayers();
virtual void compositeScene(); virtual void compositeScene();
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
virtual void compositePointer(); virtual void compositePointer();
virtual void compositeExtra() {}; virtual void compositeExtra(){};
virtual gpu::PipelinePointer getCompositeScenePipeline();
virtual gpu::Element getCompositeFBColorSpace();
// These functions must only be called on the presentation thread // These functions must only be called on the presentation thread
virtual void customizeContext(); virtual void customizeContext();
@ -125,8 +119,15 @@ protected:
// Plugin specific functionality to send the composed scene to the output window or device // Plugin specific functionality to send the composed scene to the output window or device
virtual void internalPresent(); virtual void internalPresent();
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor, const gpu::FramebufferPointer& fbo); void renderFromTexture(gpu::Batch& batch,
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor); const gpu::TexturePointer& texture,
const glm::ivec4& viewport,
const glm::ivec4& scissor,
const gpu::FramebufferPointer& fbo);
void renderFromTexture(gpu::Batch& batch,
const gpu::TexturePointer& texture,
const glm::ivec4& viewport,
const glm::ivec4& scissor);
virtual void updateFrameData(); virtual void updateFrameData();
virtual glm::mat4 getViewCorrection() { return glm::mat4(); } virtual glm::mat4 getViewCorrection() { return glm::mat4(); }
@ -138,7 +139,7 @@ protected:
void render(std::function<void(gpu::Batch& batch)> f); void render(std::function<void(gpu::Batch& batch)> f);
bool _vsyncEnabled { true }; bool _vsyncEnabled{ true };
QThread* _presentThread{ nullptr }; QThread* _presentThread{ nullptr };
std::queue<gpu::FramePointer> _newFrameQueue; std::queue<gpu::FramePointer> _newFrameQueue;
RateCounter<200> _droppedFrameRate; RateCounter<200> _droppedFrameRate;
@ -147,7 +148,7 @@ protected:
RateCounter<200> _renderRate; RateCounter<200> _renderRate;
gpu::FramePointer _currentFrame; gpu::FramePointer _currentFrame;
gpu::Frame* _lastFrame { nullptr }; gpu::Frame* _lastFrame{ nullptr };
mat4 _prevRenderView; mat4 _prevRenderView;
gpu::FramebufferPointer _compositeFramebuffer; gpu::FramebufferPointer _compositeFramebuffer;
gpu::PipelinePointer _hudPipeline; gpu::PipelinePointer _hudPipeline;
@ -157,9 +158,12 @@ protected:
gpu::PipelinePointer _linearToSRGBPipeline; gpu::PipelinePointer _linearToSRGBPipeline;
gpu::PipelinePointer _SRGBToLinearPipeline; gpu::PipelinePointer _SRGBToLinearPipeline;
gpu::PipelinePointer _cursorPipeline; gpu::PipelinePointer _cursorPipeline;
gpu::TexturePointer _displayTexture{}; gpu::TexturePointer _displayTexture{};
float _compositeHUDAlpha { 1.0f }; float _compositeHUDAlpha{ 1.0f };
virtual gpu::PipelinePointer getRenderTexturePipeline();
virtual gpu::PipelinePointer getCompositeScenePipeline();
virtual gpu::Element getCompositeFBColorSpace();
struct CursorData { struct CursorData {
QImage image; QImage image;
@ -169,19 +173,19 @@ protected:
}; };
std::map<uint16_t, CursorData> _cursorsData; std::map<uint16_t, CursorData> _cursorsData;
bool _lockCurrentTexture { false }; bool _lockCurrentTexture{ false };
void assertNotPresentThread() const; void assertNotPresentThread() const;
void assertIsPresentThread() const; void assertIsPresentThread() const;
template<typename F> template <typename F>
void withPresentThreadLock(F f) const { void withPresentThreadLock(F f) const {
assertIsPresentThread(); assertIsPresentThread();
Lock lock(_presentMutex); Lock lock(_presentMutex);
f(); f();
} }
template<typename F> template <typename F>
void withNonPresentThreadLock(F f) const { void withNonPresentThreadLock(F f) const {
assertNotPresentThread(); assertNotPresentThread();
Lock lock(_presentMutex); Lock lock(_presentMutex);
@ -198,4 +202,3 @@ protected:
QImage getScreenshot(float aspectRatio); QImage getScreenshot(float aspectRatio);
QImage getSecondaryCameraScreenshot(); QImage getSecondaryCameraScreenshot();
}; };

View file

@ -167,6 +167,7 @@ void OculusDisplayPlugin::hmdPresent() {
batch.setStateScissorRect(ivec4(uvec2(), _outputFramebuffer->getSize())); batch.setStateScissorRect(ivec4(uvec2(), _outputFramebuffer->getSize()));
batch.resetViewTransform(); batch.resetViewTransform();
batch.setProjectionTransform(mat4()); batch.setProjectionTransform(mat4());
//batch.setPipeline(_drawTexturePipeline);
batch.setPipeline(_drawTexturePipeline); batch.setPipeline(_drawTexturePipeline);
batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0)); batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0));
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);

View file

@ -24,6 +24,8 @@ public:
virtual QJsonObject getHardwareStats() const; virtual QJsonObject getHardwareStats() const;
virtual gpu::PipelinePointer getCompositeScenePipeline() override;
protected: protected:
QThread::Priority getPresentPriority() override { return QThread::TimeCriticalPriority; } QThread::Priority getPresentPriority() override { return QThread::TimeCriticalPriority; }
@ -34,8 +36,6 @@ protected:
void uncustomizeContext() override; void uncustomizeContext() override;
void cycleDebugOutput() override; void cycleDebugOutput() override;
virtual gpu::PipelinePointer getCompositeScenePipeline() override;
private: private:
static const char* NAME; static const char* NAME;
ovrTextureSwapChain _textureSwapChain; ovrTextureSwapChain _textureSwapChain;