#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) 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; } if (layerIt->renderer) layerIt->renderer->ShutdownGl(); layerIt = mLayers.erase(layerIt); } for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers) { if (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; next.renderer = std::make_unique(); mLayers.push_back(std::move(next)); program = &mLayers.back(); } if (program->shaderId == layer.shaderId && program->sourceFingerprint == fingerprint && program->renderer && program->renderer->HasProgram()) continue; if (program->pendingFingerprint == fingerprint) continue; 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; } bool RuntimeRenderScene::HasLayers() { ConsumePreparedPrograms(); for (const std::string& layerId : mLayerOrder) { const LayerProgram* layer = FindLayer(layerId); if (layer && layer->renderer && layer->renderer->HasProgram()) return true; } return false; } void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height) { ConsumePreparedPrograms(); std::vector readyLayers; for (const std::string& layerId : mLayerOrder) { LayerProgram* layer = FindLayer(layerId); if (!layer || !layer->renderer || !layer->renderer->HasProgram()) continue; readyLayers.push_back(layer); } if (readyLayers.empty()) return; GLint outputFramebuffer = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &outputFramebuffer); if (readyLayers.size() == 1) { readyLayers.front()->renderer->RenderFrame(frameIndex, width, height); return; } if (!EnsureLayerTargets(width, height)) { glBindFramebuffer(GL_FRAMEBUFFER, static_cast(outputFramebuffer)); readyLayers.back()->renderer->RenderFrame(frameIndex, width, height); return; } GLuint layerInputTexture = 0; std::size_t nextTargetIndex = 0; for (std::size_t layerIndex = 0; layerIndex < readyLayers.size(); ++layerIndex) { const bool isFinalLayer = layerIndex == readyLayers.size() - 1; if (isFinalLayer) { glBindFramebuffer(GL_FRAMEBUFFER, static_cast(outputFramebuffer)); readyLayers[layerIndex]->renderer->RenderFrame(frameIndex, width, height, layerInputTexture, layerInputTexture); continue; } glBindFramebuffer(GL_FRAMEBUFFER, mLayerFramebuffers[nextTargetIndex]); readyLayers[layerIndex]->renderer->RenderFrame(frameIndex, width, height, layerInputTexture, layerInputTexture); layerInputTexture = mLayerTextures[nextTargetIndex]; nextTargetIndex = 1 - nextTargetIndex; } } void RuntimeRenderScene::ShutdownGl() { mPrepareWorker.Stop(); for (LayerProgram& layer : mLayers) { if (layer.renderer) layer.renderer->ShutdownGl(); } 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; } std::unique_ptr nextRenderer = std::make_unique(); std::string error; if (!nextRenderer->CommitPreparedProgram(preparedProgram, error)) { preparedProgram.ReleaseGl(); continue; } if (layer->renderer) layer->renderer->ShutdownGl(); layer->renderer = std::move(nextRenderer); layer->shaderId = preparedProgram.shaderId; layer->sourceFingerprint = preparedProgram.sourceFingerprint; layer->pendingFingerprint.clear(); } } bool RuntimeRenderScene::EnsureLayerTargets(unsigned width, unsigned height) { if (width == 0 || height == 0) return false; if (mLayerFramebuffers[0] != 0 && mLayerFramebuffers[1] != 0 && mLayerTextures[0] != 0 && mLayerTextures[1] != 0 && mLayerTargetWidth == width && mLayerTargetHeight == height) return true; DestroyLayerTargets(); mLayerTargetWidth = width; mLayerTargetHeight = height; glGenFramebuffers(2, mLayerFramebuffers); glGenTextures(2, mLayerTextures); for (int index = 0; index < 2; ++index) { glBindTexture(GL_TEXTURE_2D, mLayerTextures[index]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, static_cast(width), static_cast(height), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr); glBindFramebuffer(GL_FRAMEBUFFER, mLayerFramebuffers[index]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mLayerTextures[index], 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); DestroyLayerTargets(); return false; } } glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); return true; } void RuntimeRenderScene::DestroyLayerTargets() { if (mLayerFramebuffers[0] != 0 || mLayerFramebuffers[1] != 0) glDeleteFramebuffers(2, mLayerFramebuffers); if (mLayerTextures[0] != 0 || mLayerTextures[1] != 0) glDeleteTextures(2, mLayerTextures); mLayerFramebuffers[0] = 0; mLayerFramebuffers[1] = 0; mLayerTextures[0] = 0; mLayerTextures[1] = 0; mLayerTargetWidth = 0; mLayerTargetHeight = 0; } 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; } std::string RuntimeRenderScene::Fingerprint(const RuntimeShaderArtifact& artifact) { const std::hash hasher; return artifact.shaderId + ":" + std::to_string(artifact.fragmentShaderSource.size()) + ":" + std::to_string(hasher(artifact.fragmentShaderSource)); }