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 | |
9 | namespace 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 | }} |