Cogs.Core
RenderTargetsGL20.cpp
1#include "RenderTargetsGL20.h"
2#include "TexturesGL20.h"
3#include "GraphicsDeviceGL20.h"
4
5#include "Foundation/Logging/Logger.h"
6
7namespace
8{
9 static Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderTargetsGL20");
10
11 bool checkFrameBuffer()
12 {
13 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
14
15 if (status == GL_FRAMEBUFFER_UNDEFINED) { return false; }
16 else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
17 LOG_ERROR(logger, "FBO contains unsupported image formats.");
18 return false;
19 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
20 LOG_ERROR(logger, "FBO incomplete, missing any image attachments.");
21 return false;
22 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
23 LOG_ERROR(logger, "FBO incomplete, missing complete attachments.");
24 return false;
25 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) {
26 LOG_ERROR(logger, "FBO incomplete, draw buffer.");
27 return false;
28 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) {
29 LOG_ERROR(logger, "FBO incomplete, read buffer.");
30 return false;
31 } else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
32 LOG_ERROR(logger, "FBO incomplete, unsupported combination of internal formats.");
33 return false;
34 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) {
35 LOG_ERROR(logger, "FBO incomplete, multisample.");
36 return false;
37 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS) {
38 LOG_ERROR(logger, "FBO incomplete, layers.");
39 return false;
40 }
41 assert(status == GL_FRAMEBUFFER_COMPLETE);
42
43 return true;
44 }
45}
46
47Cogs::RenderTargetsGL20::~RenderTargetsGL20()
48{
49 if (this->renderTargets.size()) {
50 LOG_WARNING(logger, "Render targets resources not empty. %zu resources left.", this->renderTargets.size());
51 }
52 if (this->depthStencils.size()) {
53 LOG_WARNING(logger, "Depth stencil target resources not empty. %zu resources left.", this->depthStencils.size());
54 }
55}
56
58{
59 RenderTargetGL20 renderTarget = {};
60
61 glGenFramebuffers(1, &renderTarget.frameBuffer);
62 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.frameBuffer);
63
64 renderTarget.numTextures = numViews;
65
66 for (size_t i = 0; i < numViews; ++i) {
67 TextureGL20 & texture = this->textures->textures[renderTargetViews[i].texture];
68 GLenum target = texture.type;
69 renderTarget.textures[i] = renderTargetViews[i].texture;
70
71 if(target == GL_TEXTURE_CUBE_MAP){
72 GLint face = renderTargetViews[i].layerIndex%6;
73 GLint layer = renderTargetViews[i].layerIndex/6;
74 assert(layer == 0);
75 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
76 GL_TEXTURE_CUBE_MAP_POSITIVE_X+face,
77 texture.textureId, renderTargetViews[i].layerIndex);
78 } else if(target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_2D_ARRAY) {
79 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
80 texture.textureId,
81 renderTargetViews[i].levelIndex, renderTargetViews[i].layerIndex);
82 } else {
83 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
84 target, texture.textureId, renderTargetViews[i].levelIndex);
85 }
86 }
87
88 if (numViews && !checkFrameBuffer()) {
90 }
91
92 glBindFramebuffer(GL_FRAMEBUFFER, 0);
93
94 return this->renderTargets.addResource(renderTarget);
95}
96
98{
99 auto & renderTarget = this->renderTargets[renderTargetHandle];
100
101 glDeleteFramebuffers(1, &renderTarget.frameBuffer);
102
103 this->renderTargets.removeResource(renderTargetHandle);
104}
105
107{
108 RenderTargetGL20 & renderTarget = this->renderTargets[handle];
109 TextureGL20 & texture = this->textures->textures[renderTarget.textures[0]];
110
111 GLuint depthRenderBuffer;
112 glGenRenderbuffers(1, &depthRenderBuffer);
113 glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
114
115 GLenum format = GL_DEPTH_COMPONENT32F;
116 if (texture.numSamples == 1) {
117 glRenderbufferStorage(GL_RENDERBUFFER, format, texture.width, texture.height);
118 } else {
119 glRenderbufferStorageMultisample(GL_RENDERBUFFER, texture.numSamples, format, texture.width, texture.height);
120 }
121
122 glBindRenderbuffer(GL_RENDERBUFFER, 0);
123
124 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.frameBuffer);
125 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
126
127 if (!checkFrameBuffer()){
129 }
130
131 glBindFramebuffer(GL_FRAMEBUFFER, 0);
132
133 DepthStencilTargetGL20 depthStencilTarget = { TextureHandle::NoHandle, handle, true, depthRenderBuffer };
134
135 return this->depthStencils.addResource(depthStencilTarget);
136}
137
139{
140 RenderTargetHandle renderTargetHandle = handle;
141 if(!HandleIsValid(renderTargetHandle)){
142 renderTargetHandle = createRenderTarget(nullptr, 0);
143 }
144 RenderTargetGL20 & renderTarget = this->renderTargets[renderTargetHandle];
145 TextureGL20 & texture = this->textures->textures[textureHandle];
146 GLenum target = texture.type;
147
148 GLuint frameBuffer = renderTarget.frameBuffer;
149
150 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
151 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, texture.textureId, 0);
152
153 if (!checkFrameBuffer()){
155 }
156
157 glBindFramebuffer(GL_FRAMEBUFFER, 0);
158
159 DepthStencilTargetGL20 depthTarget = { textureHandle, renderTargetHandle, false, frameBuffer };
160
161 return this->depthStencils.addResource(depthTarget);
162}
163
165{
166 RenderTargetHandle renderTargetHandle = handle;
167 if(!HandleIsValid(renderTargetHandle)){
168 renderTargetHandle = createRenderTarget(nullptr, 0);
169 }
170 RenderTargetGL20 & renderTarget = this->renderTargets[renderTargetHandle];
171 TextureGL20 & texture = this->textures->textures[depthStencilView.texture];
172 GLenum target = texture.type;
173 GLuint frameBuffer = renderTarget.frameBuffer;
174
175 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
176
177 if(target == GL_TEXTURE_CUBE_MAP){
178 GLint face = depthStencilView.layerIndex%6;
179 GLint layer = depthStencilView.layerIndex/6;
180 assert(layer == 0);
181 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
182 GL_TEXTURE_CUBE_MAP_POSITIVE_X+face,
183 texture.textureId, depthStencilView.levelIndex);
184 }
185 else if(target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_2D_ARRAY){
186 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture.textureId,
187 depthStencilView.levelIndex, depthStencilView.layerIndex);
188 }
189 else if(depthStencilView.layerIndex == 0){
190 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
191 target, texture.textureId, depthStencilView.levelIndex);
192 }
193
194 if (!checkFrameBuffer()){
196 }
197
198 glBindFramebuffer(GL_FRAMEBUFFER, 0);
199
200 DepthStencilTargetGL20 depthTarget = { depthStencilView.texture, renderTargetHandle, false, frameBuffer };
201
202 return this->depthStencils.addResource(depthTarget);
203}
204
206{
207 auto & depthStencil = this->depthStencils[depthStencilHandle];
208
209 if (depthStencil.renderBuffer) {
210 glDeleteRenderbuffers(1, &depthStencil.depthBuffer);
211 }
212
213 this->depthStencils.removeResource(depthStencilHandle);
214}
215
217{
218 RenderTargetLayout layout;
219
220 if (HandleIsValid(renderTargetHandle)) {
221 const RenderTargetGL20 & renderTarget = this->renderTargets[renderTargetHandle];
222 layout.numColorTargets = static_cast<uint8_t>(renderTarget.numTextures);
223
224 for (size_t i = 0; i < renderTarget.numTextures; ++i) {
225 const TextureGL20 & texture = this->textures->textures[renderTarget.textures[i]];
226 layout.colorFormats[i] = texture.format;
227 layout.samples = static_cast<uint8_t>(texture.numSamples);
228 }
229 } else {
230 const GraphicsDeviceSettings & settings = graphicsDevice->getSettings();
231 layout.numColorTargets = 1;
232 layout.colorFormats[0] = settings.colorFormat;
233 layout.samples = static_cast<uint8_t>(settings.numSamples);
234 }
235
236 if (HandleIsValid(depthStencilHandle)) {
237 const DepthStencilTargetGL20 & depthStencil = this->depthStencils[depthStencilHandle];
238 layout.depthStencilFormat = HandleIsValid(depthStencil.texture)
239 ? this->textures->textures[depthStencil.texture].format
240 : TextureFormat::D32_FLOAT; // Renderbuffer-only depth targets are always created as GL_DEPTH_COMPONENT32F.
241 } else if (!HandleIsValid(renderTargetHandle)) {
242 layout.depthStencilFormat = graphicsDevice->getSettings().depthFormat;
243 }
244
245 return layout;
246}
247
249{
250 return this->depthStencilStates.addResource(depthStencilState);
251}
252
254{
255 this->depthStencilStates.removeResource(handle);
256}
257
259{
260 return this->rasterizerStates.addResource(rasterizerState);
261}
262
264{
265 this->rasterizerStates.removeResource(handle);
266}
267
269{
270 return loadBlendState(blendState, blendState);
271}
272
274{
275 BlendStateGL20 blendState{};
276 blendState.color = blendStateColor;
277 blendState.alpha = blendStateAlpha;
278 return this->blendStates.addResource(std::move(blendState));
279}
280
281
283{
284 this->blendStates.removeResource(handle);
285}
286
288{
289 std::vector<RenderTargetHandle> rtHandles;
290 for (auto & rt : renderTargets) {
291 rtHandles.push_back(renderTargets.getHandle(rt));
292 }
293
294 for (auto & handle : rtHandles) {
295 releaseRenderTarget(handle);
296 }
297
298 std::vector<DepthStencilHandle> dsHandles;
299 for (auto & ds : depthStencils) {
300 dsHandles.push_back(depthStencils.getHandle(ds));
301 }
302
303 for (auto & handle : dsHandles) {
304 releaseDepthStencilTarget(handle);
305 }
306
307 this->blendStates.clear();
308 this->rasterizerStates.clear();
309 this->depthStencilStates.clear();
310}
311
313{
314 if(name.empty() || !HandleIsValid(handle)) return;
315
316#ifndef __APPLE__
317 auto & renderTarget = this->renderTargets[handle];
318 glObjectLabel(GL_FRAMEBUFFER, renderTarget.frameBuffer, static_cast<GLsizei>(name.size()), name.data());
319#else
320 (void)name;
321#endif
322}
323
325{
326 if(name.empty() || !HandleIsValid(handle)) return;
327
328 auto & depthStencil = this->depthStencils[handle];
329 if(depthStencil.renderBuffer){
330#ifndef __APPLE__
331 glObjectLabel(GL_RENDERBUFFER, depthStencil.depthBuffer, static_cast<GLsizei>(name.size()), name.data());
332#else
333 (void)name;
334#endif
335 }
336}
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:197
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:204
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:148
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Encapsulates blend state for the graphics pipeline in a state object.
Definition: BlendState.h:9
Encapsulates state for depth buffer usage and stencil buffer usage in a state object.
Describes a single depth stencil view and which resources to use from the underlying texture.
TextureHandle texture
Texture handle.
uint8_t levelIndex
Index of the mipmap level to render to.
uint16_t layerIndex
Index of the first layer (if array) to write depth to.
Settings for graphics device initialization.
int numSamples
Number of samples to use for back buffer MSAA.
TextureFormat colorFormat
Back buffer format.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81
Encapsulates state for primitive rasterization in a state object.
Describes the formats and sample count of a render target's attachments.
TextureFormat colorFormats[8]
Formats of the color targets, only the first numColorTargets entries are valid.
TextureFormat depthStencilFormat
Format of the depth stencil target, TextureFormat::Unknown if there is none.
uint8_t samples
Number of samples, 1 implies no multisampling.
uint8_t numColorTargets
Number of valid entries in colorFormats.
Describes a single render target view and which resources to use from the underlying texture.
uint16_t layerIndex
Index of the first layer (if array) to render to.
TextureHandle texture
Texture handle.
uint8_t levelIndex
Index of the mipmap level to render to.
void releaseRasterizerState(RasterizerStateHandle handle) override
Release the rasterizer state with the given handle.
void releaseRenderTarget(RenderTargetHandle renderTargetHandle) override
Release the render target with the given renderTargetHandle.
void releaseResources() override
Release all allocated render target resources.
void releaseBlendState(BlendStateHandle handle) override
Release the blend state with the given handle.
void releaseDepthStencilTarget(DepthStencilHandle depthStencilHandle) override
Release the depth target with the given depthStencilHandle.
RenderTargetHandle createRenderTarget(const RenderTargetViewDescription *renderTargetViews, const size_t numViews) override
Create a render target using the given view descriptions.
RenderTargetLayout getLayout(const RenderTargetHandle renderTargetHandle, const DepthStencilHandle depthStencilHandle) override
Get the view layout for the given render target / depth stencil target pair.
void releaseDepthStencilState(DepthStencilStateHandle handle) override
Release the depth stencil state with the given handle.
BlendStateHandle loadBlendState(const BlendState &blendState) override
Load a blend state object.
DepthStencilHandle createDepthStencilTarget(const RenderTargetHandle handle) override
Creates a depth/stencil target to back the render target with the given handle.
void annotate(RenderTargetHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
DepthStencilStateHandle loadDepthStencilState(const DepthStencilState &depthStencilState) override
Load a depth stencil state object.
RasterizerStateHandle loadRasterizerState(const RasterizerState &rasterizerState) override
Load a rasterizer state object.