mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #14419 from SamGondelman/splash
Case 19740: Improve startup times by pre-compiling shaders with splash screen
This commit is contained in:
commit
0a80c16686
14 changed files with 148 additions and 345 deletions
|
@ -1,47 +1,32 @@
|
|||
const vec3 COLOR = vec3(0x00, 0xD8, 0x02) / vec3(0xFF);
|
||||
const float CUTOFF = 0.65;
|
||||
const float NOISE_MULT = 8.0;
|
||||
const float NOISE_POWER = 1.0;
|
||||
// Replicate the default skybox texture
|
||||
|
||||
float noise4D(vec4 p) {
|
||||
return fract(sin(dot(p ,vec4(12.9898,78.233,126.7235, 593.2241))) * 43758.5453);
|
||||
}
|
||||
|
||||
float worley4D(vec4 p) {
|
||||
float r = 3.0;
|
||||
vec4 f = floor(p);
|
||||
vec4 x = fract(p);
|
||||
for(int i = -1; i<=1; i++)
|
||||
{
|
||||
for(int j = -1; j<=1; j++)
|
||||
{
|
||||
for(int k = -1; k<=1; k++)
|
||||
{
|
||||
for (int l = -1; l <= 1; l++) {
|
||||
vec4 q = vec4(float(i),float(j),float(k), float(l));
|
||||
vec4 v = q + vec4(noise4D((q+f)*1.11), noise4D((q+f)*1.14), noise4D((q+f)*1.17), noise4D((q+f)*1.20)) - x;
|
||||
float d = dot(v, v);
|
||||
r = min(r, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqrt(r);
|
||||
}
|
||||
|
||||
|
||||
vec3 mainColor(vec3 direction) {
|
||||
float n = worley4D(vec4(direction * NOISE_MULT, iGlobalTime / 3.0));
|
||||
n = 1.0 - n;
|
||||
n = pow(n, NOISE_POWER);
|
||||
if (n < CUTOFF) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
|
||||
n = (n - CUTOFF) / (1.0 - CUTOFF);
|
||||
return COLOR * (1.0 - n);
|
||||
}
|
||||
const int NUM_COLORS = 5;
|
||||
const vec3 WHITISH = vec3(0.471, 0.725, 0.825);
|
||||
const vec3 GREENISH = vec3(0.157, 0.529, 0.588);
|
||||
const vec3 COLORS[NUM_COLORS] = vec3[](
|
||||
GREENISH,
|
||||
GREENISH,
|
||||
WHITISH,
|
||||
WHITISH,
|
||||
vec3(0.6, 0.275, 0.706) // purple
|
||||
);
|
||||
const float PI = 3.14159265359;
|
||||
const vec3 BLACK = vec3(0.0);
|
||||
const vec3 SPACE_BLUE = vec3(0.0, 0.118, 0.392);
|
||||
const float HORIZONTAL_OFFSET = 3.75;
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
return mainColor(normalize(_normal));
|
||||
vec2 horizontal = vec2(_normal.x, _normal.z);
|
||||
horizontal = normalize(horizontal);
|
||||
float theta = atan(horizontal.y, horizontal.x);
|
||||
theta = 0.5 * (theta / PI + 1.0);
|
||||
float index = theta * NUM_COLORS;
|
||||
index = mod(index + HORIZONTAL_OFFSET, NUM_COLORS);
|
||||
int index1 = int(index) % NUM_COLORS;
|
||||
int index2 = (index1 + 1) % NUM_COLORS;
|
||||
vec3 horizonColor = mix(COLORS[index1], COLORS[index2], index - index1);
|
||||
horizonColor = mix(horizonColor, SPACE_BLUE, smoothstep(0.0, 0.08, _normal.y));
|
||||
horizonColor = mix(horizonColor, BLACK, smoothstep(0.04, 0.15, _normal.y));
|
||||
horizonColor = mix(BLACK, horizonColor, smoothstep(-0.01, 0.0, _normal.y));
|
||||
return pow(horizonColor, vec3(0.4545));;
|
||||
}
|
||||
|
|
|
@ -150,7 +150,6 @@
|
|||
#include <trackers/EyeTracker.h>
|
||||
#include <avatars-renderer/ScriptAvatar.h>
|
||||
#include <RenderableEntityItem.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <model-networking/MaterialCache.h>
|
||||
#include "recording/ClipCache.h"
|
||||
|
||||
|
@ -2819,8 +2818,6 @@ void Application::initializeGL() {
|
|||
_graphicsEngine.initializeGPU(_glWidget);
|
||||
}
|
||||
|
||||
static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
|
||||
|
||||
void Application::initializeDisplayPlugins() {
|
||||
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
|
||||
Setting::Handle<QString> activeDisplayPluginSetting{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME, displayPlugins.at(0)->getName() };
|
||||
|
@ -2856,45 +2853,6 @@ void Application::initializeDisplayPlugins() {
|
|||
|
||||
// Submit a default frame to render until the engine starts up
|
||||
updateRenderArgs(0.0f);
|
||||
|
||||
#define ENABLE_SPLASH_FRAME 0
|
||||
#if ENABLE_SPLASH_FRAME
|
||||
{
|
||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
|
||||
if (_appRenderArgs._isStereo) {
|
||||
_gpuContext->enableStereo(true);
|
||||
_gpuContext->setStereoProjections(_appRenderArgs._eyeProjections);
|
||||
_gpuContext->setStereoViews(_appRenderArgs._eyeOffsets);
|
||||
}
|
||||
|
||||
// Frame resources
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
gpu::FramebufferPointer finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
std::shared_ptr<ProceduralSkybox> procedural = std::make_shared<ProceduralSkybox>();
|
||||
procedural->parse(SPLASH_SKYBOX);
|
||||
|
||||
_gpuContext->beginFrame(_appRenderArgs._view, _appRenderArgs._headPose);
|
||||
gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, { 0, 0, 0, 1 });
|
||||
batch.enableSkybox(true);
|
||||
batch.enableStereo(_appRenderArgs._isStereo);
|
||||
batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() });
|
||||
procedural->render(batch, _appRenderArgs._renderArgs.getViewFrustum());
|
||||
});
|
||||
auto frame = _gpuContext->endFrame();
|
||||
frame->frameIndex = 0;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->pose = _appRenderArgs._headPose;
|
||||
frame->framebufferRecycler = [framebufferCache, procedural](const gpu::FramebufferPointer& framebuffer) {
|
||||
framebufferCache->releaseFramebuffer(framebuffer);
|
||||
};
|
||||
_displayPlugin->submitFrame(frame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::initializeRenderEngine() {
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
#include "workload/GameWorkload.h"
|
||||
#include "graphics/GraphicsEngine.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <graphics/Skybox.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
|
||||
|
@ -761,5 +760,6 @@ private:
|
|||
|
||||
bool _showTrackedObjects { false };
|
||||
bool _prevShowTrackedObjects { false };
|
||||
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
//
|
||||
// Application_render.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Copyright 2013 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 "Application.h"
|
||||
#include <MainWindow.h>
|
||||
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include "ui/Stats.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
//void Application::paintGL() {
|
||||
// // Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
//
|
||||
// _renderFrameCount++;
|
||||
// // SG: Moved into the RenderEventHandler
|
||||
// //_lastTimeRendered.start();
|
||||
//
|
||||
// auto lastPaintBegin = usecTimestampNow();
|
||||
// PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
||||
// PerformanceTimer perfTimer("paintGL");
|
||||
//
|
||||
// if (nullptr == _displayPlugin) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// DisplayPluginPointer displayPlugin;
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||
// displayPlugin = getActiveDisplayPlugin();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||
// // If a display plugin loses it's underlying support, it
|
||||
// // needs to be able to signal us to not use it
|
||||
// if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
||||
// QMetaObject::invokeMethod(this, "updateDisplayMode");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// RenderArgs renderArgs;
|
||||
// glm::mat4 HMDSensorPose;
|
||||
// glm::mat4 eyeToWorld;
|
||||
// glm::mat4 sensorToWorld;
|
||||
//
|
||||
// bool isStereo;
|
||||
// glm::mat4 stereoEyeOffsets[2];
|
||||
// glm::mat4 stereoEyeProjections[2];
|
||||
//
|
||||
// {
|
||||
// QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
// renderArgs = _appRenderArgs._renderArgs;
|
||||
//
|
||||
// // don't render if there is no context.
|
||||
// if (!_appRenderArgs._renderArgs._context) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// HMDSensorPose = _appRenderArgs._headPose;
|
||||
// eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||
// sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||
// isStereo = _appRenderArgs._isStereo;
|
||||
// for_each_eye([&](Eye eye) {
|
||||
// stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||
// stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/gpuContextReset");
|
||||
// _graphicsEngine.getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose);
|
||||
// // Reset the gpu::Context Stages
|
||||
// // Back to the default framebuffer;
|
||||
// gpu::doInBatch("Application_render::gpuContextReset", _graphicsEngine.getGPUContext(), [&](gpu::Batch& batch) {
|
||||
// batch.resetStages();
|
||||
// });
|
||||
// }
|
||||
//
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/renderOverlay");
|
||||
// PerformanceTimer perfTimer("renderOverlay");
|
||||
// // NOTE: There is no batch associated with this renderArgs
|
||||
// // the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
// renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize() * getRenderResolutionScale());
|
||||
// _applicationOverlay.renderOverlay(&renderArgs);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/updateCompositor");
|
||||
// getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
// }
|
||||
//
|
||||
// gpu::FramebufferPointer finalFramebuffer;
|
||||
// QSize finalFramebufferSize;
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||
// // Primary rendering pass
|
||||
// auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
// finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||
// // Final framebuffer that will be handled to the display-plugin
|
||||
// finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// if (isStereo) {
|
||||
// renderArgs._context->enableStereo(true);
|
||||
// renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
// renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
// }
|
||||
//
|
||||
// renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
// renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
|
||||
// renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
// _graphicsEngine.render_runRenderFrame(&renderArgs);
|
||||
// }
|
||||
//
|
||||
// auto frame = _graphicsEngine.getGPUContext()->endFrame();
|
||||
// frame->frameIndex = _renderFrameCount;
|
||||
// frame->framebuffer = finalFramebuffer;
|
||||
// frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
// auto frameBufferCache = DependencyManager::get<FramebufferCache>();
|
||||
// if (frameBufferCache) {
|
||||
// frameBufferCache->releaseFramebuffer(framebuffer);
|
||||
// }
|
||||
// };
|
||||
// // deliver final scene rendering commands to the display plugin
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/pluginOutput");
|
||||
// PerformanceTimer perfTimer("pluginOutput");
|
||||
// _renderLoopCounter.increment();
|
||||
// displayPlugin->submitFrame(frame);
|
||||
// }
|
||||
//
|
||||
// // Reset the framebuffer and stereo state
|
||||
// renderArgs._blitFramebuffer.reset();
|
||||
// renderArgs._context->enableStereo(false);
|
||||
//
|
||||
// {
|
||||
// Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||
// }
|
||||
//
|
||||
// uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||
// _frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||
//}
|
||||
|
||||
|
||||
// WorldBox Render Data & rendering functions
|
||||
//
|
||||
//class WorldBoxRenderData {
|
||||
//public:
|
||||
// typedef render::Payload<WorldBoxRenderData> Payload;
|
||||
// typedef Payload::DataPointer Pointer;
|
||||
//
|
||||
// int _val = 0;
|
||||
// static render::ItemID _item; // unique WorldBoxRenderData
|
||||
//};
|
||||
//
|
||||
//render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||
//
|
||||
//namespace render {
|
||||
// template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
// template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
// template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
// if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
// PerformanceTimer perfTimer("worldBox");
|
||||
//
|
||||
// auto& batch = *args->_batch;
|
||||
// DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||
// renderWorldBox(args, batch);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void Application::runRenderFrame(RenderArgs* renderArgs) {
|
||||
// PROFILE_RANGE(render, __FUNCTION__);
|
||||
// PerformanceTimer perfTimer("display");
|
||||
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
|
||||
//
|
||||
// // The pending changes collecting the changes here
|
||||
// render::Transaction transaction;
|
||||
//
|
||||
// if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
// // render models...
|
||||
// PerformanceTimer perfTimer("entities");
|
||||
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
// "Application::runRenderFrame() ... entities...");
|
||||
//
|
||||
// RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
//
|
||||
// renderArgs->_debugFlags = renderDebugFlags;
|
||||
// }
|
||||
//
|
||||
// // Make sure the WorldBox is in the scene
|
||||
// // For the record, this one RenderItem is the first one we created and added to the scene.
|
||||
// // We could move that code elsewhere but you know...
|
||||
// if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||
// auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
|
||||
// auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||
//
|
||||
// WorldBoxRenderData::_item = _main3DScene->allocateID();
|
||||
//
|
||||
// transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||
// _main3DScene->enqueueTransaction(transaction);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PerformanceTimer perfTimer("EngineRun");
|
||||
// _renderEngine->getRenderContext()->args = renderArgs;
|
||||
// _renderEngine->run();
|
||||
// }
|
||||
//}
|
||||
|
|
@ -34,6 +34,8 @@
|
|||
#include "Application.h"
|
||||
|
||||
GraphicsEngine::GraphicsEngine() {
|
||||
const QString SPLASH_SKYBOX { "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
|
||||
_splashScreen->parse(SPLASH_SKYBOX);
|
||||
}
|
||||
|
||||
GraphicsEngine::~GraphicsEngine() {
|
||||
|
@ -54,6 +56,10 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
|
|||
glwidget->makeCurrent();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
_gpuContext->pushProgramsToSync(shader::allPrograms(), [this] {
|
||||
_programsCompiled.store(true);
|
||||
}, 1);
|
||||
|
||||
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
|
||||
}
|
||||
|
||||
|
@ -122,11 +128,7 @@ void GraphicsEngine::render_runRenderFrame(RenderArgs* renderArgs) {
|
|||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
||||
|
||||
|
||||
|
||||
bool GraphicsEngine::shouldPaint() const {
|
||||
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
|
||||
#ifdef DEBUG_PAINT_DELAY
|
||||
|
@ -145,7 +147,7 @@ bool GraphicsEngine::shouldPaint() const {
|
|||
|
||||
// Throttle if requested
|
||||
//if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
if ( displayPlugin->isThrottled() &&
|
||||
if (displayPlugin->isThrottled() &&
|
||||
(static_cast<RenderEventHandler*>(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -158,8 +160,6 @@ bool GraphicsEngine::checkPendingRenderEvent() {
|
|||
return (_renderEventHandler && static_cast<RenderEventHandler*>(_renderEventHandler)->_pendingRenderEvent.compare_exchange_strong(expected, true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GraphicsEngine::render_performFrame() {
|
||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
|
||||
|
@ -189,6 +189,7 @@ void GraphicsEngine::render_performFrame() {
|
|||
glm::mat4 HMDSensorPose;
|
||||
glm::mat4 eyeToWorld;
|
||||
glm::mat4 sensorToWorld;
|
||||
ViewFrustum viewFrustum;
|
||||
|
||||
bool isStereo;
|
||||
glm::mat4 stereoEyeOffsets[2];
|
||||
|
@ -211,6 +212,7 @@ void GraphicsEngine::render_performFrame() {
|
|||
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||
});
|
||||
viewFrustum = _appRenderArgs._renderArgs.getViewFrustum();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -221,21 +223,12 @@ void GraphicsEngine::render_performFrame() {
|
|||
gpu::doInBatch("Application_render::gpuContextReset", getGPUContext(), [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/renderOverlay");
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
// NOTE: There is no batch associated with this renderArgs
|
||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize());
|
||||
qApp->getApplicationOverlay().renderOverlay(&renderArgs);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/updateCompositor");
|
||||
qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
if (isStereo) {
|
||||
renderArgs._context->enableStereo(true);
|
||||
renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer finalFramebuffer;
|
||||
|
@ -245,21 +238,40 @@ void GraphicsEngine::render_performFrame() {
|
|||
// Primary rendering pass
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
// Final framebuffer that will be handed to the display-plugin
|
||||
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
}
|
||||
|
||||
{
|
||||
if (isStereo) {
|
||||
renderArgs._context->enableStereo(true);
|
||||
renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
if (!_programsCompiled.load()) {
|
||||
gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.enableSkybox(true);
|
||||
batch.enableStereo(isStereo);
|
||||
batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() });
|
||||
_splashScreen->render(batch, viewFrustum);
|
||||
});
|
||||
} else {
|
||||
{
|
||||
PROFILE_RANGE(render, "/renderOverlay");
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
// NOTE: There is no batch associated with this renderArgs
|
||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize());
|
||||
qApp->getApplicationOverlay().renderOverlay(&renderArgs);
|
||||
}
|
||||
|
||||
renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
render_runRenderFrame(&renderArgs);
|
||||
{
|
||||
PROFILE_RANGE(render, "/updateCompositor");
|
||||
qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/runRenderFrame");
|
||||
renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
render_runRenderFrame(&renderArgs);
|
||||
}
|
||||
}
|
||||
|
||||
auto frame = getGPUContext()->endFrame();
|
||||
|
@ -283,18 +295,19 @@ void GraphicsEngine::render_performFrame() {
|
|||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
|
||||
#if !defined(DISABLE_QML)
|
||||
{
|
||||
auto stats = Stats::getInstance();
|
||||
if (stats) {
|
||||
stats->setRenderDetails(renderArgs._details);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||
}
|
||||
|
||||
|
||||
void GraphicsEngine::editRenderArgs(RenderArgsEditor editor) {
|
||||
QMutexLocker renderLocker(&_renderArgsMutex);
|
||||
editor(_appRenderArgs);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <qmutex.h>
|
||||
|
||||
#include <render/Engine.h>
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
|
||||
#include <OctreeConstants.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
@ -84,6 +85,9 @@ protected:
|
|||
|
||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||
|
||||
std::shared_ptr<ProceduralSkybox> _splashScreen { std::make_shared<ProceduralSkybox>() };
|
||||
std::atomic<bool> _programsCompiled { false };
|
||||
|
||||
friend class Application;
|
||||
};
|
||||
|
||||
|
|
|
@ -525,6 +525,9 @@ void OpenGLDisplayPlugin::updateFrameData() {
|
|||
if (_newFrameQueue.size() > 1) {
|
||||
_droppedFrameRate.increment(_newFrameQueue.size() - 1);
|
||||
}
|
||||
|
||||
_gpuContext->processProgramsToSync();
|
||||
|
||||
while (!_newFrameQueue.empty()) {
|
||||
_currentFrame = _newFrameQueue.front();
|
||||
_newFrameQueue.pop();
|
||||
|
@ -645,6 +648,7 @@ void OpenGLDisplayPlugin::present() {
|
|||
auto frameId = (uint64_t)presentCount();
|
||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId)
|
||||
uint64_t startPresent = usecTimestampNow();
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId)
|
||||
updateFrameData();
|
||||
|
@ -837,7 +841,6 @@ void OpenGLDisplayPlugin::render(std::function<void(gpu::Batch& batch)> f) {
|
|||
_gpuContext->executeBatch(batch);
|
||||
}
|
||||
|
||||
|
||||
OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
|
||||
}
|
||||
|
||||
|
|
|
@ -859,3 +859,7 @@ void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRend
|
|||
_pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction);
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
}
|
||||
|
||||
void GLBackend::syncProgram(const gpu::ShaderPointer& program) {
|
||||
gpu::gl::GLShader::sync(*this, *program);
|
||||
}
|
|
@ -249,6 +249,8 @@ public:
|
|||
// Let's try to avoid to do that as much as possible!
|
||||
void syncCache() final override;
|
||||
|
||||
void syncProgram(const gpu::ShaderPointer& program) override;
|
||||
|
||||
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
||||
// Just avoid using it, it's ugly and will break performances
|
||||
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer,
|
||||
|
|
|
@ -37,6 +37,7 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader:
|
|||
if (object) {
|
||||
return object;
|
||||
}
|
||||
PROFILE_RANGE(render, "/GLShader::sync");
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader, handler);
|
||||
|
|
|
@ -760,4 +760,4 @@ void Batch::flush() {
|
|||
}
|
||||
buffer->flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@ Context::~Context() {
|
|||
delete batch;
|
||||
}
|
||||
_batchPool.clear();
|
||||
_syncedPrograms.clear();
|
||||
}
|
||||
|
||||
void Context::shutdown() {
|
||||
|
@ -346,6 +347,40 @@ Size Context::getTextureResourceIdealGPUMemSize() {
|
|||
return Backend::textureResourceIdealGPUMemSize.getValue();
|
||||
}
|
||||
|
||||
void Context::pushProgramsToSync(const std::vector<uint32_t>& programIDs, std::function<void()> callback, size_t rate) {
|
||||
std::vector<gpu::ShaderPointer> programs;
|
||||
for (auto programID : programIDs) {
|
||||
programs.push_back(gpu::Shader::createProgram(programID));
|
||||
}
|
||||
pushProgramsToSync(programs, callback, rate);
|
||||
}
|
||||
|
||||
void Context::pushProgramsToSync(const std::vector<gpu::ShaderPointer>& programs, std::function<void()> callback, size_t rate) {
|
||||
Lock lock(_programsToSyncMutex);
|
||||
_programsToSyncQueue.emplace(programs, callback, rate == 0 ? programs.size() : rate);
|
||||
}
|
||||
|
||||
void Context::processProgramsToSync() {
|
||||
if (!_programsToSyncQueue.empty()) {
|
||||
Lock lock(_programsToSyncMutex);
|
||||
ProgramsToSync programsToSync = _programsToSyncQueue.front();
|
||||
size_t numSynced = 0;
|
||||
while (_nextProgramToSyncIndex < programsToSync.programs.size() && numSynced < programsToSync.rate) {
|
||||
auto nextProgram = programsToSync.programs.at(_nextProgramToSyncIndex);
|
||||
_backend->syncProgram(nextProgram);
|
||||
_syncedPrograms.push_back(nextProgram);
|
||||
_nextProgramToSyncIndex++;
|
||||
numSynced++;
|
||||
}
|
||||
|
||||
if (_nextProgramToSyncIndex == programsToSync.programs.size()) {
|
||||
programsToSync.callback();
|
||||
_nextProgramToSyncIndex = 0;
|
||||
_programsToSyncQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BatchPointer Context::acquireBatch(const char* name) {
|
||||
Batch* rawBatch = nullptr;
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
|
@ -61,6 +62,7 @@ public:
|
|||
|
||||
virtual void render(const Batch& batch) = 0;
|
||||
virtual void syncCache() = 0;
|
||||
virtual void syncProgram(const gpu::ShaderPointer& program) = 0;
|
||||
virtual void recycle() const = 0;
|
||||
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0;
|
||||
|
||||
|
@ -247,6 +249,20 @@ public:
|
|||
static Size getTextureResourcePopulatedGPUMemSize();
|
||||
static Size getTextureResourceIdealGPUMemSize();
|
||||
|
||||
struct ProgramsToSync {
|
||||
ProgramsToSync(const std::vector<gpu::ShaderPointer>& programs, std::function<void()> callback, size_t rate) :
|
||||
programs(programs), callback(callback), rate(rate) {}
|
||||
|
||||
std::vector<gpu::ShaderPointer> programs;
|
||||
std::function<void()> callback;
|
||||
size_t rate;
|
||||
};
|
||||
|
||||
void pushProgramsToSync(const std::vector<uint32_t>& programIDs, std::function<void()> callback, size_t rate = 0);
|
||||
void pushProgramsToSync(const std::vector<gpu::ShaderPointer>& programs, std::function<void()> callback, size_t rate = 0);
|
||||
|
||||
void processProgramsToSync();
|
||||
|
||||
protected:
|
||||
Context(const Context& context);
|
||||
|
||||
|
@ -258,6 +274,11 @@ protected:
|
|||
RangeTimerPointer _frameRangeTimer;
|
||||
StereoState _stereo;
|
||||
|
||||
std::mutex _programsToSyncMutex;
|
||||
std::queue<ProgramsToSync> _programsToSyncQueue;
|
||||
gpu::Shaders _syncedPrograms;
|
||||
size_t _nextProgramToSyncIndex { 0 };
|
||||
|
||||
// Sampled at the end of every frame, the stats of all the counters
|
||||
mutable ContextStats _frameStats;
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
// Let's try to avoid to do that as much as possible!
|
||||
void syncCache() final { }
|
||||
|
||||
void syncProgram(const gpu::ShaderPointer& program) final {}
|
||||
|
||||
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
||||
// Just avoid using it, it's ugly and will break performances
|
||||
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final { }
|
||||
|
|
Loading…
Reference in a new issue