LCOV - code coverage report
Current view: directory - content/canvas/src - WebGLContext.h (source / functions) Found Hit Coverage
Test: app.info Lines: 1034 1 0.1 %
Date: 2012-06-02 Functions: 422 1 0.2 %

       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(&currentGLError);
     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

Generated by: LCOV version 1.7