1 //
2 // Copyright (c) 2002-2014 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 #include "libGLESv2/main.h"
12 #include "libGLESv2/formatutils.h"
13 #include "libGLESv2/Texture.h"
14 #include "libGLESv2/Context.h"
15 #include "libGLESv2/Renderbuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/renderer/Renderer.h"
18 #include "libGLESv2/renderer/RenderTarget.h"
19 #include "libGLESv2/renderer/d3d/TextureD3D.h"
20
21 #include "common/utilities.h"
22
23 namespace rx
24 {
GetAttachmentRenderTarget(gl::FramebufferAttachment * attachment)25 RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment)
26 {
27 if (attachment->isTexture())
28 {
29 gl::Texture *texture = attachment->getTexture();
30 ASSERT(texture);
31 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
32 const gl::ImageIndex *index = attachment->getTextureImageIndex();
33 ASSERT(index);
34 return textureD3D->getRenderTarget(*index);
35 }
36
37 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
38 ASSERT(renderbuffer);
39
40 // TODO: cast to RenderbufferD3D
41 return renderbuffer->getStorage()->getRenderTarget();
42 }
43
44 // Note: RenderTarget serials should ideally be in the RenderTargets themselves.
GetAttachmentSerial(gl::FramebufferAttachment * attachment)45 unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment)
46 {
47 if (attachment->isTexture())
48 {
49 gl::Texture *texture = attachment->getTexture();
50 ASSERT(texture);
51 TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation());
52 const gl::ImageIndex *index = attachment->getTextureImageIndex();
53 ASSERT(index);
54 return textureD3D->getRenderTargetSerial(*index);
55 }
56
57 gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
58 ASSERT(renderbuffer);
59
60 // TODO: cast to RenderbufferD3D
61 return renderbuffer->getStorage()->getSerial();
62 }
63
64 }
65
66 namespace gl
67 {
68
Framebuffer(rx::Renderer * renderer,GLuint id)69 Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id)
70 : mRenderer(renderer),
71 mId(id),
72 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
73 mDepthbuffer(NULL),
74 mStencilbuffer(NULL)
75 {
76 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
77 {
78 mColorbuffers[colorAttachment] = NULL;
79 mDrawBufferStates[colorAttachment] = GL_NONE;
80 }
81 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
82 }
83
~Framebuffer()84 Framebuffer::~Framebuffer()
85 {
86 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
87 {
88 SafeDelete(mColorbuffers[colorAttachment]);
89 }
90 SafeDelete(mDepthbuffer);
91 SafeDelete(mStencilbuffer);
92 }
93
createAttachment(GLenum binding,GLenum type,GLuint handle,GLint level,GLint layer) const94 FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const
95 {
96 if (handle == 0)
97 {
98 return NULL;
99 }
100
101 gl::Context *context = gl::getContext();
102
103 switch (type)
104 {
105 case GL_NONE:
106 return NULL;
107
108 case GL_RENDERBUFFER:
109 return new RenderbufferAttachment(binding, context->getRenderbuffer(handle));
110
111 case GL_TEXTURE_2D:
112 {
113 Texture *texture = context->getTexture(handle);
114 if (texture && texture->getTarget() == GL_TEXTURE_2D)
115 {
116 return new TextureAttachment(binding, texture, ImageIndex::Make2D(level));
117 }
118 else
119 {
120 return NULL;
121 }
122 }
123
124 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
125 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
126 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
127 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
128 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
129 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
130 {
131 Texture *texture = context->getTexture(handle);
132 if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP)
133 {
134 return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level));
135 }
136 else
137 {
138 return NULL;
139 }
140 }
141
142 case GL_TEXTURE_3D:
143 {
144 Texture *texture = context->getTexture(handle);
145 if (texture && texture->getTarget() == GL_TEXTURE_3D)
146 {
147 return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer));
148 }
149 else
150 {
151 return NULL;
152 }
153 }
154
155 case GL_TEXTURE_2D_ARRAY:
156 {
157 Texture *texture = context->getTexture(handle);
158 if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY)
159 {
160 return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer));
161 }
162 else
163 {
164 return NULL;
165 }
166 }
167
168 default:
169 UNREACHABLE();
170 return NULL;
171 }
172 }
173
setColorbuffer(unsigned int colorAttachment,GLenum type,GLuint colorbuffer,GLint level,GLint layer)174 void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer)
175 {
176 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
177 SafeDelete(mColorbuffers[colorAttachment]);
178 GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0;
179 mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer);
180 }
181
setDepthbuffer(GLenum type,GLuint depthbuffer,GLint level,GLint layer)182 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer)
183 {
184 SafeDelete(mDepthbuffer);
185 mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer);
186 }
187
setStencilbuffer(GLenum type,GLuint stencilbuffer,GLint level,GLint layer)188 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer)
189 {
190 SafeDelete(mStencilbuffer);
191 mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer);
192 }
193
setDepthStencilBuffer(GLenum type,GLuint depthStencilBuffer,GLint level,GLint layer)194 void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer)
195 {
196 FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
197
198 SafeDelete(mDepthbuffer);
199 SafeDelete(mStencilbuffer);
200
201 // ensure this is a legitimate depth+stencil format
202 if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0)
203 {
204 mDepthbuffer = attachment;
205
206 // Make a new attachment object to ensure we do not double-delete
207 // See angle issue 686
208 mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer);
209 }
210 }
211
detachTexture(GLuint textureId)212 void Framebuffer::detachTexture(GLuint textureId)
213 {
214 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
215 {
216 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
217
218 if (attachment && attachment->isTextureWithId(textureId))
219 {
220 SafeDelete(mColorbuffers[colorAttachment]);
221 }
222 }
223
224 if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId))
225 {
226 SafeDelete(mDepthbuffer);
227 }
228
229 if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId))
230 {
231 SafeDelete(mStencilbuffer);
232 }
233 }
234
detachRenderbuffer(GLuint renderbufferId)235 void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
236 {
237 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
238 {
239 FramebufferAttachment *attachment = mColorbuffers[colorAttachment];
240
241 if (attachment && attachment->isRenderbufferWithId(renderbufferId))
242 {
243 SafeDelete(mColorbuffers[colorAttachment]);
244 }
245 }
246
247 if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId))
248 {
249 SafeDelete(mDepthbuffer);
250 }
251
252 if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId))
253 {
254 SafeDelete(mStencilbuffer);
255 }
256 }
257
getColorbuffer(unsigned int colorAttachment) const258 FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
259 {
260 ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
261 return mColorbuffers[colorAttachment];
262 }
263
getDepthbuffer() const264 FramebufferAttachment *Framebuffer::getDepthbuffer() const
265 {
266 return mDepthbuffer;
267 }
268
getStencilbuffer() const269 FramebufferAttachment *Framebuffer::getStencilbuffer() const
270 {
271 return mStencilbuffer;
272 }
273
getDepthStencilBuffer() const274 FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
275 {
276 return (hasValidDepthStencil() ? mDepthbuffer : NULL);
277 }
278
getDepthOrStencilbuffer() const279 FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
280 {
281 FramebufferAttachment *depthstencilbuffer = mDepthbuffer;
282
283 if (!depthstencilbuffer)
284 {
285 depthstencilbuffer = mStencilbuffer;
286 }
287
288 return depthstencilbuffer;
289 }
290
getReadColorbuffer() const291 FramebufferAttachment *Framebuffer::getReadColorbuffer() const
292 {
293 // Will require more logic if glReadBuffers is supported
294 return mColorbuffers[0];
295 }
296
getReadColorbufferType() const297 GLenum Framebuffer::getReadColorbufferType() const
298 {
299 // Will require more logic if glReadBuffers is supported
300 return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE);
301 }
302
getFirstColorbuffer() const303 FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
304 {
305 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
306 {
307 if (mColorbuffers[colorAttachment])
308 {
309 return mColorbuffers[colorAttachment];
310 }
311 }
312
313 return NULL;
314 }
315
getAttachment(GLenum attachment) const316 FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
317 {
318 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
319 {
320 return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
321 }
322 else
323 {
324 switch (attachment)
325 {
326 case GL_DEPTH_ATTACHMENT:
327 return getDepthbuffer();
328 case GL_STENCIL_ATTACHMENT:
329 return getStencilbuffer();
330 case GL_DEPTH_STENCIL_ATTACHMENT:
331 return getDepthStencilBuffer();
332 default:
333 UNREACHABLE();
334 return NULL;
335 }
336 }
337 }
338
getDrawBufferState(unsigned int colorAttachment) const339 GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
340 {
341 return mDrawBufferStates[colorAttachment];
342 }
343
setDrawBufferState(unsigned int colorAttachment,GLenum drawBuffer)344 void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
345 {
346 mDrawBufferStates[colorAttachment] = drawBuffer;
347 }
348
isEnabledColorAttachment(unsigned int colorAttachment) const349 bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
350 {
351 return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE);
352 }
353
hasEnabledColorAttachment() const354 bool Framebuffer::hasEnabledColorAttachment() const
355 {
356 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
357 {
358 if (isEnabledColorAttachment(colorAttachment))
359 {
360 return true;
361 }
362 }
363
364 return false;
365 }
366
hasStencil() const367 bool Framebuffer::hasStencil() const
368 {
369 return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0);
370 }
371
usingExtendedDrawBuffers() const372 bool Framebuffer::usingExtendedDrawBuffers() const
373 {
374 for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
375 {
376 if (isEnabledColorAttachment(colorAttachment))
377 {
378 return true;
379 }
380 }
381
382 return false;
383 }
384
completeness() const385 GLenum Framebuffer::completeness() const
386 {
387 int width = 0;
388 int height = 0;
389 unsigned int colorbufferSize = 0;
390 int samples = -1;
391 bool missingAttachment = true;
392 GLuint clientVersion = mRenderer->getCurrentClientVersion();
393
394 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
395 {
396 const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
397
398 if (colorbuffer)
399 {
400 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
401 {
402 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
403 }
404
405 GLenum internalformat = colorbuffer->getInternalFormat();
406 // TODO(geofflang): use context's texture caps
407 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
408 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
409 if (colorbuffer->isTexture())
410 {
411 if (!formatCaps.renderable)
412 {
413 return GL_FRAMEBUFFER_UNSUPPORTED;
414 }
415
416 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
417 {
418 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
419 }
420 }
421 else
422 {
423 if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
424 {
425 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
426 }
427 }
428
429 if (!missingAttachment)
430 {
431 // all color attachments must have the same width and height
432 if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
433 {
434 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
435 }
436
437 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
438 // all color attachments have the same number of samples for the FBO to be complete.
439 if (colorbuffer->getSamples() != samples)
440 {
441 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
442 }
443
444 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
445 // in GLES 3.0, there is no such restriction
446 if (clientVersion < 3)
447 {
448 if (formatInfo.pixelBytes != colorbufferSize)
449 {
450 return GL_FRAMEBUFFER_UNSUPPORTED;
451 }
452 }
453
454 // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
455 for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
456 {
457 const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment];
458
459 if (previousAttachment &&
460 (colorbuffer->id() == previousAttachment->id() &&
461 colorbuffer->type() == previousAttachment->type()))
462 {
463 return GL_FRAMEBUFFER_UNSUPPORTED;
464 }
465 }
466 }
467 else
468 {
469 width = colorbuffer->getWidth();
470 height = colorbuffer->getHeight();
471 samples = colorbuffer->getSamples();
472 colorbufferSize = formatInfo.pixelBytes;
473 missingAttachment = false;
474 }
475 }
476 }
477
478 if (mDepthbuffer)
479 {
480 if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0)
481 {
482 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
483 }
484
485 GLenum internalformat = mDepthbuffer->getInternalFormat();
486 // TODO(geofflang): use context's texture caps
487 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
488 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
489 if (mDepthbuffer->isTexture())
490 {
491 // depth texture attachments require OES/ANGLE_depth_texture
492 // TODO(geofflang): use context's extensions
493 if (!mRenderer->getRendererExtensions().depthTextures)
494 {
495 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
496 }
497
498 if (!formatCaps.renderable)
499 {
500 return GL_FRAMEBUFFER_UNSUPPORTED;
501 }
502
503 if (formatInfo.depthBits == 0)
504 {
505 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
506 }
507 }
508 else
509 {
510 if (!formatCaps.renderable || formatInfo.depthBits == 0)
511 {
512 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
513 }
514 }
515
516 if (missingAttachment)
517 {
518 width = mDepthbuffer->getWidth();
519 height = mDepthbuffer->getHeight();
520 samples = mDepthbuffer->getSamples();
521 missingAttachment = false;
522 }
523 else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight())
524 {
525 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
526 }
527 else if (samples != mDepthbuffer->getSamples())
528 {
529 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
530 }
531 }
532
533 if (mStencilbuffer)
534 {
535 if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0)
536 {
537 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
538 }
539
540 GLenum internalformat = mStencilbuffer->getInternalFormat();
541 // TODO(geofflang): use context's texture caps
542 const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat);
543 const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
544 if (mStencilbuffer->isTexture())
545 {
546 // texture stencil attachments come along as part
547 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
548 // TODO(geofflang): use context's extensions
549 if (!mRenderer->getRendererExtensions().depthTextures)
550 {
551 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
552 }
553
554 if (!formatCaps.renderable)
555 {
556 return GL_FRAMEBUFFER_UNSUPPORTED;
557 }
558
559 if (formatInfo.stencilBits == 0)
560 {
561 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
562 }
563 }
564 else
565 {
566 if (!formatCaps.renderable || formatInfo.stencilBits == 0)
567 {
568 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
569 }
570 }
571
572 if (missingAttachment)
573 {
574 width = mStencilbuffer->getWidth();
575 height = mStencilbuffer->getHeight();
576 samples = mStencilbuffer->getSamples();
577 missingAttachment = false;
578 }
579 else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight())
580 {
581 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
582 }
583 else if (samples != mStencilbuffer->getSamples())
584 {
585 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
586 }
587 }
588
589 // if we have both a depth and stencil buffer, they must refer to the same object
590 // since we only support packed_depth_stencil and not separate depth and stencil
591 if (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil())
592 {
593 return GL_FRAMEBUFFER_UNSUPPORTED;
594 }
595
596 // we need to have at least one attachment to be complete
597 if (missingAttachment)
598 {
599 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
600 }
601
602 return GL_FRAMEBUFFER_COMPLETE;
603 }
604
invalidate(const Caps & caps,GLsizei numAttachments,const GLenum * attachments)605 void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments)
606 {
607 GLuint maxDimension = caps.maxRenderbufferSize;
608 invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension);
609 }
610
invalidateSub(const Caps & caps,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)611 void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments,
612 GLint x, GLint y, GLsizei width, GLsizei height)
613 {
614 ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE);
615 for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex)
616 {
617 GLenum attachmentTarget = attachments[attachIndex];
618
619 gl::FramebufferAttachment *attachment =
620 (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() :
621 getAttachment(attachmentTarget);
622
623 if (attachment)
624 {
625 rx::RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment);
626 if (renderTarget)
627 {
628 renderTarget->invalidate(x, y, width, height);
629 }
630 }
631 }
632 }
633
DefaultFramebuffer(rx::Renderer * renderer,Colorbuffer * colorbuffer,DepthStencilbuffer * depthStencil)634 DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
635 : Framebuffer(renderer, 0)
636 {
637 Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer);
638 mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer);
639
640 GLenum depthStencilActualFormat = depthStencil->getActualFormat();
641 const gl::InternalFormat &depthStencilFormatInfo = GetInternalFormatInfo(depthStencilActualFormat);
642
643 if (depthStencilFormatInfo.depthBits != 0 || depthStencilFormatInfo.stencilBits != 0)
644 {
645 Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil);
646
647 // Make a new attachment objects to ensure we do not double-delete
648 // See angle issue 686
649 mDepthbuffer = (depthStencilFormatInfo.depthBits != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL);
650 mStencilbuffer = (depthStencilFormatInfo.stencilBits != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL);
651 }
652 else
653 {
654 // This method transfers ownership, so delete the unused storage if we don't keep it.
655 SafeDelete(depthStencil);
656 }
657
658 mDrawBufferStates[0] = GL_BACK;
659 mReadBufferState = GL_BACK;
660 }
661
getSamples() const662 int Framebuffer::getSamples() const
663 {
664 if (completeness() == GL_FRAMEBUFFER_COMPLETE)
665 {
666 // for a complete framebuffer, all attachments must have the same sample count
667 // in this case return the first nonzero sample size
668 for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
669 {
670 if (mColorbuffers[colorAttachment])
671 {
672 return mColorbuffers[colorAttachment]->getSamples();
673 }
674 }
675 }
676
677 return 0;
678 }
679
hasValidDepthStencil() const680 bool Framebuffer::hasValidDepthStencil() const
681 {
682 // A valid depth-stencil attachment has the same resource bound to both the
683 // depth and stencil attachment points.
684 return (mDepthbuffer && mStencilbuffer &&
685 mDepthbuffer->type() == mStencilbuffer->type() &&
686 mDepthbuffer->id() == mStencilbuffer->id());
687 }
688
getColorbuffersForRender() const689 ColorbufferInfo Framebuffer::getColorbuffersForRender() const
690 {
691 ColorbufferInfo colorbuffersForRender;
692
693 for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment)
694 {
695 GLenum drawBufferState = mDrawBufferStates[colorAttachment];
696 FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment];
697
698 if (colorbuffer != NULL && drawBufferState != GL_NONE)
699 {
700 ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
701 colorbuffersForRender.push_back(colorbuffer);
702 }
703 #if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED)
704 else
705 {
706 colorbuffersForRender.push_back(NULL);
707 }
708 #endif
709 }
710
711 return colorbuffersForRender;
712 }
713
completeness() const714 GLenum DefaultFramebuffer::completeness() const
715 {
716 // The default framebuffer *must* always be complete, though it may not be
717 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
718 return GL_FRAMEBUFFER_COMPLETE;
719 }
720
getAttachment(GLenum attachment) const721 FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const
722 {
723 switch (attachment)
724 {
725 case GL_COLOR:
726 case GL_BACK:
727 return getColorbuffer(0);
728 case GL_DEPTH:
729 return getDepthbuffer();
730 case GL_STENCIL:
731 return getStencilbuffer();
732 case GL_DEPTH_STENCIL:
733 return getDepthStencilBuffer();
734 default:
735 UNREACHABLE();
736 return NULL;
737 }
738 }
739
740 }
741