1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/textconsole.h"
24 #include "common/util.h"
25
26 #if defined(USE_OPENGL) && !defined(AMIGAOS)
27
28 #if defined(SDL_BACKEND) && !defined(USE_GLEW) && !defined(USE_GLES2)
29 #define GL_GLEXT_PROTOTYPES // For the GL_EXT_framebuffer_object extension
30 #include "graphics/opengl/framebuffer.h"
31 #ifndef GL_ARB_framebuffer_object
32 #define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
33 #define GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
34 #define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
35 #define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
36 #define GL_RENDERBUFFER GL_RENDERBUFFER_EXT
37 #define GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
38 #define GL_STENCIL_INDEX8 GL_STENCIL_INDEX8_EXT
39 #define GL_DEPTH24_STENCIL8 0x88F0
40 #define GL_READ_FRAMEBUFFER 0x8CA8
41 #define GL_DRAW_FRAMEBUFFER 0x8CA9
42 #endif // defined(GL_ARB_framebuffer_object)
43 #include "backends/platform/sdl/sdl-sys.h"
44 #else
45 #include "graphics/opengl/framebuffer.h"
46 #endif
47
48 #include "graphics/opengl/context.h"
49
50 #ifdef USE_GLES2
51 #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
52 #endif
53
54 namespace OpenGL {
55
56 #if defined(SDL_BACKEND) && !defined(USE_GLEW) && !defined(USE_GLES2)
57 static bool framebuffer_object_functions = false;
58 static PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebuffer;
59 static PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbuffer;
60 static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
61 static PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffers;
62 static PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffers;
63 static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbuffer;
64 static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2D;
65 static PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffers;
66 static PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffers;
67 static PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorage;
68 typedef void (* PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
69 static PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisample;
70 typedef void (* PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
71 static PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebuffer;
72
73
grabFramebufferObjectPointers()74 static void grabFramebufferObjectPointers() {
75 if (framebuffer_object_functions)
76 return;
77 framebuffer_object_functions = true;
78
79 union {
80 void *obj_ptr;
81 void (APIENTRY *func_ptr)();
82 } u;
83 // We're casting from an object pointer to a function pointer, the
84 // sizes need to be the same for this to work.
85 assert(sizeof(u.obj_ptr) == sizeof(u.func_ptr));
86 u.obj_ptr = SDL_GL_GetProcAddress("glBlitFramebuffer");
87 glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC)u.func_ptr;
88 u.obj_ptr = SDL_GL_GetProcAddress("glBindFramebuffer");
89 glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)u.func_ptr;
90 u.obj_ptr = SDL_GL_GetProcAddress("glBindRenderbuffer");
91 glBindRenderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)u.func_ptr;
92 u.obj_ptr = SDL_GL_GetProcAddress("glCheckFramebufferStatus");
93 glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)u.func_ptr;
94 u.obj_ptr = SDL_GL_GetProcAddress("glDeleteFramebuffers");
95 glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)u.func_ptr;
96 u.obj_ptr = SDL_GL_GetProcAddress("glDeleteRenderbuffers");
97 glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)u.func_ptr;
98 u.obj_ptr = SDL_GL_GetProcAddress("glFramebufferRenderbuffer");
99 glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)u.func_ptr;
100 u.obj_ptr = SDL_GL_GetProcAddress("glFramebufferTexture2D");
101 glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)u.func_ptr;
102 u.obj_ptr = SDL_GL_GetProcAddress("glGenFramebuffers");
103 glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)u.func_ptr;
104 u.obj_ptr = SDL_GL_GetProcAddress("glGenRenderbuffers");
105 glGenRenderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)u.func_ptr;
106 u.obj_ptr = SDL_GL_GetProcAddress("glRenderbufferStorage");
107 glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)u.func_ptr;
108 u.obj_ptr = SDL_GL_GetProcAddress("glRenderbufferStorageMultisample");
109 glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)u.func_ptr;
110 }
111 #endif // defined(SDL_BACKEND) && !defined(USE_GLEW) && !defined(USE_GLES2)
112
113
114
usePackedBuffer()115 static bool usePackedBuffer() {
116 return OpenGLContext.packedDepthStencilSupported;
117 }
118
FrameBuffer(uint width,uint height)119 FrameBuffer::FrameBuffer(uint width, uint height) :
120 Texture(width, height) {
121 if (!OpenGLContext.framebufferObjectSupported) {
122 error("FrameBuffer Objects are not supported by the current OpenGL context");
123 }
124
125 #if defined(SDL_BACKEND) && !defined(USE_GLEW) && !defined(USE_GLES2)
126 grabFramebufferObjectPointers();
127 #endif
128
129 init();
130 }
131
FrameBuffer(GLuint texture_name,uint width,uint height,uint texture_width,uint texture_height)132 FrameBuffer::FrameBuffer(GLuint texture_name, uint width, uint height, uint texture_width, uint texture_height) :
133 Texture(texture_name, width, height, texture_width, texture_height) {
134 init();
135 }
136
~FrameBuffer()137 FrameBuffer::~FrameBuffer() {
138 glDeleteRenderbuffers(2, _renderBuffers);
139 glDeleteFramebuffers(1, &_frameBuffer);
140 }
141
init()142 void FrameBuffer::init() {
143 glGenFramebuffers(1, &_frameBuffer);
144 glGenRenderbuffers(2, _renderBuffers);
145
146 glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
147 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
148
149 if (usePackedBuffer()) {
150 glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
151 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _texWidth, _texHeight);
152 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
153 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
154 glBindRenderbuffer(GL_RENDERBUFFER, 0);
155 } else {
156 glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
157 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _texWidth, _texHeight);
158 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
159
160 glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[1]);
161 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, _texWidth, _texHeight);
162 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[1]);
163 glBindRenderbuffer(GL_RENDERBUFFER, 0);
164 }
165
166 glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
167 GLenum status=glCheckFramebufferStatus(GL_FRAMEBUFFER);
168 if (status != GL_FRAMEBUFFER_COMPLETE)
169 error("Framebuffer is not complete! status: %d", status);
170
171 glBindTexture(GL_TEXTURE_2D, 0);
172 glBindFramebuffer(GL_FRAMEBUFFER, 0);
173 }
174
attach()175 void FrameBuffer::attach() {
176 glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
177 glViewport(0,0, _width, _height);
178
179 glClearColor(0, 0, 0, 1.0f);
180 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
181 }
182
detach()183 void FrameBuffer::detach() {
184 glBindFramebuffer(GL_FRAMEBUFFER, 0);
185 }
186
187 #if !defined(USE_GLES2) && !defined(AMIGAOS)
MultiSampleFrameBuffer(uint width,uint height,int samples)188 MultiSampleFrameBuffer::MultiSampleFrameBuffer(uint width, uint height, int samples)
189 : FrameBuffer(width,height) {
190 if (!OpenGLContext.framebufferObjectMultisampleSupported) {
191 error("The current OpenGL context does not support multisample framebuffer objects!");
192 }
193
194 if (samples > OpenGLContext.multisampleMaxSamples) {
195 warning("Requested anti-aliasing with '%d' samples, but the current OpenGL context supports '%d' samples at most",
196 samples, OpenGLContext.multisampleMaxSamples);
197 }
198
199 _msSamples = MIN(samples, OpenGLContext.multisampleMaxSamples);
200
201 init();
202 }
203
~MultiSampleFrameBuffer()204 MultiSampleFrameBuffer::~MultiSampleFrameBuffer() {
205 glDeleteRenderbuffers(1, &_msColorId);
206 glDeleteRenderbuffers(1, &_msDepthId);
207 glBindFramebuffer(GL_FRAMEBUFFER, 0);
208 glDeleteFramebuffers(1, &_msFrameBufferId);
209 }
210
init()211 void MultiSampleFrameBuffer::init() {
212 glGenFramebuffers(1, &_msFrameBufferId);
213 glBindFramebuffer(GL_FRAMEBUFFER, _msFrameBufferId);
214
215 glGenRenderbuffers(1, &_msColorId);
216 glBindRenderbuffer(GL_RENDERBUFFER, _msColorId);
217 glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msSamples, GL_RGBA8, getTexWidth(), getTexHeight());
218
219 glGenRenderbuffers(1, &_msDepthId);
220 glBindRenderbuffer(GL_RENDERBUFFER, _msDepthId);
221 glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msSamples, GL_DEPTH24_STENCIL8, getTexWidth(), getTexHeight());
222
223 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _msColorId);
224 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _msDepthId);
225 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _msDepthId);
226
227 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
228 if (status != GL_FRAMEBUFFER_COMPLETE)
229 error("Framebuffer is not complete! status: %d", status);
230
231 glBindFramebuffer(GL_FRAMEBUFFER, 0);
232 }
233
attach()234 void MultiSampleFrameBuffer::attach() {
235 glBindFramebuffer(GL_READ_FRAMEBUFFER, getFrameBufferName());
236 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _msFrameBufferId);
237 glViewport(0,0, getWidth(), getHeight());
238
239 glClearColor(0, 0, 0, 1.0f);
240 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
241 }
242
detach()243 void MultiSampleFrameBuffer::detach() {
244 glBindFramebuffer(GL_READ_FRAMEBUFFER, _msFrameBufferId);
245 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getFrameBufferName());
246 glBlitFramebuffer(0, 0, getWidth(), getHeight(), 0, 0, getWidth(), getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
247 glBindFramebuffer(GL_FRAMEBUFFER, 0);
248 }
249
250 #endif // !defined(USE_GLES2) && !defined(AMIGAOS)
251
252 } // End of namespace OpenGL
253
254 #endif
255