Merge pull request #14419 from SamGondelman/splash

Case 19740: Improve startup times by pre-compiling shaders with splash screen
This commit is contained in:
John Conklin II 2018-12-07 16:10:52 -08:00 committed by GitHub
commit 0a80c16686
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 148 additions and 345 deletions

View file

@ -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));;
}

View file

@ -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() {

View file

@ -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

View file

@ -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();
// }
//}

View file

@ -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);

View file

@ -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;
};

View file

@ -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() {
}

View file

@ -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);
}

View file

@ -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,

View file

@ -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);

View file

@ -760,4 +760,4 @@ void Batch::flush() {
}
buffer->flush();
}
}
}

View file

@ -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;
{

View file

@ -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;

View file

@ -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 { }