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

Last change on this file since 2770 was 2770, checked in by sam, 9 years ago

gpu: get rid of the global D3D device pointer and move D3D initialisation
code from the Video to the Renderer class.

  • Property svn:keywords set to Id
File size: 13.9 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
26namespace lol
27{
28
29//
30// The FramebufferData class
31// -------------------------
32//
33
34class FramebufferData
35{
36    friend class Framebuffer;
37
38    ibox2 m_saved_viewport;
39    ivec2 m_size;
40    bool m_bound;
41
42#if defined USE_D3D9
43    IDirect3DDevice9 *m_dev;
44    IDirect3DTexture9 *m_texture;
45    IDirect3DSurface9 *m_surface, *m_back_surface;
46#elif defined _XBOX
47    D3DDevice9 *m_dev;
48    D3DTexture *m_texture;
49    D3DSurface *m_surface, *m_back_surface;
50#else
51    GLuint m_fbo, m_texture, m_depth;
52#endif
53};
54
55//
56// The FramebufferFormat struct
57// ----------------------
58//
59
60uint32_t FramebufferFormat::GetFormat()
61{
62    switch (m_format)
63    {
64#if defined USE_D3D9 || defined _XBOX
65    case R_16_F:        return D3DFMT_R16F;
66    case R_32_F:        return D3DFMT_R32F;
67    case RG_16:
68    case RG_16_I:
69    case RG_16_UI:      return D3DFMT_G16R16;
70    case RG_16_F:       return D3DFMT_G16R16F;
71    case RG_32_F:       return D3DFMT_G32R32F;
72    case RGB_8:
73    case RGB_8_I:
74    case RGB_8_UI:      return D3DFMT_R8G8B8;
75    case RGBA_8:
76    case RGBA_8_I:
77    case RGBA_8_UI:     return D3DFMT_A8R8G8B8;
78    case RGBA_16:
79    case RGBA_16_I:
80    case RGBA_16_UI:    return D3DFMT_A16B16G16R16;
81    case RGBA_16_F:     return D3DFMT_A16B16G16R16F;
82    case RGBA_32_F:     return D3DFMT_A32B32G32R32F;
83#elif defined __CELLOS_LV2__
84    /* Supported drawable formats on the PS3: GL_ARGB_SCE, GL_RGB16F_ARB,
85     * GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB, GL_LUMINANCE32F_ARB. */
86    case RGB_16_F:      return GL_RGB16F_ARB;
87    case RGB_32_F:      return GL_RGB32F_ARB;
88    case RGBA_8:        return GL_ARGB_SCE;
89    case RGBA_16_F:     return GL_RGBA16F_ARB;
90    case RGBA_32_F:     return GL_RGBA32F_ARB;
91#elif defined HAVE_GLES_2X
92    /* FIXME: incomplete */
93    case RGBA_8:
94    case RGBA_8_I:
95    case RGBA_8_UI:     return GL_RGBA;
96#elif defined __APPLE__ && defined __MACH__
97    case R_8:
98    case R_8_I:
99    case R_8_UI:
100    case R_8_F:
101
102    case R_16:
103    case R_16_I:
104    case R_16_UI:
105    case R_16_F:
106
107    case R_32_I:
108    case R_32:
109    case R_32_UI:
110    case R_32_F:        return GL_RED;
111
112    case RG_8:
113    case RG_8_I:
114    case RG_8_UI:
115    case RG_8_F:
116
117    case RG_16:
118    case RG_16_I:
119    case RG_16_UI:
120    case RG_16_F:
121
122    case RG_32:
123    case RG_32_I:
124    case RG_32_UI:
125    case RG_32_F:       return GL_RG;
126
127    case RGB_8:
128    case RGB_8_I:
129    case RGB_8_UI:
130    case RGB_8_F:
131
132    case RGB_16:
133    case RGB_16_I:
134    case RGB_16_UI:
135    case RGB_16_F:
136
137    case RGB_32:
138    case RGB_32_I:
139    case RGB_32_UI:
140    case RGB_32_F:      return (m_invert_rgb)?(GL_BGR):(GL_RGB);
141
142    case RGBA_8:
143    case RGBA_8_I:
144    case RGBA_8_UI:
145    case RGBA_8_F:
146
147    case RGBA_16:
148    case RGBA_16_I:
149    case RGBA_16_UI:
150    case RGBA_16_F:
151
152    case RGBA_32:
153    case RGBA_32_I:
154    case RGBA_32_UI:
155    case RGBA_32_F:     return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
156#else
157    case R_8:           return GL_R8;
158    case R_8_I:         return GL_R8I;
159    case R_8_UI:        return GL_R8UI;
160
161    case R_16:          return GL_R16;
162    case R_16_I:        return GL_R16I;
163    case R_16_UI:       return GL_R16UI;
164    case R_16_F:        return GL_R16F;
165
166    case R_32_I:        return GL_R32I;
167    case R_32_UI:       return GL_R32UI;
168    case R_32_F:        return GL_R32F;
169
170    case RG_8:          return GL_RG8;
171    case RG_8_I:        return GL_RG8I;
172    case RG_8_UI:       return GL_RG8UI;
173
174    case RG_16:         return GL_RG16;
175    case RG_16_I:       return GL_RG16I;
176    case RG_16_UI:      return GL_RG16UI;
177    case RG_16_F:       return GL_RG16F;
178
179    case RG_32_I:       return GL_RG32I;
180    case RG_32_UI:      return GL_RG32UI;
181    case RG_32_F:       return GL_RG32F;
182
183    case RGB_8:         return GL_RGB8;
184    case RGB_8_I:       return GL_RGB8I;
185    case RGB_8_UI:      return GL_RGB8UI;
186
187    case RGB_16:        return GL_RGB16;
188    case RGB_16_I:      return GL_RGB16I;
189    case RGB_16_UI:     return GL_RGB16UI;
190    case RGB_16_F:      return GL_RGB16F;
191
192    case RGB_32_I:      return GL_RGB32I;
193    case RGB_32_UI:     return GL_RGB32UI;
194    case RGB_32_F:      return GL_RGB32F;
195
196    case RGBA_8:        return GL_RGBA8;
197    case RGBA_8_I:      return GL_RGBA8I;
198    case RGBA_8_UI:     return GL_RGBA8UI;
199
200    case RGBA_16:       return GL_RGBA16;
201    case RGBA_16_I:     return GL_RGBA16I;
202    case RGBA_16_UI:    return GL_RGBA16UI;
203    case RGBA_16_F:     return GL_RGBA16F;
204
205    case RGBA_32_I:     return GL_RGBA32I;
206    case RGBA_32_UI:    return GL_RGBA32UI;
207    case RGBA_32_F:     return GL_RGBA32F;
208#endif
209    default:
210        ASSERT(false, "unknown framebuffer format %d", m_format);
211        return 0;
212    }
213}
214
215uint32_t FramebufferFormat::GetFormatOrder()
216{
217    switch (m_format)
218    {
219#if defined USE_D3D9 || defined _XBOX
220    /* FIXME: not implemented at all */
221#elif defined __CELLOS_LV2__
222    /* FIXME: not implemented at all */
223#elif defined HAVE_GLES_2X
224    /* FIXME: incomplete */
225    case R_8:   case RG_8:   case RGB_8:   case RGBA_8:
226    case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
227        return GL_BYTE;
228    case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
229        return GL_UNSIGNED_BYTE;
230#elif defined __APPLE__ && defined __MACH__
231    case R_8:   case RG_8:   case RGB_8:   case RGBA_8:
232    case R_8_I: case RG_8_I: case RGB_8_I: case RGBA_8_I:
233        return GL_BYTE;
234    case R_8_UI: case RG_8_UI: case RGB_8_UI: case RGBA_8_UI:
235        return GL_UNSIGNED_BYTE;
236
237    case R_16:   case RG_16:   case RGB_16:   case RGBA_16:
238    case R_16_I: case RG_16_I: case RGB_16_I: case RGBA_16_I:
239        return GL_SHORT;
240    case R_16_UI: case RG_16_UI: case RGB_16_UI: case RGBA_16_UI:
241        return GL_UNSIGNED_SHORT;
242
243    case R_16_F: case RG_16_F: case RGB_16_F: case RGBA_16_F:
244        ASSERT(false, "unsupported framebuffer format order %d", m_format);
245        return 0;
246
247    case R_32_I: case RG_32_I: case RGB_32_I: case RGBA_32_I:
248        return GL_INT;
249    case R_32_UI: case RG_32_UI: case RGB_32_UI: case RGBA_32_UI:
250        return GL_UNSIGNED_INT;
251    case R_32_F: case RG_32_F: case RGB_32_F: case RGBA_32_F:
252        return GL_FLOAT;
253#else
254    case R_8:  case R_8_I:  case R_8_UI:  case R_8_F:
255    case R_16: case R_16_I: case R_16_UI: case R_16_F:
256    case R_32: case R_32_I: case R_32_UI: case R_32_F:
257        return GL_RED;
258
259    case RG_8:  case RG_8_I:  case RG_8_UI:  case RG_8_F:
260    case RG_16: case RG_16_I: case RG_16_UI: case RG_16_F:
261    case RG_32: case RG_32_I: case RG_32_UI: case RG_32_F:
262        return GL_RG;
263
264    case RGB_8:  case RGB_8_I:  case RGB_8_UI:  case RGB_8_F:
265    case RGB_16: case RGB_16_I: case RGB_16_UI: case RGB_16_F:
266    case RGB_32: case RGB_32_I: case RGB_32_UI: case RGB_32_F:
267        return m_invert_rgb ? GL_BGR : GL_RGB;
268
269    case RGBA_8:  case RGBA_8_I:  case RGBA_8_UI:  case RGBA_8_F:
270    case RGBA_16: case RGBA_16_I: case RGBA_16_UI: case RGBA_16_F:
271    case RGBA_32: case RGBA_32_I: case RGBA_32_UI: case RGBA_32_F:
272        return (m_invert_rgb)?(GL_BGRA):(GL_RGBA);
273#endif
274    default:
275        ASSERT(false, "unknown framebuffer format order %d", m_format);
276        return 0;
277    }
278}
279
280//
281// The Framebuffer class
282// ----------------------
283//
284
285Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format)
286  : m_data(new FramebufferData)
287{
288    m_data->m_size = size;
289    m_data->m_bound = false;
290#if defined USE_D3D9
291    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
292
293    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1,
294                                          D3DUSAGE_RENDERTARGET,
295                                          (D3DFORMAT)fbo_format.GetFormat(), D3DPOOL_DEFAULT,
296                                          &m_data->m_texture, nullptr)))
297        Abort();
298    if (FAILED(m_data->m_texture->GetSurfaceLevel(0, &m_data->m_surface)))
299        Abort();
300#elif defined _XBOX
301    m_data->m_dev = (D3DDevice9 *)g_renderer->GetDevice();
302
303    if (FAILED(m_data->m_dev->CreateTexture(size.x, size.y, 1, 0,
304                                          fbo_format.GetFormat(), D3DPOOL_DEFAULT,
305                                          &m_data->m_texture, nullptr)))
306        Abort();
307    if (FAILED(m_data->m_dev->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(m_data->m_dev->GetRenderTarget(0, &m_data->m_back_surface)))
426        Abort();
427    if (FAILED(m_data->m_dev->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(m_data->m_dev->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr,
452                                    m_data->m_texture, nullptr, 0, 0, nullptr,
453                                    0, 0, nullptr)))
454        Abort();
455#   endif
456    if (FAILED(m_data->m_dev->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.