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
17 namespace gl
18 {
19
Framebuffer()20 Framebuffer::Framebuffer()
21 {
22 mColorbufferType = GL_NONE;
23 mDepthbufferType = GL_NONE;
24 mStencilbufferType = GL_NONE;
25 }
26
~Framebuffer()27 Framebuffer::~Framebuffer()
28 {
29 mColorbufferPointer.set(NULL);
30 mDepthbufferPointer.set(NULL);
31 mStencilbufferPointer.set(NULL);
32 }
33
lookupRenderbuffer(GLenum type,GLuint handle) const34 Renderbuffer *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
setColorbuffer(GLenum type,GLuint colorbuffer)59 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
60 {
61 mColorbufferType = type;
62 mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
63 }
64
setDepthbuffer(GLenum type,GLuint depthbuffer)65 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
66 {
67 mDepthbufferType = type;
68 mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
69 }
70
setStencilbuffer(GLenum type,GLuint stencilbuffer)71 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
72 {
73 mStencilbufferType = type;
74 mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
75 }
76
detachTexture(GLuint texture)77 void 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
detachRenderbuffer(GLuint renderbuffer)98 void 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
getRenderTargetSerial()119 unsigned 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
getRenderTarget()131 IDirect3DSurface9 *Framebuffer::getRenderTarget()
132 {
133 Renderbuffer *colorbuffer = mColorbufferPointer.get();
134
135 if (colorbuffer)
136 {
137 return colorbuffer->getRenderTarget();
138 }
139
140 return NULL;
141 }
142
getDepthStencil()143 IDirect3DSurface9 *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
getDepthbufferSerial()160 unsigned 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
getStencilbufferSerial()172 unsigned 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
getColorbuffer()184 Colorbuffer *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
getDepthbuffer()198 DepthStencilbuffer *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
getStencilbuffer()212 DepthStencilbuffer *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
getColorbufferType()226 GLenum Framebuffer::getColorbufferType()
227 {
228 return mColorbufferType;
229 }
230
getDepthbufferType()231 GLenum Framebuffer::getDepthbufferType()
232 {
233 return mDepthbufferType;
234 }
235
getStencilbufferType()236 GLenum Framebuffer::getStencilbufferType()
237 {
238 return mStencilbufferType;
239 }
240
getColorbufferHandle()241 GLuint Framebuffer::getColorbufferHandle()
242 {
243 return mColorbufferPointer.id();
244 }
245
getDepthbufferHandle()246 GLuint Framebuffer::getDepthbufferHandle()
247 {
248 return mDepthbufferPointer.id();
249 }
250
getStencilbufferHandle()251 GLuint Framebuffer::getStencilbufferHandle()
252 {
253 return mStencilbufferPointer.id();
254 }
255
hasStencil()256 bool 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
isMultisample()271 bool 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
completeness()288 GLenum 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
DefaultFramebuffer(Colorbuffer * color,DepthStencilbuffer * depthStencil)438 DefaultFramebuffer::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
getSamples()451 int Framebuffer::getSamples()
452 {
453 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
454 {
455 return getColorbuffer()->getSamples();
456 }
457 else
458 {
459 return 0;
460 }
461 }
462
completeness()463 GLenum 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