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