1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Vladimir Vukicevic <vladimir@pobox.com> (original author)
24 : * Mark Steele <mwsteele@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef WEBGLCONTEXT_H_
41 : #define WEBGLCONTEXT_H_
42 :
43 : #include <stdarg.h>
44 : #include <vector>
45 :
46 : #include "nsTArray.h"
47 : #include "nsDataHashtable.h"
48 : #include "nsRefPtrHashtable.h"
49 : #include "nsHashKeys.h"
50 :
51 : #include "nsIDocShell.h"
52 :
53 : #include "nsIDOMWebGLRenderingContext.h"
54 : #include "nsICanvasRenderingContextInternal.h"
55 : #include "nsHTMLCanvasElement.h"
56 : #include "nsWeakReference.h"
57 : #include "nsIDOMHTMLElement.h"
58 : #include "nsIMemoryReporter.h"
59 : #include "nsIJSNativeInitializer.h"
60 : #include "nsContentUtils.h"
61 :
62 : #include "GLContextProvider.h"
63 : #include "Layers.h"
64 :
65 : #include "CheckedInt.h"
66 : #include "nsDataHashtable.h"
67 :
68 : #ifdef XP_MACOSX
69 : #include "ForceDiscreteGPUHelperCGL.h"
70 : #endif
71 :
72 : /*
73 : * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
74 : * https://bugzilla.mozilla.org/show_bug.cgi?id=686732
75 : *
76 : * Exceptions: some of the following values are set to higher values than in the spec because
77 : * the values in the spec are ridiculously low. They are explicitly marked below
78 : */
79 : #define MINVALUE_GL_MAX_TEXTURE_SIZE 1024 // Different from the spec, which sets it to 64 on page 162
80 : #define MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE 512 // Different from the spec, which sets it to 16 on page 162
81 : #define MINVALUE_GL_MAX_VERTEX_ATTRIBS 8 // Page 164
82 : #define MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS 16 // Page 164
83 : #define MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS 128 // Page 164
84 : #define MINVALUE_GL_MAX_VARYING_VECTORS 8 // Page 164
85 : #define MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS 8 // Page 164
86 : #define MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0 // Page 164
87 : #define MINVALUE_GL_MAX_RENDERBUFFER_SIZE 1024 // Different from the spec, which sets it to 1 on page 164
88 : #define MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 8 // Page 164
89 :
90 : class nsIDocShell;
91 : class nsIPropertyBag;
92 :
93 : namespace mozilla {
94 :
95 : class WebGLTexture;
96 : class WebGLBuffer;
97 : class WebGLProgram;
98 : class WebGLShader;
99 : class WebGLFramebuffer;
100 : class WebGLRenderbuffer;
101 : class WebGLUniformLocation;
102 : class WebGLExtension;
103 : struct WebGLVertexAttribData;
104 :
105 : class WebGLRectangleObject;
106 : class WebGLContextBoundObject;
107 :
108 : enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
109 :
110 : struct VertexAttrib0Status {
111 : enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
112 : };
113 :
114 : struct BackbufferClearingStatus {
115 : enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo };
116 : };
117 :
118 : struct WebGLTexelFormat {
119 : enum { Generic, Auto, RGBA8, RGB8, RGBX8, BGRA8, BGR8, BGRX8, RGBA5551, RGBA4444, RGB565, R8, RA8, A8,
120 : RGBA32F, RGB32F, A32F, R32F, RA32F };
121 : };
122 :
123 : struct WebGLTexelPremultiplicationOp {
124 : enum { Generic, None, Premultiply, Unmultiply };
125 : };
126 :
127 : int GetWebGLTexelFormat(GLenum format, GLenum type);
128 :
129 0 : inline bool is_pot_assuming_nonnegative(WebGLsizei x)
130 : {
131 0 : return (x & (x-1)) == 0;
132 : }
133 :
134 : /* Each WebGL object class WebGLFoo wants to:
135 : * - inherit WebGLRefCountedObject<WebGLFoo>
136 : * - implement a Delete() method
137 : * - have its destructor call DeleteOnce()
138 : *
139 : * This base class provides two features to WebGL object types:
140 : * 1. support for OpenGL object reference counting
141 : * 2. support for OpenGL deletion statuses
142 : *
143 : ***** 1. OpenGL object reference counting *****
144 : *
145 : * WebGL objects such as WebGLTexture's really have two different refcounts:
146 : * the XPCOM refcount, that is directly exposed to JavaScript, and the OpenGL
147 : * refcount.
148 : *
149 : * For example, when in JavaScript one does: var newname = existingTexture;
150 : * that increments the XPCOM refcount, but doesn't affect the OpenGL refcount.
151 : * When one attaches the texture to a framebuffer object, that does increment
152 : * its OpenGL refcount (and also its XPCOM refcount, to prevent the regular
153 : * XPCOM refcounting mechanism from destroying objects prematurely).
154 : *
155 : * The actual OpenGL refcount is opaque to us (it's internal to the OpenGL
156 : * implementation) but is affects the WebGL semantics that we have to implement:
157 : * for example, a WebGLTexture that is attached to a WebGLFramebuffer must not
158 : * be actually deleted, even if deleteTexture has been called on it, and even
159 : * if JavaScript doesn't have references to it anymore. We can't just rely on
160 : * OpenGL to keep alive the underlying OpenGL texture for us, for a variety of
161 : * reasons, most importantly: we'd need to know when OpenGL objects are actually
162 : * deleted, and OpenGL doesn't notify us about that, so we would have to query
163 : * status very often with glIsXxx calls which isn't practical.
164 : *
165 : * This means that we have to keep track of the OpenGL refcount ourselves,
166 : * in addition to the XPCOM refcount.
167 : *
168 : * This class implements such a refcount, see the mWebGLRefCnt
169 : * member. In order to avoid name clashes (with regular XPCOM refcounting)
170 : * in the derived class, we prefix members with 'WebGL', whence the names
171 : * WebGLAddRef, WebGLRelease, etc.
172 : *
173 : * In practice, WebGLAddRef and WebGLRelease are only called from the
174 : * WebGLRefPtr class.
175 : *
176 : ***** 2. OpenGL deletion statuses *****
177 : *
178 : * In OpenGL, an object can go through 3 different deletion statuses during its
179 : * lifetime, which correspond to the 3 enum values for DeletionStatus in this class:
180 : * - the Default status, which it has from its creation to when the
181 : * suitable glDeleteXxx function is called on it;
182 : * - the DeleteRequested status, which is has from when the suitable glDeleteXxx
183 : * function is called on it to when it is no longer referenced by other OpenGL
184 : * objects. For example, a texture that is attached to a non-current FBO
185 : * will enter that status when glDeleteTexture is called on it. For objects
186 : * with that status, GL_DELETE_STATUS queries return true, but glIsXxx
187 : * functions still return true.
188 : * - the Deleted status, which is the status of objects on which the
189 : * suitable glDeleteXxx function has been called, and that are not referenced
190 : * by other OpenGL objects.
191 : *
192 : * This state is stored in the mDeletionStatus member of this class.
193 : *
194 : * When the GL refcount hits zero, if the status is DeleteRequested then we call
195 : * the Delete() method on the derived class and the status becomes Deleted. This is
196 : * what the MaybeDelete() function does.
197 : *
198 : * The DeleteOnce() function implemented here is a helper to ensure that we don't
199 : * call Delete() twice on the same object. Since the derived class' destructor
200 : * needs to call DeleteOnce() which calls Delete(), we can't allow either to be
201 : * virtual. Strictly speaking, we could let them be virtual if the derived class
202 : * were final, but that would be impossible to enforce and would lead to strange
203 : * bugs if it were subclassed.
204 : *
205 : * This WebGLRefCountedObject class takes the Derived type
206 : * as template parameter, as a means to allow DeleteOnce to call Delete()
207 : * on the Derived class, without either method being virtual. This is a common
208 : * C++ pattern known as the "curiously recursive template pattern (CRTP)".
209 : */
210 : template<typename Derived>
211 : class WebGLRefCountedObject
212 : {
213 : public:
214 : enum DeletionStatus { Default, DeleteRequested, Deleted };
215 :
216 0 : WebGLRefCountedObject()
217 0 : : mDeletionStatus(Default)
218 0 : { }
219 :
220 0 : ~WebGLRefCountedObject() {
221 0 : NS_ABORT_IF_FALSE(mWebGLRefCnt == 0, "destroying WebGL object still referenced by other WebGL objects");
222 0 : NS_ABORT_IF_FALSE(mDeletionStatus == Deleted, "Derived class destructor must call DeleteOnce()");
223 0 : }
224 :
225 : // called by WebGLRefPtr
226 0 : void WebGLAddRef() {
227 0 : ++mWebGLRefCnt;
228 0 : }
229 :
230 : // called by WebGLRefPtr
231 0 : void WebGLRelease() {
232 0 : NS_ABORT_IF_FALSE(mWebGLRefCnt > 0, "releasing WebGL object with WebGL refcnt already zero");
233 0 : --mWebGLRefCnt;
234 0 : MaybeDelete();
235 0 : }
236 :
237 : // this is the function that WebGL.deleteXxx() functions want to call
238 0 : void RequestDelete() {
239 0 : if (mDeletionStatus == Default)
240 0 : mDeletionStatus = DeleteRequested;
241 0 : MaybeDelete();
242 0 : }
243 :
244 0 : bool IsDeleted() const {
245 0 : return mDeletionStatus == Deleted;
246 : }
247 :
248 0 : bool IsDeleteRequested() const {
249 0 : return mDeletionStatus != Default;
250 : }
251 :
252 0 : void DeleteOnce() {
253 0 : if (mDeletionStatus != Deleted) {
254 0 : static_cast<Derived*>(this)->Delete();
255 0 : mDeletionStatus = Deleted;
256 : }
257 0 : }
258 :
259 : private:
260 0 : void MaybeDelete() {
261 0 : if (mWebGLRefCnt == 0 &&
262 : mDeletionStatus == DeleteRequested)
263 : {
264 0 : DeleteOnce();
265 : }
266 0 : }
267 :
268 : protected:
269 : nsAutoRefCnt mWebGLRefCnt;
270 : DeletionStatus mDeletionStatus;
271 : };
272 :
273 : /* This WebGLRefPtr class is meant to be used for references between WebGL objects.
274 : * For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's attached
275 : * to it.
276 : *
277 : * Why the need for a separate refptr class? The only special thing that WebGLRefPtr
278 : * does is that it increments and decrements the WebGL refcount of
279 : * WebGLRefCountedObject's, in addition to incrementing and decrementing the
280 : * usual XPCOM refcount.
281 : *
282 : * This means that by using a WebGLRefPtr instead of a nsRefPtr, you ensure that
283 : * the WebGL refcount is incremented, which means that the object will be kept
284 : * alive by this reference even if the matching webgl.deleteXxx() function is
285 : * called on it.
286 : */
287 : template<typename T>
288 : class WebGLRefPtr
289 : {
290 : public:
291 0 : WebGLRefPtr()
292 0 : : mRawPtr(0)
293 0 : { }
294 :
295 : WebGLRefPtr(const WebGLRefPtr<T>& aSmartPtr)
296 : : mRawPtr(aSmartPtr.mRawPtr)
297 : {
298 : AddRefOnPtr(mRawPtr);
299 : }
300 :
301 0 : WebGLRefPtr(T *aRawPtr)
302 0 : : mRawPtr(aRawPtr)
303 : {
304 0 : AddRefOnPtr(mRawPtr);
305 0 : }
306 :
307 0 : ~WebGLRefPtr() {
308 0 : ReleasePtr(mRawPtr);
309 0 : }
310 :
311 : WebGLRefPtr<T>&
312 0 : operator=(const WebGLRefPtr<T>& rhs)
313 : {
314 0 : assign_with_AddRef(rhs.mRawPtr);
315 0 : return *this;
316 : }
317 :
318 : WebGLRefPtr<T>&
319 0 : operator=(T* rhs)
320 : {
321 0 : assign_with_AddRef(rhs);
322 0 : return *this;
323 : }
324 :
325 0 : T* get() const {
326 0 : return static_cast<T*>(mRawPtr);
327 : }
328 :
329 0 : operator T*() const {
330 0 : return get();
331 : }
332 :
333 0 : T* operator->() const {
334 0 : NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL WebGLRefPtr with operator->()!");
335 0 : return get();
336 : }
337 :
338 : T& operator*() const {
339 : NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL WebGLRefPtr with operator*()!");
340 : return *get();
341 : }
342 :
343 : private:
344 :
345 0 : static void AddRefOnPtr(T* rawPtr) {
346 0 : if (rawPtr) {
347 0 : rawPtr->WebGLAddRef();
348 0 : rawPtr->AddRef();
349 : }
350 0 : }
351 :
352 0 : static void ReleasePtr(T* rawPtr) {
353 0 : if (rawPtr) {
354 0 : rawPtr->WebGLRelease(); // must be done first before Release(), as Release() might actually destroy the object
355 0 : rawPtr->Release();
356 : }
357 0 : }
358 :
359 0 : void assign_with_AddRef(T* rawPtr) {
360 0 : AddRefOnPtr(rawPtr);
361 0 : assign_assuming_AddRef(rawPtr);
362 0 : }
363 :
364 0 : void assign_assuming_AddRef(T* newPtr) {
365 0 : T* oldPtr = mRawPtr;
366 0 : mRawPtr = newPtr;
367 0 : ReleasePtr(oldPtr);
368 0 : }
369 :
370 : protected:
371 : T *mRawPtr;
372 : };
373 :
374 : typedef PRUint64 WebGLMonotonicHandle;
375 :
376 : /* WebGLFastArray offers a fast array for the use case where all what one needs is to append
377 : * and remove elements. Removal is fast because the array is always kept sorted with respect
378 : * to "monotonic handles". Appending an element returns such a "monotonic handle" which the
379 : * user needs to keep for future use for when it will want to remove the element.
380 : */
381 : template<typename ElementType>
382 : class WebGLFastArray
383 0 : {
384 0 : struct Entry {
385 : ElementType mElement;
386 : WebGLMonotonicHandle mMonotonicHandle;
387 :
388 0 : Entry(ElementType elem, WebGLMonotonicHandle monotonicHandle)
389 0 : : mElement(elem), mMonotonicHandle(monotonicHandle)
390 0 : {}
391 :
392 : struct Comparator {
393 0 : bool Equals(const Entry& a, const Entry& b) const {
394 0 : return a.mMonotonicHandle == b.mMonotonicHandle;
395 : }
396 0 : bool LessThan(const Entry& a, const Entry& b) const {
397 0 : return a.mMonotonicHandle < b.mMonotonicHandle;
398 : }
399 : };
400 : };
401 :
402 : public:
403 0 : WebGLFastArray()
404 0 : : mCurrentMonotonicHandle(0) // CheckedInt already does it, this is just defensive coding
405 0 : {}
406 :
407 0 : ElementType operator[](size_t index) const {
408 0 : return mArray[index].mElement;
409 : }
410 :
411 0 : size_t Length() const {
412 0 : return mArray.Length();
413 : }
414 :
415 0 : ElementType Last() const {
416 0 : return operator[](Length() - 1);
417 : }
418 :
419 0 : WebGLMonotonicHandle AppendElement(ElementType elem)
420 : {
421 0 : WebGLMonotonicHandle monotonicHandle = NextMonotonicHandle();
422 0 : mArray.AppendElement(Entry(elem, monotonicHandle));
423 0 : return monotonicHandle;
424 : }
425 :
426 0 : void RemoveElement(WebGLMonotonicHandle monotonicHandle)
427 : {
428 0 : mArray.RemoveElementSorted(Entry(ElementType(), monotonicHandle),
429 : typename Entry::Comparator());
430 0 : }
431 :
432 : private:
433 0 : WebGLMonotonicHandle NextMonotonicHandle() {
434 0 : ++mCurrentMonotonicHandle;
435 0 : if (!mCurrentMonotonicHandle.valid())
436 0 : NS_RUNTIMEABORT("ran out of monotonic ids!");
437 0 : return mCurrentMonotonicHandle.value();
438 : }
439 :
440 : nsTArray<Entry> mArray;
441 : CheckedInt<WebGLMonotonicHandle> mCurrentMonotonicHandle;
442 : };
443 :
444 : // this class is a mixin for GL objects that have dimensions
445 : // that we need to track.
446 : class WebGLRectangleObject
447 : {
448 : public:
449 0 : WebGLRectangleObject()
450 0 : : mWidth(0), mHeight(0) { }
451 :
452 0 : WebGLRectangleObject(WebGLsizei width, WebGLsizei height)
453 0 : : mWidth(width), mHeight(height) { }
454 :
455 0 : WebGLsizei Width() const { return mWidth; }
456 : void width(WebGLsizei value) { mWidth = value; }
457 :
458 0 : WebGLsizei Height() const { return mHeight; }
459 : void height(WebGLsizei value) { mHeight = value; }
460 :
461 0 : void setDimensions(WebGLsizei width, WebGLsizei height) {
462 0 : mWidth = width;
463 0 : mHeight = height;
464 0 : }
465 :
466 : void setDimensions(WebGLRectangleObject *rect) {
467 : if (rect) {
468 : mWidth = rect->Width();
469 : mHeight = rect->Height();
470 : } else {
471 : mWidth = 0;
472 : mHeight = 0;
473 : }
474 : }
475 :
476 0 : bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
477 0 : return Width() == other.Width() && Height() == other.Height();
478 : }
479 :
480 : protected:
481 : WebGLsizei mWidth;
482 : WebGLsizei mHeight;
483 : };
484 :
485 : struct WebGLContextOptions {
486 : // these are defaults
487 0 : WebGLContextOptions()
488 : : alpha(true), depth(true), stencil(false),
489 : premultipliedAlpha(true), antialias(true),
490 0 : preserveDrawingBuffer(false)
491 0 : { }
492 :
493 0 : bool operator==(const WebGLContextOptions& other) const {
494 : return
495 : alpha == other.alpha &&
496 : depth == other.depth &&
497 : stencil == other.stencil &&
498 : premultipliedAlpha == other.premultipliedAlpha &&
499 : antialias == other.antialias &&
500 0 : preserveDrawingBuffer == other.preserveDrawingBuffer;
501 : }
502 :
503 0 : bool operator!=(const WebGLContextOptions& other) const {
504 0 : return !operator==(other);
505 : }
506 :
507 : bool alpha;
508 : bool depth;
509 : bool stencil;
510 : bool premultipliedAlpha;
511 : bool antialias;
512 : bool preserveDrawingBuffer;
513 : };
514 :
515 : class WebGLContext :
516 : public nsIDOMWebGLRenderingContext,
517 : public nsICanvasRenderingContextInternal,
518 : public nsSupportsWeakReference,
519 : public nsITimerCallback,
520 : public WebGLRectangleObject
521 : {
522 : friend class WebGLMemoryMultiReporterWrapper;
523 : friend class WebGLExtensionLoseContext;
524 : friend class WebGLContextUserData;
525 :
526 : public:
527 : WebGLContext();
528 : virtual ~WebGLContext();
529 :
530 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
531 :
532 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebGLContext, nsIDOMWebGLRenderingContext)
533 :
534 : NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
535 :
536 : NS_DECL_NSITIMERCALLBACK
537 :
538 : // nsICanvasRenderingContextInternal
539 : NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
540 : NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
541 0 : NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height)
542 0 : { return NS_ERROR_NOT_IMPLEMENTED; }
543 0 : NS_IMETHOD Reset()
544 0 : { /* (InitializeWithSurface) */ return NS_ERROR_NOT_IMPLEMENTED; }
545 : NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter f);
546 : NS_IMETHOD GetInputStream(const char* aMimeType,
547 : const PRUnichar* aEncoderOptions,
548 : nsIInputStream **aStream);
549 : NS_IMETHOD GetThebesSurface(gfxASurface **surface);
550 0 : mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot()
551 0 : { return nsnull; }
552 :
553 0 : NS_IMETHOD SetIsOpaque(bool b) { return NS_OK; };
554 : NS_IMETHOD SetContextOptions(nsIPropertyBag *aOptions);
555 :
556 0 : NS_IMETHOD SetIsIPC(bool b) { return NS_ERROR_NOT_IMPLEMENTED; }
557 0 : NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }
558 0 : NS_IMETHOD Swap(mozilla::ipc::Shmem& aBack,
559 : PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h)
560 0 : { return NS_ERROR_NOT_IMPLEMENTED; }
561 0 : NS_IMETHOD Swap(PRUint32 nativeID,
562 : PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h)
563 0 : { return NS_ERROR_NOT_IMPLEMENTED; }
564 :
565 : bool LoseContext();
566 : bool RestoreContext();
567 :
568 : nsresult SynthesizeGLError(WebGLenum err);
569 : nsresult SynthesizeGLError(WebGLenum err, const char *fmt, ...);
570 :
571 : nsresult ErrorInvalidEnum(const char *fmt = 0, ...);
572 : nsresult ErrorInvalidOperation(const char *fmt = 0, ...);
573 : nsresult ErrorInvalidValue(const char *fmt = 0, ...);
574 : nsresult ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
575 0 : nsresult ErrorInvalidEnumInfo(const char *info, PRUint32 enumvalue) {
576 0 : return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
577 : }
578 : nsresult ErrorOutOfMemory(const char *fmt = 0, ...);
579 :
580 : const char *ErrorName(GLenum error);
581 :
582 : nsresult DummyFramebufferOperation(const char *info);
583 :
584 0 : WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
585 0 : return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
586 0 : : mBoundCubeMapTextures[mActiveTexture];
587 : }
588 :
589 : already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
590 : CanvasLayer *aOldLayer,
591 : LayerManager *aManager);
592 0 : void MarkContextClean() { mInvalidated = false; }
593 :
594 : // a number that increments every time we have an event that causes
595 : // all context resources to be lost.
596 0 : PRUint32 Generation() { return mGeneration.value(); }
597 :
598 : const WebGLRectangleObject *FramebufferRectangleObject() const;
599 :
600 : // this is similar to GLContext::ClearSafely, but is more comprehensive
601 : // (takes care of scissor, stencil write mask, dithering, viewport...)
602 : // WebGL has more complex needs than GLContext as content controls GL state.
603 : void ForceClearFramebufferWithDefaultValues(PRUint32 mask, const nsIntRect& viewportRect);
604 :
605 : // if the preserveDrawingBuffer context option is false, we need to clear the back buffer
606 : // after it's been presented to the compositor. This function does that if needed.
607 : // See section 2.2 in the WebGL spec.
608 : void EnsureBackbufferClearedAsNeeded();
609 :
610 : // checks for GL errors, clears any pending GL error, stores the current GL error in currentGLError,
611 : // and copies it into mWebGLError if it doesn't already have an error set
612 0 : void UpdateWebGLErrorAndClearGLError(GLenum *currentGLError) {
613 : // get and clear GL error in ALL cases
614 0 : *currentGLError = gl->GetAndClearError();
615 : // only store in mWebGLError if is hasn't already recorded an error
616 0 : if (!mWebGLError)
617 0 : mWebGLError = *currentGLError;
618 0 : }
619 :
620 : // checks for GL errors, clears any pending GL error,
621 : // and stores the current GL error into mWebGLError if it doesn't already have an error set
622 0 : void UpdateWebGLErrorAndClearGLError() {
623 : GLenum currentGLError;
624 0 : UpdateWebGLErrorAndClearGLError(¤tGLError);
625 0 : }
626 :
627 0 : bool MinCapabilityMode() const {
628 0 : return mMinCapability;
629 : }
630 :
631 : // See the comment over WebGLContext::Notify() for more information on this.
632 0 : bool ShouldEnableRobustnessTimer() {
633 : return mHasRobustness ||
634 0 : IsExtensionEnabled(WebGL_MOZ_WEBGL_lose_context) ||
635 0 : (gl != nsnull && gl->GetContextType() == gl::GLContext::ContextTypeEGL);
636 : }
637 :
638 : // Sets up the GL_ARB_robustness timer if it isn't already, so that if the
639 : // driver gets restarted, the context may get reset with it.
640 0 : void SetupRobustnessTimer() {
641 0 : if (!ShouldEnableRobustnessTimer())
642 0 : return;
643 :
644 : // If the timer was already running, don't restart it here. Instead,
645 : // wait until the previous call is done, then fire it one more time.
646 : // This is an optimization to prevent unnecessary cross-communication
647 : // between threads.
648 0 : if (mRobustnessTimerRunning) {
649 0 : mDrawSinceRobustnessTimerSet = true;
650 0 : return;
651 : }
652 :
653 0 : mContextRestorer->InitWithCallback(static_cast<nsITimerCallback*>(this),
654 : PR_MillisecondsToInterval(1000),
655 0 : nsITimer::TYPE_ONE_SHOT);
656 0 : mRobustnessTimerRunning = true;
657 0 : mDrawSinceRobustnessTimerSet = false;
658 : }
659 :
660 0 : void TerminateRobustnessTimer() {
661 0 : if (mRobustnessTimerRunning) {
662 0 : mContextRestorer->Cancel();
663 0 : mRobustnessTimerRunning = false;
664 : }
665 0 : }
666 :
667 : protected:
668 0 : void SetDontKnowIfNeedFakeBlack() {
669 0 : mFakeBlackStatus = DontKnowIfNeedFakeBlack;
670 0 : }
671 :
672 : bool NeedFakeBlack();
673 : void BindFakeBlackTextures();
674 : void UnbindFakeBlackTextures();
675 :
676 : int WhatDoesVertexAttrib0Need();
677 : bool DoFakeVertexAttrib0(WebGLuint vertexCount);
678 : void UndoFakeVertexAttrib0();
679 : void InvalidateFakeVertexAttrib0();
680 :
681 : static CheckedUint32 GetImageSize(WebGLsizei height,
682 : WebGLsizei width,
683 : PRUint32 pixelSize,
684 : PRUint32 alignment);
685 :
686 : // Returns x rounded to the next highest multiple of y.
687 0 : static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
688 0 : return ((x + y - 1) / y) * y;
689 : }
690 :
691 : nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
692 0 : nsHTMLCanvasElement *HTMLCanvasElement() {
693 0 : return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
694 : }
695 :
696 : nsRefPtr<gl::GLContext> gl;
697 :
698 : CheckedUint32 mGeneration;
699 :
700 : WebGLContextOptions mOptions;
701 :
702 : bool mInvalidated;
703 : bool mResetLayer;
704 : bool mVerbose;
705 : bool mOptionsFrozen;
706 : bool mMinCapability;
707 : bool mDisableExtensions;
708 : bool mHasRobustness;
709 :
710 : template<typename WebGLObjectType>
711 : void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
712 :
713 : WebGLuint mActiveTexture;
714 : WebGLenum mWebGLError;
715 :
716 : // whether shader validation is supported
717 : bool mShaderValidation;
718 :
719 : // some GL constants
720 : PRInt32 mGLMaxVertexAttribs;
721 : PRInt32 mGLMaxTextureUnits;
722 : PRInt32 mGLMaxTextureSize;
723 : PRInt32 mGLMaxCubeMapTextureSize;
724 : PRInt32 mGLMaxTextureImageUnits;
725 : PRInt32 mGLMaxVertexTextureImageUnits;
726 : PRInt32 mGLMaxVaryingVectors;
727 : PRInt32 mGLMaxFragmentUniformVectors;
728 : PRInt32 mGLMaxVertexUniformVectors;
729 :
730 : // Represents current status, or state, of the context. That is, is it lost
731 : // or stable and what part of the context lost process are we currently at.
732 : // This is used to support the WebGL spec's asyncronous nature in handling
733 : // context loss.
734 : enum ContextStatus {
735 : // The context is stable; there either are none or we don't know of any.
736 : ContextStable,
737 : // The context has been lost, but we have not yet sent an event to the
738 : // script informing it of this.
739 : ContextLostAwaitingEvent,
740 : // The context has been lost, and we have sent the script an event
741 : // informing it of this.
742 : ContextLost,
743 : // The context is lost, an event has been sent to the script, and the
744 : // script correctly handled the event. We are waiting for the context to
745 : // be restored.
746 : ContextLostAwaitingRestore
747 : };
748 :
749 : // extensions
750 : enum WebGLExtensionID {
751 : WebGL_OES_texture_float,
752 : WebGL_OES_standard_derivatives,
753 : WebGL_EXT_texture_filter_anisotropic,
754 : WebGL_MOZ_WEBGL_lose_context,
755 : WebGLExtensionID_Max
756 : };
757 : nsRefPtr<WebGLExtension> mEnabledExtensions[WebGLExtensionID_Max];
758 0 : bool IsExtensionEnabled(WebGLExtensionID ext) const {
759 0 : NS_ABORT_IF_FALSE(ext >= 0 && ext < WebGLExtensionID_Max, "bogus index!");
760 0 : return mEnabledExtensions[ext] != nsnull;
761 : }
762 : bool IsExtensionSupported(WebGLExtensionID ei);
763 :
764 : bool InitAndValidateGL();
765 : bool ValidateBuffers(PRInt32* maxAllowedCount, const char *info);
766 : bool ValidateCapabilityEnum(WebGLenum cap, const char *info);
767 : bool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
768 : bool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);
769 : bool ValidateBlendFuncSrcEnum(WebGLenum mode, const char *info);
770 : bool ValidateBlendFuncEnumsCompatibility(WebGLenum sfactor, WebGLenum dfactor, const char *info);
771 : bool ValidateTextureTargetEnum(WebGLenum target, const char *info);
772 : bool ValidateComparisonEnum(WebGLenum target, const char *info);
773 : bool ValidateStencilOpEnum(WebGLenum action, const char *info);
774 : bool ValidateFaceEnum(WebGLenum face, const char *info);
775 : bool ValidateBufferUsageEnum(WebGLenum target, const char *info);
776 : bool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
777 : PRUint32 *texelSize, const char *info);
778 : bool ValidateDrawModeEnum(WebGLenum mode, const char *info);
779 : bool ValidateAttribIndex(WebGLuint index, const char *info);
780 : bool ValidateStencilParamsForDrawCall();
781 :
782 : bool ValidateGLSLVariableName(const nsAString& name, const char *info);
783 : bool ValidateGLSLCharacter(PRUnichar c);
784 : bool ValidateGLSLString(const nsAString& string, const char *info);
785 :
786 : static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
787 :
788 : void Invalidate();
789 : void DestroyResourcesAndContext();
790 :
791 0 : void MakeContextCurrent() { gl->MakeCurrent(); }
792 :
793 : // helpers
794 : nsresult TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
795 : WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero, WebGLint border,
796 : WebGLenum format, WebGLenum type,
797 : void *data, PRUint32 byteLength,
798 : int jsArrayType,
799 : int srcFormat, bool srcPremultiplied);
800 : nsresult TexSubImage2D_base(WebGLenum target, WebGLint level,
801 : WebGLint xoffset, WebGLint yoffset,
802 : WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
803 : WebGLenum format, WebGLenum type,
804 : void *pixels, PRUint32 byteLength,
805 : int jsArrayType,
806 : int srcFormat, bool srcPremultiplied);
807 : nsresult ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
808 : WebGLenum format, WebGLenum type, JSObject* pixels);
809 : nsresult TexParameter_base(WebGLenum target, WebGLenum pname,
810 : WebGLint *intParamPtr, WebGLfloat *floatParamPtr);
811 :
812 : void ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
813 : const PRUint8*src, PRUint8 *dst,
814 : int srcFormat, bool srcPremultiplied,
815 : int dstFormat, bool dstPremultiplied,
816 : size_t dstTexelSize);
817 :
818 : nsresult DOMElementToImageSurface(dom::Element* imageOrCanvas,
819 : gfxImageSurface **imageOut,
820 : int *format);
821 :
822 : nsresult CopyTexSubImage2D_base(WebGLenum target,
823 : WebGLint level,
824 : WebGLenum internalformat,
825 : WebGLint xoffset,
826 : WebGLint yoffset,
827 : WebGLint x,
828 : WebGLint y,
829 : WebGLsizei width,
830 : WebGLsizei height,
831 : bool sub
832 : );
833 :
834 : // Conversion from public nsI* interfaces to concrete objects
835 : template<class ConcreteObjectType, class BaseInterfaceType>
836 : bool GetConcreteObject(const char *info,
837 : BaseInterfaceType *aInterface,
838 : ConcreteObjectType **aConcreteObject,
839 : bool *isNull = 0,
840 : bool *isDeleted = 0,
841 : bool generateErrors = true);
842 :
843 : template<class ConcreteObjectType, class BaseInterfaceType>
844 0 : bool GetConcreteObjectAndGLName(const char *info,
845 : BaseInterfaceType *aInterface,
846 : ConcreteObjectType **aConcreteObject,
847 : WebGLuint *aGLObjectName,
848 : bool *isNull = 0,
849 : bool *isDeleted = 0);
850 :
851 : template<class ConcreteObjectType, class BaseInterfaceType>
852 : bool GetGLName(const char *info,
853 : BaseInterfaceType *aInterface,
854 : WebGLuint *aGLObjectName,
855 : bool *isNull = 0,
856 : bool *isDeleted = 0);
857 :
858 : template<class ConcreteObjectType, class BaseInterfaceType>
859 : bool CanGetConcreteObject(const char *info,
860 : BaseInterfaceType *aInterface,
861 : bool *isNull = 0,
862 : bool *isDeleted = 0);
863 :
864 0 : PRInt32 MaxTextureSizeForTarget(WebGLenum target) const {
865 0 : return target == LOCAL_GL_TEXTURE_2D ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
866 : }
867 :
868 : /** like glBufferData but if the call may change the buffer size, checks any GL error generated
869 : * by this glBufferData call and returns it */
870 : GLenum CheckedBufferData(GLenum target,
871 : GLsizeiptr size,
872 : const GLvoid *data,
873 : GLenum usage);
874 : /** like glTexImage2D but if the call may change the texture size, checks any GL error generated
875 : * by this glTexImage2D call and returns it */
876 : GLenum CheckedTexImage2D(GLenum target,
877 : GLint level,
878 : GLenum internalFormat,
879 : GLsizei width,
880 : GLsizei height,
881 : GLint border,
882 : GLenum format,
883 : GLenum type,
884 : const GLvoid *data);
885 :
886 : void MaybeRestoreContext();
887 : bool IsContextStable();
888 : void ForceLoseContext();
889 : void ForceRestoreContext();
890 :
891 : // the buffers bound to the current program's attribs
892 : nsTArray<WebGLVertexAttribData> mAttribBuffers;
893 :
894 : nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
895 : nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
896 :
897 : WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
898 : WebGLRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
899 :
900 : WebGLRefPtr<WebGLProgram> mCurrentProgram;
901 :
902 : PRUint32 mMaxFramebufferColorAttachments;
903 :
904 : WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
905 : WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
906 :
907 : WebGLFastArray<WebGLTexture*> mTextures;
908 : WebGLFastArray<WebGLBuffer*> mBuffers;
909 : WebGLFastArray<WebGLProgram*> mPrograms;
910 : WebGLFastArray<WebGLShader*> mShaders;
911 : WebGLFastArray<WebGLRenderbuffer*> mRenderbuffers;
912 : WebGLFastArray<WebGLFramebuffer*> mFramebuffers;
913 : WebGLFastArray<WebGLUniformLocation*> mUniformLocations;
914 :
915 : // PixelStore parameters
916 : PRUint32 mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
917 : bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
918 :
919 : FakeBlackStatus mFakeBlackStatus;
920 :
921 : WebGLuint mBlackTexture2D, mBlackTextureCubeMap;
922 : bool mBlackTexturesAreInitialized;
923 :
924 : WebGLfloat mVertexAttrib0Vector[4];
925 : WebGLfloat mFakeVertexAttrib0BufferObjectVector[4];
926 : size_t mFakeVertexAttrib0BufferObjectSize;
927 : GLuint mFakeVertexAttrib0BufferObject;
928 : int mFakeVertexAttrib0BufferStatus;
929 :
930 : WebGLint mStencilRefFront, mStencilRefBack;
931 : WebGLuint mStencilValueMaskFront, mStencilValueMaskBack,
932 : mStencilWriteMaskFront, mStencilWriteMaskBack;
933 : realGLboolean mColorWriteMask[4];
934 : realGLboolean mDepthWriteMask;
935 : realGLboolean mScissorTestEnabled;
936 : realGLboolean mDitherEnabled;
937 : WebGLfloat mColorClearValue[4];
938 : WebGLint mStencilClearValue;
939 : WebGLfloat mDepthClearValue;
940 :
941 : int mBackbufferClearingStatus;
942 :
943 : nsCOMPtr<nsITimer> mContextRestorer;
944 : bool mAllowRestore;
945 : bool mRobustnessTimerRunning;
946 : bool mDrawSinceRobustnessTimerSet;
947 : ContextStatus mContextStatus;
948 : bool mContextLostErrorSet;
949 : bool mContextLostDueToTest;
950 :
951 : #ifdef XP_MACOSX
952 : // see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime
953 : // Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy
954 : // these objects at high frequency. Having WebGLContext's hold one such object seems fine,
955 : // because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
956 : // If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
957 : ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
958 : #endif
959 :
960 :
961 : public:
962 : // console logging helpers
963 : static void LogMessage(const char *fmt, ...);
964 : static void LogMessage(const char *fmt, va_list ap);
965 : void LogMessageIfVerbose(const char *fmt, ...);
966 : void LogMessageIfVerbose(const char *fmt, va_list ap);
967 :
968 : friend class WebGLTexture;
969 : friend class WebGLFramebuffer;
970 : friend class WebGLRenderbuffer;
971 : friend class WebGLProgram;
972 : friend class WebGLBuffer;
973 : friend class WebGLShader;
974 : friend class WebGLUniformLocation;
975 : };
976 :
977 : // This class is a mixin for objects that are tied to a specific
978 : // context (which is to say, all of them). They provide initialization
979 : // as well as comparison with the current context.
980 : class WebGLContextBoundObject
981 : {
982 : public:
983 0 : WebGLContextBoundObject(WebGLContext *context) {
984 0 : mContext = context;
985 0 : mContextGeneration = context->Generation();
986 0 : }
987 :
988 0 : bool IsCompatibleWithContext(WebGLContext *other) {
989 : return mContext == other &&
990 0 : mContextGeneration == other->Generation();
991 : }
992 :
993 : protected:
994 : WebGLContext *mContext;
995 : PRUint32 mContextGeneration;
996 : };
997 :
998 0 : struct WebGLVertexAttribData {
999 : // note that these initial values are what GL initializes vertex attribs to
1000 0 : WebGLVertexAttribData()
1001 : : buf(0), stride(0), size(4), byteOffset(0),
1002 0 : type(LOCAL_GL_FLOAT), enabled(false), normalized(false)
1003 0 : { }
1004 :
1005 : WebGLRefPtr<WebGLBuffer> buf;
1006 : WebGLuint stride;
1007 : WebGLuint size;
1008 : GLuint byteOffset;
1009 : GLenum type;
1010 : bool enabled;
1011 : bool normalized;
1012 :
1013 0 : GLuint componentSize() const {
1014 0 : switch(type) {
1015 : case LOCAL_GL_BYTE:
1016 0 : return sizeof(GLbyte);
1017 : break;
1018 : case LOCAL_GL_UNSIGNED_BYTE:
1019 0 : return sizeof(GLubyte);
1020 : break;
1021 : case LOCAL_GL_SHORT:
1022 0 : return sizeof(GLshort);
1023 : break;
1024 : case LOCAL_GL_UNSIGNED_SHORT:
1025 0 : return sizeof(GLushort);
1026 : break;
1027 : // XXX case LOCAL_GL_FIXED:
1028 : case LOCAL_GL_FLOAT:
1029 0 : return sizeof(GLfloat);
1030 : break;
1031 : default:
1032 0 : NS_ERROR("Should never get here!");
1033 0 : return 0;
1034 : }
1035 : }
1036 :
1037 0 : GLuint actualStride() const {
1038 0 : if (stride) return stride;
1039 0 : return size * componentSize();
1040 : }
1041 : };
1042 :
1043 : class WebGLBuffer MOZ_FINAL
1044 : : public nsIWebGLBuffer
1045 : , public WebGLRefCountedObject<WebGLBuffer>
1046 : , public WebGLContextBoundObject
1047 : {
1048 : public:
1049 0 : WebGLBuffer(WebGLContext *context)
1050 : : WebGLContextBoundObject(context)
1051 : , mHasEverBeenBound(false)
1052 : , mByteLength(0)
1053 : , mTarget(LOCAL_GL_NONE)
1054 0 : , mData(nsnull)
1055 : {
1056 0 : mContext->MakeContextCurrent();
1057 0 : mContext->gl->fGenBuffers(1, &mGLName);
1058 0 : mMonotonicHandle = mContext->mBuffers.AppendElement(this);
1059 0 : }
1060 :
1061 0 : ~WebGLBuffer() {
1062 0 : DeleteOnce();
1063 0 : }
1064 :
1065 0 : void Delete() {
1066 0 : mContext->MakeContextCurrent();
1067 0 : mContext->gl->fDeleteBuffers(1, &mGLName);
1068 0 : free(mData);
1069 0 : mData = nsnull;
1070 0 : mByteLength = 0;
1071 0 : mContext->mBuffers.RemoveElement(mMonotonicHandle);
1072 0 : }
1073 :
1074 0 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
1075 0 : return aMallocSizeOf(this) + aMallocSizeOf(mData);
1076 : }
1077 :
1078 0 : bool HasEverBeenBound() { return mHasEverBeenBound; }
1079 0 : void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
1080 0 : GLuint GLName() const { return mGLName; }
1081 0 : GLuint ByteLength() const { return mByteLength; }
1082 0 : GLenum Target() const { return mTarget; }
1083 0 : const void *Data() const { return mData; }
1084 :
1085 0 : void SetByteLength(GLuint byteLength) { mByteLength = byteLength; }
1086 0 : void SetTarget(GLenum target) { mTarget = target; }
1087 :
1088 : // element array buffers are the only buffers for which we need to keep a copy of the data.
1089 : // this method assumes that the byte length has previously been set by calling SetByteLength.
1090 0 : bool CopyDataIfElementArray(const void* data) {
1091 0 : if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
1092 0 : mData = realloc(mData, mByteLength);
1093 0 : if (!mData) {
1094 0 : mByteLength = 0;
1095 0 : return false;
1096 : }
1097 0 : memcpy(mData, data, mByteLength);
1098 : }
1099 0 : return true;
1100 : }
1101 :
1102 : // same comments as for CopyElementArrayData
1103 0 : bool ZeroDataIfElementArray() {
1104 0 : if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
1105 0 : mData = realloc(mData, mByteLength);
1106 0 : if (!mData) {
1107 0 : mByteLength = 0;
1108 0 : return false;
1109 : }
1110 0 : memset(mData, 0, mByteLength);
1111 : }
1112 0 : return true;
1113 : }
1114 :
1115 : // same comments as for CopyElementArrayData
1116 0 : void CopySubDataIfElementArray(GLuint byteOffset, GLuint byteLength, const void* data) {
1117 0 : if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER && mByteLength) {
1118 0 : memcpy((void*) (size_t(mData)+byteOffset), data, byteLength);
1119 : }
1120 0 : }
1121 :
1122 : // this method too is only for element array buffers. It returns the maximum value in the part of
1123 : // the buffer starting at given offset, consisting of given count of elements. The type T is the type
1124 : // to interprete the array elements as, must be GLushort or GLubyte.
1125 : template<typename T>
1126 0 : PRInt32 FindMaxElementInSubArray(GLuint count, GLuint byteOffset)
1127 : {
1128 0 : const T* start = reinterpret_cast<T*>(reinterpret_cast<size_t>(mData) + byteOffset);
1129 0 : const T* stop = start + count;
1130 0 : T result = 0;
1131 0 : for(const T* ptr = start; ptr != stop; ++ptr) {
1132 0 : if (*ptr > result) result = *ptr;
1133 : }
1134 0 : return result;
1135 : }
1136 :
1137 0 : void InvalidateCachedMaxElements() {
1138 0 : mHasCachedMaxUbyteElement = false;
1139 0 : mHasCachedMaxUshortElement = false;
1140 0 : }
1141 :
1142 0 : PRInt32 FindMaxUbyteElement() {
1143 0 : if (mHasCachedMaxUbyteElement) {
1144 0 : return mCachedMaxUbyteElement;
1145 : } else {
1146 0 : mHasCachedMaxUbyteElement = true;
1147 0 : mCachedMaxUbyteElement = FindMaxElementInSubArray<GLubyte>(mByteLength, 0);
1148 0 : return mCachedMaxUbyteElement;
1149 : }
1150 : }
1151 :
1152 0 : PRInt32 FindMaxUshortElement() {
1153 0 : if (mHasCachedMaxUshortElement) {
1154 0 : return mCachedMaxUshortElement;
1155 : } else {
1156 0 : mHasCachedMaxUshortElement = true;
1157 0 : mCachedMaxUshortElement = FindMaxElementInSubArray<GLushort>(mByteLength>>1, 0);
1158 0 : return mCachedMaxUshortElement;
1159 : }
1160 : }
1161 :
1162 : NS_DECL_ISUPPORTS
1163 : NS_DECL_NSIWEBGLBUFFER
1164 :
1165 : protected:
1166 :
1167 : WebGLuint mGLName;
1168 : bool mHasEverBeenBound;
1169 : GLuint mByteLength;
1170 : GLenum mTarget;
1171 : WebGLMonotonicHandle mMonotonicHandle;
1172 :
1173 : PRUint8 mCachedMaxUbyteElement;
1174 : bool mHasCachedMaxUbyteElement;
1175 : PRUint16 mCachedMaxUshortElement;
1176 : bool mHasCachedMaxUshortElement;
1177 :
1178 : void* mData; // in the case of an Element Array Buffer, we keep a copy.
1179 : };
1180 :
1181 : class WebGLTexture MOZ_FINAL
1182 : : public nsIWebGLTexture
1183 : , public WebGLRefCountedObject<WebGLTexture>
1184 : , public WebGLContextBoundObject
1185 : {
1186 : public:
1187 0 : WebGLTexture(WebGLContext *context)
1188 : : WebGLContextBoundObject(context)
1189 : , mHasEverBeenBound(false)
1190 : , mTarget(0)
1191 : , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
1192 : , mMagFilter(LOCAL_GL_LINEAR)
1193 : , mWrapS(LOCAL_GL_REPEAT)
1194 : , mWrapT(LOCAL_GL_REPEAT)
1195 : , mFacesCount(0)
1196 : , mMaxLevelWithCustomImages(0)
1197 : , mHaveGeneratedMipmap(false)
1198 0 : , mFakeBlackStatus(DoNotNeedFakeBlack)
1199 : {
1200 0 : mContext->MakeContextCurrent();
1201 0 : mContext->gl->fGenTextures(1, &mGLName);
1202 0 : mMonotonicHandle = mContext->mTextures.AppendElement(this);
1203 0 : }
1204 :
1205 0 : ~WebGLTexture() {
1206 0 : DeleteOnce();
1207 0 : }
1208 :
1209 0 : void Delete() {
1210 0 : mImageInfos.Clear();
1211 0 : mContext->MakeContextCurrent();
1212 0 : mContext->gl->fDeleteTextures(1, &mGLName);
1213 0 : mContext->mTextures.RemoveElement(mMonotonicHandle);
1214 0 : }
1215 :
1216 0 : bool HasEverBeenBound() { return mHasEverBeenBound; }
1217 : void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
1218 0 : WebGLuint GLName() { return mGLName; }
1219 0 : GLenum Target() const { return mTarget; }
1220 :
1221 : NS_DECL_ISUPPORTS
1222 : NS_DECL_NSIWEBGLTEXTURE
1223 :
1224 : protected:
1225 :
1226 : friend class WebGLContext;
1227 : friend class WebGLFramebuffer;
1228 :
1229 : bool mHasEverBeenBound;
1230 : WebGLuint mGLName;
1231 :
1232 : // we store information about the various images that are part of
1233 : // this texture (cubemap faces, mipmap levels)
1234 :
1235 : public:
1236 :
1237 0 : class ImageInfo : public WebGLRectangleObject {
1238 : public:
1239 0 : ImageInfo() : mFormat(0), mType(0), mIsDefined(false) {}
1240 0 : ImageInfo(WebGLsizei width, WebGLsizei height,
1241 : WebGLenum format, WebGLenum type)
1242 0 : : WebGLRectangleObject(width, height), mFormat(format), mType(type), mIsDefined(true) {}
1243 :
1244 0 : bool operator==(const ImageInfo& a) const {
1245 : return mWidth == a.mWidth && mHeight == a.mHeight &&
1246 0 : mFormat == a.mFormat && mType == a.mType;
1247 : }
1248 0 : bool operator!=(const ImageInfo& a) const {
1249 0 : return !(*this == a);
1250 : }
1251 0 : bool IsSquare() const {
1252 0 : return mWidth == mHeight;
1253 : }
1254 0 : bool IsPositive() const {
1255 0 : return mWidth > 0 && mHeight > 0;
1256 : }
1257 0 : bool IsPowerOfTwo() const {
1258 0 : return is_pot_assuming_nonnegative(mWidth) &&
1259 0 : is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
1260 : }
1261 0 : PRInt64 MemoryUsage() const {
1262 0 : if (!mIsDefined)
1263 0 : return 0;
1264 0 : PRInt64 texelSize = WebGLContext::GetTexelSize(mFormat, mType);
1265 0 : return PRInt64(mWidth) * PRInt64(mHeight) * texelSize;
1266 : }
1267 0 : WebGLenum Format() const { return mFormat; }
1268 0 : WebGLenum Type() const { return mType; }
1269 : protected:
1270 : WebGLenum mFormat, mType;
1271 : bool mIsDefined;
1272 :
1273 : friend class WebGLTexture;
1274 : };
1275 :
1276 0 : ImageInfo& ImageInfoAt(size_t level, size_t face = 0) {
1277 : #ifdef DEBUG
1278 0 : if (face >= mFacesCount)
1279 0 : NS_ERROR("wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
1280 : #endif
1281 : // no need to check level as a wrong value would be caught by ElementAt().
1282 0 : return mImageInfos.ElementAt(level * mFacesCount + face);
1283 : }
1284 :
1285 0 : const ImageInfo& ImageInfoAt(size_t level, size_t face) const {
1286 0 : return const_cast<WebGLTexture*>(this)->ImageInfoAt(level, face);
1287 : }
1288 :
1289 0 : bool HasImageInfoAt(size_t level, size_t face) const {
1290 0 : CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
1291 0 : return checked_index.valid() &&
1292 0 : checked_index.value() < mImageInfos.Length() &&
1293 0 : ImageInfoAt(level, face).mIsDefined;
1294 : }
1295 :
1296 0 : static size_t FaceForTarget(WebGLenum target) {
1297 0 : return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1298 : }
1299 :
1300 0 : PRInt64 MemoryUsage() const {
1301 0 : if (IsDeleted())
1302 0 : return 0;
1303 0 : PRInt64 result = 0;
1304 0 : for(size_t face = 0; face < mFacesCount; face++) {
1305 0 : if (mHaveGeneratedMipmap) {
1306 : // Each mipmap level is 1/4 the size of the previous level
1307 : // 1 + x + x^2 + ... = 1/(1-x)
1308 : // for x = 1/4, we get 1/(1-1/4) = 4/3
1309 0 : result += ImageInfoAt(0, face).MemoryUsage() * 4 / 3;
1310 : } else {
1311 0 : for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
1312 0 : result += ImageInfoAt(level, face).MemoryUsage();
1313 : }
1314 : }
1315 0 : return result;
1316 : }
1317 :
1318 : protected:
1319 :
1320 : WebGLenum mTarget;
1321 : WebGLenum mMinFilter, mMagFilter, mWrapS, mWrapT;
1322 :
1323 : size_t mFacesCount, mMaxLevelWithCustomImages;
1324 : nsTArray<ImageInfo> mImageInfos;
1325 :
1326 : bool mHaveGeneratedMipmap;
1327 : FakeBlackStatus mFakeBlackStatus;
1328 :
1329 : WebGLMonotonicHandle mMonotonicHandle;
1330 :
1331 0 : void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
1332 0 : mMaxLevelWithCustomImages = NS_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
1333 0 : mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
1334 0 : }
1335 :
1336 : bool CheckFloatTextureFilterParams() const {
1337 : // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported
1338 : return (mMagFilter == LOCAL_GL_NEAREST) &&
1339 : (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
1340 : }
1341 :
1342 0 : bool AreBothWrapModesClampToEdge() const {
1343 0 : return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
1344 : }
1345 :
1346 0 : bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(size_t face) const {
1347 0 : if (mHaveGeneratedMipmap)
1348 0 : return true;
1349 :
1350 0 : ImageInfo expected = ImageInfoAt(0, face);
1351 :
1352 : // checks if custom level>0 images are all defined up to the highest level defined
1353 : // and have the expected dimensions
1354 0 : for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
1355 0 : const ImageInfo& actual = ImageInfoAt(level, face);
1356 0 : if (actual != expected)
1357 0 : return false;
1358 0 : expected.mWidth = NS_MAX(1, expected.mWidth >> 1);
1359 0 : expected.mHeight = NS_MAX(1, expected.mHeight >> 1);
1360 :
1361 : // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
1362 : // of extra useless levels.
1363 0 : if (actual.mWidth == 1 && actual.mHeight == 1)
1364 0 : return true;
1365 : }
1366 :
1367 : // if we're here, we've exhausted all levels without finding a 1x1 image
1368 0 : return false;
1369 : }
1370 :
1371 : public:
1372 :
1373 0 : void SetDontKnowIfNeedFakeBlack() {
1374 0 : mFakeBlackStatus = DontKnowIfNeedFakeBlack;
1375 0 : mContext->SetDontKnowIfNeedFakeBlack();
1376 0 : }
1377 :
1378 0 : void Bind(WebGLenum aTarget) {
1379 : // this function should only be called by bindTexture().
1380 : // it assumes that the GL context is already current.
1381 :
1382 0 : bool firstTimeThisTextureIsBound = !mHasEverBeenBound;
1383 :
1384 0 : if (!firstTimeThisTextureIsBound && aTarget != mTarget) {
1385 0 : mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
1386 : // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
1387 : // very strange 'invalid write' crashes.
1388 0 : return;
1389 : }
1390 :
1391 0 : mTarget = aTarget;
1392 :
1393 0 : mContext->gl->fBindTexture(mTarget, mGLName);
1394 :
1395 0 : if (firstTimeThisTextureIsBound) {
1396 0 : mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
1397 0 : EnsureMaxLevelWithCustomImagesAtLeast(0);
1398 0 : SetDontKnowIfNeedFakeBlack();
1399 :
1400 : // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
1401 : // present in GLES 2, but is present in GL and it seems as if for cube maps
1402 : // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
1403 0 : if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES2())
1404 0 : mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
1405 : }
1406 :
1407 0 : mHasEverBeenBound = true;
1408 : }
1409 :
1410 0 : void SetImageInfo(WebGLenum aTarget, WebGLint aLevel,
1411 : WebGLsizei aWidth, WebGLsizei aHeight,
1412 : WebGLenum aFormat, WebGLenum aType)
1413 : {
1414 0 : if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
1415 0 : return;
1416 :
1417 0 : size_t face = FaceForTarget(aTarget);
1418 :
1419 0 : EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
1420 :
1421 0 : ImageInfoAt(aLevel, face) = ImageInfo(aWidth, aHeight, aFormat, aType);
1422 :
1423 0 : if (aLevel > 0)
1424 0 : SetCustomMipmap();
1425 :
1426 0 : SetDontKnowIfNeedFakeBlack();
1427 : }
1428 :
1429 0 : void SetMinFilter(WebGLenum aMinFilter) {
1430 0 : mMinFilter = aMinFilter;
1431 0 : SetDontKnowIfNeedFakeBlack();
1432 0 : }
1433 0 : void SetMagFilter(WebGLenum aMagFilter) {
1434 0 : mMagFilter = aMagFilter;
1435 0 : SetDontKnowIfNeedFakeBlack();
1436 0 : }
1437 0 : void SetWrapS(WebGLenum aWrapS) {
1438 0 : mWrapS = aWrapS;
1439 0 : SetDontKnowIfNeedFakeBlack();
1440 0 : }
1441 0 : void SetWrapT(WebGLenum aWrapT) {
1442 0 : mWrapT = aWrapT;
1443 0 : SetDontKnowIfNeedFakeBlack();
1444 0 : }
1445 : WebGLenum MinFilter() const { return mMinFilter; }
1446 :
1447 0 : bool DoesMinFilterRequireMipmap() const {
1448 0 : return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR);
1449 : }
1450 :
1451 0 : void SetGeneratedMipmap() {
1452 0 : if (!mHaveGeneratedMipmap) {
1453 0 : mHaveGeneratedMipmap = true;
1454 0 : SetDontKnowIfNeedFakeBlack();
1455 : }
1456 0 : }
1457 :
1458 0 : void SetCustomMipmap() {
1459 0 : if (mHaveGeneratedMipmap) {
1460 : // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
1461 : // we need to compute now all the mipmap image info.
1462 :
1463 : // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
1464 : // and are power-of-two.
1465 0 : ImageInfo imageInfo = ImageInfoAt(0, 0);
1466 0 : NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
1467 :
1468 0 : WebGLsizei size = NS_MAX(imageInfo.mWidth, imageInfo.mHeight);
1469 :
1470 : // so, the size is a power of two, let's find its log in base 2.
1471 0 : size_t maxLevel = 0;
1472 0 : for (WebGLsizei n = size; n > 1; n >>= 1)
1473 0 : ++maxLevel;
1474 :
1475 0 : EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
1476 :
1477 0 : for (size_t level = 1; level <= maxLevel; ++level) {
1478 : // again, since the sizes are powers of two, no need for any max(1,x) computation
1479 0 : imageInfo.mWidth >>= 1;
1480 0 : imageInfo.mHeight >>= 1;
1481 0 : for(size_t face = 0; face < mFacesCount; ++face)
1482 0 : ImageInfoAt(level, face) = imageInfo;
1483 : }
1484 : }
1485 0 : mHaveGeneratedMipmap = false;
1486 0 : }
1487 :
1488 0 : bool IsFirstImagePowerOfTwo() const {
1489 0 : return ImageInfoAt(0, 0).IsPowerOfTwo();
1490 : }
1491 :
1492 0 : bool AreAllLevel0ImageInfosEqual() const {
1493 0 : for (size_t face = 1; face < mFacesCount; ++face) {
1494 0 : if (ImageInfoAt(0, face) != ImageInfoAt(0, 0))
1495 0 : return false;
1496 : }
1497 0 : return true;
1498 : }
1499 :
1500 0 : bool IsMipmapTexture2DComplete() const {
1501 0 : if (mTarget != LOCAL_GL_TEXTURE_2D)
1502 0 : return false;
1503 0 : if (!ImageInfoAt(0, 0).IsPositive())
1504 0 : return false;
1505 0 : if (mHaveGeneratedMipmap)
1506 0 : return true;
1507 0 : return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(0);
1508 : }
1509 :
1510 0 : bool IsCubeComplete() const {
1511 0 : if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
1512 0 : return false;
1513 0 : const ImageInfo &first = ImageInfoAt(0, 0);
1514 0 : if (!first.IsPositive() || !first.IsSquare())
1515 0 : return false;
1516 0 : return AreAllLevel0ImageInfosEqual();
1517 : }
1518 :
1519 0 : bool IsMipmapCubeComplete() const {
1520 0 : if (!IsCubeComplete()) // in particular, this checks that this is a cube map
1521 0 : return false;
1522 0 : for (size_t face = 0; face < mFacesCount; ++face) {
1523 0 : if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
1524 0 : return false;
1525 : }
1526 0 : return true;
1527 : }
1528 :
1529 0 : bool NeedFakeBlack() {
1530 : // handle this case first, it's the generic case
1531 0 : if (mFakeBlackStatus == DoNotNeedFakeBlack)
1532 0 : return false;
1533 :
1534 0 : if (mFakeBlackStatus == DontKnowIfNeedFakeBlack) {
1535 : // Determine if the texture needs to be faked as a black texture.
1536 : // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
1537 :
1538 0 : for (size_t face = 0; face < mFacesCount; ++face) {
1539 0 : if (!ImageInfoAt(0, face).mIsDefined) {
1540 : // In case of undefined texture image, we don't print any message because this is a very common
1541 : // and often legitimate case, for example when doing asynchronous texture loading.
1542 : // An extreme case of this is the photowall google demo.
1543 : // Exiting early here allows us to avoid making noise on valid webgl code.
1544 0 : mFakeBlackStatus = DoNeedFakeBlack;
1545 0 : return true;
1546 : }
1547 : }
1548 :
1549 : const char *msg_rendering_as_black
1550 : = "A texture is going to be rendered as if it were black, as per the OpenGL ES 2.0.24 spec section 3.8.2, "
1551 0 : "because it";
1552 :
1553 0 : if (mTarget == LOCAL_GL_TEXTURE_2D)
1554 : {
1555 0 : if (DoesMinFilterRequireMipmap())
1556 : {
1557 0 : if (!IsMipmapTexture2DComplete()) {
1558 : mContext->LogMessageIfVerbose
1559 : ("%s is a 2D texture, with a minification filter requiring a mipmap, "
1560 0 : "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
1561 0 : mFakeBlackStatus = DoNeedFakeBlack;
1562 0 : } else if (!ImageInfoAt(0).IsPowerOfTwo()) {
1563 : mContext->LogMessageIfVerbose
1564 : ("%s is a 2D texture, with a minification filter requiring a mipmap, "
1565 0 : "and either its width or height is not a power of two.", msg_rendering_as_black);
1566 0 : mFakeBlackStatus = DoNeedFakeBlack;
1567 : }
1568 : }
1569 : else // no mipmap required
1570 : {
1571 0 : if (!ImageInfoAt(0).IsPositive()) {
1572 : mContext->LogMessageIfVerbose
1573 : ("%s is a 2D texture and its width or height is equal to zero.",
1574 0 : msg_rendering_as_black);
1575 0 : mFakeBlackStatus = DoNeedFakeBlack;
1576 0 : } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(0).IsPowerOfTwo()) {
1577 : mContext->LogMessageIfVerbose
1578 : ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
1579 : "with its width or height not a power of two, and with a wrap mode "
1580 0 : "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
1581 0 : mFakeBlackStatus = DoNeedFakeBlack;
1582 : }
1583 : }
1584 : }
1585 : else // cube map
1586 : {
1587 0 : bool areAllLevel0ImagesPOT = true;
1588 0 : for (size_t face = 0; face < mFacesCount; ++face)
1589 0 : areAllLevel0ImagesPOT &= ImageInfoAt(0, face).IsPowerOfTwo();
1590 :
1591 0 : if (DoesMinFilterRequireMipmap())
1592 : {
1593 0 : if (!IsMipmapCubeComplete()) {
1594 : mContext->LogMessageIfVerbose("%s is a cube map texture, with a minification filter requiring a mipmap, "
1595 : "and is not mipmap cube complete (as defined in section 3.7.10).",
1596 0 : msg_rendering_as_black);
1597 0 : mFakeBlackStatus = DoNeedFakeBlack;
1598 0 : } else if (!areAllLevel0ImagesPOT) {
1599 : mContext->LogMessageIfVerbose("%s is a cube map texture, with a minification filter requiring a mipmap, "
1600 : "and either the width or the height of some level 0 image is not a power of two.",
1601 0 : msg_rendering_as_black);
1602 0 : mFakeBlackStatus = DoNeedFakeBlack;
1603 : }
1604 : }
1605 : else // no mipmap required
1606 : {
1607 0 : if (!IsCubeComplete()) {
1608 : mContext->LogMessageIfVerbose("%s is a cube map texture, with a minification filter not requiring a mipmap, "
1609 : "and is not cube complete (as defined in section 3.7.10).",
1610 0 : msg_rendering_as_black);
1611 0 : mFakeBlackStatus = DoNeedFakeBlack;
1612 0 : } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
1613 : mContext->LogMessageIfVerbose("%s is a cube map texture, with a minification filter not requiring a mipmap, "
1614 : "with some level 0 image having width or height not a power of two, and with a wrap mode "
1615 0 : "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
1616 0 : mFakeBlackStatus = DoNeedFakeBlack;
1617 : }
1618 : }
1619 : }
1620 :
1621 : // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
1622 : // that means that we do NOT need it.
1623 0 : if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
1624 0 : mFakeBlackStatus = DoNotNeedFakeBlack;
1625 : }
1626 :
1627 0 : return mFakeBlackStatus == DoNeedFakeBlack;
1628 : }
1629 : };
1630 :
1631 0 : struct WebGLMappedIdentifier {
1632 : nsCString original, mapped; // ASCII strings
1633 0 : WebGLMappedIdentifier(const nsACString& o, const nsACString& m) : original(o), mapped(m) {}
1634 : };
1635 :
1636 : class WebGLShader MOZ_FINAL
1637 : : public nsIWebGLShader
1638 : , public WebGLRefCountedObject<WebGLShader>
1639 : , public WebGLContextBoundObject
1640 : {
1641 : friend class WebGLContext;
1642 : friend class WebGLProgram;
1643 :
1644 : public:
1645 0 : WebGLShader(WebGLContext *context, WebGLenum stype)
1646 : : WebGLContextBoundObject(context)
1647 : , mType(stype)
1648 : , mNeedsTranslation(true)
1649 0 : , mAttribMaxNameLength(0)
1650 : {
1651 0 : mContext->MakeContextCurrent();
1652 0 : mGLName = mContext->gl->fCreateShader(mType);
1653 0 : mMonotonicHandle = mContext->mShaders.AppendElement(this);
1654 0 : }
1655 :
1656 0 : ~WebGLShader() {
1657 0 : DeleteOnce();
1658 0 : }
1659 :
1660 0 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
1661 0 : return aMallocSizeOf(this) +
1662 0 : mSource.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
1663 0 : mTranslationLog.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1664 : }
1665 :
1666 0 : void Delete() {
1667 0 : mSource.Truncate();
1668 0 : mTranslationLog.Truncate();
1669 0 : mContext->MakeContextCurrent();
1670 0 : mContext->gl->fDeleteShader(mGLName);
1671 0 : mContext->mShaders.RemoveElement(mMonotonicHandle);
1672 0 : }
1673 :
1674 0 : WebGLuint GLName() { return mGLName; }
1675 0 : WebGLenum ShaderType() { return mType; }
1676 :
1677 0 : void SetSource(const nsAString& src) {
1678 : // XXX do some quick gzip here maybe -- getting this will be very rare
1679 0 : mSource.Assign(src);
1680 0 : }
1681 :
1682 0 : const nsString& Source() const { return mSource; }
1683 :
1684 0 : void SetNeedsTranslation() { mNeedsTranslation = true; }
1685 0 : bool NeedsTranslation() const { return mNeedsTranslation; }
1686 :
1687 0 : void SetTranslationSuccess() {
1688 0 : mTranslationLog.SetIsVoid(true);
1689 0 : mNeedsTranslation = false;
1690 0 : }
1691 :
1692 0 : void SetTranslationFailure(const nsCString& msg) {
1693 0 : mTranslationLog.Assign(msg);
1694 0 : }
1695 :
1696 0 : const nsCString& TranslationLog() const { return mTranslationLog; }
1697 :
1698 : NS_DECL_ISUPPORTS
1699 : NS_DECL_NSIWEBGLSHADER
1700 :
1701 : protected:
1702 :
1703 : WebGLuint mGLName;
1704 : WebGLenum mType;
1705 : nsString mSource;
1706 : nsCString mTranslationLog; // The translation log should contain only ASCII characters
1707 : bool mNeedsTranslation;
1708 : WebGLMonotonicHandle mMonotonicHandle;
1709 : nsTArray<WebGLMappedIdentifier> mAttributes;
1710 : nsTArray<WebGLMappedIdentifier> mUniforms;
1711 : int mAttribMaxNameLength;
1712 : };
1713 :
1714 : /** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
1715 : *
1716 : * \param string input/output: the string to split, becomes the string without the bracket part
1717 : * \param bracketPart output: gets the bracket part.
1718 : *
1719 : * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split.
1720 : */
1721 0 : static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
1722 : {
1723 0 : NS_ABORT_IF_FALSE(bracketPart.Length() == 0, "SplitLastSquareBracket must be called with empty bracketPart string");
1724 0 : char *string_start = string.BeginWriting();
1725 0 : char *s = string_start + string.Length() - 1;
1726 :
1727 0 : if (*s != ']')
1728 0 : return false;
1729 :
1730 0 : while (*s != '[' && s != string_start)
1731 0 : s--;
1732 :
1733 0 : if (*s != '[')
1734 0 : return false;
1735 :
1736 0 : bracketPart.Assign(s);
1737 0 : *s = 0;
1738 0 : string.EndWriting();
1739 0 : string.SetLength(s - string_start);
1740 0 : return true;
1741 : }
1742 :
1743 : typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringHash;
1744 :
1745 : class WebGLProgram MOZ_FINAL
1746 : : public nsIWebGLProgram
1747 : , public WebGLRefCountedObject<WebGLProgram>
1748 : , public WebGLContextBoundObject
1749 : {
1750 : public:
1751 0 : WebGLProgram(WebGLContext *context)
1752 : : WebGLContextBoundObject(context)
1753 : , mLinkStatus(false)
1754 : , mGeneration(0)
1755 0 : , mAttribMaxNameLength(0)
1756 : {
1757 0 : mContext->MakeContextCurrent();
1758 0 : mGLName = mContext->gl->fCreateProgram();
1759 0 : mMonotonicHandle = mContext->mPrograms.AppendElement(this);
1760 0 : }
1761 :
1762 0 : ~WebGLProgram() {
1763 0 : DeleteOnce();
1764 0 : }
1765 :
1766 0 : void Delete() {
1767 0 : DetachShaders();
1768 0 : mContext->MakeContextCurrent();
1769 0 : mContext->gl->fDeleteProgram(mGLName);
1770 0 : mContext->mPrograms.RemoveElement(mMonotonicHandle);
1771 0 : }
1772 :
1773 0 : void DetachShaders() {
1774 0 : mAttachedShaders.Clear();
1775 0 : }
1776 :
1777 0 : WebGLuint GLName() { return mGLName; }
1778 0 : const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; }
1779 0 : bool LinkStatus() { return mLinkStatus; }
1780 0 : PRUint32 Generation() const { return mGeneration.value(); }
1781 0 : void SetLinkStatus(bool val) { mLinkStatus = val; }
1782 :
1783 0 : bool ContainsShader(WebGLShader *shader) {
1784 0 : return mAttachedShaders.Contains(shader);
1785 : }
1786 :
1787 : // return true if the shader wasn't already attached
1788 0 : bool AttachShader(WebGLShader *shader) {
1789 0 : if (ContainsShader(shader))
1790 0 : return false;
1791 0 : mAttachedShaders.AppendElement(shader);
1792 :
1793 0 : mContext->MakeContextCurrent();
1794 0 : mContext->gl->fAttachShader(GLName(), shader->GLName());
1795 :
1796 0 : return true;
1797 : }
1798 :
1799 : // return true if the shader was found and removed
1800 0 : bool DetachShader(WebGLShader *shader) {
1801 0 : if (!mAttachedShaders.RemoveElement(shader))
1802 0 : return false;
1803 :
1804 0 : mContext->MakeContextCurrent();
1805 0 : mContext->gl->fDetachShader(GLName(), shader->GLName());
1806 :
1807 0 : return true;
1808 : }
1809 :
1810 0 : bool HasAttachedShaderOfType(GLenum shaderType) {
1811 0 : for (PRUint32 i = 0; i < mAttachedShaders.Length(); ++i) {
1812 0 : if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) {
1813 0 : return true;
1814 : }
1815 : }
1816 0 : return false;
1817 : }
1818 :
1819 0 : bool HasBothShaderTypesAttached() {
1820 : return
1821 0 : HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) &&
1822 0 : HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
1823 : }
1824 :
1825 0 : bool NextGeneration()
1826 : {
1827 0 : if (!(mGeneration+1).valid())
1828 0 : return false; // must exit without changing mGeneration
1829 0 : ++mGeneration;
1830 0 : return true;
1831 : }
1832 :
1833 : /* Called only after LinkProgram */
1834 : bool UpdateInfo();
1835 :
1836 : /* Getters for cached program info */
1837 0 : bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; }
1838 :
1839 : /* Maps identifier |name| to the mapped identifier |*mappedName|
1840 : * Both are ASCII strings.
1841 : */
1842 0 : void MapIdentifier(const nsACString& name, nsCString *mappedName) {
1843 0 : if (!mIdentifierMap) {
1844 : // if the identifier map doesn't exist yet, build it now
1845 0 : mIdentifierMap = new CStringHash;
1846 0 : mIdentifierMap->Init();
1847 0 : for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
1848 0 : for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
1849 0 : const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
1850 0 : mIdentifierMap->Put(attrib.original, attrib.mapped);
1851 : }
1852 0 : for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
1853 0 : const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
1854 0 : mIdentifierMap->Put(uniform.original, uniform.mapped);
1855 : }
1856 : }
1857 : }
1858 :
1859 0 : nsCString mutableName(name);
1860 0 : nsCString bracketPart;
1861 0 : bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
1862 0 : if (hadBracketPart)
1863 0 : mutableName.AppendLiteral("[0]");
1864 :
1865 0 : if (mIdentifierMap->Get(mutableName, mappedName)) {
1866 0 : if (hadBracketPart) {
1867 0 : nsCString mappedBracketPart;
1868 0 : bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart);
1869 0 : if (mappedHadBracketPart)
1870 0 : mappedName->Append(bracketPart);
1871 : }
1872 : return;
1873 : }
1874 :
1875 : // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
1876 : // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
1877 0 : mutableName.AppendLiteral("[0]");
1878 0 : if (mIdentifierMap->Get(mutableName, mappedName))
1879 : return;
1880 :
1881 : // not found? return name unchanged. This case happens e.g. on bad user input, or when
1882 : // we're not using identifier mapping, or if we didn't store an identifier in the map because
1883 : // e.g. its mapping is trivial (as happens for short identifiers)
1884 0 : mappedName->Assign(name);
1885 : }
1886 :
1887 : /* Un-maps mapped identifier |name| to the original identifier |*reverseMappedName|
1888 : * Both are ASCII strings.
1889 : */
1890 0 : void ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) {
1891 0 : if (!mIdentifierReverseMap) {
1892 : // if the identifier reverse map doesn't exist yet, build it now
1893 0 : mIdentifierReverseMap = new CStringHash;
1894 0 : mIdentifierReverseMap->Init();
1895 0 : for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
1896 0 : for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
1897 0 : const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
1898 0 : mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
1899 : }
1900 0 : for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
1901 0 : const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
1902 0 : mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
1903 : }
1904 : }
1905 : }
1906 :
1907 0 : nsCString mutableName(name);
1908 0 : nsCString bracketPart;
1909 0 : bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
1910 0 : if (hadBracketPart)
1911 0 : mutableName.AppendLiteral("[0]");
1912 :
1913 0 : if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) {
1914 0 : if (hadBracketPart) {
1915 0 : nsCString reverseMappedBracketPart;
1916 0 : bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart);
1917 0 : if (reverseMappedHadBracketPart)
1918 0 : reverseMappedName->Append(bracketPart);
1919 : }
1920 : return;
1921 : }
1922 :
1923 : // not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
1924 : // returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
1925 0 : mutableName.AppendLiteral("[0]");
1926 0 : if (mIdentifierReverseMap->Get(mutableName, reverseMappedName))
1927 : return;
1928 :
1929 : // not found? return name unchanged. This case happens e.g. on bad user input, or when
1930 : // we're not using identifier mapping, or if we didn't store an identifier in the map because
1931 : // e.g. its mapping is trivial (as happens for short identifiers)
1932 0 : reverseMappedName->Assign(name);
1933 : }
1934 :
1935 : NS_DECL_ISUPPORTS
1936 : NS_DECL_NSIWEBGLPROGRAM
1937 :
1938 : protected:
1939 :
1940 : WebGLuint mGLName;
1941 : bool mLinkStatus;
1942 : // attached shaders of the program object
1943 : nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
1944 : CheckedUint32 mGeneration;
1945 :
1946 : // post-link data
1947 : std::vector<bool> mAttribsInUse;
1948 : WebGLMonotonicHandle mMonotonicHandle;
1949 : nsAutoPtr<CStringHash> mIdentifierMap, mIdentifierReverseMap;
1950 : int mAttribMaxNameLength;
1951 : };
1952 :
1953 : class WebGLRenderbuffer MOZ_FINAL
1954 : : public nsIWebGLRenderbuffer
1955 : , public WebGLRefCountedObject<WebGLRenderbuffer>
1956 : , public WebGLRectangleObject
1957 : , public WebGLContextBoundObject
1958 : {
1959 : public:
1960 0 : WebGLRenderbuffer(WebGLContext *context)
1961 : : WebGLContextBoundObject(context)
1962 : , mInternalFormat(0)
1963 : , mInternalFormatForGL(0)
1964 : , mHasEverBeenBound(false)
1965 0 : , mInitialized(false)
1966 : {
1967 :
1968 0 : mContext->MakeContextCurrent();
1969 0 : mContext->gl->fGenRenderbuffers(1, &mGLName);
1970 0 : mMonotonicHandle = mContext->mRenderbuffers.AppendElement(this);
1971 0 : }
1972 :
1973 0 : ~WebGLRenderbuffer() {
1974 0 : DeleteOnce();
1975 0 : }
1976 :
1977 0 : void Delete() {
1978 0 : mContext->MakeContextCurrent();
1979 0 : mContext->gl->fDeleteRenderbuffers(1, &mGLName);
1980 0 : mContext->mRenderbuffers.RemoveElement(mMonotonicHandle);
1981 0 : }
1982 :
1983 0 : bool HasEverBeenBound() { return mHasEverBeenBound; }
1984 0 : void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
1985 0 : WebGLuint GLName() const { return mGLName; }
1986 :
1987 0 : bool Initialized() const { return mInitialized; }
1988 0 : void SetInitialized(bool aInitialized) { mInitialized = aInitialized; }
1989 :
1990 0 : WebGLenum InternalFormat() const { return mInternalFormat; }
1991 0 : void SetInternalFormat(WebGLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
1992 :
1993 : WebGLenum InternalFormatForGL() const { return mInternalFormatForGL; }
1994 0 : void SetInternalFormatForGL(WebGLenum aInternalFormatForGL) { mInternalFormatForGL = aInternalFormatForGL; }
1995 :
1996 0 : PRInt64 MemoryUsage() const {
1997 0 : PRInt64 pixels = PRInt64(Width()) * PRInt64(Height());
1998 0 : switch (mInternalFormatForGL) {
1999 : case LOCAL_GL_STENCIL_INDEX8:
2000 0 : return pixels;
2001 : case LOCAL_GL_RGBA4:
2002 : case LOCAL_GL_RGB5_A1:
2003 : case LOCAL_GL_RGB565:
2004 : case LOCAL_GL_DEPTH_COMPONENT16:
2005 0 : return 2 * pixels;
2006 : case LOCAL_GL_RGB8:
2007 : case LOCAL_GL_DEPTH_COMPONENT24:
2008 0 : return 3*pixels;
2009 : case LOCAL_GL_RGBA8:
2010 : case LOCAL_GL_DEPTH24_STENCIL8:
2011 0 : return 4*pixels;
2012 : default:
2013 : break;
2014 : }
2015 0 : NS_ABORT();
2016 0 : return 0;
2017 : }
2018 :
2019 : NS_DECL_ISUPPORTS
2020 : NS_DECL_NSIWEBGLRENDERBUFFER
2021 :
2022 : protected:
2023 :
2024 : WebGLuint mGLName;
2025 : WebGLenum mInternalFormat;
2026 : WebGLenum mInternalFormatForGL;
2027 : WebGLMonotonicHandle mMonotonicHandle;
2028 : bool mHasEverBeenBound;
2029 : bool mInitialized;
2030 :
2031 : friend class WebGLFramebuffer;
2032 : };
2033 :
2034 : class WebGLFramebufferAttachment
2035 0 : {
2036 : // deleting a texture or renderbuffer immediately detaches it
2037 : WebGLRefPtr<WebGLTexture> mTexturePtr;
2038 : WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
2039 : WebGLenum mAttachmentPoint;
2040 : WebGLint mTextureLevel;
2041 : WebGLenum mTextureCubeMapFace;
2042 :
2043 : public:
2044 0 : WebGLFramebufferAttachment(WebGLenum aAttachmentPoint)
2045 0 : : mAttachmentPoint(aAttachmentPoint)
2046 0 : {}
2047 :
2048 0 : bool IsDefined() const {
2049 0 : return Texture() || Renderbuffer();
2050 : }
2051 :
2052 : bool IsDeleteRequested() const {
2053 : return Texture() ? Texture()->IsDeleteRequested()
2054 : : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
2055 : : false;
2056 : }
2057 :
2058 0 : bool HasAlpha() const {
2059 0 : WebGLenum format = 0;
2060 0 : if (Texture() && Texture()->HasImageInfoAt(mTextureLevel, mTextureCubeMapFace))
2061 0 : format = Texture()->ImageInfoAt(mTextureLevel, mTextureCubeMapFace).Format();
2062 0 : else if (Renderbuffer())
2063 0 : format = Renderbuffer()->InternalFormat();
2064 : return format == LOCAL_GL_RGBA ||
2065 : format == LOCAL_GL_LUMINANCE_ALPHA ||
2066 : format == LOCAL_GL_ALPHA ||
2067 : format == LOCAL_GL_RGBA4 ||
2068 0 : format == LOCAL_GL_RGB5_A1;
2069 : }
2070 :
2071 0 : void SetTexture(WebGLTexture *tex, WebGLint level, WebGLenum face) {
2072 0 : mTexturePtr = tex;
2073 0 : mRenderbufferPtr = nsnull;
2074 0 : mTextureLevel = level;
2075 0 : mTextureCubeMapFace = face;
2076 0 : }
2077 0 : void SetRenderbuffer(WebGLRenderbuffer *rb) {
2078 0 : mTexturePtr = nsnull;
2079 0 : mRenderbufferPtr = rb;
2080 0 : }
2081 0 : const WebGLTexture *Texture() const {
2082 0 : return mTexturePtr;
2083 : }
2084 0 : WebGLTexture *Texture() {
2085 0 : return mTexturePtr;
2086 : }
2087 0 : const WebGLRenderbuffer *Renderbuffer() const {
2088 0 : return mRenderbufferPtr;
2089 : }
2090 0 : WebGLRenderbuffer *Renderbuffer() {
2091 0 : return mRenderbufferPtr;
2092 : }
2093 0 : WebGLint TextureLevel() const {
2094 0 : return mTextureLevel;
2095 : }
2096 0 : WebGLenum TextureCubeMapFace() const {
2097 0 : return mTextureCubeMapFace;
2098 : }
2099 :
2100 0 : bool HasUninitializedRenderbuffer() const {
2101 0 : return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
2102 : }
2103 :
2104 0 : void Reset() {
2105 0 : mTexturePtr = nsnull;
2106 0 : mRenderbufferPtr = nsnull;
2107 0 : }
2108 :
2109 0 : const WebGLRectangleObject* RectangleObject() const {
2110 0 : if (Texture() && Texture()->HasImageInfoAt(mTextureLevel, mTextureCubeMapFace))
2111 0 : return &Texture()->ImageInfoAt(mTextureLevel, mTextureCubeMapFace);
2112 0 : else if (Renderbuffer())
2113 0 : return Renderbuffer();
2114 : else
2115 0 : return nsnull;
2116 : }
2117 0 : bool HasSameDimensionsAs(const WebGLFramebufferAttachment& other) const {
2118 0 : const WebGLRectangleObject *thisRect = RectangleObject();
2119 0 : const WebGLRectangleObject *otherRect = other.RectangleObject();
2120 : return thisRect &&
2121 : otherRect &&
2122 0 : thisRect->HasSameDimensionsAs(*otherRect);
2123 : }
2124 :
2125 0 : bool IsComplete() const {
2126 0 : const WebGLRectangleObject *thisRect = RectangleObject();
2127 :
2128 0 : if (!thisRect ||
2129 0 : !thisRect->Width() ||
2130 0 : !thisRect->Height())
2131 0 : return false;
2132 :
2133 0 : if (mTexturePtr)
2134 0 : return mAttachmentPoint == LOCAL_GL_COLOR_ATTACHMENT0;
2135 :
2136 0 : if (mRenderbufferPtr) {
2137 0 : WebGLenum format = mRenderbufferPtr->InternalFormat();
2138 0 : switch (mAttachmentPoint) {
2139 : case LOCAL_GL_COLOR_ATTACHMENT0:
2140 : return format == LOCAL_GL_RGB565 ||
2141 : format == LOCAL_GL_RGB5_A1 ||
2142 0 : format == LOCAL_GL_RGBA4;
2143 : case LOCAL_GL_DEPTH_ATTACHMENT:
2144 0 : return format == LOCAL_GL_DEPTH_COMPONENT16;
2145 : case LOCAL_GL_STENCIL_ATTACHMENT:
2146 0 : return format == LOCAL_GL_STENCIL_INDEX8;
2147 : case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
2148 0 : return format == LOCAL_GL_DEPTH_STENCIL;
2149 : default:
2150 0 : NS_ABORT(); // should have been validated earlier
2151 : }
2152 : }
2153 :
2154 0 : NS_ABORT(); // should never get there
2155 0 : return false;
2156 : }
2157 : };
2158 :
2159 : class WebGLFramebuffer MOZ_FINAL
2160 : : public nsIWebGLFramebuffer
2161 : , public WebGLRefCountedObject<WebGLFramebuffer>
2162 : , public WebGLContextBoundObject
2163 : {
2164 : public:
2165 0 : WebGLFramebuffer(WebGLContext *context)
2166 : : WebGLContextBoundObject(context)
2167 : , mHasEverBeenBound(false)
2168 : , mColorAttachment(LOCAL_GL_COLOR_ATTACHMENT0)
2169 : , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
2170 : , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
2171 0 : , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
2172 : {
2173 0 : mContext->MakeContextCurrent();
2174 0 : mContext->gl->fGenFramebuffers(1, &mGLName);
2175 0 : mMonotonicHandle = mContext->mFramebuffers.AppendElement(this);
2176 0 : }
2177 :
2178 0 : ~WebGLFramebuffer() {
2179 0 : DeleteOnce();
2180 0 : }
2181 :
2182 0 : void Delete() {
2183 0 : mColorAttachment.Reset();
2184 0 : mDepthAttachment.Reset();
2185 0 : mStencilAttachment.Reset();
2186 0 : mDepthStencilAttachment.Reset();
2187 0 : mContext->MakeContextCurrent();
2188 0 : mContext->gl->fDeleteFramebuffers(1, &mGLName);
2189 0 : mContext->mFramebuffers.RemoveElement(mMonotonicHandle);
2190 0 : }
2191 :
2192 0 : bool HasEverBeenBound() { return mHasEverBeenBound; }
2193 0 : void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
2194 0 : WebGLuint GLName() { return mGLName; }
2195 :
2196 0 : nsresult FramebufferRenderbuffer(WebGLenum target,
2197 : WebGLenum attachment,
2198 : WebGLenum rbtarget,
2199 : nsIWebGLRenderbuffer *rbobj)
2200 : {
2201 : WebGLuint renderbuffername;
2202 : bool isNull;
2203 : WebGLRenderbuffer *wrb;
2204 :
2205 0 : if (!mContext->GetConcreteObjectAndGLName("framebufferRenderbuffer: renderbuffer",
2206 0 : rbobj, &wrb, &renderbuffername, &isNull))
2207 : {
2208 0 : return NS_OK;
2209 : }
2210 :
2211 0 : if (target != LOCAL_GL_FRAMEBUFFER)
2212 0 : return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
2213 :
2214 0 : if (rbtarget != LOCAL_GL_RENDERBUFFER)
2215 0 : return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
2216 :
2217 0 : switch (attachment) {
2218 : case LOCAL_GL_DEPTH_ATTACHMENT:
2219 0 : mDepthAttachment.SetRenderbuffer(wrb);
2220 0 : break;
2221 : case LOCAL_GL_STENCIL_ATTACHMENT:
2222 0 : mStencilAttachment.SetRenderbuffer(wrb);
2223 0 : break;
2224 : case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
2225 0 : mDepthStencilAttachment.SetRenderbuffer(wrb);
2226 0 : break;
2227 : default:
2228 : // finish checking that the 'attachment' parameter is among the allowed values
2229 0 : if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
2230 0 : return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: attachment", attachment);
2231 :
2232 0 : mColorAttachment.SetRenderbuffer(wrb);
2233 0 : break;
2234 : }
2235 :
2236 0 : mContext->MakeContextCurrent();
2237 0 : if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
2238 0 : mContext->gl->fFramebufferRenderbuffer(target, LOCAL_GL_DEPTH_ATTACHMENT, rbtarget, renderbuffername);
2239 0 : mContext->gl->fFramebufferRenderbuffer(target, LOCAL_GL_STENCIL_ATTACHMENT, rbtarget, renderbuffername);
2240 : } else {
2241 0 : mContext->gl->fFramebufferRenderbuffer(target, attachment, rbtarget, renderbuffername);
2242 : }
2243 :
2244 0 : return NS_OK;
2245 : }
2246 :
2247 0 : nsresult FramebufferTexture2D(WebGLenum target,
2248 : WebGLenum attachment,
2249 : WebGLenum textarget,
2250 : nsIWebGLTexture *tobj,
2251 : WebGLint level)
2252 : {
2253 : WebGLuint texturename;
2254 : bool isNull;
2255 : WebGLTexture *wtex;
2256 :
2257 0 : if (!mContext->GetConcreteObjectAndGLName("framebufferTexture2D: texture",
2258 0 : tobj, &wtex, &texturename, &isNull))
2259 : {
2260 0 : return NS_OK;
2261 : }
2262 :
2263 0 : if (target != LOCAL_GL_FRAMEBUFFER)
2264 0 : return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
2265 :
2266 0 : if (textarget != LOCAL_GL_TEXTURE_2D &&
2267 : (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
2268 : textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
2269 0 : return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
2270 :
2271 0 : if (level != 0)
2272 0 : return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
2273 :
2274 0 : size_t face = WebGLTexture::FaceForTarget(textarget);
2275 0 : switch (attachment) {
2276 : case LOCAL_GL_DEPTH_ATTACHMENT:
2277 0 : mDepthAttachment.SetTexture(wtex, level, face);
2278 0 : break;
2279 : case LOCAL_GL_STENCIL_ATTACHMENT:
2280 0 : mStencilAttachment.SetTexture(wtex, level, face);
2281 0 : break;
2282 : case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
2283 0 : mDepthStencilAttachment.SetTexture(wtex, level, face);
2284 0 : break;
2285 : default:
2286 0 : if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
2287 0 : return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: attachment", attachment);
2288 :
2289 0 : mColorAttachment.SetTexture(wtex, level, face);
2290 0 : break;
2291 : }
2292 :
2293 0 : mContext->MakeContextCurrent();
2294 0 : if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
2295 0 : mContext->gl->fFramebufferTexture2D(target, LOCAL_GL_DEPTH_ATTACHMENT, textarget, texturename, level);
2296 0 : mContext->gl->fFramebufferTexture2D(target, LOCAL_GL_STENCIL_ATTACHMENT, textarget, texturename, level);
2297 : } else {
2298 0 : mContext->gl->fFramebufferTexture2D(target, attachment, textarget, texturename, level);
2299 : }
2300 :
2301 0 : return NS_OK;
2302 : }
2303 :
2304 0 : bool HasIncompleteAttachment() const {
2305 0 : return (mColorAttachment.IsDefined() && !mColorAttachment.IsComplete()) ||
2306 0 : (mDepthAttachment.IsDefined() && !mDepthAttachment.IsComplete()) ||
2307 0 : (mStencilAttachment.IsDefined() && !mStencilAttachment.IsComplete()) ||
2308 0 : (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.IsComplete());
2309 : }
2310 :
2311 0 : bool HasDepthStencilConflict() const {
2312 0 : return int(mDepthAttachment.IsDefined()) +
2313 0 : int(mStencilAttachment.IsDefined()) +
2314 0 : int(mDepthStencilAttachment.IsDefined()) >= 2;
2315 : }
2316 :
2317 0 : bool HasAttachmentsOfMismatchedDimensions() const {
2318 0 : return (mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment)) ||
2319 0 : (mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment)) ||
2320 0 : (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment));
2321 : }
2322 :
2323 0 : const WebGLFramebufferAttachment& ColorAttachment() const {
2324 0 : return mColorAttachment;
2325 : }
2326 :
2327 : const WebGLFramebufferAttachment& DepthAttachment() const {
2328 : return mDepthAttachment;
2329 : }
2330 :
2331 : const WebGLFramebufferAttachment& StencilAttachment() const {
2332 : return mStencilAttachment;
2333 : }
2334 :
2335 : const WebGLFramebufferAttachment& DepthStencilAttachment() const {
2336 : return mDepthStencilAttachment;
2337 : }
2338 :
2339 0 : const WebGLFramebufferAttachment& GetAttachment(WebGLenum attachment) const {
2340 0 : if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
2341 0 : return mDepthStencilAttachment;
2342 0 : if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
2343 0 : return mDepthAttachment;
2344 0 : if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
2345 0 : return mStencilAttachment;
2346 :
2347 0 : NS_ASSERTION(attachment == LOCAL_GL_COLOR_ATTACHMENT0, "bad attachment!");
2348 0 : return mColorAttachment;
2349 : }
2350 :
2351 0 : void DetachTexture(const WebGLTexture *tex) {
2352 0 : if (mColorAttachment.Texture() == tex)
2353 0 : FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, nsnull, 0);
2354 0 : if (mDepthAttachment.Texture() == tex)
2355 0 : FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
2356 0 : if (mStencilAttachment.Texture() == tex)
2357 0 : FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
2358 0 : if (mDepthStencilAttachment.Texture() == tex)
2359 0 : FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
2360 0 : }
2361 :
2362 0 : void DetachRenderbuffer(const WebGLRenderbuffer *rb) {
2363 0 : if (mColorAttachment.Renderbuffer() == rb)
2364 0 : FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, nsnull);
2365 0 : if (mDepthAttachment.Renderbuffer() == rb)
2366 0 : FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
2367 0 : if (mStencilAttachment.Renderbuffer() == rb)
2368 0 : FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
2369 0 : if (mDepthStencilAttachment.Renderbuffer() == rb)
2370 0 : FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
2371 0 : }
2372 :
2373 0 : const WebGLRectangleObject *RectangleObject() {
2374 0 : return mColorAttachment.RectangleObject();
2375 : }
2376 :
2377 : NS_DECL_ISUPPORTS
2378 : NS_DECL_NSIWEBGLFRAMEBUFFER
2379 :
2380 0 : bool CheckAndInitializeRenderbuffers()
2381 : {
2382 : // enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
2383 : // generate the INVALID_FRAMEBUFFER_OPERATION that we need here
2384 0 : if (HasDepthStencilConflict())
2385 0 : return false;
2386 :
2387 0 : if (!mColorAttachment.HasUninitializedRenderbuffer() &&
2388 0 : !mDepthAttachment.HasUninitializedRenderbuffer() &&
2389 0 : !mStencilAttachment.HasUninitializedRenderbuffer() &&
2390 0 : !mDepthStencilAttachment.HasUninitializedRenderbuffer())
2391 0 : return true;
2392 :
2393 : // ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case
2394 0 : const WebGLRectangleObject *rect = mColorAttachment.RectangleObject();
2395 0 : if (!rect ||
2396 0 : !rect->Width() ||
2397 0 : !rect->Height())
2398 0 : return false;
2399 :
2400 0 : mContext->MakeContextCurrent();
2401 :
2402 : WebGLenum status;
2403 0 : mContext->CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER, &status);
2404 0 : if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
2405 0 : return false;
2406 :
2407 0 : PRUint32 mask = 0;
2408 :
2409 0 : if (mColorAttachment.HasUninitializedRenderbuffer())
2410 0 : mask |= LOCAL_GL_COLOR_BUFFER_BIT;
2411 :
2412 0 : if (mDepthAttachment.HasUninitializedRenderbuffer() ||
2413 0 : mDepthStencilAttachment.HasUninitializedRenderbuffer())
2414 : {
2415 0 : mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
2416 : }
2417 :
2418 0 : if (mStencilAttachment.HasUninitializedRenderbuffer() ||
2419 0 : mDepthStencilAttachment.HasUninitializedRenderbuffer())
2420 : {
2421 0 : mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
2422 : }
2423 :
2424 0 : mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0, 0, rect->Width(), rect->Height()));
2425 :
2426 0 : if (mColorAttachment.HasUninitializedRenderbuffer())
2427 0 : mColorAttachment.Renderbuffer()->SetInitialized(true);
2428 :
2429 0 : if (mDepthAttachment.HasUninitializedRenderbuffer())
2430 0 : mDepthAttachment.Renderbuffer()->SetInitialized(true);
2431 :
2432 0 : if (mStencilAttachment.HasUninitializedRenderbuffer())
2433 0 : mStencilAttachment.Renderbuffer()->SetInitialized(true);
2434 :
2435 0 : if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
2436 0 : mDepthStencilAttachment.Renderbuffer()->SetInitialized(true);
2437 :
2438 0 : return true;
2439 : }
2440 :
2441 : WebGLuint mGLName;
2442 : bool mHasEverBeenBound;
2443 :
2444 : // we only store pointers to attached renderbuffers, not to attached textures, because
2445 : // we will only need to initialize renderbuffers. Textures are already initialized.
2446 : WebGLFramebufferAttachment mColorAttachment,
2447 : mDepthAttachment,
2448 : mStencilAttachment,
2449 : mDepthStencilAttachment;
2450 :
2451 : WebGLMonotonicHandle mMonotonicHandle;
2452 : };
2453 :
2454 : class WebGLUniformLocation MOZ_FINAL
2455 : : public nsIWebGLUniformLocation
2456 : , public WebGLContextBoundObject
2457 : , public WebGLRefCountedObject<WebGLUniformLocation>
2458 : {
2459 : public:
2460 0 : WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location)
2461 : : WebGLContextBoundObject(context)
2462 : , mProgram(program)
2463 0 : , mProgramGeneration(program->Generation())
2464 0 : , mLocation(location)
2465 : {
2466 0 : mMonotonicHandle = mContext->mUniformLocations.AppendElement(this);
2467 0 : }
2468 :
2469 0 : ~WebGLUniformLocation() {
2470 0 : DeleteOnce();
2471 0 : }
2472 :
2473 0 : void Delete() {
2474 0 : mProgram = nsnull;
2475 0 : mContext->mUniformLocations.RemoveElement(mMonotonicHandle);
2476 0 : }
2477 :
2478 0 : WebGLProgram *Program() const { return mProgram; }
2479 0 : GLint Location() const { return mLocation; }
2480 0 : PRUint32 ProgramGeneration() const { return mProgramGeneration; }
2481 :
2482 : NS_DECL_ISUPPORTS
2483 : NS_DECL_NSIWEBGLUNIFORMLOCATION
2484 : protected:
2485 : // nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
2486 : // we just want to avoid having a dangling pointer.
2487 : nsRefPtr<WebGLProgram> mProgram;
2488 :
2489 : PRUint32 mProgramGeneration;
2490 : GLint mLocation;
2491 : WebGLMonotonicHandle mMonotonicHandle;
2492 : friend class WebGLProgram;
2493 : };
2494 :
2495 : class WebGLActiveInfo MOZ_FINAL
2496 : : public nsIWebGLActiveInfo
2497 0 : {
2498 : public:
2499 0 : WebGLActiveInfo(WebGLint size, WebGLenum type, const nsACString& name) :
2500 : mSize(size),
2501 : mType(type),
2502 0 : mName(NS_ConvertASCIItoUTF16(name))
2503 0 : {}
2504 :
2505 : NS_DECL_ISUPPORTS
2506 : NS_DECL_NSIWEBGLACTIVEINFO
2507 : protected:
2508 : WebGLint mSize;
2509 : WebGLenum mType;
2510 : nsString mName;
2511 : };
2512 :
2513 : class WebGLShaderPrecisionFormat MOZ_FINAL
2514 : : public nsIWebGLShaderPrecisionFormat
2515 : {
2516 : public:
2517 0 : WebGLShaderPrecisionFormat(WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
2518 : mRangeMin(rangeMin),
2519 : mRangeMax(rangeMax),
2520 0 : mPrecision(precision)
2521 : {
2522 :
2523 0 : }
2524 :
2525 : NS_DECL_ISUPPORTS
2526 : NS_DECL_NSIWEBGLSHADERPRECISIONFORMAT
2527 :
2528 : protected:
2529 : WebGLint mRangeMin;
2530 : WebGLint mRangeMax;
2531 : WebGLint mPrecision;
2532 : };
2533 :
2534 : class WebGLExtension
2535 : : public nsIWebGLExtension
2536 : , public WebGLContextBoundObject
2537 : {
2538 : public:
2539 0 : WebGLExtension(WebGLContext *baseContext)
2540 0 : : WebGLContextBoundObject(baseContext)
2541 0 : {}
2542 :
2543 : NS_DECL_ISUPPORTS
2544 : NS_DECL_NSIWEBGLEXTENSION
2545 0 : virtual ~WebGLExtension() {}
2546 : };
2547 :
2548 0 : inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
2549 0 : return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
2550 0 : : static_cast<const WebGLRectangleObject*>(this);
2551 : }
2552 :
2553 : /**
2554 : ** Template implementations
2555 : **/
2556 :
2557 : /* Helper function taking a BaseInterfaceType pointer, casting it to
2558 : * ConcreteObjectType and performing some checks along the way.
2559 : *
2560 : * By default, null (respectively: deleted) aInterface pointers are
2561 : * not allowed, but if you pass a non-null isNull (respectively:
2562 : * isDeleted) pointer, then they become allowed and the value at
2563 : * isNull (respecively isDeleted) is overwritten.
2564 : *
2565 : * If generateErrors is true (which is the default) then upon errors,
2566 : * GL errors are synthesized and error messages are printed, prepended by
2567 : * the 'info' string.
2568 : */
2569 :
2570 : template<class ConcreteObjectType, class BaseInterfaceType>
2571 : inline bool
2572 0 : WebGLContext::GetConcreteObject(const char *info,
2573 : BaseInterfaceType *aInterface,
2574 : ConcreteObjectType **aConcreteObject,
2575 : bool *isNull,
2576 : bool *isDeleted,
2577 : bool generateErrors)
2578 : {
2579 0 : if (!aInterface) {
2580 0 : if (NS_LIKELY(isNull)) {
2581 : // non-null isNull means that the caller will accept a null arg
2582 0 : *isNull = true;
2583 0 : if(isDeleted) *isDeleted = false;
2584 0 : *aConcreteObject = 0;
2585 0 : return true;
2586 : } else {
2587 0 : if (generateErrors)
2588 0 : ErrorInvalidValue("%s: null object passed as argument", info);
2589 0 : return false;
2590 : }
2591 : }
2592 :
2593 0 : if (isNull)
2594 0 : *isNull = false;
2595 :
2596 : // the key to why this static_cast is all we need to do (as opposed to the QueryInterface check we used to do)
2597 : // is that since bug 638328, WebGL interfaces are marked 'builtinclass' in the IDL
2598 0 : ConcreteObjectType *concrete = static_cast<ConcreteObjectType*>(aInterface);
2599 0 : *aConcreteObject = concrete;
2600 :
2601 0 : if (!concrete->IsCompatibleWithContext(this)) {
2602 : // the object doesn't belong to this WebGLContext
2603 0 : if (generateErrors)
2604 0 : ErrorInvalidOperation("%s: object from different WebGL context (or older generation of this one) "
2605 : "passed as argument", info);
2606 0 : return false;
2607 : }
2608 :
2609 0 : if (concrete->IsDeleted()) {
2610 0 : if (NS_LIKELY(isDeleted)) {
2611 : // non-null isDeleted means that the caller will accept a deleted arg
2612 0 : *isDeleted = true;
2613 0 : return true;
2614 : } else {
2615 0 : if (generateErrors)
2616 0 : ErrorInvalidValue("%s: deleted object passed as argument", info);
2617 0 : return false;
2618 : }
2619 : }
2620 :
2621 0 : if (isDeleted)
2622 0 : *isDeleted = false;
2623 :
2624 0 : return true;
2625 : }
2626 :
2627 : /* Same as GetConcreteObject, and in addition gets the GL object name.
2628 : * Null objects give the name 0.
2629 : */
2630 : template<class ConcreteObjectType, class BaseInterfaceType>
2631 : inline bool
2632 0 : WebGLContext::GetConcreteObjectAndGLName(const char *info,
2633 : BaseInterfaceType *aInterface,
2634 : ConcreteObjectType **aConcreteObject,
2635 : WebGLuint *aGLObjectName,
2636 : bool *isNull,
2637 : bool *isDeleted)
2638 : {
2639 0 : bool result = GetConcreteObject(info, aInterface, aConcreteObject, isNull, isDeleted);
2640 0 : if (result == false) return false;
2641 0 : *aGLObjectName = *aConcreteObject ? (*aConcreteObject)->GLName() : 0;
2642 0 : return true;
2643 : }
2644 :
2645 : /* Same as GetConcreteObjectAndGLName when you don't need the concrete object pointer.
2646 : */
2647 : template<class ConcreteObjectType, class BaseInterfaceType>
2648 : inline bool
2649 0 : WebGLContext::GetGLName(const char *info,
2650 : BaseInterfaceType *aInterface,
2651 : WebGLuint *aGLObjectName,
2652 : bool *isNull,
2653 : bool *isDeleted)
2654 : {
2655 : ConcreteObjectType *aConcreteObject;
2656 0 : return GetConcreteObjectAndGLName(info, aInterface, &aConcreteObject, aGLObjectName, isNull, isDeleted);
2657 : }
2658 :
2659 : /* Same as GetConcreteObject when you only want to check if the conversion succeeds.
2660 : */
2661 : template<class ConcreteObjectType, class BaseInterfaceType>
2662 : inline bool
2663 : WebGLContext::CanGetConcreteObject(const char *info,
2664 : BaseInterfaceType *aInterface,
2665 : bool *isNull,
2666 : bool *isDeleted)
2667 : {
2668 : ConcreteObjectType *aConcreteObject;
2669 : return GetConcreteObject(info, aInterface, &aConcreteObject, isNull, isDeleted, false);
2670 : }
2671 :
2672 : class WebGLMemoryMultiReporterWrapper
2673 : {
2674 : WebGLMemoryMultiReporterWrapper();
2675 : ~WebGLMemoryMultiReporterWrapper();
2676 : static WebGLMemoryMultiReporterWrapper* sUniqueInstance;
2677 :
2678 : // here we store plain pointers, not RefPtrs: we don't want the
2679 : // WebGLMemoryMultiReporterWrapper unique instance to keep alive all
2680 : // WebGLContexts ever created.
2681 : typedef nsTArray<const WebGLContext*> ContextsArrayType;
2682 : ContextsArrayType mContexts;
2683 :
2684 : nsCOMPtr<nsIMemoryMultiReporter> mReporter;
2685 :
2686 : static WebGLMemoryMultiReporterWrapper* UniqueInstance();
2687 :
2688 0 : static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
2689 :
2690 : public:
2691 :
2692 0 : static void AddWebGLContext(const WebGLContext* c) {
2693 0 : Contexts().AppendElement(c);
2694 0 : }
2695 :
2696 0 : static void RemoveWebGLContext(const WebGLContext* c) {
2697 0 : ContextsArrayType & contexts = Contexts();
2698 0 : contexts.RemoveElement(c);
2699 0 : if (contexts.IsEmpty()) {
2700 0 : delete sUniqueInstance;
2701 0 : sUniqueInstance = nsnull;
2702 : }
2703 0 : }
2704 :
2705 0 : static PRInt64 GetTextureMemoryUsed() {
2706 0 : const ContextsArrayType & contexts = Contexts();
2707 0 : PRInt64 result = 0;
2708 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2709 0 : for (size_t j = 0; j < contexts[i]->mTextures.Length(); ++j)
2710 0 : result += contexts[i]->mTextures[j]->MemoryUsage();
2711 0 : return result;
2712 : }
2713 :
2714 0 : static PRInt64 GetTextureCount() {
2715 0 : const ContextsArrayType & contexts = Contexts();
2716 0 : PRInt64 result = 0;
2717 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2718 0 : result += contexts[i]->mTextures.Length();
2719 0 : return result;
2720 : }
2721 :
2722 0 : static PRInt64 GetBufferMemoryUsed() {
2723 0 : const ContextsArrayType & contexts = Contexts();
2724 0 : PRInt64 result = 0;
2725 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2726 0 : for (size_t j = 0; j < contexts[i]->mBuffers.Length(); ++j)
2727 0 : result += contexts[i]->mBuffers[j]->ByteLength();
2728 0 : return result;
2729 : }
2730 :
2731 : static PRInt64 GetBufferCacheMemoryUsed();
2732 :
2733 0 : static PRInt64 GetBufferCount() {
2734 0 : const ContextsArrayType & contexts = Contexts();
2735 0 : PRInt64 result = 0;
2736 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2737 0 : result += contexts[i]->mBuffers.Length();
2738 0 : return result;
2739 : }
2740 :
2741 0 : static PRInt64 GetRenderbufferMemoryUsed() {
2742 0 : const ContextsArrayType & contexts = Contexts();
2743 0 : PRInt64 result = 0;
2744 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2745 0 : for (size_t j = 0; j < contexts[i]->mRenderbuffers.Length(); ++j)
2746 0 : result += contexts[i]->mRenderbuffers[j]->MemoryUsage();
2747 0 : return result;
2748 : }
2749 :
2750 0 : static PRInt64 GetRenderbufferCount() {
2751 0 : const ContextsArrayType & contexts = Contexts();
2752 0 : PRInt64 result = 0;
2753 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2754 0 : result += contexts[i]->mRenderbuffers.Length();
2755 0 : return result;
2756 : }
2757 :
2758 : static PRInt64 GetShaderSize();
2759 :
2760 0 : static PRInt64 GetShaderCount() {
2761 0 : const ContextsArrayType & contexts = Contexts();
2762 0 : PRInt64 result = 0;
2763 0 : for(size_t i = 0; i < contexts.Length(); ++i)
2764 0 : result += contexts[i]->mShaders.Length();
2765 0 : return result;
2766 : }
2767 :
2768 0 : static PRInt64 GetContextCount() {
2769 0 : return Contexts().Length();
2770 : }
2771 : };
2772 :
2773 : }
2774 :
2775 : #endif
|