1//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
8// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
9
10#include "libGLESv2/Framebuffer.h"
11
12#include "libGLESv2/main.h"
13#include "libGLESv2/Renderbuffer.h"
14#include "libGLESv2/Texture.h"
15#include "libGLESv2/utilities.h"
16
17namespace gl
18{
19
20Framebuffer::Framebuffer()
21{
22    mColorbufferType = GL_NONE;
23    mDepthbufferType = GL_NONE;
24    mStencilbufferType = GL_NONE;
25}
26
27Framebuffer::~Framebuffer()
28{
29    mColorbufferPointer.set(NULL);
30    mDepthbufferPointer.set(NULL);
31    mStencilbufferPointer.set(NULL);
32}
33
34Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
35{
36    gl::Context *context = gl::getContext();
37    Renderbuffer *buffer = NULL;
38
39    if (type == GL_NONE)
40    {
41        buffer = NULL;
42    }
43    else if (type == GL_RENDERBUFFER)
44    {
45        buffer = context->getRenderbuffer(handle);
46    }
47    else if (IsTextureTarget(type))
48    {
49        buffer = context->getTexture(handle)->getColorbuffer(type);
50    }
51    else
52    {
53        UNREACHABLE();
54    }
55
56    return buffer;
57}
58
59void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
60{
61    mColorbufferType = type;
62    mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
63}
64
65void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
66{
67    mDepthbufferType = type;
68    mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
69}
70
71void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
72{
73    mStencilbufferType = type;
74    mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
75}
76
77void Framebuffer::detachTexture(GLuint texture)
78{
79    if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
80    {
81        mColorbufferType = GL_NONE;
82        mColorbufferPointer.set(NULL);
83    }
84
85    if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
86    {
87        mDepthbufferType = GL_NONE;
88        mDepthbufferPointer.set(NULL);
89    }
90
91    if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
92    {
93        mStencilbufferType = GL_NONE;
94        mStencilbufferPointer.set(NULL);
95    }
96}
97
98void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
99{
100    if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
101    {
102        mColorbufferType = GL_NONE;
103        mColorbufferPointer.set(NULL);
104    }
105
106    if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
107    {
108        mDepthbufferType = GL_NONE;
109        mDepthbufferPointer.set(NULL);
110    }
111
112    if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
113    {
114        mStencilbufferType = GL_NONE;
115        mStencilbufferPointer.set(NULL);
116    }
117}
118
119unsigned int Framebuffer::getRenderTargetSerial()
120{
121    Renderbuffer *colorbuffer = mColorbufferPointer.get();
122
123    if (colorbuffer)
124    {
125        return colorbuffer->getSerial();
126    }
127
128    return 0;
129}
130
131IDirect3DSurface9 *Framebuffer::getRenderTarget()
132{
133    Renderbuffer *colorbuffer = mColorbufferPointer.get();
134
135    if (colorbuffer)
136    {
137        return colorbuffer->getRenderTarget();
138    }
139
140    return NULL;
141}
142
143IDirect3DSurface9 *Framebuffer::getDepthStencil()
144{
145    Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
146
147    if (!depthstencilbuffer)
148    {
149        depthstencilbuffer = mStencilbufferPointer.get();
150    }
151
152    if (depthstencilbuffer)
153    {
154        return depthstencilbuffer->getDepthStencil();
155    }
156
157    return NULL;
158}
159
160unsigned int Framebuffer::getDepthbufferSerial()
161{
162    Renderbuffer *depthbuffer = mDepthbufferPointer.get();
163
164    if (depthbuffer)
165    {
166        return depthbuffer->getSerial();
167    }
168
169    return 0;
170}
171
172unsigned int Framebuffer::getStencilbufferSerial()
173{
174    Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
175
176    if (stencilbuffer)
177    {
178        return stencilbuffer->getSerial();
179    }
180
181    return 0;
182}
183
184Colorbuffer *Framebuffer::getColorbuffer()
185{
186    Renderbuffer *rb = mColorbufferPointer.get();
187
188    if (rb != NULL && rb->isColorbuffer())
189    {
190        return static_cast<Colorbuffer*>(rb->getStorage());
191    }
192    else
193    {
194        return NULL;
195    }
196}
197
198DepthStencilbuffer *Framebuffer::getDepthbuffer()
199{
200    Renderbuffer *rb = mDepthbufferPointer.get();
201
202    if (rb != NULL && rb->isDepthbuffer())
203    {
204        return static_cast<DepthStencilbuffer*>(rb->getStorage());
205    }
206    else
207    {
208        return NULL;
209    }
210}
211
212DepthStencilbuffer *Framebuffer::getStencilbuffer()
213{
214    Renderbuffer *rb = mStencilbufferPointer.get();
215
216    if (rb != NULL && rb->isStencilbuffer())
217    {
218        return static_cast<DepthStencilbuffer*>(rb->getStorage());
219    }
220    else
221    {
222        return NULL;
223    }
224}
225
226GLenum Framebuffer::getColorbufferType()
227{
228    return mColorbufferType;
229}
230
231GLenum Framebuffer::getDepthbufferType()
232{
233    return mDepthbufferType;
234}
235
236GLenum Framebuffer::getStencilbufferType()
237{
238    return mStencilbufferType;
239}
240
241GLuint Framebuffer::getColorbufferHandle()
242{
243    return mColorbufferPointer.id();
244}
245
246GLuint Framebuffer::getDepthbufferHandle()
247{
248    return mDepthbufferPointer.id();
249}
250
251GLuint Framebuffer::getStencilbufferHandle()
252{
253    return mStencilbufferPointer.id();
254}
255
256bool Framebuffer::hasStencil()
257{
258    if (mStencilbufferType != GL_NONE)
259    {
260        DepthStencilbuffer *stencilbufferObject = getStencilbuffer();
261
262        if (stencilbufferObject)
263        {
264            return stencilbufferObject->getStencilSize() > 0;
265        }
266    }
267
268    return false;
269}
270
271bool Framebuffer::isMultisample()
272{
273    // If the framebuffer is not complete, attachment samples may be mismatched, and it
274    // cannot be used as a multisample framebuffer. If it is complete, it is required to
275    // have a color attachment, and all its attachments must have the same number of samples,
276    // so the number of samples for the colorbuffer will indicate whether the framebuffer is
277    // multisampled.
278    if (completeness() == GL_FRAMEBUFFER_COMPLETE && getColorbuffer()->getSamples() > 0)
279    {
280        return true;
281    }
282    else
283    {
284        return false;
285    }
286}
287
288GLenum Framebuffer::completeness()
289{
290    int width = 0;
291    int height = 0;
292    int samples = -1;
293
294    if (mColorbufferType != GL_NONE)
295    {
296        Colorbuffer *colorbuffer = getColorbuffer();
297
298        if (!colorbuffer)
299        {
300            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
301        }
302
303        if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
304        {
305            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
306        }
307
308        if (mColorbufferType == GL_RENDERBUFFER)
309        {
310            if (!gl::IsColorRenderable(colorbuffer->getFormat()))
311            {
312                return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
313            }
314        }
315        else if (IsTextureTarget(mColorbufferType))
316        {
317            if (IsCompressed(colorbuffer->getFormat()))
318            {
319                return GL_FRAMEBUFFER_UNSUPPORTED;
320            }
321
322            if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() ||
323                                                   !getContext()->supportsHalfFloatRenderableTextures()))
324            {
325                return GL_FRAMEBUFFER_UNSUPPORTED;
326            }
327
328            if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA)
329            {
330                return GL_FRAMEBUFFER_UNSUPPORTED;
331            }
332        }
333        else UNREACHABLE();
334
335        width = colorbuffer->getWidth();
336        height = colorbuffer->getHeight();
337        samples = colorbuffer->getSamples();
338    }
339    else
340    {
341        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
342    }
343
344    DepthStencilbuffer *depthbuffer = NULL;
345    DepthStencilbuffer *stencilbuffer = NULL;
346
347    if (mDepthbufferType != GL_NONE)
348    {
349        if (mDepthbufferType != GL_RENDERBUFFER)
350        {
351            return GL_FRAMEBUFFER_UNSUPPORTED;   // Requires GL_OES_depth_texture
352        }
353
354        depthbuffer = getDepthbuffer();
355
356        if (!depthbuffer)
357        {
358            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
359        }
360
361        if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
362        {
363            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
364        }
365
366        if (width == 0)
367        {
368            width = depthbuffer->getWidth();
369            height = depthbuffer->getHeight();
370        }
371        else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
372        {
373            return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
374        }
375
376        if (samples == -1)
377        {
378            samples = depthbuffer->getSamples();
379        }
380        else if (samples != depthbuffer->getSamples())
381        {
382            return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
383        }
384    }
385
386    if (mStencilbufferType != GL_NONE)
387    {
388        if (mStencilbufferType != GL_RENDERBUFFER)
389        {
390            return GL_FRAMEBUFFER_UNSUPPORTED;
391        }
392
393        stencilbuffer = getStencilbuffer();
394
395        if (!stencilbuffer)
396        {
397            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
398        }
399
400        if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
401        {
402            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
403        }
404
405        if (width == 0)
406        {
407            width = stencilbuffer->getWidth();
408            height = stencilbuffer->getHeight();
409        }
410        else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
411        {
412            return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
413        }
414
415        if (samples == -1)
416        {
417            samples = stencilbuffer->getSamples();
418        }
419        else if (samples != stencilbuffer->getSamples())
420        {
421            return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
422        }
423    }
424
425    if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
426    {
427        if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
428            stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
429            depthbuffer->getSerial() != stencilbuffer->getSerial())
430        {
431            return GL_FRAMEBUFFER_UNSUPPORTED;
432        }
433    }
434
435    return GL_FRAMEBUFFER_COMPLETE;
436}
437
438DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil)
439{
440    mColorbufferType = GL_RENDERBUFFER;
441    mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
442    mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
443
444    mColorbufferPointer.set(new Renderbuffer(0, color));
445
446    Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
447    mDepthbufferPointer.set(depthStencilRenderbuffer);
448    mStencilbufferPointer.set(depthStencilRenderbuffer);
449}
450
451int Framebuffer::getSamples()
452{
453    if (completeness() == GL_FRAMEBUFFER_COMPLETE)
454    {
455        return getColorbuffer()->getSamples();
456    }
457    else
458    {
459        return 0;
460    }
461}
462
463GLenum DefaultFramebuffer::completeness()
464{
465    // The default framebuffer should always be complete
466    ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
467
468    return GL_FRAMEBUFFER_COMPLETE;
469}
470
471}
472