Index: ps/trunk/source/graphics/LOSTexture.h =================================================================== --- ps/trunk/source/graphics/LOSTexture.h +++ ps/trunk/source/graphics/LOSTexture.h @@ -18,11 +18,10 @@ #ifndef INCLUDED_LOSTEXTURE #define INCLUDED_LOSTEXTURE -#include "lib/ogl.h" - #include "graphics/ShaderTechniquePtr.h" #include "maths/Matrix3D.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Texture.h" #include @@ -89,14 +88,15 @@ bool m_ShaderInitialized = false; std::unique_ptr - m_Texture, m_TextureSmooth1, m_TextureSmooth2; + m_Texture, m_SmoothTextures[2]; - bool m_WhichTex = true; + uint32_t m_WhichTexture = 0; - // 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; + // We update textures once a frame, so we change a Framebuffer once a frame. + // That allows us to use two ping-pong FBOs instead of checking completeness + // of Framebuffer each frame. + std::unique_ptr + m_SmoothFramebuffers[2]; CShaderTechniquePtr m_SmoothTech; size_t m_MapSize = 0; // vertexes per side Index: ps/trunk/source/graphics/LOSTexture.cpp =================================================================== --- ps/trunk/source/graphics/LOSTexture.cpp +++ ps/trunk/source/graphics/LOSTexture.cpp @@ -26,6 +26,7 @@ #include "ps/CStrInternStatic.h" #include "ps/Game.h" #include "ps/Profile.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/TimeManager.h" @@ -68,10 +69,8 @@ CLOSTexture::~CLOSTexture() { - if (m_SmoothFBO1) - glDeleteFramebuffersEXT(1, &m_SmoothFBO1); - if (m_SmoothFBO2) - glDeleteFramebuffersEXT(1, &m_SmoothFBO2); + m_SmoothFramebuffers[0].reset(); + m_SmoothFramebuffers[1].reset(); if (m_Texture) DeleteTexture(); @@ -92,16 +91,14 @@ return false; } - glGenFramebuffersEXT(1, &m_SmoothFBO1); - glGenFramebuffersEXT(1, &m_SmoothFBO2); return true; } void CLOSTexture::DeleteTexture() { m_Texture.reset(); - m_TextureSmooth1.reset(); - m_TextureSmooth2.reset(); + m_SmoothTextures[0].reset(); + m_SmoothTextures[1].reset(); } void CLOSTexture::MakeDirty() @@ -114,7 +111,7 @@ if (CRenderer::IsInitialised() && !g_RenderingOptions.GetSmoothLOS()) return GetTexture(); else - return (m_WhichTex ? m_TextureSmooth1 : m_TextureSmooth2).get(); + return m_SmoothTextures[m_WhichTexture].get(); } void CLOSTexture::InterpolateLOS(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) @@ -141,7 +138,7 @@ if (skipSmoothLOS) return; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (m_WhichTex ? m_SmoothFBO2 : m_SmoothFBO1)); + deviceCommandContext->SetFramebuffer(m_SmoothFramebuffers[m_WhichTexture].get()); m_SmoothTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( @@ -150,7 +147,7 @@ const CShaderProgramPtr& shader = m_SmoothTech->GetShader(); shader->BindTexture(str_losTex1, m_Texture.get()); - shader->BindTexture(str_losTex2, (m_WhichTex ? m_TextureSmooth1 : m_TextureSmooth2).get()); + shader->BindTexture(str_losTex2, m_SmoothTextures[m_WhichTexture].get()); shader->Uniform(str_delta, (float)g_Renderer.GetTimeManager().GetFrameDelta() * 4.0f, 0.0f, 0.0f, 0.0f); @@ -192,9 +189,10 @@ m_SmoothTech->EndPass(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); - m_WhichTex = !m_WhichTex; + m_WhichTexture = 1u - m_WhichTexture; } @@ -241,27 +239,23 @@ if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS()) { - m_TextureSmooth1 = Renderer::Backend::GL::CTexture::Create2D( + m_SmoothTextures[0] = Renderer::Backend::GL::CTexture::Create2D( Renderer::Backend::Format::A8, textureSize, textureSize, defaultSamplerDesc); - m_TextureSmooth2 = Renderer::Backend::GL::CTexture::Create2D( + m_SmoothTextures[1] = 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) + m_SmoothFramebuffers[0] = Renderer::Backend::GL::CFramebuffer::Create( + m_SmoothTextures[0].get(), nullptr); + m_SmoothFramebuffers[1] = Renderer::Backend::GL::CFramebuffer::Create( + m_SmoothTextures[1].get(), nullptr); + if (!m_SmoothFramebuffers[0] || !m_SmoothFramebuffers[1]) { - LOGWARNING("LOS framebuffer object incomplete: 0x%04X 0x%04X", status1, status2); + LOGERROR("Failed to create LOS framebuffers"); + g_RenderingOptions.SetSmoothLOS(false); } - 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); + deviceCommandContext->UploadTexture(m_SmoothTextures[0].get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize); + deviceCommandContext->UploadTexture(m_SmoothTextures[1].get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize); } deviceCommandContext->UploadTexture(m_Texture.get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize); @@ -331,10 +325,10 @@ if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS() && recreated) { deviceCommandContext->UploadTextureRegion( - m_TextureSmooth1.get(), Renderer::Backend::Format::A8, losData.get(), + m_SmoothTextures[0].get(), Renderer::Backend::Format::A8, losData.get(), pitch * m_MapSize, 0, 0, pitch, m_MapSize); deviceCommandContext->UploadTextureRegion( - m_TextureSmooth2.get(), Renderer::Backend::Format::A8, losData.get(), + m_SmoothTextures[1].get(), Renderer::Backend::Format::A8, losData.get(), pitch * m_MapSize, 0, 0, pitch, m_MapSize); } Index: ps/trunk/source/graphics/MiniMapTexture.h =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.h +++ ps/trunk/source/graphics/MiniMapTexture.h @@ -18,7 +18,6 @@ #ifndef INCLUDED_MINIMAPTEXTURE #define INCLUDED_MINIMAPTEXTURE -#include "lib/ogl.h" #include "renderer/backend/gl/DeviceCommandContext.h" #include "renderer/backend/gl/Texture.h" #include "renderer/VertexArray.h" @@ -73,7 +72,8 @@ std::unique_ptr m_TerrainTexture, m_FinalTexture; - GLuint m_FinalTextureFBO = 0; + std::unique_ptr + m_FinalTextureFramebuffer; // texture data std::unique_ptr m_TerrainData; Index: ps/trunk/source/graphics/MiniMapTexture.cpp =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.cpp +++ ps/trunk/source/graphics/MiniMapTexture.cpp @@ -37,6 +37,7 @@ #include "ps/Game.h" #include "ps/World.h" #include "ps/XML/Xeromyces.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/SceneRenderer.h" @@ -236,17 +237,9 @@ m_FinalTexture = Renderer::Backend::GL::CTexture::Create2D( Renderer::Backend::Format::R8G8B8A8, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE, defaultSamplerDesc); - glGenFramebuffersEXT(1, &m_FinalTextureFBO); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FinalTextureFBO); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FinalTexture->GetHandle(), 0); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("MiniMapTexture Framebuffer object incomplete (A): 0x%04X", status); - } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + m_FinalTextureFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_FinalTexture.get(), nullptr); + ENSURE(m_FinalTextureFramebuffer); } void CMiniMapTexture::DestroyTextures() @@ -337,7 +330,7 @@ return; m_FinalTextureDirty = false; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FinalTextureFBO); + deviceCommandContext->SetFramebuffer(m_FinalTextureFramebuffer.get()); const SViewPort oldViewPort = g_Renderer.GetViewport(); const SViewPort viewPort = { 0, 0, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE }; @@ -525,8 +518,8 @@ } tech->EndPass(); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); g_Renderer.SetViewport(oldViewPort); } Index: ps/trunk/source/renderer/DebugRenderer.cpp =================================================================== --- ps/trunk/source/renderer/DebugRenderer.cpp +++ ps/trunk/source/renderer/DebugRenderer.cpp @@ -77,7 +77,7 @@ const float width, const bool depthTestEnabled) { #if CONFIG2_GLES - UNUSED2(line); UNUSED2(color); UNUSED2(width); + UNUSED2(line); UNUSED2(color); UNUSED2(width); UNUSED2(depthTestEnabled); #warning TODO: implement drawing line for GLES #else CShaderTechniquePtr debugLineTech = Index: ps/trunk/source/renderer/PostprocManager.h =================================================================== --- ps/trunk/source/renderer/PostprocManager.h +++ ps/trunk/source/renderer/PostprocManager.h @@ -19,11 +19,12 @@ #define INCLUDED_POSTPROCMANAGER #include "graphics/ShaderTechniquePtr.h" -#include "lib/ogl.h" #include "ps/CStr.h" +#include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/DeviceCommandContext.h" #include "renderer/backend/gl/Texture.h" +#include #include class CPostprocManager @@ -64,7 +65,8 @@ // Clears the two color buffers and depth buffer, and redirects all rendering // to our textures instead of directly to the system framebuffer. // @note CPostprocManager must be initialized first - void CaptureRenderOutput(); + void CaptureRenderOutput( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); // First renders blur textures, then calls ApplyEffect for each effect pass, // ping-ponging the buffers at each step. @@ -81,14 +83,16 @@ bool IsMultisampleEnabled() const; // Resolves the MSAA framebuffer into the regular one. - void ResolveMultisampleFramebuffer(); + void ResolveMultisampleFramebuffer( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); private: void CreateMultisampleBuffer(); void DestroyMultisampleBuffer(); // Two framebuffers, that we flip between at each shader pass. - GLuint m_PingFbo, m_PongFbo; + std::unique_ptr + m_CaptureFramebuffer, m_PingFramebuffer, m_PongFramebuffer; // Unique color textures for the framebuffers. std::unique_ptr m_ColorTex1, m_ColorTex2; @@ -98,9 +102,16 @@ float m_NearPlane, m_FarPlane; // A framebuffer and textures x2 for each blur level we render. - GLuint m_BloomFbo; - std::unique_ptr - m_BlurTex2a, m_BlurTex2b, m_BlurTex4a, m_BlurTex4b, m_BlurTex8a, m_BlurTex8b; + struct BlurScale + { + struct Step + { + std::unique_ptr framebuffer; + std::unique_ptr texture; + }; + std::array steps; + }; + std::array m_BlurScales; // Indicates which of the ping-pong buffers is used for reading and which for drawing. bool m_WhichBuffer; @@ -117,7 +128,7 @@ CStr m_AAName; CShaderTechniquePtr m_AATech; bool m_UsingMultisampleBuffer; - GLuint m_MultisampleFBO; + std::unique_ptr m_MultisampleFramebuffer; std::unique_ptr m_MultisampleColorTex, m_MultisampleDepthTex; GLsizei m_MultisampleCount; @@ -137,14 +148,20 @@ // of inTex. inWidth and inHeight are the dimensions of inTex in texels. void ApplyBlurDownscale2x( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CTexture* inTex, Renderer::Backend::GL::CTexture* outTex, int inWidth, int inHeight); + Renderer::Backend::GL::CFramebuffer* framebuffer, + Renderer::Backend::GL::CTexture* inTex, + int inWidth, int inHeight); // GPU-based Gaussian blur in two passes. inOutTex contains the input image and will be filled // with the blurred image. tempTex must have the same size as inOutTex. // inWidth and inHeight are the dimensions of the images in texels. void ApplyBlurGauss( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CTexture* inOutTex, Renderer::Backend::GL::CTexture* tempTex, int inWidth, int inHeight); + Renderer::Backend::GL::CTexture* inTex, + Renderer::Backend::GL::CTexture* tempTex, + Renderer::Backend::GL::CFramebuffer* tempFramebuffer, + Renderer::Backend::GL::CFramebuffer* outFramebuffer, + int inWidth, int inHeight); // Applies a pass of a given effect to the entire current framebuffer. The shader is // provided with a number of general-purpose variables, including the rendered screen so far, @@ -152,7 +169,7 @@ // some other parameters used by the optional bloom/HDR pass. void ApplyEffect( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderTechniquePtr& shaderTech1, int pass); + const CShaderTechniquePtr& shaderTech, int pass); // Delete all allocated buffers/textures from GPU memory. void Cleanup(); Index: ps/trunk/source/renderer/PostprocManager.cpp =================================================================== --- ps/trunk/source/renderer/PostprocManager.cpp +++ ps/trunk/source/renderer/PostprocManager.cpp @@ -32,6 +32,7 @@ #include "ps/Game.h" #include "ps/VideoMode.h" #include "ps/World.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "tools/atlas/GameInterface/GameLoop.h" @@ -39,9 +40,8 @@ #if !CONFIG2_GLES CPostprocManager::CPostprocManager() - : m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), - m_BloomFbo(0), m_WhichBuffer(true), m_Sharpness(0.3f), m_UsingMultisampleBuffer(false), - m_MultisampleFBO(0), m_MultisampleCount(0) + : m_IsInitialized(false), m_PostProcEffect(L"default"), m_WhichBuffer(true), + m_Sharpness(0.3f), m_UsingMultisampleBuffer(false), m_MultisampleCount(0) { } @@ -61,21 +61,23 @@ if (!m_IsInitialized) // Only cleanup if previously used return; - if (m_PingFbo) glDeleteFramebuffersEXT(1, &m_PingFbo); - if (m_PongFbo) glDeleteFramebuffersEXT(1, &m_PongFbo); - if (m_BloomFbo) glDeleteFramebuffersEXT(1, &m_BloomFbo); - m_PingFbo = m_PongFbo = m_BloomFbo = 0; + m_CaptureFramebuffer.reset(); + + m_PingFramebuffer.reset(); + m_PongFramebuffer.reset(); m_ColorTex1.reset(); m_ColorTex2.reset(); m_DepthTex.reset(); - m_BlurTex2a.reset(); - m_BlurTex2b.reset(); - m_BlurTex4a.reset(); - m_BlurTex4b.reset(); - m_BlurTex8a.reset(); - m_BlurTex8b.reset(); + for (BlurScale& scale : m_BlurScales) + { + for (BlurScale::Step& step : scale.steps) + { + step.framebuffer.reset(); + step.texture.reset(); + } + } } void CPostprocManager::Initialize() @@ -136,14 +138,18 @@ // m_BlurTex2b, thus avoiding the need for m_BlurTex4b and m_BlurTex8b, though given // that these are fairly small it's probably not worth complicating the coordinates passed // to the blur helper functions. - GEN_BUFFER_RGBA(m_BlurTex2a, m_Width / 2, m_Height / 2); - GEN_BUFFER_RGBA(m_BlurTex2b, m_Width / 2, m_Height / 2); - - GEN_BUFFER_RGBA(m_BlurTex4a, m_Width / 4, m_Height / 4); - GEN_BUFFER_RGBA(m_BlurTex4b, m_Width / 4, m_Height / 4); - - GEN_BUFFER_RGBA(m_BlurTex8a, m_Width / 8, m_Height / 8); - GEN_BUFFER_RGBA(m_BlurTex8b, m_Width / 8, m_Height / 8); + uint32_t width = m_Width / 2, height = m_Height / 2; + for (BlurScale& scale : m_BlurScales) + { + for (BlurScale::Step& step : scale.steps) + { + GEN_BUFFER_RGBA(step.texture, width, height); + step.framebuffer = Renderer::Backend::GL::CFramebuffer::Create( + step.texture.get(), nullptr); + } + width /= 2; + height /= 2; + } #undef GEN_BUFFER_RGBA @@ -159,68 +165,35 @@ glBindTexture(GL_TEXTURE_2D, 0); // Set up the framebuffers with some initial textures. + m_CaptureFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_ColorTex1.get(), m_DepthTex.get(), + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()->GetClearColor()); + + m_PingFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_ColorTex1.get(), nullptr); + m_PongFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_ColorTex2.get(), nullptr); - glGenFramebuffersEXT(1, &m_PingFbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_ColorTex1->GetHandle(), 0); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, m_DepthTex->GetHandle(), 0); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!m_CaptureFramebuffer || !m_PingFramebuffer || !m_PongFramebuffer) { - LOGWARNING("Framebuffer object incomplete (A): 0x%04X", status); + LOGWARNING("Failed to create postproc framebuffers"); + g_RenderingOptions.SetPostProc(false); } - glGenFramebuffersEXT(1, &m_PongFbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_ColorTex2->GetHandle(), 0); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, m_DepthTex->GetHandle(), 0); - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Framebuffer object incomplete (B): 0x%04X", status); - } - - glGenFramebuffersEXT(1, &m_BloomFbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - - /* - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_BloomTex1, 0); - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - LOGWARNING("Framebuffer object incomplete (B): 0x%04X", status); - } - */ - if (m_UsingMultisampleBuffer) { DestroyMultisampleBuffer(); CreateMultisampleBuffer(); } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } void CPostprocManager::ApplyBlurDownscale2x( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CTexture* inTex, Renderer::Backend::GL::CTexture* outTex, int inWidth, int inHeight) + Renderer::Backend::GL::CFramebuffer* framebuffer, + Renderer::Backend::GL::CTexture* inTex, int inWidth, int inHeight) { - // Bind inTex to framebuffer for rendering. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, outTex->GetHandle(), 0); + deviceCommandContext->SetFramebuffer(framebuffer); // Get bloom shader with instructions to simply copy texels. CShaderDefines defines; @@ -270,11 +243,13 @@ void CPostprocManager::ApplyBlurGauss( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CTexture* inOutTex, Renderer::Backend::GL::CTexture* tempTex, int inWidth, int inHeight) + Renderer::Backend::GL::CTexture* inTex, + Renderer::Backend::GL::CTexture* tempTex, + Renderer::Backend::GL::CFramebuffer* tempFramebuffer, + Renderer::Backend::GL::CFramebuffer* outFramebuffer, + int inWidth, int inHeight) { - // Set tempTex as our rendering target. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tempTex->GetHandle(), 0); + deviceCommandContext->SetFramebuffer(tempFramebuffer); // Get bloom shader, for a horizontal Gaussian blur pass. CShaderDefines defines2; @@ -285,7 +260,7 @@ deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); CShaderProgramPtr shader = tech->GetShader(); - shader->BindTexture(str_renderedTex, inOutTex); + shader->BindTexture(str_renderedTex, inTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); const SViewPort oldVp = g_Renderer.GetViewport(); @@ -321,9 +296,7 @@ tech->EndPass(); - // Set result texture as our render target. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, inOutTex->GetHandle(), 0); + deviceCommandContext->SetFramebuffer(outFramebuffer); // Get bloom shader, for a vertical Gaussian blur pass. CShaderDefines defines3; @@ -352,43 +325,35 @@ void CPostprocManager::ApplyBlur( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { - int width = m_Width, height = m_Height; - - #define SCALE_AND_BLUR(tex1, tex2, temptex) \ - ApplyBlurDownscale2x(deviceCommandContext, (tex1).get(), (tex2).get(), width, height); \ - width /= 2; \ - height /= 2; \ - ApplyBlurGauss(deviceCommandContext, (tex2).get(), (temptex).get(), width, height); + uint32_t width = m_Width, height = m_Height; + Renderer::Backend::GL::CTexture* previousTexture = + (m_WhichBuffer ? m_ColorTex1 : m_ColorTex2).get(); - // We do the same thing for each scale, incrementally adding more and more blur. - SCALE_AND_BLUR(m_WhichBuffer ? m_ColorTex1 : m_ColorTex2, m_BlurTex2a, m_BlurTex2b); - SCALE_AND_BLUR(m_BlurTex2a, m_BlurTex4a, m_BlurTex4b); - SCALE_AND_BLUR(m_BlurTex4a, m_BlurTex8a, m_BlurTex8b); - - #undef SCALE_AND_BLUR + for (BlurScale& scale : m_BlurScales) + { + ApplyBlurDownscale2x(deviceCommandContext, scale.steps[0].framebuffer.get(), previousTexture, width, height); + width /= 2; + height /= 2; + ApplyBlurGauss(deviceCommandContext, scale.steps[0].texture.get(), + scale.steps[1].texture.get(), scale.steps[1].framebuffer.get(), + scale.steps[0].framebuffer.get(), width, height); + } } -void CPostprocManager::CaptureRenderOutput() +void CPostprocManager::CaptureRenderOutput( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { ENSURE(m_IsInitialized); // Leaves m_PingFbo selected for rendering; m_WhichBuffer stays true at this point. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - - GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; - glDrawBuffers(1, buffers); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - glDrawBuffers(1, buffers); + if (m_UsingMultisampleBuffer) + deviceCommandContext->SetFramebuffer(m_MultisampleFramebuffer.get()); + else + deviceCommandContext->SetFramebuffer(m_CaptureFramebuffer.get()); m_WhichBuffer = true; - - if (m_UsingMultisampleBuffer) - { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO); - glDrawBuffers(1, buffers); - } } @@ -397,40 +362,27 @@ { ENSURE(m_IsInitialized); - const Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + // We blit to the backbuffer from the previous active buffer. + deviceCommandContext->BlitFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer(), + (m_WhichBuffer ? m_PingFramebuffer : m_PongFramebuffer).get()); - // we blit to screen from the previous active buffer - if (m_WhichBuffer) - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PingFbo); - else - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PongFbo); - - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - glBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height, - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } void CPostprocManager::ApplyEffect( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderTechniquePtr& shaderTech1, int pass) + const CShaderTechniquePtr& shaderTech, int pass) { // select the other FBO for rendering - if (!m_WhichBuffer) - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - else - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); + deviceCommandContext->SetFramebuffer( + (m_WhichBuffer ? m_PongFramebuffer : m_PingFramebuffer).get()); - shaderTech1->BeginPass(pass); + shaderTech->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState( - shaderTech1->GetGraphicsPipelineStateDesc(pass)); - const CShaderProgramPtr& shader = shaderTech1->GetShader(pass); + shaderTech->GetGraphicsPipelineStateDesc(pass)); + const CShaderProgramPtr& shader = shaderTech->GetShader(pass); // Use the textures from the current FBO as input to the shader. // We also bind a bunch of other textures and parameters, but since @@ -442,9 +394,9 @@ shader->BindTexture(str_depthTex, m_DepthTex.get()); - shader->BindTexture(str_blurTex2, m_BlurTex2a.get()); - shader->BindTexture(str_blurTex4, m_BlurTex4a.get()); - shader->BindTexture(str_blurTex8, m_BlurTex8a.get()); + shader->BindTexture(str_blurTex2, m_BlurScales[0].steps[0].texture.get()); + shader->BindTexture(str_blurTex4, m_BlurScales[1].steps[0].texture.get()); + shader->BindTexture(str_blurTex8, m_BlurScales[2].steps[0].texture.get()); shader->Uniform(str_width, m_Width); shader->Uniform(str_height, m_Height); @@ -483,7 +435,7 @@ shader->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, 0, 6); - shaderTech1->EndPass(pass); + shaderTech->EndPass(pass); m_WhichBuffer = !m_WhichBuffer; } @@ -501,28 +453,11 @@ if (!hasEffects && !hasAA && !hasSharp) return; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0); - - GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT }; - glDrawBuffers(1, buffers); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0); - glDrawBuffers(1, buffers); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - if (hasEffects) { // First render blur textures. Note that this only happens ONLY ONCE, before any effects are applied! // (This may need to change depending on future usage, however that will have a fps hit) ApplyBlur(deviceCommandContext); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); for (int pass = 0; pass < m_PostProcTech->GetNumPasses(); ++pass) ApplyEffect(deviceCommandContext, m_PostProcTech, pass); } @@ -538,12 +473,6 @@ for (int pass = 0; pass < m_SharpTech->GetNumPasses(); ++pass) ApplyEffect(deviceCommandContext, m_SharpTech, pass); } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex->GetHandle(), 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex->GetHandle(), 0); } @@ -692,35 +621,23 @@ Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, m_MultisampleCount); // Set up the framebuffers with some initial textures. - glGenFramebuffersEXT(1, &m_MultisampleFBO); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleColorTex->GetHandle(), 0); + m_MultisampleFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_MultisampleColorTex.get(), m_MultisampleDepthTex.get(), + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()->GetClearColor()); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleDepthTex->GetHandle(), 0); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!m_MultisampleFramebuffer) { - LOGWARNING("Multisample framebuffer object incomplete (A): 0x%04X", status); + LOGERROR("Failed to create postproc multisample framebuffer"); m_UsingMultisampleBuffer = false; DestroyMultisampleBuffer(); } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - glBindTexture(GL_TEXTURE_2D, 0); } void CPostprocManager::DestroyMultisampleBuffer() { if (m_UsingMultisampleBuffer) return; - if (m_MultisampleFBO) - glDeleteFramebuffersEXT(1, &m_MultisampleFBO); + m_MultisampleFramebuffer.reset(); m_MultisampleColorTex.reset(); m_MultisampleDepthTex.reset(); glDisable(GL_MULTISAMPLE); @@ -731,16 +648,15 @@ return m_UsingMultisampleBuffer; } -void CPostprocManager::ResolveMultisampleFramebuffer() +void CPostprocManager::ResolveMultisampleFramebuffer( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { if (!m_UsingMultisampleBuffer) return; - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_PingFbo); - glBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height, - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo); + deviceCommandContext->BlitFramebuffer( + m_PingFramebuffer.get(), m_MultisampleFramebuffer.get()); + deviceCommandContext->SetFramebuffer(m_PingFramebuffer.get()); } #else @@ -749,23 +665,25 @@ void ApplyBlurDownscale2x( Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext), + Renderer::Backend::GL::CFramebuffer* UNUSED(framebuffer), Renderer::Backend::GL::CTexture* UNUSED(inTex), - Renderer::Backend::GL::CTexture* UNUSED(outTex), int UNUSED(inWidth), int UNUSED(inHeight)) { } void CPostprocManager::ApplyBlurGauss( Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext), - Renderer::Backend::GL::CTexture* UNUSED(inOutTex), + Renderer::Backend::GL::CTexture* UNUSED(inTex), Renderer::Backend::GL::CTexture* UNUSED(tempTex), + Renderer::Backend::GL::CFramebuffer* UNUSED(tempFramebuffer), + Renderer::Backend::GL::CFramebuffer* UNUSED(outFramebuffer), int UNUSED(inWidth), int UNUSED(inHeight)) { } void CPostprocManager::ApplyEffect( Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext), - const CShaderTechniquePtr& UNUSED(shaderTech1), int UNUSED(pass)) + const CShaderTechniquePtr& UNUSED(shaderTech), int UNUSED(pass)) { } @@ -823,7 +741,8 @@ { } -void CPostprocManager::CaptureRenderOutput() +void CPostprocManager::CaptureRenderOutput( + Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext)) { } @@ -850,7 +769,8 @@ return false; } -void CPostprocManager::ResolveMultisampleFramebuffer() +void CPostprocManager::ResolveMultisampleFramebuffer( + Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext)) { } Index: ps/trunk/source/renderer/Renderer.cpp =================================================================== --- ps/trunk/source/renderer/Renderer.cpp +++ ps/trunk/source/renderer/Renderer.cpp @@ -387,7 +387,7 @@ // Validate the currently selected render path SetRenderPath(g_RenderingOptions.GetRenderPath()); - m->deviceCommandContext = Renderer::Backend::GL::CDeviceCommandContext::Create(); + m->deviceCommandContext = g_VideoMode.GetBackendDevice()->CreateCommandContext(); if (m->postprocManager.IsEnabled()) m->postprocManager.Initialize(); @@ -502,6 +502,9 @@ ogl_WarnIfError(); } + m->deviceCommandContext->SetFramebuffer( + m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); + m->sceneRenderer.RenderTextOverlays(); // If we're in Atlas game view, render special tools Index: ps/trunk/source/renderer/SceneRenderer.h =================================================================== --- ps/trunk/source/renderer/SceneRenderer.h +++ ps/trunk/source/renderer/SceneRenderer.h @@ -271,8 +271,6 @@ Scene* m_CurrentScene; int m_CurrentCullGroup; - // color used to clear screen in BeginFrame - float m_ClearColor[4]; // current lighting setup CLightEnv* m_LightEnv; Index: ps/trunk/source/renderer/SceneRenderer.cpp =================================================================== --- ps/trunk/source/renderer/SceneRenderer.cpp +++ ps/trunk/source/renderer/SceneRenderer.cpp @@ -44,6 +44,7 @@ #include "ps/Profile.h" #include "ps/VideoMode.h" #include "ps/World.h" +#include "renderer/backend/gl/Device.h" #include "renderer/DebugRenderer.h" #include "renderer/HWLightingModelRenderer.h" #include "renderer/InstancingModelRenderer.h" @@ -194,21 +195,9 @@ m_WaterRenderMode = SOLID; m_ModelRenderMode = SOLID; m_OverlayRenderMode = SOLID; - m_ClearColor[0] = m_ClearColor[1] = m_ClearColor[2] = m_ClearColor[3] = 0; m_DisplayTerrainPriorities = false; - CStr skystring = "0 0 0"; - CColor skycolor; - CFG_GET_VAL("skycolor", skystring); - if (skycolor.ParseString(skystring, 255.f)) - { - m_ClearColor[0] = skycolor.r; - m_ClearColor[1] = skycolor.g; - m_ClearColor[2] = skycolor.b; - m_ClearColor[3] = skycolor.a; - } - m_LightEnv = nullptr; m_CurrentScene = nullptr; @@ -639,14 +628,8 @@ scissorRect.height = screenScissor.y2 - screenScissor.y1; deviceCommandContext->SetScissors(1, &scissorRect); - // try binding the framebuffer - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_ReflectionFbo); - - const Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - glClearColor(0.5f, 0.5f, 1.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + deviceCommandContext->SetFramebuffer(wm.m_ReflectionFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); if (!g_RenderingOptions.GetWaterReflection()) { @@ -680,7 +663,8 @@ m_ViewCamera = normalCamera; g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } // RenderRefractions: render the water refractions to the refraction texture @@ -726,14 +710,8 @@ scissorRect.height = screenScissor.y2 - screenScissor.y1; deviceCommandContext->SetScissors(1, &scissorRect); - // try binding the framebuffer - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_RefractionFbo); - - const Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - glClearColor(1.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + deviceCommandContext->SetFramebuffer(wm.m_RefractionFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); // Render terrain and models RenderPatches(deviceCommandContext, context, CULL_REFRACTIONS); @@ -749,7 +727,8 @@ m_ViewCamera = normalCamera; g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } void CSceneRenderer::RenderSilhouettes( @@ -772,7 +751,7 @@ // inverted depth test so any behind an occluder will get drawn in a constant // color. - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + deviceCommandContext->ClearFramebuffer(false, true, true); // Render occluders: @@ -901,13 +880,17 @@ m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane() ); postprocManager.Initialize(); - postprocManager.CaptureRenderOutput(); + postprocManager.CaptureRenderOutput(deviceCommandContext); + } + else + { + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } { PROFILE3_GPU("clear buffers"); - glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + deviceCommandContext->ClearFramebuffer(); } m->skyManager.RenderSky(deviceCommandContext); @@ -978,7 +961,7 @@ if (postprocManager.IsEnabled()) { if (g_Renderer.GetPostprocManager().IsMultisampleEnabled()) - g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(); + g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(deviceCommandContext); postprocManager.ApplyPostproc(deviceCommandContext); postprocManager.ReleaseRenderOutput(deviceCommandContext); Index: ps/trunk/source/renderer/ShadowMap.cpp =================================================================== --- ps/trunk/source/renderer/ShadowMap.cpp +++ ps/trunk/source/renderer/ShadowMap.cpp @@ -35,6 +35,7 @@ #include "ps/CStrInternStatic.h" #include "ps/Profile.h" #include "ps/VideoMode.h" +#include "renderer/backend/gl/Device.h" #include "renderer/backend/gl/Texture.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" @@ -58,9 +59,7 @@ */ struct ShadowMapInternals { - // the EXT_framebuffer_object framebuffer - GLuint Framebuffer; - // handle of shadow map + std::unique_ptr Framebuffer; std::unique_ptr Texture; // bit depth for the depth texture @@ -210,12 +209,10 @@ ShadowMap::~ShadowMap() { + m->Framebuffer.reset(); m->Texture.reset(); m->DummyTexture.reset(); - if (m->Framebuffer) - glDeleteFramebuffersEXT(1, &m->Framebuffer); - delete m; } @@ -223,14 +220,10 @@ // size has changed void ShadowMap::RecreateTexture() { + m->Framebuffer.reset(); m->Texture.reset(); m->DummyTexture.reset(); - if (m->Framebuffer) - glDeleteFramebuffersEXT(1, &m->Framebuffer); - - m->Framebuffer = 0; - m->UpdateCascadesParameters(); // (Texture will be constructed in next SetupFrame) @@ -476,17 +469,10 @@ void ShadowMapInternals::CreateTexture() { // Cleanup + Framebuffer.reset(); Texture.reset(); DummyTexture.reset(); - if (Framebuffer) - { - glDeleteFramebuffersEXT(1, &Framebuffer); - Framebuffer = 0; - } - - glGenFramebuffersEXT(1, &Framebuffer); - CFG_GET_VAL("shadowquality", QualityLevel); // Get shadow map size as next power of two up from view width/height. @@ -573,39 +559,14 @@ ogl_WarnIfError(); - // bind to framebuffer object - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Texture->GetHandle(), 0); - - if (g_RenderingOptions.GetShadowAlphaFix()) - { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture->GetHandle(), 0); - } - else - { -#if CONFIG2_GLES -#warning TODO: figure out whether the glDrawBuffer/glReadBuffer stuff is needed, since it is not supported by GLES -#else - glDrawBuffer(GL_NONE); -#endif - } - -#if !CONFIG2_GLES - glReadBuffer(GL_NONE); -#endif - - ogl_WarnIfError(); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + Framebuffer = Renderer::Backend::GL::CFramebuffer::Create( + g_RenderingOptions.GetShadowAlphaFix() ? DummyTexture.get() : nullptr, Texture.get()); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (!Framebuffer) { - LOGWARNING("Framebuffer object incomplete: 0x%04X", status); + LOGERROR("Failed to create shadows framebuffer"); - // Disable shadow rendering (but let the user try again if they want) + // Disable shadow rendering (but let the user try again if they want). g_RenderingOptions.SetShadows(false); } } @@ -613,10 +574,13 @@ // Set up to render into shadow map texture void ShadowMap::BeginRender() { + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = + g_Renderer.GetDeviceCommandContext(); + { PROFILE("bind framebuffer"); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m->Framebuffer); + deviceCommandContext->SetFramebuffer(m->Framebuffer.get()); } // clear buffers @@ -625,10 +589,7 @@ // In case we used m_ShadowAlphaFix, we ought to clear the unused // color buffer too, else Mali 400 drivers get confused. // Might as well clear stencil too for completeness. - if (g_RenderingOptions.GetShadowAlphaFix()) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - else - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + deviceCommandContext->ClearFramebuffer(); } m->SavedViewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -664,7 +625,8 @@ { PROFILE("unbind framebuffer"); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + g_Renderer.GetDeviceCommandContext()->SetFramebuffer( + g_VideoMode.GetBackendDevice()->GetCurrentBackbuffer()); } const SViewPort vp = { 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight() }; Index: ps/trunk/source/renderer/TerrainOverlay.cpp =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.cpp +++ ps/trunk/source/renderer/TerrainOverlay.cpp @@ -173,6 +173,7 @@ #if CONFIG2_GLES UNUSED2(deviceCommandContext); UNUSED2(color); + UNUSED2(drawHidden); UNUSED2(i); UNUSED2(j); #warning TODO: implement TerrainOverlay::RenderTile for GLES @@ -258,6 +259,7 @@ UNUSED2(deviceCommandContext); UNUSED2(color); UNUSED2(lineWidth); + UNUSED2(drawHidden); UNUSED2(i); UNUSED2(j); #warning TODO: implement TerrainOverlay::RenderTileOutline for GLES Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp +++ ps/trunk/source/renderer/TerrainRenderer.cpp @@ -37,6 +37,7 @@ #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" +#include "renderer/backend/gl/Device.h" #include "renderer/DecalRData.h" #include "renderer/PatchRData.h" #include "renderer/Renderer.h" @@ -581,7 +582,7 @@ return; // Render normals and foam to a framebuffer if we're using fancy effects. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, waterManager.m_FancyEffectsFBO); + deviceCommandContext->SetFramebuffer(waterManager.m_FancyEffectsFramebuffer.get()); // Overwrite waves that would be behind the ground. CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); @@ -599,7 +600,8 @@ data->RenderWaterShore(dummyShader); dummyTech->EndPass(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } void TerrainRenderer::RenderPriorities(int cullGroup) Index: ps/trunk/source/renderer/WaterManager.h =================================================================== --- ps/trunk/source/renderer/WaterManager.h +++ ps/trunk/source/renderer/WaterManager.h @@ -27,6 +27,7 @@ #include "maths/Matrix3D.h" #include "maths/Vector2D.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Texture.h" #include "renderer/VertexBufferManager.h" @@ -105,9 +106,9 @@ size_t m_RefTextureSize; // framebuffer objects - GLuint m_RefractionFbo; - GLuint m_ReflectionFbo; - GLuint m_FancyEffectsFBO; + std::unique_ptr m_RefractionFramebuffer; + std::unique_ptr m_ReflectionFramebuffer; + std::unique_ptr m_FancyEffectsFramebuffer; // Model-view-projection matrices for reflected & refracted cameras // (used to let the vertex shader do projective texturing) Index: ps/trunk/source/renderer/WaterManager.cpp =================================================================== --- ps/trunk/source/renderer/WaterManager.cpp +++ ps/trunk/source/renderer/WaterManager.cpp @@ -32,10 +32,11 @@ #include "ps/Game.h" #include "ps/VideoMode.h" #include "ps/World.h" -#include "renderer/WaterManager.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/SceneRenderer.h" +#include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpWaterManager.h" #include "simulation2/components/ICmpRangeManager.h" @@ -81,10 +82,6 @@ m_RefTextureSize = 0; - m_ReflectionFbo = 0; - m_RefractionFbo = 0; - m_FancyEffectsFBO = 0; - m_WaterTexTimer = 0.0; m_WindAngle = 0.0f; @@ -123,17 +120,14 @@ m_DistanceHeightmap.reset(); m_WindStrength.reset(); - if (!g_Renderer.GetCapabilities().m_PrettyWater) - return; + m_FancyEffectsFramebuffer.reset(); + m_RefractionFramebuffer.reset(); + m_ReflectionFramebuffer.reset(); m_FancyTexture.reset(); m_FancyTextureDepth.reset(); m_ReflFboDepthTexture.reset(); m_RefrFboDepthTexture.reset(); - - glDeleteFramebuffersEXT(1, &m_FancyEffectsFBO); - glDeleteFramebuffersEXT(1, &m_RefractionFbo); - glDeleteFramebuffersEXT(1, &m_ReflectionFbo); } @@ -190,9 +184,7 @@ } // Use screen-sized textures for minimum artifacts. - m_RefTextureSize = g_Renderer.GetHeight(); - - m_RefTextureSize = round_up_to_pow2(m_RefTextureSize); + m_RefTextureSize = round_up_to_pow2(g_Renderer.GetHeight()); // Create reflection texture m_ReflectionTexture = Renderer::Backend::GL::CTexture::Create2D( @@ -225,55 +217,30 @@ // Create the water framebuffers - m_ReflectionFbo = 0; - glGenFramebuffersEXT(1, &m_ReflectionFbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_ReflectionFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_ReflectionTexture->GetHandle(), 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_ReflFboDepthTexture->GetHandle(), 0); - - ogl_WarnIfError(); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + m_ReflectionFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_ReflectionTexture.get(), m_ReflFboDepthTexture.get(), CColor(0.5f, 0.5f, 1.0f, 0.0f)); + if (!m_ReflectionFramebuffer) { - LOGWARNING("Reflection framebuffer object incomplete: 0x%04X", status); g_RenderingOptions.SetWaterReflection(false); UpdateQuality(); } - m_RefractionFbo = 0; - glGenFramebuffersEXT(1, &m_RefractionFbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_RefractionFbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_RefractionTexture->GetHandle(), 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_RefrFboDepthTexture->GetHandle(), 0); - - ogl_WarnIfError(); - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + m_RefractionFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_RefractionTexture.get(), m_RefrFboDepthTexture.get(), CColor(1.0f, 0.0f, 0.0f, 0.0f)); + if (!m_RefractionFramebuffer) { - LOGWARNING("Refraction framebuffer object incomplete: 0x%04X", status); g_RenderingOptions.SetWaterRefraction(false); UpdateQuality(); } - glGenFramebuffersEXT(1, &m_FancyEffectsFBO); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FancyTexture->GetHandle(), 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_FancyTextureDepth->GetHandle(), 0); - - ogl_WarnIfError(); - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + m_FancyEffectsFramebuffer = Renderer::Backend::GL::CFramebuffer::Create( + m_FancyTexture.get(), m_FancyTextureDepth.get()); + if (!m_FancyEffectsFramebuffer) { - LOGWARNING("Fancy Effects framebuffer object incomplete: 0x%04X", status); g_RenderingOptions.SetWaterRefraction(false); UpdateQuality(); } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - // Enable rendering, now that we've succeeded this far m_RenderWater = true; #endif @@ -328,10 +295,10 @@ for (size_t i = 0; i < ARRAY_SIZE(m_NormalMap); i++) m_NormalMap[i].reset(); + m_RefractionFramebuffer.reset(); + m_ReflectionFramebuffer.reset(); m_ReflectionTexture.reset(); m_RefractionTexture.reset(); - glDeleteFramebuffersEXT(1, &m_RefractionFbo); - glDeleteFramebuffersEXT(1, &m_ReflectionFbo); } template @@ -808,13 +775,8 @@ if (!m_WaterFancyEffects) return; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); - - GLuint attachments[1] = { GL_COLOR_ATTACHMENT0_EXT }; - glDrawBuffers(1, attachments); - - glClearColor(0.0f,0.0f, 0.0f,0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + deviceCommandContext->SetFramebuffer(m_FancyEffectsFramebuffer.get()); + deviceCommandContext->ClearFramebuffer(); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_water_waves); tech->BeginPass(); @@ -864,7 +826,8 @@ CVertexBuffer::Unbind(); } tech->EndPass(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + deviceCommandContext->SetFramebuffer( + deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); #endif } Index: ps/trunk/source/renderer/backend/gl/Device.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.h +++ ps/trunk/source/renderer/backend/gl/Device.h @@ -18,6 +18,7 @@ #ifndef INCLUDED_RENDERER_BACKEND_GL_DEVICE #define INCLUDED_RENDERER_BACKEND_GL_DEVICE +#include "renderer/backend/gl/Framebuffer.h" #include "scriptinterface/ScriptForward.h" #include @@ -36,6 +37,8 @@ namespace GL { +class CDeviceCommandContext; + class CDevice { public: @@ -53,6 +56,10 @@ void Report(const ScriptRequest& rq, JS::HandleValue settings); + CFramebuffer* GetCurrentBackbuffer() { return m_Backbuffer.get(); } + + std::unique_ptr CreateCommandContext(); + void Present(); private: @@ -65,6 +72,8 @@ std::string m_Version; std::string m_DriverInformation; std::vector m_Extensions; + + std::unique_ptr m_Backbuffer; }; } // namespace GL Index: ps/trunk/source/renderer/backend/gl/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.cpp +++ ps/trunk/source/renderer/backend/gl/Device.cpp @@ -24,6 +24,7 @@ #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Profile.h" +#include "renderer/backend/gl/DeviceCommandContext.h" #include "scriptinterface/JSON.h" #include "scriptinterface/Object.h" #include "scriptinterface/ScriptInterface.h" @@ -196,6 +197,8 @@ glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + device->m_Backbuffer = CFramebuffer::CreateBackbuffer(); + return device; } @@ -594,6 +597,11 @@ #endif // SDL_VIDEO_DRIVER_X11 } +std::unique_ptr CDevice::CreateCommandContext() +{ + return CDeviceCommandContext::Create(this); +} + void CDevice::Present() { if (m_Window) Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h @@ -34,6 +34,8 @@ namespace GL { +class CDevice; +class CFramebuffer; class CTexture; class CDeviceCommandContext @@ -41,10 +43,16 @@ public: ~CDeviceCommandContext(); - static std::unique_ptr Create(); + CDevice* GetDevice() { return m_Device; } void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc); + void BlitFramebuffer(CFramebuffer* destinationFramebuffer, CFramebuffer* sourceFramebuffer); + + void ClearFramebuffer(); + void ClearFramebuffer(const bool color, const bool depth, const bool stencil); + void SetFramebuffer(CFramebuffer* framebuffer); + void UploadTexture(CTexture* texture, const Format dataFormat, const void* data, const size_t dataSize, const uint32_t level = 0, const uint32_t layer = 0); @@ -65,14 +73,21 @@ void Flush(); private: - CDeviceCommandContext(); + friend class CDevice; + + static std::unique_ptr Create(CDevice* device); + + CDeviceCommandContext(CDevice* device); void ResetStates(); void SetGraphicsPipelineStateImpl( const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force); + CDevice* m_Device = nullptr; + GraphicsPipelineStateDesc m_GraphicsPipelineStateDesc{}; + CFramebuffer* m_Framebuffer = nullptr; uint32_t m_ScissorCount = 0; // GL2.1 doesn't support more than 1 scissor. std::array m_Scissors; Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -19,9 +19,13 @@ #include "DeviceCommandContext.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Mapping.h" #include "renderer/backend/gl/Texture.h" +#include + namespace Renderer { @@ -63,17 +67,40 @@ return !operator==(lhs, rhs); } +void ApplyDepthMask(const bool depthWriteEnabled) +{ + glDepthMask(depthWriteEnabled ? GL_TRUE : GL_FALSE); +} + +void ApplyColorMask(const uint8_t colorWriteMask) +{ + glColorMask( + (colorWriteMask & ColorWriteMask::RED) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::GREEN) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::BLUE) != 0 ? GL_TRUE : GL_FALSE, + (colorWriteMask & ColorWriteMask::ALPHA) != 0 ? GL_TRUE : GL_FALSE); +} + +void ApplyStencilMask(const uint32_t stencilWriteMask) +{ + glStencilMask(stencilWriteMask); +} + } // anonymous namespace // static -std::unique_ptr CDeviceCommandContext::Create() +std::unique_ptr CDeviceCommandContext::Create(CDevice* device) { - std::unique_ptr deviceCommandContext(new CDeviceCommandContext()); + std::unique_ptr deviceCommandContext(new CDeviceCommandContext(device)); + deviceCommandContext->m_Framebuffer = device->GetCurrentBackbuffer(); deviceCommandContext->ResetStates(); return deviceCommandContext; } -CDeviceCommandContext::CDeviceCommandContext() = default; +CDeviceCommandContext::CDeviceCommandContext(CDevice* device) + : m_Device(device) +{ +} CDeviceCommandContext::~CDeviceCommandContext() = default; @@ -99,6 +126,7 @@ const uint32_t width, const uint32_t height, const uint32_t level, const uint32_t layer) { + ENSURE(texture); if (texture->GetType() == CTexture::Type::TEXTURE_2D) { ENSURE(level == 0 && layer == 0); @@ -166,6 +194,7 @@ { SetGraphicsPipelineStateImpl(MakeDefaultGraphicsPipelineStateDesc(), true); SetScissors(0, nullptr); + SetFramebuffer(m_Device->GetCurrentBackbuffer()); } void CDeviceCommandContext::SetGraphicsPipelineStateImpl( @@ -186,7 +215,7 @@ } if (force || currentDepthStencilStateDesc.depthWriteEnabled != nextDepthStencilStateDesc.depthWriteEnabled) { - glDepthMask(nextDepthStencilStateDesc.depthWriteEnabled ? GL_TRUE : GL_FALSE); + ApplyDepthMask(nextDepthStencilStateDesc.depthWriteEnabled); } if (force || currentDepthStencilStateDesc.stencilTestEnabled != nextDepthStencilStateDesc.stencilTestEnabled) @@ -229,7 +258,7 @@ } if (force || currentDepthStencilStateDesc.stencilWriteMask != nextDepthStencilStateDesc.stencilWriteMask) { - glStencilMask(nextDepthStencilStateDesc.stencilWriteMask); + ApplyStencilMask(nextDepthStencilStateDesc.stencilWriteMask); } if (force || currentDepthStencilStateDesc.stencilReference != nextDepthStencilStateDesc.stencilReference || @@ -318,11 +347,7 @@ if (force || currentBlendStateDesc.colorWriteMask != nextBlendStateDesc.colorWriteMask) { - glColorMask( - (nextBlendStateDesc.colorWriteMask & ColorWriteMask::RED) != 0 ? GL_TRUE : GL_FALSE, - (nextBlendStateDesc.colorWriteMask & ColorWriteMask::GREEN) != 0 ? GL_TRUE : GL_FALSE, - (nextBlendStateDesc.colorWriteMask & ColorWriteMask::BLUE) != 0 ? GL_TRUE : GL_FALSE, - (nextBlendStateDesc.colorWriteMask & ColorWriteMask::ALPHA) != 0 ? GL_TRUE : GL_FALSE); + ApplyColorMask(nextBlendStateDesc.colorWriteMask); } const RasterizationStateDesc& currentRasterizationStateDesc = m_GraphicsPipelineStateDesc.rasterizationState; @@ -354,6 +379,77 @@ m_GraphicsPipelineStateDesc = pipelineStateDesc; } +void CDeviceCommandContext::BlitFramebuffer( + CFramebuffer* destinationFramebuffer, CFramebuffer* sourceFramebuffer) +{ +#if CONFIG2_GLES + UNUSED2(destinationFramebuffer); + UNUSED2(sourceFramebuffer); + debug_warn("CDeviceCommandContext::BlitFramebuffer is not implemented for GLES"); +#else + // Source framebuffer should not be backbuffer. + ENSURE( sourceFramebuffer->GetHandle() != 0); + ENSURE( destinationFramebuffer != sourceFramebuffer ); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, sourceFramebuffer->GetHandle()); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, destinationFramebuffer->GetHandle()); + // TODO: add more check for internal formats. And currently we don't support + // scaling inside blit. + glBlitFramebufferEXT( + 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(), + 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(), + (sourceFramebuffer->GetAttachmentMask() & destinationFramebuffer->GetAttachmentMask()), + GL_NEAREST); +#endif +} + +void CDeviceCommandContext::ClearFramebuffer() +{ + ClearFramebuffer(true, true, true); +} + +void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil) +{ + const bool needsColor = color && (m_Framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT) != 0; + const bool needsDepth = depth && (m_Framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) != 0; + const bool needsStencil = stencil && (m_Framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) != 0; + GLbitfield mask = 0; + if (needsColor) + { + ApplyColorMask(ColorWriteMask::RED | ColorWriteMask::GREEN | ColorWriteMask::BLUE | ColorWriteMask::ALPHA); + glClearColor( + m_Framebuffer->GetClearColor().r, + m_Framebuffer->GetClearColor().g, + m_Framebuffer->GetClearColor().b, + m_Framebuffer->GetClearColor().a); + mask |= GL_COLOR_BUFFER_BIT; + } + if (needsDepth) + { + ApplyDepthMask(true); + mask |= GL_DEPTH_BUFFER_BIT; + } + if (needsStencil) + { + ApplyStencilMask(std::numeric_limits::max()); + mask |= GL_STENCIL_BUFFER_BIT; + } + glClear(mask); + if (needsColor) + ApplyColorMask(m_GraphicsPipelineStateDesc.blendState.colorWriteMask); + if (needsDepth) + ApplyDepthMask(m_GraphicsPipelineStateDesc.depthStencilState.depthWriteEnabled); + if (needsStencil) + ApplyStencilMask(m_GraphicsPipelineStateDesc.depthStencilState.stencilWriteMask); +} + +void CDeviceCommandContext::SetFramebuffer(CFramebuffer* framebuffer) +{ + ENSURE(framebuffer); + ENSURE(framebuffer->GetHandle() == 0 || (framebuffer->GetWidth() > 0 && framebuffer->GetHeight() > 0)); + m_Framebuffer = framebuffer; + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->GetHandle()); +} + void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const ScissorRect* scissors) { ENSURE(scissorCount <= 1); @@ -366,9 +462,9 @@ { if (m_ScissorCount != scissorCount) glEnable(GL_SCISSOR_TEST); + ENSURE(scissors); if (m_ScissorCount != scissorCount || m_Scissors[0] != scissors[0]) { - ENSURE(scissors); m_Scissors[0] = scissors[0]; glScissor(m_Scissors[0].x, m_Scissors[0].y, m_Scissors[0].width, m_Scissors[0].height); } Index: ps/trunk/source/renderer/backend/gl/Framebuffer.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Framebuffer.h +++ ps/trunk/source/renderer/backend/gl/Framebuffer.h @@ -0,0 +1,75 @@ +/* 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 + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER +#define INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER + +#include "graphics/Color.h" +#include "lib/ogl.h" +#include "renderer/backend/gl/Texture.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +class CFramebuffer +{ +public: + static std::unique_ptr Create( + CTexture* colorAttachment, CTexture* depthStencilAttachment); + static std::unique_ptr Create( + CTexture* colorAttachment, CTexture* depthStencilAttachment, const CColor& clearColor); + + ~CFramebuffer(); + + GLuint GetHandle() const { return m_Handle; } + GLbitfield GetAttachmentMask() const { return m_AttachmentMask; } + const CColor& GetClearColor() const { return m_ClearColor; } + + uint32_t GetWidth() const { return m_Width; } + uint32_t GetHeight() const { return m_Height; } + +private: + friend class CDevice; + + static std::unique_ptr CreateBackbuffer(); + + CFramebuffer(); + + GLuint m_Handle = 0; + uint32_t m_Width = 0, m_Height = 0; + GLbitfield m_AttachmentMask = 0; + CColor m_ClearColor; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_FRAMEBUFFER Index: ps/trunk/source/renderer/backend/gl/Framebuffer.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Framebuffer.cpp +++ ps/trunk/source/renderer/backend/gl/Framebuffer.cpp @@ -0,0 +1,169 @@ +/* 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 + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Framebuffer.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "lib/res/graphics/ogl_tex.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Texture.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +// static +std::unique_ptr CFramebuffer::Create( + CTexture* colorAttachment, CTexture* depthStencilAttachment) +{ + return Create(colorAttachment, depthStencilAttachment, CColor(0.0f, 0.0f, 0.0f, 0.0f)); +} + +// static +std::unique_ptr CFramebuffer::Create( + CTexture* colorAttachment, CTexture* depthStencilAttachment, + const CColor& clearColor) +{ + ENSURE(colorAttachment || depthStencilAttachment); + + std::unique_ptr framebuffer(new CFramebuffer()); + framebuffer->m_ClearColor = clearColor; + + glGenFramebuffersEXT(1, &framebuffer->m_Handle); + if (!framebuffer->m_Handle) + { + LOGERROR("Failed to create CFramebuffer object"); + return nullptr; + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->m_Handle); + + if (colorAttachment) + { + framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT; + +#if CONFIG2_GLES + ENSURE(colorAttachment->GetType() == CTexture::Type::TEXTURE_2D); + const GLenum textureTarget = GL_TEXTURE_2D; +#else + const GLenum textureTarget = colorAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; +#endif + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + textureTarget, colorAttachment->GetHandle(), 0); + } + if (depthStencilAttachment) + { + framebuffer->m_Width = depthStencilAttachment->GetWidth(); + framebuffer->m_Height = depthStencilAttachment->GetHeight(); + framebuffer->m_AttachmentMask |= GL_DEPTH_BUFFER_BIT; + if (depthStencilAttachment->GetFormat() == Format::D24_S8) + framebuffer->m_AttachmentMask |= GL_STENCIL_BUFFER_BIT; + if (colorAttachment) + { + ENSURE(colorAttachment->GetWidth() == depthStencilAttachment->GetWidth()); + ENSURE(colorAttachment->GetHeight() == depthStencilAttachment->GetHeight()); + ENSURE(colorAttachment->GetType() == depthStencilAttachment->GetType()); + } + ENSURE( + depthStencilAttachment->GetFormat() == Format::D16 || + depthStencilAttachment->GetFormat() == Format::D24 || + depthStencilAttachment->GetFormat() == Format::D32 || + depthStencilAttachment->GetFormat() == Format::D24_S8); +#if CONFIG2_GLES + ENSURE(depthStencilAttachment->GetFormat() != Format::D24_S8); + const GLenum attachment = GL_DEPTH_ATTACHMENT; + ENSURE(depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D); + const GLenum textureTarget = GL_TEXTURE_2D; +#else + const GLenum attachment = depthStencilAttachment->GetFormat() == Format::D24_S8 ? + GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; + const GLenum textureTarget = depthStencilAttachment->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ? + GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; +#endif + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + textureTarget, depthStencilAttachment->GetHandle(), 0); + } + else + { + framebuffer->m_Width = colorAttachment->GetWidth(); + framebuffer->m_Height = colorAttachment->GetHeight(); + } + + ogl_WarnIfError(); + +#if !CONFIG2_GLES + if (!colorAttachment) + { + glReadBuffer(GL_NONE); + glDrawBuffer(GL_NONE); + } + else + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); +#endif + + ogl_WarnIfError(); + + const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + LOGERROR("CFramebuffer object incomplete: 0x%04X", status); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + return nullptr; + } + + ogl_WarnIfError(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + return framebuffer; +} + +// static +std::unique_ptr CFramebuffer::CreateBackbuffer() +{ + // Backbuffer for GL is a special case with a zero framebuffer. + std::unique_ptr framebuffer(new CFramebuffer()); + framebuffer->m_AttachmentMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + CStr skyString = "0 0 0"; + CFG_GET_VAL("skycolor", skyString); + framebuffer->m_ClearColor.ParseString(skyString, 0.0f); + return framebuffer; +} + +CFramebuffer::CFramebuffer() = default; + +CFramebuffer::~CFramebuffer() +{ + if (m_Handle) + glDeleteFramebuffersEXT(1, &m_Handle); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer