Cogs.Core
RenderTargetsGL20.cpp
1#include "RenderTargetsGL20.h"
2#include "TexturesGL20.h"
3
4#include "Foundation/Logging/Logger.h"
5
6namespace
7{
8 static Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderTargetsGL20");
9
10 bool checkFrameBuffer()
11 {
12 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
13
14 if (status == GL_FRAMEBUFFER_UNDEFINED) { return false; }
15 else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
16 LOG_ERROR(logger, "FBO contains unsupported image formats.");
17 return false;
18 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
19 LOG_ERROR(logger, "FBO incomplete, missing any image attachments.");
20 return false;
21 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
22 LOG_ERROR(logger, "FBO incomplete, missing complete attachments.");
23 return false;
24 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) {
25 LOG_ERROR(logger, "FBO incomplete, draw buffer.");
26 return false;
27 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) {
28 LOG_ERROR(logger, "FBO incomplete, read buffer.");
29 return false;
30 } else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
31 LOG_ERROR(logger, "FBO incomplete, unsupported combination of internal formats.");
32 return false;
33 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) {
34 LOG_ERROR(logger, "FBO incomplete, multisample.");
35 return false;
36 } else if (status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS) {
37 LOG_ERROR(logger, "FBO incomplete, layers.");
38 return false;
39 }
40 assert(status == GL_FRAMEBUFFER_COMPLETE);
41
42 return true;
43 }
44}
45
46Cogs::RenderTargetsGL20::~RenderTargetsGL20()
47{
48 if (this->renderTargets.size()) {
49 LOG_WARNING(logger, "Render targets resources not empty. %zu resources left.", this->renderTargets.size());
50 }
51 if (this->depthStencils.size()) {
52 LOG_WARNING(logger, "Depth stencil target resources not empty. %zu resources left.", this->depthStencils.size());
53 }
54}
55
57{
58 RenderTargetGL20 renderTarget = {};
59
60 glGenFramebuffers(1, &renderTarget.frameBuffer);
61 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.frameBuffer);
62
63 renderTarget.numTextures = numViews;
64
65 for (size_t i = 0; i < numViews; ++i) {
66 TextureGL20 & texture = this->textures->textures[renderTargetViews[i].texture];
67 GLenum target = texture.type;
68 renderTarget.textures[i] = renderTargetViews[i].texture;
69
70 if(target == GL_TEXTURE_CUBE_MAP){
71 GLint face = renderTargetViews[i].layerIndex%6;
72 GLint layer = renderTargetViews[i].layerIndex/6;
73 assert(layer == 0);
74 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
75 GL_TEXTURE_CUBE_MAP_POSITIVE_X+face,
76 texture.textureId, renderTargetViews[i].layerIndex);
77 } else if(target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_2D_ARRAY) {
78 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
79 texture.textureId,
80 renderTargetViews[i].levelIndex, renderTargetViews[i].layerIndex);
81 } else {
82 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i),
83 target, texture.textureId, renderTargetViews[i].levelIndex);
84 }
85 }
86
87 if (numViews && !checkFrameBuffer()) {
89 }
90
91 glBindFramebuffer(GL_FRAMEBUFFER, 0);
92
93 return this->renderTargets.addResource(renderTarget);
94}
95
97{
98 auto & renderTarget = this->renderTargets[renderTargetHandle];
99
100 glDeleteFramebuffers(1, &renderTarget.frameBuffer);
101
102 this->renderTargets.removeResource(renderTargetHandle);
103}
104
106{
107 RenderTargetGL20 & renderTarget = this->renderTargets[handle];
108 TextureGL20 & texture = this->textures->textures[renderTarget.textures[0]];
109
110 GLuint depthRenderBuffer;
111 glGenRenderbuffers(1, &depthRenderBuffer);
112 glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
113
114 GLenum format = GL_DEPTH_COMPONENT32F;
115 if (texture.numSamples == 1) {
116 glRenderbufferStorage(GL_RENDERBUFFER, format, texture.width, texture.height);
117 } else {
118 glRenderbufferStorageMultisample(GL_RENDERBUFFER, texture.numSamples, format, texture.width, texture.height);
119 }
120
121 glBindRenderbuffer(GL_RENDERBUFFER, 0);
122
123 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.frameBuffer);
124 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
125
126 if (!checkFrameBuffer()){
128 }
129
130 glBindFramebuffer(GL_FRAMEBUFFER, 0);
131
132 DepthStencilTargetGL20 depthStencilTarget = { TextureHandle::NoHandle, handle, true, depthRenderBuffer };
133
134 return this->depthStencils.addResource(depthStencilTarget);
135}
136
138{
139 RenderTargetHandle renderTargetHandle = handle;
140 if(!HandleIsValid(renderTargetHandle)){
141 renderTargetHandle = createRenderTarget(nullptr, 0);
142 }
143 RenderTargetGL20 & renderTarget = this->renderTargets[renderTargetHandle];
144 TextureGL20 & texture = this->textures->textures[textureHandle];
145 GLenum target = texture.type;
146
147 GLuint frameBuffer = renderTarget.frameBuffer;
148
149 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
150 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, texture.textureId, 0);
151
152 if (!checkFrameBuffer()){
154 }
155
156 glBindFramebuffer(GL_FRAMEBUFFER, 0);
157
158 DepthStencilTargetGL20 depthTarget = { textureHandle, renderTargetHandle, false, frameBuffer };
159
160 return this->depthStencils.addResource(depthTarget);
161}
162
164{
165 RenderTargetHandle renderTargetHandle = handle;
166 if(!HandleIsValid(renderTargetHandle)){
167 renderTargetHandle = createRenderTarget(nullptr, 0);
168 }
169 RenderTargetGL20 & renderTarget = this->renderTargets[renderTargetHandle];
170 TextureGL20 & texture = this->textures->textures[depthStencilView.texture];
171 GLenum target = texture.type;
172 GLuint frameBuffer = renderTarget.frameBuffer;
173
174 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
175
176 if(target == GL_TEXTURE_CUBE_MAP){
177 GLint face = depthStencilView.layerIndex%6;
178 GLint layer = depthStencilView.layerIndex/6;
179 assert(layer == 0);
180 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
181 GL_TEXTURE_CUBE_MAP_POSITIVE_X+face,
182 texture.textureId, depthStencilView.levelIndex);
183 }
184 else if(target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_2D_ARRAY){
185 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture.textureId,
186 depthStencilView.levelIndex, depthStencilView.layerIndex);
187 }
188 else if(depthStencilView.layerIndex == 0){
189 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
190 target, texture.textureId, depthStencilView.levelIndex);
191 }
192
193 if (!checkFrameBuffer()){
195 }
196
197 glBindFramebuffer(GL_FRAMEBUFFER, 0);
198
199 DepthStencilTargetGL20 depthTarget = { depthStencilView.texture, renderTargetHandle, false, frameBuffer };
200
201 return this->depthStencils.addResource(depthTarget);
202}
203
205{
206 auto & depthStencil = this->depthStencils[depthStencilHandle];
207
208 if (depthStencil.renderBuffer) {
209 glDeleteRenderbuffers(1, &depthStencil.depthBuffer);
210 }
211
212 this->depthStencils.removeResource(depthStencilHandle);
213}
214
216{
217 return this->depthStencilStates.addResource(depthStencilState);
218}
219
221{
222 this->depthStencilStates.removeResource(handle);
223}
224
226{
227 return this->rasterizerStates.addResource(rasterizerState);
228}
229
231{
232 this->rasterizerStates.removeResource(handle);
233}
234
236{
237 return loadBlendState(blendState, blendState);
238}
239
241{
242 BlendStateGL20 blendState{};
243 blendState.color = blendStateColor;
244 blendState.alpha = blendStateAlpha;
245 return this->blendStates.addResource(std::move(blendState));
246}
247
248
250{
251 this->blendStates.removeResource(handle);
252}
253
255{
256 std::vector<RenderTargetHandle> rtHandles;
257 for (auto & rt : renderTargets) {
258 rtHandles.push_back(renderTargets.getHandle(rt));
259 }
260
261 for (auto & handle : rtHandles) {
262 releaseRenderTarget(handle);
263 }
264
265 std::vector<DepthStencilHandle> dsHandles;
266 for (auto & ds : depthStencils) {
267 dsHandles.push_back(depthStencils.getHandle(ds));
268 }
269
270 for (auto & handle : dsHandles) {
271 releaseDepthStencilTarget(handle);
272 }
273
274 this->blendStates.clear();
275 this->rasterizerStates.clear();
276 this->depthStencilStates.clear();
277}
278
280{
281 if(name.empty() || !HandleIsValid(handle)) return;
282
283#ifndef __APPLE__
284 auto & renderTarget = this->renderTargets[handle];
285 glObjectLabel(GL_FRAMEBUFFER, renderTarget.frameBuffer, static_cast<GLsizei>(name.size()), name.data());
286#else
287 (void)name;
288#endif
289}
290
292{
293 if(name.empty() || !HandleIsValid(handle)) return;
294
295 auto & depthStencil = this->depthStencils[handle];
296 if(depthStencil.renderBuffer){
297#ifndef __APPLE__
298 glObjectLabel(GL_RENDERBUFFER, depthStencil.depthBuffer, static_cast<GLsizei>(name.size()), name.data());
299#else
300 (void)name;
301#endif
302 }
303}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:178
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
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.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
Encapsulates state for primitive rasterization in a state object.
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.
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.