source: trunk/src/gpu/framebuffer.cpp @ 2792

Last change on this file since 2792 was 2792, checked in by sam, 8 years ago

gpu: add a 16-bit depth buffer to framebuffers on WebGL and GL ES.

  • Property svn:keywords set to Id
File size: 15.1 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include "core.h"
16#include "lolgl.h"
17
18#if defined _WIN32 && defined USE_D3D9
19#   define FAR
20#   define NEAR
21#   include <d3d9.h>
22#elif defined _XBOX
23#   include <xtl.h>
24#   undef near /* Fuck Microsoft */
25#   undef far /* Fuck Microsoft again */
26#endif
27
28using namespace std;
29
30namespace lol
31{
32
33//
34// The FramebufferData class
35// -------------------------
36//
37
38class FramebufferData
39{
40    friend class Framebuffer;
41
42    ibox2 m_saved_viewport;
43    ivec2 m_size;
44    bool m_bound;
45
46#if defined USE_D3D9
47    IDirect3DDevice9 *m_dev;
48    IDirect3DTexture9 *m_texture;
49    IDirect3DSurface9 *m_surface, *m_back_surface;
50#elif defined _XBOX
51    D3DDevice *m_dev;
52    D3DTexture *m_texture;
53    D3DSurface *m_surface, *m_back_surface;
54#else
55    GLuint m_fbo, m_texture, m_depth;
56#endif
57};
58
59//
60// The FramebufferFormat struct
61// ----------------------
62//
63
64uint32_t FramebufferFormat::GetFormat()
65{
66    switch (m_format)
67    {
68#if defined USE_D3D9
69    case R_16_F:        return D3DFMT_R16F;
70    case R_32_F:        return D3DFMT_R32F;
71    case RG_16:
72    case RG_16_I:
73    case RG_16_UI:      return D3DFMT_G16R16;
74    case RG_16_F:       return D3DFMT_G16R16F;
75    case RG_32_F:       return D3DFMT_G32R32F;
76    case RGB_8:
77    case RGB_8_I:
78    case RGB_8_UI:      return D3DFMT_R8G8B8;
79    case RGBA_8:
80    case RGBA_8_I:
81    case RGBA_8_UI:     return D3DFMT_A8R8G8B8;
82    case RGBA_16:
83    case RGBA_16_I:
84    case RGBA_16_UI:    return D3DFMT_A16B16G16R16;
85    case RGBA_16_F:     return D3DFMT_A16B16G16R16F;
86    case RGBA_32_F:     return D3DFMT_A32B32G32R32F;
87#elif defined _XBOX
88    case R_16_F:        return D3DFMT_R16F;
89    case R_32_F:        return D3DFMT_R32F;
90    case RG_16:
91    case RG_16_I:
92    case RG_16_UI:      return D3DFMT_G16R16;
93    case RG_16_F:       return D3DFMT_G16R16F;
94    case RG_32_F:       return D3DFMT_G32R32F;
95    case RGB_8:
96    case RGB_8_I:
97    case RGB_8_UI:      return D3DFMT_X8R8G8B8;
98    case RGBA_8:
99    case RGBA_8_I:
100    case RGBA_8_UI:     return D3DFMT_A8R8G8B8;
101    case RGBA_16:
102    case RGBA_16_I:
103    case RGBA_16_UI:    return D3DFMT_A16B16G16R16;
104    case RGBA_16_F:     return D3DFMT_A16B16G16R16F;
105    case RGBA_32_F:     return D3DFMT_A32B32G32R32F;
106#elif defined __CELLOS_LV2__
107    /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
108     * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
109    case RGB_16_F:      return GL_RGB16F_ARB;
110    case RGB_32_F:      return GL_RGB32F_ARB;
111    case RGBA_8:        return GL_ARGB_SCE;
112    case RGBA_16_F:     return GL_RGBA16F_ARB;
113    case RGBA_32_F:     return GL_RGBA32F_ARB;
114#elif defined HAVE_GLES_2X
115    /* FIXME: incomplete */
116    case RGBA_8:
117    case RGBA_8_I:
118    case RGBA_8_UI:     return GL_RGBA;
119#elif defined __APPLE__ && defined __MACH__
120    case R_8:
121    case R_8_I:
122    case R_8_UI:
123    case R_8_F:
124
125    case R_16:
126    case R_16_I:
127    case R_16_UI:
128    case R_16_F:
129
130    case R_32_I:
131    case R_32:
132    case R_32_UI:
133    case R_32_F:        return GL_RED;
134
135    case RG_8:
136    case RG_8_I:
137    case RG_8_UI:
138    case RG_8_F:
139
140    case RG_16:
141    case RG_16_I:
142    case RG_16_UI:
143    case RG_16_F:
144
145    case RG_32:
146    case RG_32_I:
147    case RG_32_UI:
148    case RG_32_F:       return GL_RG;
149
150    case RGB_8:
151    case RGB_8_I:
152    case RGB_8_UI:
153    case RGB_8_F:
154
155    case RGB_16:
156    case RGB_16_I:
157    case RGB_16_UI:
158    case RGB_16_F:
159
160    case RGB_32:
161    case RGB_32_I:
162    case RGB_32_UI:
163    case RGB_32_F:      return (m_invert_rgb)?(GL_BGR):(GL_RGB);
164
165    case RGBA_8:
166    case RGBA_8_I:
167    case RGBA_8_UI:
168    case RGBA_8_F:
169
170    case RGBA_16:
171    case RGBA_16_I:
172    case RGBA_16_UI:
173    case RGBA_16_F:
174
175    case RGBA_32:
176    case RGBA_32_I:
177    case RGBA_32_UI:
178    case RGBA_32_F:     return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
179#else
180    case R_8:           return GL_R8;
181    case R_8_I:         return GL_R8I;
182    case R_8_UI:        return GL_R8UI;
183
184    case R_16:          return GL_R16;
185    case R_16_I:        return GL_R16I;
186    case R_16_UI:       return GL_R16UI;
187    case R_16_F:        return GL_R16F;
188
189    case R_32_I:        return GL_R32I;
190    case R_32_UI:       return GL_R32UI;
191    case R_32_F:        return GL_R32F;
192
193    case RG_8:          return GL_RG8;
194    case RG_8_I:        return GL_RG8I;
195    case RG_8_UI:       return GL_RG8UI;
196
197    case RG_16:         return GL_RG16;
198    case RG_16_I:       return GL_RG16I;
199    case RG_16_UI:      return GL_RG16UI;
200    case RG_16_F:       return GL_RG16F;
201
202    case RG_32_I:       return GL_RG32I;
203    case RG_32_UI:      return GL_RG32UI;
204    case RG_32_F:       return GL_RG32F;
205
206    case RGB_8:         return GL_RGB8;
207    case RGB_8_I:       return GL_RGB8I;
208    case RGB_8_UI:      return GL_RGB8UI;
209
210    case RGB_16:        return GL_RGB16;
211    case RGB_16_I:      return GL_RGB16I;
212    case RGB_16_UI:     return GL_RGB16UI;
213    case RGB_16_F:      return GL_RGB16F;
214
215    case RGB_32_I:      return GL_RGB32I;
216    case RGB_32_UI:     return GL_RGB32UI;
217    case RGB_32_F:      return GL_RGB32F;
218
219    case RGBA_8:        return GL_RGBA8;
220    case RGBA_8_I:      return GL_RGBA8I;
221    case RGBA_8_UI:     return GL_RGBA8UI;
222
223    case RGBA_16:       return GL_RGBA16;
224    case RGBA_16_I:     return GL_RGBA16I;
225    case RGBA_16_UI:    return GL_RGBA16UI;
226    case RGBA_16_F:     return GL_RGBA16F;
227
228    case RGBA_32_I:     return GL_RGBA32I;
229    case RGBA_32_UI:    return GL_RGBA32UI;
230    case RGBA_32_F:     return GL_RGBA32F;
231#endif
232    default:
233        ASSERT(false, "unknown framebuffer format %d", m_format);
234        return 0;
235    }
236}
237
238uint32_t FramebufferFormat::GetFormatOrder()
239{
240    switch (m_format)
241    {
242#if defined USE_D3D9 || defined _XBOX
243    /* FIXME: not implemented at all */
244#elif defined __CELLOS_LV2__
245    /* FIXME: not implemented at all */
246#elif defined HAVE_GLES_2X
247    /* FIXME: incomplete */
248    case R_8:   case RG_8:   case RGB_8:   case RGBA_8:
249    case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
250        return GL_BYTE;
251    case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
252        return GL_UNSIGNED_BYTE;
253#elif defined __APPLE__ && defined __MACH__
254    case R_8:   case RG_8:   case RGB_8:   case RGBA_8:
255    case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
256        return GL_BYTE;
257    case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
258        return GL_UNSIGNED_BYTE;
259
260    case R_16:   case RG_16:   case RGB_16:   case RGBA_16:
261    case R_16_I: case RG_16_I: case RGB_16_I: case RGBA_16_I:
262        return GL_SHORT;
263    case R_16_UI: case RG_16_UI: case RGB_16_UI: case RGBA_16_UI:
264        return GL_UNSIGNED_SHORT;
265
266    case R_16_F: case RG_16_F: case RGB_16_F: case RGBA_16_F:
267        ASSERT(false, "unsupported framebuffer format order %d", m_format);
268        return 0;
269
270    case R_32_I: case RG_32_I: case RGB_32_I: case RGBA_32_I:
271        return GL_INT;
272    case R_32_UI: case RG_32_UI: case RGB_32_UI: case RGBA_32_UI:
273        return GL_UNSIGNED_INT;
274    case R_32_F: case RG_32_F: case RGB_32_F: case RGBA_32_F:
275        return GL_FLOAT;
276#else
277    case R_8:  case R_8_I:  case R_8_UI:  case R_8_F:
278    case R_16: case R_16_I: case R_16_UI: case R_16_F:
279    case R_32: case R_32_I: case R_32_UI: case R_32_F:
280        return GL_RED;
281
282    case RG_8:  case RG_8_I:  case RG_8_UI:  case RG_8_F:
283    case RG_16: case RG_16_I: case RG_16_UI: case RG_16_F:
284    case RG_32: case RG_32_I: case RG_32_UI: case RG_32_F:
285        return GL_RG;
286
287    case RGB_8:  case RGB_8_I:  case RGB_8_UI:  case RGB_8_F:
288    case RGB_16: case RGB_16_I: case RGB_16_UI: case RGB_16_F:
289    case RGB_32: case RGB_32_I: case RGB_32_UI: case RGB_32_F:
290        return m_invert_rgb ? GL_BGR : GL_RGB;
291
292    case RGBA_8:  case RGBA_8_I:  case RGBA_8_UI:  case RGBA_8_F:
293    case RGBA_16: case RGBA_16_I: case RGBA_16_UI: case RGBA_16_F:
294    case RGBA_32: case RGBA_32_I: case RGBA_32_UI: case RGBA_32_F:
295        return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
296#endif
297    default:
298        ASSERT(false, "unknown framebuffer format order %d", m_format);
299        return 0;
300    }
301}
302
303//
304// The Framebuffer class
305// ----------------------
306//
307
308Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
309  : m_data(new FramebufferData)
310{
311    m_data->m_size = size;
312    m_data->m_bound = false;
313#if defined USE_D3D9
314    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
315
316    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1,
317                                            D3DUSAGE_RENDERTARGET,
318                                            (D3DFORMAT)fbo_format.GetFormat(),
319                                            D3DPOOL_DEFAULT,
320                                            &m_data->m_texture, nullptr)))
321        Abort();
322    if (FAILED(m_data->m_texture->GetSurfaceLevel(0, &m_data->m_surface)))
323        Abort();
324#elif defined _XBOX
325    m_data->m_dev = (D3DDevice *)g_renderer->GetDevice();
326
327    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1, 0,
328                                            (D3DFORMAT)fbo_format.GetFormat(),
329                                            D3DPOOL_DEFAULT,
330                                            &m_data->m_texture, nullptr)))
331        Abort();
332    if (FAILED(m_data->m_dev->CreateRenderTarget(size.x, size.y,
333                                                 (D3DFORMAT)fbo_format.GetFormat(),
334                                                 D3DMULTISAMPLE_NONE, 0, 0,
335                                                 &m_data->m_surface, nullptr)))
336        Abort();
337#else
338#   if GL_VERSION_1_1
339    GLenum internal_format = fbo_format.GetFormat();
340    GLenum format = fbo_format.GetFormatOrder();
341    GLenum depth = GL_DEPTH_COMPONENT;
342#   elif defined __CELLOS_LV2__
343    /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
344     * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
345    GLenum internal_format = fbo_format.GetFormat();
346    GLenum format = fbo_format.GetFormatOrder();
347#   elif GL_ES_VERSION_2_0
348    /* In OpenGL ES, internal format and format must match. */
349    GLenum internal_format = fbo_format.GetFormat();
350    GLenum format = fbo_format.GetFormat();
351    GLenum depth = GL_DEPTH_COMPONENT16; /* for WebGL */
352#   else
353    /* In OpenGL ES, internal format and format must match. */
354    GLenum internal_format = fbo_format.GetFormat();
355    GLenum format = fbo_format.GetFormat();
356#   endif
357    GLenum wrapmode = GL_CLAMP_TO_EDGE;
358    GLenum filtering = GL_NEAREST;
359
360#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
361    glGenFramebuffers(1, &m_data->m_fbo);
362    glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
363#   else
364    glGenFramebuffersOES(1, &m_data->m_fbo);
365    glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
366#   endif
367
368    glGenTextures(1, &m_data->m_texture);
369    glActiveTexture(GL_TEXTURE0);
370    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
371    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapmode);
372    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapmode);
373    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
374    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
375    glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size.x, size.y, 0,
376                 format, GL_UNSIGNED_BYTE, nullptr);
377
378#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
379    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
380                           GL_TEXTURE_2D, m_data->m_texture, 0);
381#   else
382    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_EXT,
383                              GL_TEXTURE_2D, m_data->m_texture, 0);
384#   endif
385
386    m_data->m_depth = GL_INVALID_ENUM;
387#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
388    if (depth != GL_INVALID_ENUM)
389    {
390        /* XXX: might not work on GL ES, see
391         * http://stackoverflow.com/q/4041682/111461
392         * See also http://qt-project.org/forums/viewthread/11734 */
393        glGenRenderbuffers(1, &m_data->m_depth);
394        glBindRenderbuffer(GL_RENDERBUFFER, m_data->m_depth);
395        glRenderbufferStorage(GL_RENDERBUFFER, depth, size.x, size.y);
396        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
397                                  GL_RENDERBUFFER, m_data->m_depth);
398    }
399#   endif
400
401    glBindTexture(GL_TEXTURE_2D, 0);
402
403#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
404    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
405    ASSERT(status == GL_FRAMEBUFFER_COMPLETE,
406           "invalid framebuffer status 0x%x", status);
407#   endif
408
409#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
410    glBindFramebuffer(GL_FRAMEBUFFER, 0);
411#   else
412    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
413#   endif
414#endif
415}
416
417Framebuffer::~Framebuffer()
418{
419#if defined USE_D3D9 || defined _XBOX
420    m_data->m_surface->Release();
421    m_data->m_texture->Release();
422#else
423#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
424    glDeleteFramebuffers(1, &m_data->m_fbo);
425#   else
426    glDeleteFramebuffersOES(1, &m_data->m_fbo);
427#   endif
428    glDeleteTextures(1, &m_data->m_texture);
429#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
430    if (m_data->m_depth != GL_INVALID_ENUM)
431        glDeleteRenderbuffers(1, &m_data->m_depth);
432#   endif
433#endif
434    delete m_data;
435}
436
437ShaderTexture Framebuffer::GetTexture() const
438{
439    ShaderTexture ret;
440#if defined USE_D3D9 || defined _XBOX
441    ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture;
442#else
443    ret.m_flags = m_data->m_texture;
444#endif
445    return ret;
446}
447
448ivec2 Framebuffer::GetSize() const
449{
450    return m_data->m_size;
451}
452
453void Framebuffer::Bind()
454{
455    ASSERT(!m_data->m_bound, "trying to bind an already bound framebuffer");
456
457#if defined USE_D3D9 || defined _XBOX
458    if (FAILED(m_data->m_dev->GetRenderTarget(0, &m_data->m_back_surface)))
459        Abort();
460    if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_surface)))
461        Abort();
462#else
463#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
464    glBindFramebuffer(GL_FRAMEBUFFER, m_data->m_fbo);
465#   else
466    glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo);
467#   endif
468#endif
469
470    /* FIXME: this should be done in the RenderContext object
471     * instead, maybe by getting rid of Framebuffer::Bind() and
472     * creating RenderContext::SetFramebuffer() instead. */
473    m_data->m_saved_viewport = g_renderer->GetViewport();
474    g_renderer->SetViewport(ibox2(ivec2(0), m_data->m_size));
475    m_data->m_bound = true;
476}
477
478void Framebuffer::Unbind()
479{
480    ASSERT(m_data->m_bound, "trying to unbind an unbound framebuffer");
481
482#if defined USE_D3D9 || defined _XBOX
483#   if defined _XBOX
484    if (FAILED(m_data->m_dev->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
485                                    m_data->m_texture, nullptr, 0, 0, nullptr,
486                                    0, 0, nullptr)))
487        Abort();
488#   endif
489    if (FAILED(m_data->m_dev->SetRenderTarget(0, m_data->m_back_surface)))
490        Abort();
491    m_data->m_back_surface->Release();
492#else
493#   if GL_VERSION_1_1 || GL_ES_VERSION_2_0
494    glBindFramebuffer(GL_FRAMEBUFFER, 0);
495#   else
496    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
497#   endif
498#endif
499
500    g_renderer->SetViewport(m_data->m_saved_viewport);
501    m_data->m_bound = false;
502}
503
504} /* namespace lol */
505
Note: See TracBrowser for help on using the repository browser.