blob: 39a10b56243731fc00b2ddb6b9fb22c0684d3356 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Framebuffer.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000012#include "libGLESv2/main.h"
13#include "libGLESv2/Renderbuffer.h"
14#include "libGLESv2/Texture.h"
daniel@transgaming.com93a81472010-04-20 18:52:58 +000015#include "libGLESv2/utilities.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000016
17namespace gl
18{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000019
apatrick@chromium.orgff8bdfb2010-09-15 17:27:49 +000020Framebuffer::Framebuffer()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021{
22 mColorbufferType = GL_NONE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023 mDepthbufferType = GL_NONE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024 mStencilbufferType = GL_NONE;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025}
26
27Framebuffer::~Framebuffer()
28{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000029 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;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000057}
58
59void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
60{
61 mColorbufferType = type;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000062 mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000063}
64
65void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
66{
67 mDepthbufferType = type;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000068 mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069}
70
71void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
72{
73 mStencilbufferType = type;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000074 mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
77void Framebuffer::detachTexture(GLuint texture)
78{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000079 if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080 {
81 mColorbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000082 mColorbufferPointer.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083 }
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000084
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000085 if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000086 {
87 mDepthbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000088 mDepthbufferPointer.set(NULL);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000089 }
90
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000091 if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000092 {
93 mStencilbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000094 mStencilbufferPointer.set(NULL);
daniel@transgaming.comfbc09532010-04-26 15:33:41 +000095 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096}
97
98void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
99{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000100 if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101 {
102 mColorbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000103 mColorbufferPointer.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104 }
105
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000106 if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000107 {
108 mDepthbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000109 mDepthbufferPointer.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110 }
111
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000112 if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000113 {
114 mStencilbufferType = GL_NONE;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000115 mStencilbufferPointer.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116 }
117}
118
daniel@transgaming.com092bd482010-05-12 03:39:36 +0000119unsigned int Framebuffer::getRenderTargetSerial()
120{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000121 Renderbuffer *colorbuffer = mColorbufferPointer.get();
daniel@transgaming.com092bd482010-05-12 03:39:36 +0000122
123 if (colorbuffer)
124 {
125 return colorbuffer->getSerial();
126 }
127
128 return 0;
129}
130
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131IDirect3DSurface9 *Framebuffer::getRenderTarget()
132{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000133 Renderbuffer *colorbuffer = mColorbufferPointer.get();
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000134
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 if (colorbuffer)
136 {
137 return colorbuffer->getRenderTarget();
138 }
139
140 return NULL;
141}
142
daniel@transgaming.com4cbc5902010-08-24 19:20:26 +0000143IDirect3DSurface9 *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
daniel@transgaming.com339ae702010-05-12 03:40:20 +0000160unsigned int Framebuffer::getDepthbufferSerial()
161{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000162 Renderbuffer *depthbuffer = mDepthbufferPointer.get();
daniel@transgaming.com339ae702010-05-12 03:40:20 +0000163
164 if (depthbuffer)
165 {
166 return depthbuffer->getSerial();
167 }
168
169 return 0;
170}
171
daniel@transgaming.com4cbc5902010-08-24 19:20:26 +0000172unsigned 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184Colorbuffer *Framebuffer::getColorbuffer()
185{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000186 Renderbuffer *rb = mColorbufferPointer.get();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000188 if (rb != NULL && rb->isColorbuffer())
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000189 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000190 return static_cast<Colorbuffer*>(rb->getStorage());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000192 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000194 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196}
197
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000198DepthStencilbuffer *Framebuffer::getDepthbuffer()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000199{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000200 Renderbuffer *rb = mDepthbufferPointer.get();
201
202 if (rb != NULL && rb->isDepthbuffer())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000204 return static_cast<DepthStencilbuffer*>(rb->getStorage());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000206 else
207 {
208 return NULL;
209 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210}
211
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000212DepthStencilbuffer *Framebuffer::getStencilbuffer()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000214 Renderbuffer *rb = mStencilbufferPointer.get();
215
216 if (rb != NULL && rb->isStencilbuffer())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000218 return static_cast<DepthStencilbuffer*>(rb->getStorage());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000220 else
221 {
222 return NULL;
223 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224}
225
daniel@transgaming.comc46c9c02010-04-23 18:34:55 +0000226GLenum 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{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000243 return mColorbufferPointer.id();
daniel@transgaming.comc46c9c02010-04-23 18:34:55 +0000244}
245
246GLuint Framebuffer::getDepthbufferHandle()
247{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000248 return mDepthbufferPointer.id();
daniel@transgaming.comc46c9c02010-04-23 18:34:55 +0000249}
250
251GLuint Framebuffer::getStencilbufferHandle()
252{
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000253 return mStencilbufferPointer.id();
daniel@transgaming.comc46c9c02010-04-23 18:34:55 +0000254}
255
daniel@transgaming.coma27ff1e2010-08-24 19:20:11 +0000256bool 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
daniel@transgaming.comd470a1b2010-08-24 19:20:48 +0000271bool 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288GLenum Framebuffer::completeness()
289{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 int width = 0;
291 int height = 0;
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000292 int samples = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000294 if (mColorbufferType != GL_NONE)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000296 Colorbuffer *colorbuffer = getColorbuffer();
297
298 if (!colorbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000300 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301 }
302
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000303 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000305 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000306 }
307
daniel@transgaming.com01868132010-08-24 19:21:17 +0000308 if (IsTextureTarget(mColorbufferType))
309 {
310 if (IsCompressed(colorbuffer->getFormat()))
311 {
312 return GL_FRAMEBUFFER_UNSUPPORTED;
313 }
daniel@transgaming.com1297d922010-09-01 15:47:47 +0000314
315 if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() ||
316 !getContext()->supportsHalfFloatRenderableTextures()))
317 {
318 return GL_FRAMEBUFFER_UNSUPPORTED;
319 }
daniel@transgaming.comb6b2e672010-10-15 17:57:47 +0000320
321 if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA)
322 {
323 return GL_FRAMEBUFFER_UNSUPPORTED;
324 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000325 }
326
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000327 width = colorbuffer->getWidth();
328 height = colorbuffer->getHeight();
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000329 samples = colorbuffer->getSamples();
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000330 }
331 else
332 {
333 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
334 }
335
336 DepthStencilbuffer *depthbuffer = NULL;
337 DepthStencilbuffer *stencilbuffer = NULL;
338
339 if (mDepthbufferType != GL_NONE)
340 {
341 depthbuffer = getDepthbuffer();
342
343 if (!depthbuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000345 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 }
347
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000348 if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000350 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
351 }
352
353 if (width == 0)
354 {
355 width = depthbuffer->getWidth();
356 height = depthbuffer->getHeight();
357 }
358 else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
359 {
360 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
361 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000362
363 if (samples == -1)
364 {
365 samples = depthbuffer->getSamples();
366 }
367 else if (samples != depthbuffer->getSamples())
368 {
369 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
370 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000371
372 if (IsTextureTarget(mDepthbufferType))
373 {
374 if (IsCompressed(depthbuffer->getFormat()))
375 {
376 return GL_FRAMEBUFFER_UNSUPPORTED;
377 }
378 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000379 }
380
381 if (mStencilbufferType != GL_NONE)
382 {
383 stencilbuffer = getStencilbuffer();
384
385 if (!stencilbuffer)
386 {
387 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
388 }
389
390 if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
391 {
392 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
393 }
394
395 if (width == 0)
396 {
397 width = stencilbuffer->getWidth();
398 height = stencilbuffer->getHeight();
399 }
400 else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
401 {
402 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
403 }
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000404
405 if (samples == -1)
406 {
407 samples = stencilbuffer->getSamples();
408 }
409 else if (samples != stencilbuffer->getSamples())
410 {
411 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
412 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000413
414 if (IsTextureTarget(mStencilbufferType))
415 {
416 if (IsCompressed(stencilbuffer->getFormat()))
417 {
418 return GL_FRAMEBUFFER_UNSUPPORTED;
419 }
420 }
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000421 }
422
423 if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
424 {
425 if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
426 stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
427 depthbuffer->getSerial() != stencilbuffer->getSerial())
428 {
429 return GL_FRAMEBUFFER_UNSUPPORTED;
daniel@transgaming.comcdacc8e2010-07-28 19:20:50 +0000430 }
431 }
432
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433 return GL_FRAMEBUFFER_COMPLETE;
434}
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000435
436DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil)
437{
438 mColorbufferType = GL_RENDERBUFFER;
439 mDepthbufferType = GL_RENDERBUFFER;
440 mStencilbufferType = GL_RENDERBUFFER;
441
442 mColorbufferPointer.set(new Renderbuffer(0, color));
443
444 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
445 mDepthbufferPointer.set(depthStencilRenderbuffer);
446 mStencilbufferPointer.set(depthStencilRenderbuffer);
447}
448
daniel@transgaming.com1f135d82010-08-24 19:20:36 +0000449int Framebuffer::getSamples()
450{
451 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
452 {
453 return getColorbuffer()->getSamples();
454 }
455 else
456 {
457 return 0;
458 }
459}
460
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000461GLenum DefaultFramebuffer::completeness()
462{
463 return GL_FRAMEBUFFER_COMPLETE;
464}
465
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466}