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

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

gpu: framebuffers now use the g_render object to restore viewport data.

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