1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef WEBGL_FRAMEBUFFER_H_
7 #define WEBGL_FRAMEBUFFER_H_
8 
9 #include <vector>
10 
11 #include "mozilla/LinkedList.h"
12 #include "mozilla/WeakPtr.h"
13 #include "nsWrapperCache.h"
14 
15 #include "WebGLObjectModel.h"
16 #include "WebGLRenderbuffer.h"
17 #include "WebGLStrongTypes.h"
18 #include "WebGLTexture.h"
19 #include "WebGLTypes.h"
20 
21 namespace mozilla {
22 
23 class WebGLFramebuffer;
24 class WebGLRenderbuffer;
25 class WebGLTexture;
26 
27 template <typename T>
28 class PlacementArray;
29 
30 namespace gl {
31 class GLContext;
32 }  // namespace gl
33 
34 class WebGLFBAttachPoint final {
35   friend class WebGLFramebuffer;
36 
37  public:
38   WebGLFramebuffer* const mFB;
39   const GLenum mAttachmentPoint;
40 
41  protected:
42   WebGLRefPtr<WebGLTexture> mTexturePtr;
43   WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
44   TexImageTarget mTexImageTarget;
45   GLint mTexImageLayer;
46   uint32_t mTexImageLevel;
47 
48   ////
49 
50   WebGLFBAttachPoint();
51   WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
52 
53  public:
54   ~WebGLFBAttachPoint();
55 
56   ////
57 
58   void Unlink();
59 
60   bool IsDefined() const;
61   bool IsDeleteRequested() const;
62 
63   const webgl::FormatUsageInfo* Format() const;
64   uint32_t Samples() const;
65 
66   bool HasAlpha() const;
67   bool IsReadableFloat() const;
68 
69   void Clear(const char* funcName);
70 
71   void SetTexImage(const char* funcName, WebGLTexture* tex,
72                    TexImageTarget target, GLint level, GLint layer = 0);
73   void SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb);
74 
Texture()75   WebGLTexture* Texture() const { return mTexturePtr; }
Renderbuffer()76   WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
77 
ImageTarget()78   TexImageTarget ImageTarget() const { return mTexImageTarget; }
Layer()79   GLint Layer() const { return mTexImageLayer; }
MipLevel()80   uint32_t MipLevel() const { return mTexImageLevel; }
81   void AttachmentName(nsCString* out) const;
82 
83   bool HasUninitializedImageData() const;
84   void SetImageDataStatus(WebGLImageDataStatus x) const;
85 
86   void Size(uint32_t* const out_width, uint32_t* const out_height) const;
87 
88   bool HasImage() const;
89   bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
90 
91   void Resolve(gl::GLContext* gl) const;
92 
93   JS::Value GetParameter(const char* funcName, WebGLContext* webgl,
94                          JSContext* cx, GLenum target, GLenum attachment,
95                          GLenum pname, ErrorResult* const out_error) const;
96 
97   void OnBackingStoreRespecified(const char* funcName) const;
98 
IsEquivalentForFeedback(const WebGLFBAttachPoint & other)99   bool IsEquivalentForFeedback(const WebGLFBAttachPoint& other) const {
100     if (!IsDefined() || !other.IsDefined()) return false;
101 
102 #define _(X) X == other.X
103     return (_(mRenderbufferPtr) && _(mTexturePtr) && _(mTexImageTarget.get()) &&
104             _(mTexImageLevel) && _(mTexImageLayer));
105 #undef _
106   }
107 
108   ////
109 
110   struct Ordered {
111     const WebGLFBAttachPoint& mRef;
112 
OrderedOrdered113     explicit Ordered(const WebGLFBAttachPoint& ref) : mRef(ref) {}
114 
115     bool operator<(const Ordered& other) const {
116       MOZ_ASSERT(mRef.IsDefined() && other.mRef.IsDefined());
117 
118 #define ORDER_BY(X) \
119   if (X != other.X) return X < other.X;
120 
121       ORDER_BY(mRef.mRenderbufferPtr)
122       ORDER_BY(mRef.mTexturePtr)
123       ORDER_BY(mRef.mTexImageTarget.get())
124       ORDER_BY(mRef.mTexImageLevel)
125       ORDER_BY(mRef.mTexImageLayer)
126 
127 #undef ORDER_BY
128       return false;
129     }
130   };
131 };
132 
133 class WebGLFramebuffer final : public nsWrapperCache,
134                                public WebGLRefCountedObject<WebGLFramebuffer>,
135                                public LinkedListElement<WebGLFramebuffer>,
136                                public SupportsWeakPtr<WebGLFramebuffer> {
137   friend class WebGLContext;
138 
139  public:
140   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
141 
142   const GLuint mGLName;
143 
144  private:
145   uint64_t mNumFBStatusInvals;
146 
147  protected:
148 #ifdef ANDROID
149   // Bug 1140459: Some drivers (including our test slaves!) don't
150   // give reasonable answers for IsRenderbuffer, maybe others.
151   // This shows up on Android 2.3 emulator.
152   //
153   // So we track the `is a Framebuffer` state ourselves.
154   bool mIsFB;
155 #endif
156 
157   ////
158 
159   WebGLFBAttachPoint mDepthAttachment;
160   WebGLFBAttachPoint mStencilAttachment;
161   WebGLFBAttachPoint mDepthStencilAttachment;
162 
163   // In theory, this number can be unbounded based on the driver. However, no
164   // driver appears to expose more than 8. We might as well stop there too, for
165   // now.
166   // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
167   static const size_t kMaxColorAttachments =
168       8;  // jgilbert's MacBook Pro exposes 8.
169   WebGLFBAttachPoint mColorAttachments[kMaxColorAttachments];
170 
171   ////
172 
173   std::vector<const WebGLFBAttachPoint*> mColorDrawBuffers;  // Non-null
174   const WebGLFBAttachPoint* mColorReadBuffer;                // Null if NONE
175 
176   ////
177 
178   struct ResolvedData {
179     // IsFeedback
180     std::vector<const WebGLFBAttachPoint*> texDrawBuffers;  // Non-null
181     std::set<WebGLFBAttachPoint::Ordered> drawSet;
182     std::set<WebGLFBAttachPoint::Ordered> readSet;
183 
184     explicit ResolvedData(const WebGLFramebuffer& parent);
185   };
186 
187   mutable UniquePtr<const ResolvedData> mResolvedCompleteData;
188 
189   ////
190 
191  public:
192   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
193   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
194 
195   WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
196 
GetParentObject()197   WebGLContext* GetParentObject() const { return mContext; }
198   virtual JSObject* WrapObject(JSContext* cx,
199                                JS::Handle<JSObject*> givenProto) override;
200 
201  private:
~WebGLFramebuffer()202   ~WebGLFramebuffer() { DeleteOnce(); }
203 
204  public:
205   void Delete();
206 
207   ////
208 
209   bool HasDuplicateAttachments() const;
210   bool HasDefinedAttachments() const;
211   bool HasIncompleteAttachments(nsCString* const out_info) const;
212   bool AllImageRectsMatch() const;
213   bool AllImageSamplesMatch() const;
214   FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
215 
216  protected:
217   Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment);  // Fallible
218   Maybe<WebGLFBAttachPoint*> GetColorAttachPoint(
219       GLenum attachment);  // Fallible
220   void ResolveAttachments() const;
221   void RefreshDrawBuffers() const;
222   void RefreshReadBuffer() const;
223   bool ResolveAttachmentData(const char* funcName) const;
224 
225  public:
226   void DetachTexture(const char* funcName, const WebGLTexture* tex);
227   void DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb);
228   bool ValidateAndInitAttachments(const char* funcName) const;
229   bool ValidateClearBufferType(const char* funcName, GLenum buffer,
230                                uint32_t drawBuffer, GLenum funcType) const;
231 
232   bool ValidateForColorRead(const char* funcName,
233                             const webgl::FormatUsageInfo** out_format,
234                             uint32_t* out_width, uint32_t* out_height) const;
235 
236   ////////////////
237   // Getters
238 
239 #define GETTER(X) \
240   const decltype(m##X)& X() const { return m##X; }
241 
242   GETTER(DepthAttachment)
GETTER(StencilAttachment)243   GETTER(StencilAttachment)
244   GETTER(DepthStencilAttachment)
245   GETTER(ColorDrawBuffers)
246   GETTER(ColorReadBuffer)
247   GETTER(ResolvedCompleteData)
248 
249 #undef GETTER
250 
251   ////////////////
252   // Invalidation
253 
254   bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
255   void InvalidateFramebufferStatus(const char* funcName);
256   void RefreshResolvedData();
257 
258   ////////////////
259   // WebGL funcs
260 
IsCheckFramebufferStatusComplete(const char * const funcName)261   bool IsCheckFramebufferStatusComplete(const char* const funcName) const {
262     return CheckFramebufferStatus(funcName) == LOCAL_GL_FRAMEBUFFER_COMPLETE;
263   }
264 
265   FBStatus CheckFramebufferStatus(const char* funcName) const;
266   void FramebufferRenderbuffer(const char* funcName, GLenum attachment,
267                                GLenum rbtarget, WebGLRenderbuffer* rb);
268   void FramebufferTexture2D(const char* funcName, GLenum attachment,
269                             GLenum texImageTarget, WebGLTexture* tex,
270                             GLint level);
271   void FramebufferTextureLayer(const char* funcName, GLenum attachment,
272                                WebGLTexture* tex, GLint level, GLint layer);
273   void DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers);
274   void ReadBuffer(const char* funcName, GLenum attachPoint);
275 
276   JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx,
277                                    GLenum target, GLenum attachment,
278                                    GLenum pname, ErrorResult* const out_error);
279 
280   static void BlitFramebuffer(WebGLContext* webgl, GLint srcX0, GLint srcY0,
281                               GLint srcX1, GLint srcY1, GLint dstX0,
282                               GLint dstY0, GLint dstX1, GLint dstY1,
283                               GLbitfield mask, GLenum filter);
284 };
285 
286 }  // namespace mozilla
287 
288 #endif  // WEBGL_FRAMEBUFFER_H_
289