From b061a7ead4ad223bcda3549e9fb63151b2852c54 Mon Sep 17 00:00:00 2001 From: vladislavbelov Date: Thu, 6 Jan 2022 22:44:54 +0000 Subject: [PATCH] Optimizes FBO usages for LOSTexture and water shore foam. Tested By: Stan Differential Revision: https://code.wildfiregames.com/D4418 This was SVN commit r26180. --- source/graphics/LOSTexture.cpp | 50 ++++++++++++--------- source/graphics/LOSTexture.h | 15 ++++--- source/renderer/SceneRenderer.cpp | 4 ++ source/renderer/TerrainRenderer.cpp | 69 ++++++++++++++--------------- source/renderer/TerrainRenderer.h | 7 ++- 5 files changed, 80 insertions(+), 65 deletions(-) diff --git a/source/graphics/LOSTexture.cpp b/source/graphics/LOSTexture.cpp index 6790ec93e4..88599b1340 100644 --- a/source/graphics/LOSTexture.cpp +++ b/source/graphics/LOSTexture.cpp @@ -60,8 +60,7 @@ static const size_t g_BlurSize = 7; static const size_t g_SubTextureAlignment = 4; CLOSTexture::CLOSTexture(CSimulation2& simulation) - : m_Simulation(simulation), m_Dirty(true), m_ShaderInitialized(false), - m_SmoothFBO(0), m_MapSize(0), m_WhichTex(true) + : m_Simulation(simulation) { if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS()) CreateShader(); @@ -69,8 +68,10 @@ CLOSTexture::CLOSTexture(CSimulation2& simulation) CLOSTexture::~CLOSTexture() { - if (m_SmoothFBO) - glDeleteFramebuffersEXT(1, &m_SmoothFBO); + if (m_SmoothFBO1) + glDeleteFramebuffersEXT(1, &m_SmoothFBO1); + if (m_SmoothFBO2) + glDeleteFramebuffersEXT(1, &m_SmoothFBO2); if (m_Texture) DeleteTexture(); @@ -79,10 +80,10 @@ CLOSTexture::~CLOSTexture() // Create the LOS texture engine. Should be ran only once. bool CLOSTexture::CreateShader() { - m_smoothShader = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); - CShaderProgramPtr shader = m_smoothShader->GetShader(); + m_SmoothTech = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); + CShaderProgramPtr shader = m_SmoothTech->GetShader(); - m_ShaderInitialized = m_smoothShader && shader; + m_ShaderInitialized = m_SmoothTech && shader; if (!m_ShaderInitialized) { @@ -91,7 +92,8 @@ bool CLOSTexture::CreateShader() return false; } - glGenFramebuffersEXT(1, &m_SmoothFBO); + glGenFramebuffersEXT(1, &m_SmoothFBO1); + glGenFramebuffersEXT(1, &m_SmoothFBO2); return true; } @@ -139,18 +141,10 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::GL::CDeviceCommandContext* d if (skipSmoothLOS) return; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_SmoothFBO); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, - (m_WhichTex ? m_TextureSmooth2 : m_TextureSmooth1)->GetHandle(), 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (m_WhichTex ? m_SmoothFBO2 : m_SmoothFBO1)); - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("LOS framebuffer object incomplete: 0x%04X", status); - } - - m_smoothShader->BeginPass(); - CShaderProgramPtr shader = m_smoothShader->GetShader(); + m_SmoothTech->BeginPass(); + CShaderProgramPtr shader = m_SmoothTech->GetShader(); glDisable(GL_BLEND); @@ -198,9 +192,7 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::GL::CDeviceCommandContext* d g_Renderer.SetViewport(oldVp); shader->Unbind(); - m_smoothShader->EndPass(); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); + m_SmoothTech->EndPass(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -256,6 +248,20 @@ void CLOSTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandContext* m_TextureSmooth2 = Renderer::Backend::GL::CTexture::Create2D( Renderer::Backend::Format::A8, textureSize, textureSize, defaultSamplerDesc); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_SmoothFBO1); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + m_TextureSmooth1->GetHandle(), 0); + GLenum status1 = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_SmoothFBO2); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + m_TextureSmooth2->GetHandle(), 0); + GLenum status2 = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status1 != GL_FRAMEBUFFER_COMPLETE_EXT || status2 != GL_FRAMEBUFFER_COMPLETE_EXT) + { + LOGWARNING("LOS framebuffer object incomplete: 0x%04X 0x%04X", status1, status2); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->UploadTexture(m_TextureSmooth1.get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize); deviceCommandContext->UploadTexture(m_TextureSmooth2.get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize); } diff --git a/source/graphics/LOSTexture.h b/source/graphics/LOSTexture.h index 1949eb6417..a729f4639f 100644 --- a/source/graphics/LOSTexture.h +++ b/source/graphics/LOSTexture.h @@ -84,19 +84,22 @@ private: CSimulation2& m_Simulation; - bool m_Dirty; + bool m_Dirty = true; - bool m_ShaderInitialized; + bool m_ShaderInitialized = false; std::unique_ptr m_Texture, m_TextureSmooth1, m_TextureSmooth2; - bool m_WhichTex; + bool m_WhichTex = true; - GLuint m_SmoothFBO; - CShaderTechniquePtr m_smoothShader; + // We update textures once a frame, so we change a FBO once a frame. That + // allows us to use two ping-pong FBOs instead of checking completeness of + // FBO each frame. + GLuint m_SmoothFBO1 = 0, m_SmoothFBO2 = 0; + CShaderTechniquePtr m_SmoothTech; - size_t m_MapSize; // vertexes per side + size_t m_MapSize = 0; // vertexes per side CMatrix3D m_TextureMatrix; CMatrix3D m_MinimapTextureMatrix; diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp index 35624de902..3815ea65ff 100644 --- a/source/renderer/SceneRenderer.cpp +++ b/source/renderer/SceneRenderer.cpp @@ -880,11 +880,15 @@ void CSceneRenderer::RenderSubmissions( { if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) { + m->waterManager.UpdateQuality(); + PROFILE3_GPU("water scissor"); RenderReflections(context, waterScissor); if (g_RenderingOptions.GetWaterRefraction()) RenderRefractions(context, waterScissor); + + m->terrainRenderer.RenderWaterFoamOccluders(cullGroup); } } diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 2e5b3ca58e..2eb73f893e 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -51,7 +51,8 @@ * TerrainRenderer keeps track of which phase it is in, to detect * when Submit, PrepareForRendering etc. are called in the wrong order. */ -enum Phase { +enum Phase +{ Phase_Submit, Phase_Render }; @@ -400,38 +401,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr const double time = waterManager.m_WaterTexTimer; const float repeatPeriod = waterManager.m_RepeatPeriod; - // Render normals and foam to a framebuffer if we're in fancy effects - if (waterManager.m_WaterFancyEffects) - { - // Save the post-processing framebuffer. - GLint fbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, waterManager.m_FancyEffectsFBO); - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - glDisable(GL_CULL_FACE); - // Overwrite waves that would be behind the ground. - CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - dummyTech->BeginPass(); - CShaderProgramPtr dummyShader = dummyTech->GetShader(); - - dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); - dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); - std::vector& visiblePatches = m->visiblePatches[cullGroup]; - for (size_t i = 0; i < visiblePatches.size(); ++i) - { - CPatchRData* data = visiblePatches[i]; - data->RenderWater(dummyShader, true, true); - } - dummyTech->EndPass(); - - glEnable(GL_CULL_FACE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); @@ -580,9 +549,7 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) // Render water that is part of the terrain void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { - WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); - - waterManager.UpdateQuality(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); if (!waterManager.WillRenderFancyWater()) RenderSimpleWater(cullGroup); @@ -590,6 +557,36 @@ void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, RenderFancyWater(context, cullGroup, shadow); } +void TerrainRenderer::RenderWaterFoamOccluders(int cullGroup) +{ + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); + const WaterManager& waterManager = sceneRenderer.GetWaterManager(); + if (!waterManager.WillRenderFancyWater()) + return; + + // Render normals and foam to a framebuffer if we're using fancy effects. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, waterManager.m_FancyEffectsFBO); + + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glDisable(GL_CULL_FACE); + // Overwrite waves that would be behind the ground. + CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); + dummyTech->BeginPass(); + CShaderProgramPtr dummyShader = dummyTech->GetShader(); + + dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); + dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); + for (CPatchRData* data : m->visiblePatches[cullGroup]) + data->RenderWater(dummyShader, true, true); + dummyTech->EndPass(); + + glEnable(GL_CULL_FACE); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +} + void TerrainRenderer::RenderPriorities(int cullGroup) { PROFILE("priorities"); diff --git a/source/renderer/TerrainRenderer.h b/source/renderer/TerrainRenderer.h index dde80ec2a0..af03177a6f 100644 --- a/source/renderer/TerrainRenderer.h +++ b/source/renderer/TerrainRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -130,6 +130,11 @@ public: */ void RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow); + /** + * Renders terrain to a framebuffer to occlude shore foams. + */ + void RenderWaterFoamOccluders(int cullGroup); + /** * Calculate a scissor rectangle for the visible water patches. */