Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "Framebuffer.h"
21 :
22 : #include "lib/code_annotation.h"
23 : #include "lib/config2.h"
24 : #include "ps/CLogger.h"
25 : #include "renderer/backend/gl/Device.h"
26 : #include "renderer/backend/gl/Texture.h"
27 :
28 : namespace Renderer
29 : {
30 :
31 : namespace Backend
32 : {
33 :
34 : namespace GL
35 : {
36 :
37 : // static
38 0 : std::unique_ptr<CFramebuffer> CFramebuffer::Create(
39 : CDevice* device, const char* name, SColorAttachment* colorAttachment,
40 : SDepthStencilAttachment* depthStencilAttachment)
41 : {
42 0 : ENSURE(colorAttachment || depthStencilAttachment);
43 :
44 0 : std::unique_ptr<CFramebuffer> framebuffer(new CFramebuffer());
45 0 : framebuffer->m_Device = device;
46 0 : if (colorAttachment)
47 : {
48 0 : framebuffer->m_ClearColor = colorAttachment->clearColor;
49 0 : framebuffer->m_ColorAttachmentLoadOp = colorAttachment->loadOp;
50 0 : framebuffer->m_ColorAttachmentStoreOp = colorAttachment->storeOp;
51 : }
52 0 : if (depthStencilAttachment)
53 : {
54 0 : framebuffer->m_DepthStencilAttachmentLoadOp = depthStencilAttachment->loadOp;
55 0 : framebuffer->m_DepthStencilAttachmentStoreOp = depthStencilAttachment->storeOp;
56 : }
57 :
58 0 : glGenFramebuffersEXT(1, &framebuffer->m_Handle);
59 0 : if (!framebuffer->m_Handle)
60 : {
61 0 : LOGERROR("Failed to create CFramebuffer object");
62 0 : return nullptr;
63 : }
64 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->m_Handle);
65 :
66 0 : if (colorAttachment)
67 : {
68 0 : CTexture* colorAttachmentTexture = colorAttachment->texture->As<CTexture>();
69 0 : ENSURE(device->IsFramebufferFormatSupported(colorAttachmentTexture->GetFormat()));
70 0 : ENSURE(colorAttachmentTexture->GetUsage() & Renderer::Backend::ITexture::Usage::COLOR_ATTACHMENT);
71 :
72 0 : framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT;
73 :
74 : #if CONFIG2_GLES
75 : ENSURE(colorAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D);
76 : const GLenum textureTarget = GL_TEXTURE_2D;
77 : #else
78 0 : const GLenum textureTarget = colorAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ?
79 0 : GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
80 : #endif
81 0 : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
82 : textureTarget, colorAttachmentTexture->GetHandle(), 0);
83 : }
84 :
85 0 : if (depthStencilAttachment)
86 : {
87 0 : CTexture* depthStencilAttachmentTexture = depthStencilAttachment->texture->As<CTexture>();
88 0 : ENSURE(depthStencilAttachmentTexture->GetUsage() & Renderer::Backend::ITexture::Usage::DEPTH_STENCIL_ATTACHMENT);
89 :
90 0 : framebuffer->m_Width = depthStencilAttachmentTexture->GetWidth();
91 0 : framebuffer->m_Height = depthStencilAttachmentTexture->GetHeight();
92 0 : framebuffer->m_AttachmentMask |= GL_DEPTH_BUFFER_BIT;
93 : const bool hasStencil =
94 0 : depthStencilAttachmentTexture->GetFormat() == Format::D24_UNORM_S8_UINT ||
95 0 : depthStencilAttachmentTexture->GetFormat() == Format::D32_SFLOAT_S8_UINT;
96 0 : if (hasStencil)
97 0 : framebuffer->m_AttachmentMask |= GL_STENCIL_BUFFER_BIT;
98 0 : if (colorAttachment)
99 : {
100 0 : ENSURE(colorAttachment->texture->GetWidth() == depthStencilAttachmentTexture->GetWidth());
101 0 : ENSURE(colorAttachment->texture->GetHeight() == depthStencilAttachmentTexture->GetHeight());
102 0 : ENSURE(colorAttachment->texture->GetType() == depthStencilAttachmentTexture->GetType());
103 : }
104 0 : ENSURE(IsDepthFormat(depthStencilAttachmentTexture->GetFormat()));
105 : #if CONFIG2_GLES
106 : ENSURE(depthStencilAttachmentTexture->GetFormat() == Format::D24_UNORM);
107 : const GLenum attachment = GL_DEPTH_ATTACHMENT;
108 : ENSURE(depthStencilAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D);
109 : const GLenum textureTarget = GL_TEXTURE_2D;
110 : #else
111 0 : const GLenum attachment = hasStencil ?
112 : GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
113 0 : const GLenum textureTarget = depthStencilAttachmentTexture->GetType() == CTexture::Type::TEXTURE_2D_MULTISAMPLE ?
114 0 : GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
115 : #endif
116 0 : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
117 : textureTarget, depthStencilAttachmentTexture->GetHandle(), 0);
118 : }
119 : else
120 : {
121 0 : framebuffer->m_Width = colorAttachment->texture->GetWidth();
122 0 : framebuffer->m_Height = colorAttachment->texture->GetHeight();
123 : }
124 :
125 0 : ogl_WarnIfError();
126 :
127 : #if !CONFIG2_GLES
128 0 : if (!colorAttachment)
129 : {
130 0 : glReadBuffer(GL_NONE);
131 0 : glDrawBuffer(GL_NONE);
132 : }
133 : else
134 0 : glDrawBuffer(GL_COLOR_ATTACHMENT0);
135 : #endif
136 :
137 0 : ogl_WarnIfError();
138 :
139 : #if !CONFIG2_GLES
140 0 : if (framebuffer->m_Device->GetCapabilities().debugLabels)
141 : {
142 0 : glObjectLabel(GL_FRAMEBUFFER, framebuffer->m_Handle, -1, name);
143 : }
144 : #else
145 : UNUSED2(name);
146 : #endif
147 :
148 0 : const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
149 0 : if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
150 : {
151 0 : LOGERROR("CFramebuffer object incomplete: 0x%04X", status);
152 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
153 0 : return nullptr;
154 : }
155 :
156 0 : ogl_WarnIfError();
157 :
158 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
159 :
160 0 : return framebuffer;
161 : }
162 :
163 : // static
164 0 : std::unique_ptr<CFramebuffer> CFramebuffer::CreateBackbuffer(
165 : CDevice* device,
166 : const int surfaceDrawableWidth, const int surfaceDrawableHeight,
167 : const AttachmentLoadOp colorAttachmentLoadOp,
168 : const AttachmentStoreOp colorAttachmentStoreOp,
169 : const AttachmentLoadOp depthStencilAttachmentLoadOp,
170 : const AttachmentStoreOp depthStencilAttachmentStoreOp)
171 : {
172 : // Backbuffer for GL is a special case with a zero framebuffer.
173 0 : std::unique_ptr<CFramebuffer> framebuffer(new CFramebuffer());
174 0 : framebuffer->m_Device = device;
175 0 : framebuffer->m_AttachmentMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
176 0 : framebuffer->m_ClearColor = CColor(0.0f, 0.0f, 0.0f, 0.0f);
177 0 : framebuffer->m_ColorAttachmentLoadOp = colorAttachmentLoadOp;
178 0 : framebuffer->m_ColorAttachmentStoreOp = colorAttachmentStoreOp;
179 0 : framebuffer->m_DepthStencilAttachmentLoadOp = depthStencilAttachmentLoadOp;
180 0 : framebuffer->m_DepthStencilAttachmentStoreOp = depthStencilAttachmentStoreOp;
181 0 : framebuffer->m_Width = surfaceDrawableWidth;
182 0 : framebuffer->m_Height = surfaceDrawableHeight;
183 0 : return framebuffer;
184 : }
185 :
186 : CFramebuffer::CFramebuffer() = default;
187 :
188 0 : CFramebuffer::~CFramebuffer()
189 : {
190 0 : if (m_Handle)
191 0 : glDeleteFramebuffersEXT(1, &m_Handle);
192 0 : }
193 :
194 0 : IDevice* CFramebuffer::GetDevice()
195 : {
196 0 : return m_Device;
197 : }
198 :
199 : } // namespace GL
200 :
201 : } // namespace Backend
202 :
203 3 : } // namespace Renderer
|