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