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 "libANGLE/Framebuffer.h"
11
12 #include "common/Optional.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Config.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/FramebufferAttachment.h"
17 #include "libANGLE/Renderbuffer.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/Texture.h"
20 #include "libANGLE/formatutils.h"
21 #include "libANGLE/renderer/ContextImpl.h"
22 #include "libANGLE/renderer/FramebufferImpl.h"
23 #include "libANGLE/renderer/GLImplFactory.h"
24 #include "libANGLE/renderer/RenderbufferImpl.h"
25 #include "libANGLE/renderer/SurfaceImpl.h"
26
27 using namespace angle;
28
29 namespace gl
30 {
31
32 namespace
33 {
34
BindResourceChannel(ChannelBinding * binding,FramebufferAttachmentObject * resource)35 void BindResourceChannel(ChannelBinding *binding, FramebufferAttachmentObject *resource)
36 {
37 binding->bind(resource ? resource->getDirtyChannel() : nullptr);
38 }
39
40 } // anonymous namespace
41
FramebufferState()42 FramebufferState::FramebufferState()
43 : mLabel(),
44 mColorAttachments(1),
45 mDrawBufferStates(1, GL_NONE),
46 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
47 {
48 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
49 }
50
FramebufferState(const Caps & caps)51 FramebufferState::FramebufferState(const Caps &caps)
52 : mLabel(),
53 mColorAttachments(caps.maxColorAttachments),
54 mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
55 mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
56 {
57 ASSERT(mDrawBufferStates.size() > 0);
58 mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
59 }
60
~FramebufferState()61 FramebufferState::~FramebufferState()
62 {
63 }
64
getLabel()65 const std::string &FramebufferState::getLabel()
66 {
67 return mLabel;
68 }
69
getAttachment(GLenum attachment) const70 const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const
71 {
72 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
73 {
74 return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
75 }
76
77 switch (attachment)
78 {
79 case GL_COLOR:
80 case GL_BACK:
81 return getColorAttachment(0);
82 case GL_DEPTH:
83 case GL_DEPTH_ATTACHMENT:
84 return getDepthAttachment();
85 case GL_STENCIL:
86 case GL_STENCIL_ATTACHMENT:
87 return getStencilAttachment();
88 case GL_DEPTH_STENCIL:
89 case GL_DEPTH_STENCIL_ATTACHMENT:
90 return getDepthStencilAttachment();
91 default:
92 UNREACHABLE();
93 return nullptr;
94 }
95 }
96
getReadAttachment() const97 const FramebufferAttachment *FramebufferState::getReadAttachment() const
98 {
99 ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
100 size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
101 ASSERT(readIndex < mColorAttachments.size());
102 return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
103 }
104
getFirstColorAttachment() const105 const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const
106 {
107 for (const FramebufferAttachment &colorAttachment : mColorAttachments)
108 {
109 if (colorAttachment.isAttached())
110 {
111 return &colorAttachment;
112 }
113 }
114
115 return nullptr;
116 }
117
getDepthOrStencilAttachment() const118 const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const
119 {
120 if (mDepthAttachment.isAttached())
121 {
122 return &mDepthAttachment;
123 }
124 if (mStencilAttachment.isAttached())
125 {
126 return &mStencilAttachment;
127 }
128 return nullptr;
129 }
130
getColorAttachment(size_t colorAttachment) const131 const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
132 {
133 ASSERT(colorAttachment < mColorAttachments.size());
134 return mColorAttachments[colorAttachment].isAttached() ?
135 &mColorAttachments[colorAttachment] :
136 nullptr;
137 }
138
getDepthAttachment() const139 const FramebufferAttachment *FramebufferState::getDepthAttachment() const
140 {
141 return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
142 }
143
getStencilAttachment() const144 const FramebufferAttachment *FramebufferState::getStencilAttachment() const
145 {
146 return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
147 }
148
getDepthStencilAttachment() const149 const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const
150 {
151 // A valid depth-stencil attachment has the same resource bound to both the
152 // depth and stencil attachment points.
153 if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
154 mDepthAttachment.type() == mStencilAttachment.type() &&
155 mDepthAttachment.id() == mStencilAttachment.id())
156 {
157 return &mDepthAttachment;
158 }
159
160 return nullptr;
161 }
162
attachmentsHaveSameDimensions() const163 bool FramebufferState::attachmentsHaveSameDimensions() const
164 {
165 Optional<Extents> attachmentSize;
166
167 auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
168 {
169 if (!attachment.isAttached())
170 {
171 return false;
172 }
173
174 if (!attachmentSize.valid())
175 {
176 attachmentSize = attachment.getSize();
177 return false;
178 }
179
180 return (attachment.getSize() != attachmentSize.value());
181 };
182
183 for (const auto &attachment : mColorAttachments)
184 {
185 if (hasMismatchedSize(attachment))
186 {
187 return false;
188 }
189 }
190
191 if (hasMismatchedSize(mDepthAttachment))
192 {
193 return false;
194 }
195
196 return !hasMismatchedSize(mStencilAttachment);
197 }
198
getDrawBuffer(size_t drawBufferIdx) const199 const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const
200 {
201 ASSERT(drawBufferIdx < mDrawBufferStates.size());
202 if (mDrawBufferStates[drawBufferIdx] != GL_NONE)
203 {
204 // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
205 // must be COLOR_ATTACHMENTi or NONE"
206 ASSERT(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx ||
207 (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK));
208 return getAttachment(mDrawBufferStates[drawBufferIdx]);
209 }
210 else
211 {
212 return nullptr;
213 }
214 }
215
getDrawBufferCount() const216 size_t FramebufferState::getDrawBufferCount() const
217 {
218 return mDrawBufferStates.size();
219 }
220
colorAttachmentsAreUniqueImages() const221 bool FramebufferState::colorAttachmentsAreUniqueImages() const
222 {
223 for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size();
224 firstAttachmentIdx++)
225 {
226 const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx];
227 if (!firstAttachment.isAttached())
228 {
229 continue;
230 }
231
232 for (size_t secondAttachmentIdx = firstAttachmentIdx + 1;
233 secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++)
234 {
235 const gl::FramebufferAttachment &secondAttachment =
236 mColorAttachments[secondAttachmentIdx];
237 if (!secondAttachment.isAttached())
238 {
239 continue;
240 }
241
242 if (firstAttachment == secondAttachment)
243 {
244 return false;
245 }
246 }
247 }
248
249 return true;
250 }
251
Framebuffer(const Caps & caps,rx::GLImplFactory * factory,GLuint id)252 Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
253 : mState(caps),
254 mImpl(factory->createFramebuffer(mState)),
255 mId(id),
256 mCachedStatus(),
257 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
258 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
259 {
260 ASSERT(mId != 0);
261 ASSERT(mImpl != nullptr);
262 ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
263
264 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
265 {
266 mDirtyColorAttachmentBindings.push_back(ChannelBinding(
267 this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
268 }
269 }
270
Framebuffer(rx::SurfaceImpl * surface)271 Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
272 : mState(),
273 mImpl(surface->createDefaultFramebuffer(mState)),
274 mId(0),
275 mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
276 mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
277 mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
278 {
279 ASSERT(mImpl != nullptr);
280 mDirtyColorAttachmentBindings.push_back(
281 ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
282 }
283
~Framebuffer()284 Framebuffer::~Framebuffer()
285 {
286 SafeDelete(mImpl);
287 }
288
setLabel(const std::string & label)289 void Framebuffer::setLabel(const std::string &label)
290 {
291 mState.mLabel = label;
292 }
293
getLabel() const294 const std::string &Framebuffer::getLabel() const
295 {
296 return mState.mLabel;
297 }
298
detachTexture(GLuint textureId)299 void Framebuffer::detachTexture(GLuint textureId)
300 {
301 detachResourceById(GL_TEXTURE, textureId);
302 }
303
detachRenderbuffer(GLuint renderbufferId)304 void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
305 {
306 detachResourceById(GL_RENDERBUFFER, renderbufferId);
307 }
308
detachResourceById(GLenum resourceType,GLuint resourceId)309 void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
310 {
311 for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
312 {
313 detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
314 DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
315 }
316
317 detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
318 DIRTY_BIT_DEPTH_ATTACHMENT);
319 detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
320 DIRTY_BIT_STENCIL_ATTACHMENT);
321 }
322
detachMatchingAttachment(FramebufferAttachment * attachment,GLenum matchType,GLuint matchId,size_t dirtyBit)323 void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
324 GLenum matchType,
325 GLuint matchId,
326 size_t dirtyBit)
327 {
328 if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
329 {
330 attachment->detach();
331 mDirtyBits.set(dirtyBit);
332 }
333 }
334
getColorbuffer(size_t colorAttachment) const335 const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
336 {
337 return mState.getColorAttachment(colorAttachment);
338 }
339
getDepthbuffer() const340 const FramebufferAttachment *Framebuffer::getDepthbuffer() const
341 {
342 return mState.getDepthAttachment();
343 }
344
getStencilbuffer() const345 const FramebufferAttachment *Framebuffer::getStencilbuffer() const
346 {
347 return mState.getStencilAttachment();
348 }
349
getDepthStencilBuffer() const350 const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
351 {
352 return mState.getDepthStencilAttachment();
353 }
354
getDepthOrStencilbuffer() const355 const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
356 {
357 return mState.getDepthOrStencilAttachment();
358 }
359
getReadColorbuffer() const360 const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
361 {
362 return mState.getReadAttachment();
363 }
364
getReadColorbufferType() const365 GLenum Framebuffer::getReadColorbufferType() const
366 {
367 const FramebufferAttachment *readAttachment = mState.getReadAttachment();
368 return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
369 }
370
getFirstColorbuffer() const371 const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
372 {
373 return mState.getFirstColorAttachment();
374 }
375
getAttachment(GLenum attachment) const376 const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
377 {
378 return mState.getAttachment(attachment);
379 }
380
getDrawbufferStateCount() const381 size_t Framebuffer::getDrawbufferStateCount() const
382 {
383 return mState.mDrawBufferStates.size();
384 }
385
getDrawBufferState(size_t drawBuffer) const386 GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
387 {
388 ASSERT(drawBuffer < mState.mDrawBufferStates.size());
389 return mState.mDrawBufferStates[drawBuffer];
390 }
391
getDrawBufferStates() const392 const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
393 {
394 return mState.getDrawBufferStates();
395 }
396
setDrawBuffers(size_t count,const GLenum * buffers)397 void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
398 {
399 auto &drawStates = mState.mDrawBufferStates;
400
401 ASSERT(count <= drawStates.size());
402 std::copy(buffers, buffers + count, drawStates.begin());
403 std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
404 mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
405 }
406
getDrawBuffer(size_t drawBuffer) const407 const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
408 {
409 return mState.getDrawBuffer(drawBuffer);
410 }
411
hasEnabledDrawBuffer() const412 bool Framebuffer::hasEnabledDrawBuffer() const
413 {
414 for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
415 {
416 if (getDrawBuffer(drawbufferIdx) != nullptr)
417 {
418 return true;
419 }
420 }
421
422 return false;
423 }
424
getReadBufferState() const425 GLenum Framebuffer::getReadBufferState() const
426 {
427 return mState.mReadBufferState;
428 }
429
setReadBuffer(GLenum buffer)430 void Framebuffer::setReadBuffer(GLenum buffer)
431 {
432 ASSERT(buffer == GL_BACK || buffer == GL_NONE ||
433 (buffer >= GL_COLOR_ATTACHMENT0 &&
434 (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size()));
435 mState.mReadBufferState = buffer;
436 mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
437 }
438
getNumColorBuffers() const439 size_t Framebuffer::getNumColorBuffers() const
440 {
441 return mState.mColorAttachments.size();
442 }
443
hasDepth() const444 bool Framebuffer::hasDepth() const
445 {
446 return (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.getDepthSize() > 0);
447 }
448
hasStencil() const449 bool Framebuffer::hasStencil() const
450 {
451 return (mState.mStencilAttachment.isAttached() &&
452 mState.mStencilAttachment.getStencilSize() > 0);
453 }
454
usingExtendedDrawBuffers() const455 bool Framebuffer::usingExtendedDrawBuffers() const
456 {
457 for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx)
458 {
459 if (getDrawBuffer(drawbufferIdx) != nullptr)
460 {
461 return true;
462 }
463 }
464
465 return false;
466 }
467
checkStatus(const ContextState & state)468 GLenum Framebuffer::checkStatus(const ContextState &state)
469 {
470 // The default framebuffer *must* always be complete, though it may not be
471 // subject to the same rules as application FBOs. ie, it could have 0x0 size.
472 if (mId == 0)
473 {
474 return GL_FRAMEBUFFER_COMPLETE;
475 }
476
477 if (hasAnyDirtyBit() || !mCachedStatus.valid())
478 {
479 mCachedStatus = checkStatusImpl(state);
480 }
481
482 return mCachedStatus.value();
483 }
484
checkStatusImpl(const ContextState & state)485 GLenum Framebuffer::checkStatusImpl(const ContextState &state)
486 {
487 ASSERT(mId != 0);
488
489 unsigned int colorbufferSize = 0;
490 int samples = -1;
491 bool missingAttachment = true;
492
493 for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
494 {
495 if (colorAttachment.isAttached())
496 {
497 const Extents &size = colorAttachment.getSize();
498 if (size.width == 0 || size.height == 0)
499 {
500 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
501 }
502
503 const Format &format = colorAttachment.getFormat();
504 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
505 if (colorAttachment.type() == GL_TEXTURE)
506 {
507 if (!formatCaps.renderable)
508 {
509 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
510 }
511
512 if (format.info->depthBits > 0 || format.info->stencilBits > 0)
513 {
514 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
515 }
516
517 if (colorAttachment.layer() >= size.depth)
518 {
519 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
520 }
521
522 // ES3 specifies that cube map texture attachments must be cube complete.
523 // This language is missing from the ES2 spec, but we enforce it here because some
524 // desktop OpenGL drivers also enforce this validation.
525 // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
526 const Texture *texture = colorAttachment.getTexture();
527 ASSERT(texture);
528 if (texture->getTarget() == GL_TEXTURE_CUBE_MAP &&
529 !texture->getTextureState().isCubeComplete())
530 {
531 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
532 }
533 }
534 else if (colorAttachment.type() == GL_RENDERBUFFER)
535 {
536 if (!formatCaps.renderable || format.info->depthBits > 0 ||
537 format.info->stencilBits > 0)
538 {
539 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
540 }
541 }
542
543 if (!missingAttachment)
544 {
545 // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
546 // all color attachments have the same number of samples for the FBO to be complete.
547 if (colorAttachment.getSamples() != samples)
548 {
549 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
550 }
551
552 // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
553 // in GLES 3.0, there is no such restriction
554 if (state.getClientMajorVersion() < 3)
555 {
556 if (format.info->pixelBytes != colorbufferSize)
557 {
558 return GL_FRAMEBUFFER_UNSUPPORTED;
559 }
560 }
561 }
562 else
563 {
564 samples = colorAttachment.getSamples();
565 colorbufferSize = format.info->pixelBytes;
566 missingAttachment = false;
567 }
568 }
569 }
570
571 const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
572 if (depthAttachment.isAttached())
573 {
574 const Extents &size = depthAttachment.getSize();
575 if (size.width == 0 || size.height == 0)
576 {
577 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
578 }
579
580 const Format &format = depthAttachment.getFormat();
581 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
582 if (depthAttachment.type() == GL_TEXTURE)
583 {
584 // depth texture attachments require OES/ANGLE_depth_texture
585 if (!state.getExtensions().depthTextures)
586 {
587 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
588 }
589
590 if (!formatCaps.renderable)
591 {
592 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
593 }
594
595 if (format.info->depthBits == 0)
596 {
597 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
598 }
599 }
600 else if (depthAttachment.type() == GL_RENDERBUFFER)
601 {
602 if (!formatCaps.renderable || format.info->depthBits == 0)
603 {
604 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
605 }
606 }
607
608 if (missingAttachment)
609 {
610 samples = depthAttachment.getSamples();
611 missingAttachment = false;
612 }
613 else if (samples != depthAttachment.getSamples())
614 {
615 // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
616 // considered complete when its depth or stencil samples are a
617 // multiple of the number of color samples.
618 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
619 if (!mixedSamples)
620 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
621
622 const int colorSamples = samples ? samples : 1;
623 const int depthSamples = depthAttachment.getSamples();
624 if ((depthSamples % colorSamples) != 0)
625 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
626 }
627 }
628
629 const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
630 if (stencilAttachment.isAttached())
631 {
632 const Extents &size = stencilAttachment.getSize();
633 if (size.width == 0 || size.height == 0)
634 {
635 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
636 }
637
638 const Format &format = stencilAttachment.getFormat();
639 const TextureCaps &formatCaps = state.getTextureCap(format.asSized());
640 if (stencilAttachment.type() == GL_TEXTURE)
641 {
642 // texture stencil attachments come along as part
643 // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
644 if (!state.getExtensions().depthTextures)
645 {
646 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
647 }
648
649 if (!formatCaps.renderable)
650 {
651 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
652 }
653
654 if (format.info->stencilBits == 0)
655 {
656 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
657 }
658 }
659 else if (stencilAttachment.type() == GL_RENDERBUFFER)
660 {
661 if (!formatCaps.renderable || format.info->stencilBits == 0)
662 {
663 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
664 }
665 }
666
667 if (missingAttachment)
668 {
669 samples = stencilAttachment.getSamples();
670 missingAttachment = false;
671 }
672 else if (samples != stencilAttachment.getSamples())
673 {
674 // see the comments in depth attachment check.
675 const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
676 if (!mixedSamples)
677 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
678
679 const int colorSamples = samples ? samples : 1;
680 const int stencilSamples = stencilAttachment.getSamples();
681 if ((stencilSamples % colorSamples) != 0)
682 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
683 }
684
685 // Starting from ES 3.0 stencil and depth, if present, should be the same image
686 if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
687 stencilAttachment != depthAttachment)
688 {
689 return GL_FRAMEBUFFER_UNSUPPORTED;
690 }
691 }
692
693 // we need to have at least one attachment to be complete
694 if (missingAttachment)
695 {
696 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
697 }
698
699 // In ES 2.0, all color attachments must have the same width and height.
700 // In ES 3.0, there is no such restriction.
701 if (state.getClientMajorVersion() < 3 && !mState.attachmentsHaveSameDimensions())
702 {
703 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
704 }
705
706 syncState();
707 if (!mImpl->checkStatus())
708 {
709 return GL_FRAMEBUFFER_UNSUPPORTED;
710 }
711
712 return GL_FRAMEBUFFER_COMPLETE;
713 }
714
discard(size_t count,const GLenum * attachments)715 Error Framebuffer::discard(size_t count, const GLenum *attachments)
716 {
717 return mImpl->discard(count, attachments);
718 }
719
invalidate(size_t count,const GLenum * attachments)720 Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
721 {
722 return mImpl->invalidate(count, attachments);
723 }
724
invalidateSub(size_t count,const GLenum * attachments,const gl::Rectangle & area)725 Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area)
726 {
727 return mImpl->invalidateSub(count, attachments, area);
728 }
729
clear(rx::ContextImpl * context,GLbitfield mask)730 Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
731 {
732 if (context->getGLState().isRasterizerDiscardEnabled())
733 {
734 return gl::NoError();
735 }
736
737 return mImpl->clear(context, mask);
738 }
739
clearBufferfv(rx::ContextImpl * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)740 Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
741 GLenum buffer,
742 GLint drawbuffer,
743 const GLfloat *values)
744 {
745 if (context->getGLState().isRasterizerDiscardEnabled())
746 {
747 return gl::NoError();
748 }
749
750 return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
751 }
752
clearBufferuiv(rx::ContextImpl * context,GLenum buffer,GLint drawbuffer,const GLuint * values)753 Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
754 GLenum buffer,
755 GLint drawbuffer,
756 const GLuint *values)
757 {
758 if (context->getGLState().isRasterizerDiscardEnabled())
759 {
760 return gl::NoError();
761 }
762
763 return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
764 }
765
clearBufferiv(rx::ContextImpl * context,GLenum buffer,GLint drawbuffer,const GLint * values)766 Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
767 GLenum buffer,
768 GLint drawbuffer,
769 const GLint *values)
770 {
771 if (context->getGLState().isRasterizerDiscardEnabled())
772 {
773 return gl::NoError();
774 }
775
776 return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
777 }
778
clearBufferfi(rx::ContextImpl * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)779 Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
780 GLenum buffer,
781 GLint drawbuffer,
782 GLfloat depth,
783 GLint stencil)
784 {
785 if (context->getGLState().isRasterizerDiscardEnabled())
786 {
787 return gl::NoError();
788 }
789
790 return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
791 }
792
getImplementationColorReadFormat() const793 GLenum Framebuffer::getImplementationColorReadFormat() const
794 {
795 return mImpl->getImplementationColorReadFormat();
796 }
797
getImplementationColorReadType() const798 GLenum Framebuffer::getImplementationColorReadType() const
799 {
800 return mImpl->getImplementationColorReadType();
801 }
802
readPixels(rx::ContextImpl * context,const Rectangle & area,GLenum format,GLenum type,GLvoid * pixels) const803 Error Framebuffer::readPixels(rx::ContextImpl *context,
804 const Rectangle &area,
805 GLenum format,
806 GLenum type,
807 GLvoid *pixels) const
808 {
809 ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
810
811 Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
812 if (unpackBuffer)
813 {
814 unpackBuffer->onPixelUnpack();
815 }
816
817 return NoError();
818 }
819
blit(rx::ContextImpl * context,const Rectangle & sourceArea,const Rectangle & destArea,GLbitfield mask,GLenum filter)820 Error Framebuffer::blit(rx::ContextImpl *context,
821 const Rectangle &sourceArea,
822 const Rectangle &destArea,
823 GLbitfield mask,
824 GLenum filter)
825 {
826 return mImpl->blit(context, sourceArea, destArea, mask, filter);
827 }
828
getSamples(const ContextState & state)829 int Framebuffer::getSamples(const ContextState &state)
830 {
831 if (complete(state))
832 {
833 // For a complete framebuffer, all attachments must have the same sample count.
834 // In this case return the first nonzero sample size.
835 const auto *firstColorAttachment = mState.getFirstColorAttachment();
836 if (firstColorAttachment)
837 {
838 ASSERT(firstColorAttachment->isAttached());
839 return firstColorAttachment->getSamples();
840 }
841 }
842
843 return 0;
844 }
845
hasValidDepthStencil() const846 bool Framebuffer::hasValidDepthStencil() const
847 {
848 return mState.getDepthStencilAttachment() != nullptr;
849 }
850
setAttachment(GLenum type,GLenum binding,const ImageIndex & textureIndex,FramebufferAttachmentObject * resource)851 void Framebuffer::setAttachment(GLenum type,
852 GLenum binding,
853 const ImageIndex &textureIndex,
854 FramebufferAttachmentObject *resource)
855 {
856 if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
857 {
858 // ensure this is a legitimate depth+stencil format
859 FramebufferAttachmentObject *attachmentObj = resource;
860 if (resource)
861 {
862 FramebufferAttachment::Target target(binding, textureIndex);
863 const Format &format = resource->getAttachmentFormat(target);
864 if (format.info->depthBits == 0 || format.info->stencilBits == 0)
865 {
866 // Attaching nullptr detaches the current attachment.
867 attachmentObj = nullptr;
868 }
869 }
870
871 mState.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
872 mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
873 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
874 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
875 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
876 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
877 }
878 else
879 {
880 switch (binding)
881 {
882 case GL_DEPTH:
883 case GL_DEPTH_ATTACHMENT:
884 mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
885 mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
886 BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
887 break;
888 case GL_STENCIL:
889 case GL_STENCIL_ATTACHMENT:
890 mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
891 mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
892 BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
893 break;
894 case GL_BACK:
895 mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
896 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
897 // No need for a resource binding for the default FBO, it's always complete.
898 break;
899 default:
900 {
901 size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
902 ASSERT(colorIndex < mState.mColorAttachments.size());
903 mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
904 mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
905 BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
906 }
907 break;
908 }
909 }
910 }
911
resetAttachment(GLenum binding)912 void Framebuffer::resetAttachment(GLenum binding)
913 {
914 setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
915 }
916
syncState()917 void Framebuffer::syncState()
918 {
919 if (mDirtyBits.any())
920 {
921 mImpl->syncState(mDirtyBits);
922 mDirtyBits.reset();
923 mCachedStatus.reset();
924 }
925 }
926
signal(SignalToken token)927 void Framebuffer::signal(SignalToken token)
928 {
929 // TOOD(jmadill): Make this only update individual attachments to do less work.
930 mCachedStatus.reset();
931 }
932
complete(const ContextState & state)933 bool Framebuffer::complete(const ContextState &state)
934 {
935 return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
936 }
937
938 } // namespace gl
939