1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2013-2015 Lauri Kasanen
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #ifndef SERVER_ONLY
19
20 #include "graphics/rtts.hpp"
21
22 #include "config/user_config.hpp"
23 #include "graphics/central_settings.hpp"
24 #include "graphics/frame_buffer_layer.hpp"
25 #include "utils/log.hpp"
26
27 #include <dimension2d.h>
28
29 using namespace irr;
generateRTT3D(GLenum target,unsigned int w,unsigned int h,unsigned int d,GLint internalFormat,GLint format,GLint type,unsigned mipmaplevel=1)30 static GLuint generateRTT3D(GLenum target, unsigned int w, unsigned int h,
31 unsigned int d, GLint internalFormat, GLint format,
32 GLint type, unsigned mipmaplevel = 1)
33 {
34 GLuint result;
35 glGenTextures(1, &result);
36 glBindTexture(target, result);
37 if (CVS->isARBTextureStorageUsable())
38 glTexStorage3D(target, mipmaplevel, internalFormat, w, h, d);
39 else
40 glTexImage3D(target, 0, internalFormat, w, h, d, 0, format, type, 0);
41 return result;
42 }
43
generateRTT(const core::dimension2du & res,GLint internalFormat,GLint format,GLint type,unsigned mipmaplevel=1)44 static GLuint generateRTT(const core::dimension2du &res, GLint internalFormat, GLint format, GLint type, unsigned mipmaplevel = 1)
45 {
46 GLuint result;
47 glGenTextures(1, &result);
48 glBindTexture(GL_TEXTURE_2D, result);
49 if (CVS->isARBTextureStorageUsable())
50 glTexStorage2D(GL_TEXTURE_2D, mipmaplevel, internalFormat, res.Width, res.Height);
51 else
52 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, res.Width, res.Height, 0, format, type, 0);
53 return result;
54 }
55
RTT(unsigned int width,unsigned int height,float rtt_scale,bool use_default_fbo_only)56 RTT::RTT(unsigned int width, unsigned int height, float rtt_scale,
57 bool use_default_fbo_only)
58 {
59 m_width = (unsigned int)(width * rtt_scale);
60 m_height = (unsigned int)(height * rtt_scale);
61 m_shadow_fbo = NULL;
62
63 using namespace core;
64
65 dimension2du res(m_width, m_height);
66
67 const dimension2du half = res/2;
68 const dimension2du quarter = res/4;
69
70 const u16 shadowside = u16(1024 * rtt_scale);
71 const dimension2du shadowsize0(shadowside, shadowside);
72 const dimension2du shadowsize1(shadowside / 2, shadowside / 2);
73 const dimension2du shadowsize2(shadowside / 4, shadowside / 4);
74 const dimension2du shadowsize3(shadowside / 8, shadowside / 8);
75
76 unsigned linear_depth_mip_levels = int(ceilf(log2f( float(max_(res.Width, res.Height)) )));
77
78 if (!use_default_fbo_only)
79 {
80 m_depth_stencil_tex = generateRTT(res, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
81 }
82
83 // All RTTs are currently RGBA16F mostly with stencil. The four tmp RTTs are the same size
84 // as the screen, for use in post-processing.
85
86 GLint rgba_internal_format = GL_RGBA16F;
87 GLint rgba_format = GL_BGRA;
88 GLint red_internal_format = GL_R16F;
89 GLint red32_internal_format = GL_R32F;
90 GLint red_format = GL_RED;
91 GLint rgb_format = GL_BGR;
92 GLint diffuse_specular_internal_format = GL_R11F_G11F_B10F;
93 GLint type = GL_FLOAT;
94
95 if (!CVS->isEXTColorBufferFloatUsable())
96 {
97 rgba_internal_format = GL_RGBA8;
98 rgba_format = GL_RGBA;
99 red_internal_format = GL_R8;
100 red32_internal_format = GL_R8;
101 red_format = GL_RED;
102 rgb_format = GL_RGB;
103 diffuse_specular_internal_format = GL_RGBA8;
104 type = GL_UNSIGNED_BYTE;
105 }
106
107 if (!CVS->isDeferredEnabled())
108 {
109 // RTT is used in only deferred shading which need hdr framebuffer
110 rgba_internal_format = GL_RGBA8;
111 type = GL_UNSIGNED_BYTE;
112 }
113
114 if (!use_default_fbo_only)
115 {
116 m_render_target_textures[RTT_COLOR] = generateRTT(res, rgba_internal_format, rgba_format, type);
117 }
118 if (CVS->isDeferredEnabled())
119 {
120 m_render_target_textures[RTT_NORMAL_AND_DEPTH] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
121 m_render_target_textures[RTT_SP_DIFF_COLOR] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
122 m_render_target_textures[RTT_RGBA_2] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
123 m_render_target_textures[RTT_DIFFUSE] = generateRTT(res, diffuse_specular_internal_format, rgb_format, type);
124 m_render_target_textures[RTT_SPECULAR] = generateRTT(res, diffuse_specular_internal_format, rgb_format, type);
125 m_render_target_textures[RTT_TMP1] = generateRTT(res, rgba_internal_format, rgba_format, type);
126 m_render_target_textures[RTT_HALF1] = generateRTT(half, rgba_internal_format, rgba_format, type);
127 m_render_target_textures[RTT_HALF1_R] = generateRTT(half, red_internal_format, red_format, type);
128 m_render_target_textures[RTT_HALF2] = generateRTT(half, rgba_internal_format, rgba_format, type);
129
130 if (UserConfigParams::m_mlaa)
131 {
132 m_render_target_textures[RTT_RGBA_3] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
133 }
134
135 if (UserConfigParams::m_ssao)
136 {
137 m_render_target_textures[RTT_SSAO] = generateRTT(res, red_internal_format, red_format, type);
138 m_render_target_textures[RTT_LINEAR_DEPTH] = generateRTT(res, red32_internal_format, red_format, type, linear_depth_mip_levels);
139 m_render_target_textures[RTT_HALF2_R] = generateRTT(half, red_internal_format, red_format, type);
140 }
141
142 if (UserConfigParams::m_light_shaft || UserConfigParams::m_glow)
143 {
144 m_render_target_textures[RTT_QUARTER1] = generateRTT(quarter, rgba_internal_format, rgba_format, type);
145 }
146 if (UserConfigParams::m_light_shaft)
147 {
148 m_render_target_textures[RTT_QUARTER2] = generateRTT(quarter, rgba_internal_format, rgba_format, type);
149 }
150
151 if (UserConfigParams::m_bloom)
152 {
153 m_render_target_textures[RTT_BLOOM_1024] = generateRTT(shadowsize0, rgba_internal_format, rgb_format, type);
154 m_render_target_textures[RTT_BLOOM_512] = generateRTT(shadowsize1, rgba_internal_format, rgb_format, type);
155 m_render_target_textures[RTT_TMP_512] = generateRTT(shadowsize1, rgba_internal_format, rgb_format, type);
156 m_render_target_textures[RTT_LENS_512] = generateRTT(shadowsize1, rgba_internal_format, rgb_format, type);
157 m_render_target_textures[RTT_BLOOM_256] = generateRTT(shadowsize2, rgba_internal_format, rgb_format, type);
158 m_render_target_textures[RTT_TMP_256] = generateRTT(shadowsize2, rgba_internal_format, rgb_format, type);
159 m_render_target_textures[RTT_LENS_256] = generateRTT(shadowsize2, rgba_internal_format, rgb_format, type);
160 m_render_target_textures[RTT_BLOOM_128] = generateRTT(shadowsize3, rgba_internal_format, rgb_format, type);
161 m_render_target_textures[RTT_TMP_128] = generateRTT(shadowsize3, rgba_internal_format, rgb_format, type);
162 m_render_target_textures[RTT_LENS_128] = generateRTT(shadowsize3, rgba_internal_format, rgb_format, type);
163 }
164 }
165
166 std::vector<GLuint> somevector;
167 if (!use_default_fbo_only)
168 {
169 somevector.push_back(m_render_target_textures[RTT_COLOR]);
170 m_frame_buffers[FBO_COLORS] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
171 }
172
173 if (CVS->isDeferredEnabled())
174 {
175 somevector.clear();
176 somevector.push_back(m_render_target_textures[RTT_NORMAL_AND_DEPTH]);
177 m_frame_buffers[FBO_NORMAL_AND_DEPTHS] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
178
179 somevector.clear();
180 somevector.push_back(m_render_target_textures[RTT_SP_DIFF_COLOR]);
181 somevector.push_back(m_render_target_textures[RTT_NORMAL_AND_DEPTH]);
182 m_frame_buffers[FBO_SP] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
183
184 somevector.clear();
185 somevector.push_back(m_render_target_textures[RTT_SP_DIFF_COLOR]);
186 m_frame_buffers[FBO_RGBA_1] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
187
188 somevector.clear();
189 somevector.push_back(m_render_target_textures[RTT_RGBA_2]);
190 m_frame_buffers[FBO_RGBA_2] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
191
192 somevector.clear();
193 somevector.push_back(m_render_target_textures[RTT_DIFFUSE]);
194 somevector.push_back(m_render_target_textures[RTT_SPECULAR]);
195 m_frame_buffers[FBO_COMBINED_DIFFUSE_SPECULAR] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
196
197 somevector.clear();
198 somevector.push_back(m_render_target_textures[RTT_TMP1]);
199 m_frame_buffers[FBO_TMP1_WITH_DS] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
200
201 somevector.clear();
202 somevector.push_back(m_render_target_textures[RTT_HALF1_R]);
203 m_frame_buffers[FBO_HALF1_R] = new FrameBuffer(somevector, half.Width, half.Height);
204
205 somevector.clear();
206 somevector.push_back(m_render_target_textures[RTT_HALF1]);
207 m_frame_buffers[FBO_HALF1] = new FrameBuffer(somevector, half.Width, half.Height);
208
209 somevector.clear();
210 somevector.push_back(m_render_target_textures[RTT_HALF2]);
211 m_frame_buffers[FBO_HALF2] = new FrameBuffer(somevector, half.Width, half.Height);
212
213 if (m_render_target_textures[RTT_RGBA_3] != 0)
214 {
215 somevector.clear();
216 somevector.push_back(m_render_target_textures[RTT_RGBA_3]);
217 m_frame_buffers[FBO_RGBA_3] = new FrameBuffer(somevector, res.Width, res.Height);
218 }
219
220 if (m_render_target_textures[RTT_SSAO] != 0 &&
221 m_render_target_textures[RTT_LINEAR_DEPTH] != 0 &&
222 m_render_target_textures[RTT_HALF2_R] != 0)
223 {
224 somevector.clear();
225 somevector.push_back(m_render_target_textures[RTT_SSAO]);
226 m_frame_buffers[FBO_SSAO] = new FrameBuffer(somevector, res.Width, res.Height);
227
228 somevector.clear();
229 somevector.push_back(m_render_target_textures[RTT_LINEAR_DEPTH]);
230 m_frame_buffers[FBO_LINEAR_DEPTH] = new FrameBuffer(somevector, res.Width, res.Height);
231
232 somevector.clear();
233 somevector.push_back(m_render_target_textures[RTT_HALF2_R]);
234 m_frame_buffers[FBO_HALF2_R] = new FrameBuffer(somevector, half.Width, half.Height);
235 }
236
237 if (m_render_target_textures[RTT_QUARTER1] != 0)
238 {
239 somevector.clear();
240 somevector.push_back(m_render_target_textures[RTT_QUARTER1]);
241 m_frame_buffers[FBO_QUARTER1] = new FrameBuffer(somevector, quarter.Width, quarter.Height);
242 }
243 if (m_render_target_textures[RTT_QUARTER2] != 0)
244 {
245 somevector.clear();
246 somevector.push_back(m_render_target_textures[RTT_QUARTER2]);
247 m_frame_buffers[FBO_QUARTER2] = new FrameBuffer(somevector, quarter.Width, quarter.Height);
248 }
249
250 if (UserConfigParams::m_bloom)
251 {
252 somevector.clear();
253 somevector.push_back(m_render_target_textures[RTT_BLOOM_1024]);
254 m_frame_buffers[FBO_BLOOM_1024] = new FrameBuffer(somevector, shadowsize0.Width, shadowsize0.Height);
255
256 somevector.clear();
257 somevector.push_back(m_render_target_textures[RTT_BLOOM_512]);
258 m_frame_buffers[FBO_BLOOM_512] = new FrameBuffer(somevector, shadowsize1.Width, shadowsize1.Height);
259
260 somevector.clear();
261 somevector.push_back(m_render_target_textures[RTT_TMP_512]);
262 m_frame_buffers[FBO_TMP_512] = new FrameBuffer(somevector, shadowsize1.Width, shadowsize1.Height);
263
264 somevector.clear();
265 somevector.push_back(m_render_target_textures[RTT_LENS_512]);
266 m_frame_buffers[FBO_LENS_512] = new FrameBuffer(somevector, shadowsize1.Width, shadowsize1.Height);
267
268 somevector.clear();
269 somevector.push_back(m_render_target_textures[RTT_BLOOM_256]);
270 m_frame_buffers[FBO_BLOOM_256] = new FrameBuffer(somevector, shadowsize2.Width, shadowsize2.Height);
271
272 somevector.clear();
273 somevector.push_back(m_render_target_textures[RTT_TMP_256]);
274 m_frame_buffers[FBO_TMP_256] = new FrameBuffer(somevector, shadowsize2.Width, shadowsize2.Height);
275
276 somevector.clear();
277 somevector.push_back(m_render_target_textures[RTT_LENS_256]);
278 m_frame_buffers[FBO_LENS_256] = new FrameBuffer(somevector, shadowsize2.Width, shadowsize2.Height);
279
280 somevector.clear();
281 somevector.push_back(m_render_target_textures[RTT_BLOOM_128]);
282 m_frame_buffers[FBO_BLOOM_128] = new FrameBuffer(somevector, shadowsize3.Width, shadowsize3.Height);
283
284 somevector.clear();
285 somevector.push_back(m_render_target_textures[RTT_TMP_128]);
286 m_frame_buffers[FBO_TMP_128] = new FrameBuffer(somevector, shadowsize3.Width, shadowsize3.Height);
287
288 somevector.clear();
289 somevector.push_back(m_render_target_textures[RTT_LENS_128]);
290 m_frame_buffers[FBO_LENS_128] = new FrameBuffer(somevector, shadowsize3.Width, shadowsize3.Height);
291 }
292
293 if (CVS->isShadowEnabled())
294 {
295 m_shadow_depth_tex = generateRTT3D(GL_TEXTURE_2D_ARRAY, UserConfigParams::m_shadows_resolution, UserConfigParams::m_shadows_resolution, 4, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 1);
296 somevector.clear();
297 m_shadow_fbo = new FrameBufferLayer(somevector, m_shadow_depth_tex, UserConfigParams::m_shadows_resolution, UserConfigParams::m_shadows_resolution, 4);
298 }
299 // Clear this FBO to 1s so that if no SSAO is computed we can still use it.
300 getFBO(FBO_HALF1_R).bind();
301 glClearColor(1., 1., 1., 1.);
302 glClear(GL_COLOR_BUFFER_BIT);
303 // Raytracer reflexion use previous frame color frame buffer, so we clear it before to avoid
304 // artifacts in the begining of race
305 getFBO(FBO_COLORS).bind();
306 glClearColor(1., 1., 1., 1.);
307 glClear(GL_COLOR_BUFFER_BIT);
308 getFBO(FBO_HALF1).bind();
309 glClearColor(0., 0., 0., 0.);
310 glClear(GL_COLOR_BUFFER_BIT);
311 }
312 glBindFramebuffer(GL_FRAMEBUFFER, irr_driver->getDefaultFramebuffer());
313 }
314
~RTT()315 RTT::~RTT()
316 {
317 glBindFramebuffer(GL_FRAMEBUFFER, irr_driver->getDefaultFramebuffer());
318 glDeleteTextures(RTT_COUNT, m_render_target_textures);
319 for (FrameBuffer* fb : m_frame_buffers)
320 {
321 delete fb;
322 }
323 glDeleteTextures(1, &m_depth_stencil_tex);
324 if (CVS->isShadowEnabled())
325 {
326 delete m_shadow_fbo;
327 glDeleteTextures(1, &m_shadow_depth_tex);
328 }
329 }
330
331 #endif // !SERVER_ONLY
332