#include "RuntimeRenderScene.h" #include "../../platform/HiddenGlWindow.h" #include #include #include #ifndef GL_FRAMEBUFFER_BINDING #define GL_FRAMEBUFFER_BINDING 0x8CA6 #endif RuntimeRenderScene::~RuntimeRenderScene() { ShutdownGl(); } bool RuntimeRenderScene::StartPrepareWorker(std::unique_ptr sharedWindow, std::string& error) { return mPrepareWorker.Start(std::move(sharedWindow), error); } bool RuntimeRenderScene::CommitRenderLayers(const std::vector& layers, std::string& error) { ConsumePreparedPrograms(); std::vector nextOrder; std::vector layersToPrepare; nextOrder.reserve(layers.size()); for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers) { if (!layer.bypass) nextOrder.push_back(layer.id); } for (auto layerIt = mLayers.begin(); layerIt != mLayers.end();) { const bool stillPresent = std::find(nextOrder.begin(), nextOrder.end(), layerIt->layerId) != nextOrder.end(); if (stillPresent) { ++layerIt; continue; } for (LayerProgram::PassProgram& pass : layerIt->passes) { if (pass.renderer) pass.renderer->ShutdownGl(); } ReleasePendingPrograms(*layerIt); layerIt = mLayers.erase(layerIt); } for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers) { if (layer.bypass) continue; if (layer.artifact.passes.empty() && layer.artifact.fragmentShaderSource.empty()) continue; const std::string fingerprint = Fingerprint(layer.artifact); LayerProgram* program = FindLayer(layer.id); if (!program) { LayerProgram next; next.layerId = layer.id; mLayers.push_back(std::move(next)); program = &mLayers.back(); } bool hasReadyPass = false; for (const LayerProgram::PassProgram& pass : program->passes) { if (pass.renderer && pass.renderer->HasProgram()) { hasReadyPass = true; break; } } if (program->shaderId == layer.shaderId && program->sourceFingerprint == fingerprint && hasReadyPass) { for (LayerProgram::PassProgram& pass : program->passes) { if (pass.renderer) pass.renderer->UpdateArtifactState(layer.artifact); } continue; } if (program->pendingFingerprint == fingerprint) continue; ReleasePendingPrograms(*program); program->shaderId = layer.shaderId; program->pendingFingerprint = fingerprint; layersToPrepare.push_back(layer); } mLayerOrder = std::move(nextOrder); if (!layersToPrepare.empty()) mPrepareWorker.Submit(layersToPrepare); error.clear(); return true; } void RuntimeRenderScene::ShutdownGl() { mPrepareWorker.Stop(); for (LayerProgram& layer : mLayers) { for (LayerProgram::PassProgram& pass : layer.passes) { if (pass.renderer) pass.renderer->ShutdownGl(); } ReleasePendingPrograms(layer); } mLayers.clear(); mLayerOrder.clear(); DestroyLayerTargets(); } void RuntimeRenderScene::ConsumePreparedPrograms() { RuntimePreparedShaderProgram preparedProgram; while (mPrepareWorker.TryConsume(preparedProgram)) { if (!preparedProgram.succeeded) { preparedProgram.ReleaseGl(); continue; } LayerProgram* layer = FindLayer(preparedProgram.layerId); if (!layer || layer->pendingFingerprint != preparedProgram.sourceFingerprint) { preparedProgram.ReleaseGl(); continue; } bool replacesExistingPendingPass = false; for (RuntimePreparedShaderProgram& existing : layer->pendingPreparedPrograms) { if (existing.passId != preparedProgram.passId) continue; existing.ReleaseGl(); existing = std::move(preparedProgram); replacesExistingPendingPass = true; break; } if (!replacesExistingPendingPass) layer->pendingPreparedPrograms.push_back(std::move(preparedProgram)); TryCommitPendingPrograms(*layer); } } void RuntimeRenderScene::ReleasePendingPrograms(LayerProgram& layer) { for (RuntimePreparedShaderProgram& program : layer.pendingPreparedPrograms) program.ReleaseGl(); layer.pendingPreparedPrograms.clear(); } void RuntimeRenderScene::TryCommitPendingPrograms(LayerProgram& layer) { if (layer.pendingPreparedPrograms.empty()) return; const RuntimeShaderArtifact& artifact = layer.pendingPreparedPrograms.front().artifact; const std::size_t expectedPassCount = artifact.passes.empty() ? 1 : artifact.passes.size(); if (layer.pendingPreparedPrograms.size() < expectedPassCount) return; std::vector nextPasses; nextPasses.reserve(expectedPassCount); for (const RuntimeShaderPassArtifact& passArtifact : artifact.passes) { auto preparedIt = std::find_if( layer.pendingPreparedPrograms.begin(), layer.pendingPreparedPrograms.end(), [&passArtifact](const RuntimePreparedShaderProgram& prepared) { return prepared.passId == passArtifact.passId; }); if (preparedIt == layer.pendingPreparedPrograms.end()) return; std::unique_ptr nextRenderer = std::make_unique(); std::string error; if (!nextRenderer->CommitPreparedProgram(*preparedIt, error)) { ReleasePendingPrograms(layer); return; } LayerProgram::PassProgram nextPass; nextPass.passId = preparedIt->passId; nextPass.inputNames = preparedIt->inputNames; nextPass.outputName = preparedIt->outputName.empty() ? preparedIt->passId : preparedIt->outputName; nextPass.renderer = std::move(nextRenderer); nextPasses.push_back(std::move(nextPass)); } if (artifact.passes.empty()) { RuntimePreparedShaderProgram& prepared = layer.pendingPreparedPrograms.front(); std::unique_ptr nextRenderer = std::make_unique(); std::string error; if (!nextRenderer->CommitPreparedProgram(prepared, error)) { ReleasePendingPrograms(layer); return; } LayerProgram::PassProgram nextPass; nextPass.passId = prepared.passId; nextPass.inputNames = prepared.inputNames; nextPass.outputName = prepared.outputName.empty() ? prepared.passId : prepared.outputName; nextPass.renderer = std::move(nextRenderer); nextPasses.push_back(std::move(nextPass)); } for (LayerProgram::PassProgram& pass : layer.passes) { if (pass.renderer) pass.renderer->ShutdownGl(); } layer.passes = std::move(nextPasses); layer.shaderId = artifact.shaderId; layer.sourceFingerprint = layer.pendingPreparedPrograms.front().sourceFingerprint; layer.pendingFingerprint.clear(); layer.pendingPreparedPrograms.clear(); } RuntimeRenderScene::LayerProgram* RuntimeRenderScene::FindLayer(const std::string& layerId) { for (LayerProgram& layer : mLayers) { if (layer.layerId == layerId) return &layer; } return nullptr; } const RuntimeRenderScene::LayerProgram* RuntimeRenderScene::FindLayer(const std::string& layerId) const { for (const LayerProgram& layer : mLayers) { if (layer.layerId == layerId) return &layer; } return nullptr; } RuntimeRenderScene::LayerProgram::PassProgram* RuntimeRenderScene::FindPass(LayerProgram& layer, const std::string& passId) { for (LayerProgram::PassProgram& pass : layer.passes) { if (pass.passId == passId) return &pass; } return nullptr; } std::string RuntimeRenderScene::Fingerprint(const RuntimeShaderArtifact& artifact) { const std::hash hasher; std::string source; for (const RuntimeShaderPassArtifact& pass : artifact.passes) source += pass.passId + ":" + pass.outputName + ":" + pass.fragmentShaderSource + "\n"; if (source.empty()) source = artifact.fragmentShaderSource; return artifact.shaderId + ":" + std::to_string(source.size()) + ":" + std::to_string(hasher(source)); }