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