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

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

gpu: fix framebuffer handling in OpenGL ES and add some sanity checks.

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