1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsGLRenderTexture.h"
4#include "BsGLPixelFormat.h"
5#include "BsGLPixelBuffer.h"
6#include "RenderAPI/BsTextureView.h"
7
8namespace bs
9{
10#define PROBE_SIZE 16
11
12 static const GLenum depthFormats[] =
13 {
14 GL_NONE,
15 GL_DEPTH_COMPONENT16,
16 GL_DEPTH_COMPONENT32,
17 GL_DEPTH24_STENCIL8,
18 GL_DEPTH32F_STENCIL8
19 };
20
21#define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
22
23 GLRenderTexture::GLRenderTexture(const RENDER_TEXTURE_DESC& desc)
24 :RenderTexture(desc), mProperties(desc, true)
25 {
26
27 }
28
29 namespace ct
30 {
31 GLRenderTexture::GLRenderTexture(const RENDER_TEXTURE_DESC& desc, UINT32 deviceIdx)
32 :RenderTexture(desc, deviceIdx), mProperties(desc, true), mFB(nullptr)
33 {
34 assert(deviceIdx == 0 && "Multiple GPUs not supported natively on OpenGL.");
35 }
36
37 GLRenderTexture::~GLRenderTexture()
38 {
39 if (mFB != nullptr)
40 bs_delete(mFB);
41 }
42
43 void GLRenderTexture::initialize()
44 {
45 RenderTexture::initialize();
46
47 if (mFB != nullptr)
48 bs_delete(mFB);
49
50 mFB = bs_new<GLFrameBufferObject>();
51
52 for (size_t i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
53 {
54 if (mColorSurfaces[i] != nullptr)
55 {
56 GLTexture* glColorSurface = static_cast<GLTexture*>(mDesc.colorSurfaces[i].texture.get());
57 GLSurfaceDesc surfaceDesc;
58 surfaceDesc.numSamples = getProperties().multisampleCount;
59
60 if (mColorSurfaces[i]->getNumArraySlices() == 1) // Binding a single texture layer
61 {
62 surfaceDesc.allLayers = glColorSurface->getProperties().getNumFaces() == 1;
63
64 if (glColorSurface->getProperties().getTextureType() != TEX_TYPE_3D)
65 {
66 surfaceDesc.zoffset = 0;
67 surfaceDesc.buffer = glColorSurface->getBuffer(mColorSurfaces[i]->getFirstArraySlice(),
68 mColorSurfaces[i]->getMostDetailedMip());
69 }
70 else
71 {
72 surfaceDesc.zoffset = 0;
73 surfaceDesc.buffer = glColorSurface->getBuffer(0, mColorSurfaces[i]->getMostDetailedMip());
74 }
75 }
76 else // Binding an array of textures or a range of 3D texture slices
77 {
78 surfaceDesc.allLayers = true;
79
80 if (glColorSurface->getProperties().getTextureType() != TEX_TYPE_3D)
81 {
82 if (mColorSurfaces[i]->getNumArraySlices() != glColorSurface->getProperties().getNumFaces())
83 LOGWRN("OpenGL doesn't support binding of arbitrary ranges for array textures. The entire range will be bound instead.");
84
85 surfaceDesc.zoffset = 0;
86 surfaceDesc.buffer = glColorSurface->getBuffer(0, mColorSurfaces[i]->getMostDetailedMip());
87 }
88 else
89 {
90 surfaceDesc.zoffset = 0;
91 surfaceDesc.buffer = glColorSurface->getBuffer(0, mColorSurfaces[i]->getMostDetailedMip());
92 }
93 }
94
95 mFB->bindSurface((UINT32)i, surfaceDesc);
96 }
97 else
98 {
99 mFB->unbindSurface((UINT32)i);
100 }
101 }
102
103 if (mDepthStencilSurface != nullptr && mDesc.depthStencilSurface.texture != nullptr)
104 {
105 GLTexture* glDepthStencilTexture = static_cast<GLTexture*>(mDesc.depthStencilSurface.texture.get());
106 SPtr<GLPixelBuffer> depthStencilBuffer = nullptr;
107
108 bool allLayers = true;
109 if (mDepthStencilSurface->getNumArraySlices() == 1) // Binding a single texture layer
110 allLayers = glDepthStencilTexture->getProperties().getNumFaces() == 1;
111
112 if (glDepthStencilTexture->getProperties().getTextureType() != TEX_TYPE_3D)
113 {
114 UINT32 firstSlice = 0;
115 if (!allLayers)
116 firstSlice = mDepthStencilSurface->getFirstArraySlice();
117
118 depthStencilBuffer = glDepthStencilTexture->getBuffer(firstSlice,
119 mDepthStencilSurface->getMostDetailedMip());
120 }
121
122 mFB->bindDepthStencil(depthStencilBuffer, allLayers);
123 }
124
125 mFB->rebuild();
126 }
127
128 void GLRenderTexture::getCustomAttribute(const String& name, void* data) const
129 {
130 if(name=="FBO")
131 {
132 *static_cast<GLFrameBufferObject**>(data) = mFB;
133 }
134 else if (name == "GL_FBOID" || name == "GL_MULTISAMPLEFBOID")
135 {
136 *static_cast<GLuint*>(data) = mFB->getGLFBOID();
137 }
138 }
139
140 GLRTTManager::GLRTTManager()
141 :mBlitReadFBO(0), mBlitWriteFBO(0)
142 {
143 detectFBOFormats();
144
145 glGenFramebuffers(1, &mBlitReadFBO);
146 BS_CHECK_GL_ERROR();
147
148 glGenFramebuffers(1, &mBlitWriteFBO);
149 BS_CHECK_GL_ERROR();
150 }
151
152 GLRTTManager::~GLRTTManager()
153 {
154 glDeleteFramebuffers(1, &mBlitReadFBO);
155 BS_CHECK_GL_ERROR();
156
157 glDeleteFramebuffers(1, &mBlitWriteFBO);
158 BS_CHECK_GL_ERROR();
159 }
160
161 bool GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
162 {
163 GLuint status, depthRB = 0, stencilRB = 0;
164 bool failed = false;
165
166 if (depthFormat != GL_NONE)
167 {
168 // Generate depth renderbuffer
169 glGenRenderbuffers(1, &depthRB);
170 BS_CHECK_GL_ERROR();
171
172 // Bind it to FBO
173 glBindRenderbuffer(GL_RENDERBUFFER, depthRB);
174 BS_CHECK_GL_ERROR();
175
176 // Allocate storage for depth buffer
177 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, PROBE_SIZE, PROBE_SIZE);
178
179 if (glGetError() != GL_NO_ERROR)
180 failed = true;
181
182 // Attach depth
183 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRB);
184
185 if (glGetError() != GL_NO_ERROR)
186 failed = true;
187 }
188
189 if (stencilFormat != GL_NONE)
190 {
191 // Generate stencil renderbuffer
192 glGenRenderbuffers(1, &stencilRB);
193 BS_CHECK_GL_ERROR();
194
195 // Bind it to FBO
196 glBindRenderbuffer(GL_RENDERBUFFER, stencilRB);
197 BS_CHECK_GL_ERROR();
198
199 // Allocate storage for stencil buffer
200 glRenderbufferStorage(GL_RENDERBUFFER, stencilFormat, PROBE_SIZE, PROBE_SIZE);
201
202 if (glGetError() != GL_NO_ERROR)
203 failed = true;
204
205 // Attach stencil
206 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRB);
207
208 if (glGetError() != GL_NO_ERROR)
209 failed = true;
210 }
211
212 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
213 BS_CHECK_GL_ERROR();
214
215 // Detach and destroy
216 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
217 BS_CHECK_GL_ERROR();
218
219 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
220 BS_CHECK_GL_ERROR();
221
222 if (depthRB)
223 {
224 glDeleteRenderbuffers(1, &depthRB);
225 BS_CHECK_GL_ERROR();
226 }
227
228 if (stencilRB)
229 {
230 glDeleteRenderbuffers(1, &stencilRB);
231 BS_CHECK_GL_ERROR();
232 }
233
234 return status == GL_FRAMEBUFFER_COMPLETE && !failed;
235 }
236
237 bool GLRTTManager::_tryPackedFormat(GLenum packedFormat)
238 {
239 GLuint packedRB = 0;
240 bool failed = false; // flag on GL errors
241
242 // Generate renderbuffer
243 glGenRenderbuffers(1, &packedRB);
244 BS_CHECK_GL_ERROR();
245
246 // Bind it to FBO
247 glBindRenderbuffer(GL_RENDERBUFFER, packedRB);
248 BS_CHECK_GL_ERROR();
249
250 // Allocate storage for buffer
251 glRenderbufferStorage(GL_RENDERBUFFER, packedFormat, PROBE_SIZE, PROBE_SIZE);
252
253 if (glGetError() != GL_NO_ERROR)
254 failed = true;
255
256 // Attach depth
257 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
258 GL_RENDERBUFFER, packedRB);
259
260 if (glGetError() != GL_NO_ERROR)
261 failed = true;
262
263 // Attach stencil
264 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
265 GL_RENDERBUFFER, packedRB);
266
267 if (glGetError() != GL_NO_ERROR)
268 failed = true;
269
270 GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
271 BS_CHECK_GL_ERROR();
272
273 // Detach and destroy
274 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
275 BS_CHECK_GL_ERROR();
276
277 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
278 BS_CHECK_GL_ERROR();
279
280 glDeleteRenderbuffers(1, &packedRB);
281 BS_CHECK_GL_ERROR();
282
283 return status == GL_FRAMEBUFFER_COMPLETE && !failed;
284 }
285
286 void GLRTTManager::detectFBOFormats()
287 {
288 // Try all formats, and report which ones work as target
289 GLuint fb = 0, tid = 0;
290 GLint oldDrawbuffer = 0, oldReadbuffer = 0;
291 GLenum target = GL_TEXTURE_2D;
292
293 glGetIntegerv(GL_DRAW_BUFFER, &oldDrawbuffer);
294 BS_CHECK_GL_ERROR();
295
296 glGetIntegerv(GL_READ_BUFFER, &oldReadbuffer);
297 BS_CHECK_GL_ERROR();
298
299 for (UINT32 x = 0; x < PF_COUNT; ++x)
300 {
301 mProps[x].valid = false;
302
303 // Fetch GL format token
304 GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
305 if (fmt == GL_NONE && x != 0)
306 continue;
307
308 // No test for compressed formats
309 if(PixelUtil::isCompressed((PixelFormat)x))
310 continue;
311
312 // No test for unnormalized integer targets
313 if (!PixelUtil::isNormalized((PixelFormat)x) && !PixelUtil::isFloatingPoint((PixelFormat)x))
314 continue;
315
316 // Create and attach framebuffer
317 glGenFramebuffers(1, &fb);
318 BS_CHECK_GL_ERROR();
319
320 glBindFramebuffer(GL_FRAMEBUFFER, fb);
321 BS_CHECK_GL_ERROR();
322
323 if (fmt != GL_NONE && !PixelUtil::isDepth((PixelFormat)x))
324 {
325 // Create and attach texture
326 glGenTextures(1, &tid);
327 BS_CHECK_GL_ERROR();
328
329 glBindTexture(target, tid);
330 BS_CHECK_GL_ERROR();
331
332 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
333 BS_CHECK_GL_ERROR();
334
335 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
336 BS_CHECK_GL_ERROR();
337
338 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
339 BS_CHECK_GL_ERROR();
340
341 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
342 BS_CHECK_GL_ERROR();
343
344 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
345 BS_CHECK_GL_ERROR();
346
347 glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
348 BS_CHECK_GL_ERROR();
349
350 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tid, 0);
351 BS_CHECK_GL_ERROR();
352 }
353 else
354 {
355 // Draw to nowhere (stencil/depth only)
356 glDrawBuffer(GL_NONE);
357 BS_CHECK_GL_ERROR();
358
359 glReadBuffer(GL_NONE);
360 BS_CHECK_GL_ERROR();
361 }
362
363 // Check status
364 GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
365 BS_CHECK_GL_ERROR();
366
367 // Ignore status in case of fmt==GL_NONE, because no implementation will accept
368 // a buffer without *any* attachment. Buffers with only stencil and depth attachment
369 // might still be supported, so we must continue probing.
370 if (fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE)
371 {
372 mProps[x].valid = true;
373
374 // For each depth/stencil formats
375 for (UINT32 depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
376 {
377 if (depthFormats[depth] != GL_DEPTH24_STENCIL8 && depthFormats[depth] != GL_DEPTH32F_STENCIL8)
378 {
379 if (_tryFormat(depthFormats[depth], GL_NONE))
380 {
381 /// Add mode to allowed modes
382 FormatProperties::Mode mode;
383 mode.depth = depth;
384 mode.stencil = 0;
385 mProps[x].modes.push_back(mode);
386 }
387 }
388 else
389 {
390 // Packed depth/stencil format
391 if (_tryPackedFormat(depthFormats[depth]))
392 {
393 /// Add mode to allowed modes
394 FormatProperties::Mode mode;
395 mode.depth = depth;
396 mode.stencil = 0; // unuse
397 mProps[x].modes.push_back(mode);
398 }
399 }
400 }
401 }
402
403 // Delete texture and framebuffer
404 glBindFramebuffer(GL_FRAMEBUFFER, 0);
405 BS_CHECK_GL_ERROR();
406
407 glDeleteFramebuffers(1, &fb);
408 BS_CHECK_GL_ERROR();
409
410 glFinish();
411 BS_CHECK_GL_ERROR();
412
413 if (fmt != GL_NONE)
414 {
415 glDeleteTextures(1, &tid);
416 BS_CHECK_GL_ERROR();
417 }
418 }
419
420 glDrawBuffer(oldDrawbuffer);
421 BS_CHECK_GL_ERROR();
422
423 glReadBuffer(oldReadbuffer);
424 BS_CHECK_GL_ERROR();
425 }
426
427 PixelFormat GLRTTManager::getSupportedAlternative(PixelFormat format)
428 {
429 if (checkFormat(format))
430 return format;
431
432 // Find first alternative
433 PixelComponentType pct = PixelUtil::getElementType(format);
434 switch (pct)
435 {
436 case PCT_BYTE: format = PF_RGBA8; break;
437 case PCT_FLOAT16: format = PF_RGBA16F; break;
438 case PCT_FLOAT32: format = PF_RGBA32F; break;
439 default: break;
440 }
441
442 if (checkFormat(format))
443 return format;
444
445 // If none at all, return to default
446 return PF_RGBA8;
447 }
448 }
449}