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 "BsGLFrameBufferObject.h"
4#include "BsGLPixelFormat.h"
5#include "BsGLPixelBuffer.h"
6#include "BsGLRenderTexture.h"
7#include "Profiling/BsRenderStats.h"
8
9namespace bs { namespace ct
10{
11 GLFrameBufferObject::GLFrameBufferObject()
12 {
13 glGenFramebuffers(1, &mFB);
14 BS_CHECK_GL_ERROR();
15
16 for (UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
17 mColor[x].buffer = nullptr;
18
19 BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_FrameBufferObject);
20 }
21
22 GLFrameBufferObject::~GLFrameBufferObject()
23 {
24 glDeleteFramebuffers(1, &mFB);
25 BS_CHECK_GL_ERROR();
26
27 BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_FrameBufferObject);
28 }
29
30 void GLFrameBufferObject::bindSurface(UINT32 attachment, const GLSurfaceDesc &target)
31 {
32 assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
33 mColor[attachment] = target;
34 }
35
36 void GLFrameBufferObject::unbindSurface(UINT32 attachment)
37 {
38 assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
39 mColor[attachment].buffer = nullptr;
40 }
41
42 void GLFrameBufferObject::bindDepthStencil(SPtr<GLPixelBuffer> depthStencilBuffer, bool allLayers)
43 {
44 mDepthStencilBuffer = depthStencilBuffer;
45 mDepthStencilAllLayers = allLayers;
46 }
47
48 void GLFrameBufferObject::unbindDepthStencil()
49 {
50 mDepthStencilBuffer = nullptr;
51 }
52
53 void GLFrameBufferObject::rebuild()
54 {
55 // Store basic stats
56 UINT16 maxSupportedMRTs = RenderAPI::instancePtr()->getCapabilities(0).numMultiRenderTargets;
57
58 // Bind simple buffer to add color attachments
59 glBindFramebuffer(GL_FRAMEBUFFER, mFB);
60 BS_CHECK_GL_ERROR();
61
62 // Bind all attachment points to frame buffer
63 for (UINT16 x = 0; x < maxSupportedMRTs; ++x)
64 {
65 if (mColor[x].buffer)
66 {
67 // Note: I'm attaching textures to FBO while renderbuffers might yield better performance if I
68 // don't need to read from them
69
70 mColor[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0 + x, mColor[x].zoffset, mColor[x].allLayers);
71 }
72 else
73 {
74 // Detach
75 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, 0, 0);
76 BS_CHECK_GL_ERROR();
77 }
78 }
79
80 if (mDepthStencilBuffer != nullptr)
81 {
82 GLenum depthStencilFormat = GLPixelUtil::getDepthStencilFormatFromPF(mDepthStencilBuffer->getFormat());
83
84 GLenum attachmentPoint;
85 if (depthStencilFormat == GL_DEPTH_STENCIL)
86 attachmentPoint = GL_DEPTH_STENCIL_ATTACHMENT;
87 else // Depth only
88 attachmentPoint = GL_DEPTH_ATTACHMENT;
89
90 mDepthStencilBuffer->bindToFramebuffer(attachmentPoint, 0, mDepthStencilAllLayers);
91 }
92
93 // Do glDrawBuffer calls
94 GLenum bufs[BS_MAX_MULTIPLE_RENDER_TARGETS];
95 GLsizei n = 0;
96 for (UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
97 {
98 // Fill attached colour buffers
99 if (mColor[x].buffer)
100 {
101 bufs[x] = GL_COLOR_ATTACHMENT0 + x;
102 // Keep highest used buffer + 1
103 n = x + 1;
104 }
105 else
106 {
107 bufs[x] = GL_NONE;
108 }
109 }
110
111 glDrawBuffers(n, bufs);
112 BS_CHECK_GL_ERROR();
113
114 // No read buffer, by default, if we want to read anyway we must not forget to set this.
115 glReadBuffer(GL_NONE);
116 BS_CHECK_GL_ERROR();
117
118 // Check status
119 GLuint status;
120 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
121 BS_CHECK_GL_ERROR();
122
123 // Bind main buffer
124 glBindFramebuffer(GL_FRAMEBUFFER, 0);
125 BS_CHECK_GL_ERROR();
126
127 switch (status)
128 {
129 case GL_FRAMEBUFFER_COMPLETE:
130 break;
131 case GL_FRAMEBUFFER_UNSUPPORTED:
132 LOGERR("All framebuffer formats with this texture internal format unsupported");
133 break;
134 default:
135 LOGERR("Framebuffer incomplete or other FBO status error");
136 }
137 }
138
139 void GLFrameBufferObject::bind()
140 {
141 glBindFramebuffer(GL_FRAMEBUFFER, mFB);
142 BS_CHECK_GL_ERROR();
143 }
144}}