# User Benoit Jacob <bjacob@mozilla.com>
authorBenoit Jacob <bjacob@mozilla.com>
Tue, 08 Jun 2010 17:25:27 -0400
changeset 43331 e512b50ff272831609bef94811e74fa61d512254
parent 43330 6043ca0d3fba64514180730414c2aea513a4d262
child 43332 a02a4c380d0be7af3cc6994a80e3074c883a5e37
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs569976
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
# User Benoit Jacob <bjacob@mozilla.com> b=569976; Make GetUniformLocation preserve equality, and invalidate uniform locations on relinking of program; r=vladimir
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -640,29 +640,32 @@ class WebGLProgram :
     public WebGLZeroingObject,
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLPROGRAM_PRIVATE_IID)
 
     WebGLProgram(WebGLContext *context, WebGLuint name) :
         WebGLContextBoundObject(context),
-        mName(name), mDeleted(PR_FALSE), mLinkStatus(PR_FALSE)
-    { }
+        mName(name), mDeleted(PR_FALSE), mLinkStatus(PR_FALSE), mGeneration(0)
+    {
+        mMapUniformLocations.Init();
+    }
 
     void Delete() {
         if (mDeleted)
             return;
         ZeroOwners();
         mDeleted = PR_TRUE;
     }
 
     PRBool Deleted() { return mDeleted; }
     WebGLuint GLName() { return mName; }
     PRBool LinkStatus() { return mLinkStatus; }
+    GLuint Generation() const { return mGeneration; }
     void SetLinkStatus(PRBool val) { mLinkStatus = val; }
 
     PRBool ContainsShader(WebGLShader *shader) {
         return mAttachedShaders.Contains(shader);
     }
 
     // return true if the shader wasn't already attached
     PRBool AttachShader(WebGLShader *shader) {
@@ -687,23 +690,37 @@ public:
                 haveVertex = PR_TRUE;
             if (haveFrag && haveVertex)
                 return PR_TRUE;
         }
 
         return PR_FALSE;
     }
 
+    PRBool NextGeneration()
+    {
+        GLuint nextGeneration = mGeneration + 1;
+        if (nextGeneration == 0)
+            return PR_FALSE; // must exit without changing mGeneration
+        mGeneration = nextGeneration;
+        mMapUniformLocations.Clear();
+        return PR_TRUE;
+    }
+
+    already_AddRefed<WebGLUniformLocation> GetUniformLocationObject(GLint glLocation);
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLPROGRAM
 protected:
     WebGLuint mName;
     PRPackedBool mDeleted;
     PRPackedBool mLinkStatus;
     nsTArray<WebGLShader*> mAttachedShaders;
+    nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations;
+    GLuint mGeneration;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLProgram, WEBGLPROGRAM_PRIVATE_IID)
 
 #define WEBGLFRAMEBUFFER_PRIVATE_IID \
     {0x0052a16f, 0x4bc9, 0x4a55, {0x9d, 0xa3, 0x54, 0x95, 0xaa, 0x4e, 0x80, 0xb9}}
 class WebGLFramebuffer :
     public nsIWebGLFramebuffer,
@@ -777,28 +794,31 @@ class WebGLUniformLocation :
     public nsIWebGLUniformLocation,
     public WebGLZeroingObject,
     public WebGLContextBoundObject
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLUNIFORMLOCATION_PRIVATE_IID)
 
     WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location) :
-        WebGLContextBoundObject(context), mProgram(program), mLocation(location) { }
+        WebGLContextBoundObject(context), mProgram(program), mProgramGeneration(program->Generation()),
+        mLocation(location) { }
 
     WebGLProgram *Program() const { return mProgram; }
     GLint Location() const { return mLocation; }
+    GLuint ProgramGeneration() const { return mProgramGeneration; }
 
     // needed for our generic helpers to check nsIxxx parameters, see GetConcreteObject.
     PRBool Deleted() { return PR_FALSE; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLUNIFORMLOCATION
 protected:
     WebGLObjectRefPtr<WebGLProgram> mProgram;
+    GLuint mProgramGeneration;
     GLint mLocation;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLUniformLocation, WEBGLUNIFORMLOCATION_PRIVATE_IID)
 
 /**
  ** Template implementations
  **/
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -95,16 +95,29 @@ NS_IMETHODIMP WebGLContext::name(t1 a1, 
     MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5); return NS_OK;  \
 }
 
 #define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6)          \
 NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
     MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
 }
 
+already_AddRefed<WebGLUniformLocation> WebGLProgram::GetUniformLocationObject(GLint glLocation)
+{
+    WebGLUniformLocation *existingLocationObject;
+    if (mMapUniformLocations.Get(glLocation, &existingLocationObject)) {
+        NS_ADDREF(existingLocationObject);
+        return existingLocationObject;
+    } else {
+        nsRefPtr<WebGLUniformLocation> loc = new WebGLUniformLocation(mContext, this, glLocation);
+        mMapUniformLocations.Put(glLocation, loc);
+        return loc.forget();
+    }
+}
+
 //
 //  WebGL API
 //
 
 
 /* void present (); */
 NS_IMETHODIMP
 WebGLContext::Present()
@@ -1755,16 +1768,19 @@ WebGLContext::GetUniform(nsIWebGLProgram
 
     WebGLUniformLocation *location;
     if (!GetConcreteObject(ploc, &location))
         return ErrorInvalidValue("GetUniform: invalid uniform location");
 
     if (location->Program() != prog)
         return ErrorInvalidValue("GetUniform: this uniform location corresponds to another program");
 
+    if (location->ProgramGeneration() != prog->Generation())
+        return ErrorInvalidValue("GetUniform: this uniform location is obsolete since the program has been relinked");
+
     NativeJSContext js;
     if (NS_FAILED(js.error))
         return js.error;
 
     MakeContextCurrent();
 
     GLint uniforms = 0;
     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms);
@@ -1827,18 +1843,18 @@ WebGLContext::GetUniformLocation(nsIWebG
     WebGLProgram *prog;
     if (!GetConcreteObjectAndGLName(pobj, &prog, &progname))
         return ErrorInvalidOperation("GetUniformLocation: invalid program");
 
     MakeContextCurrent();
 
     GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
 
-    nsCOMPtr<WebGLUniformLocation> uloc = new WebGLUniformLocation(this, prog, intlocation);
-    *retval = uloc.forget().get();
+    nsRefPtr<nsIWebGLUniformLocation> loc = prog->GetUniformLocationObject(intlocation);
+    *retval = loc.forget().get();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetVertexAttrib(WebGLuint index, WebGLenum pname)
 {
     NativeJSContext js;
@@ -1976,16 +1992,18 @@ WebGLContext::LinkProgram(nsIWebGLProgra
         return ErrorInvalidOperation("LinkProgram: invalid program");
 
     if (!program->HasBothShaderTypesAttached())
         return ErrorInvalidOperation("LinkProgram: program does not have at least one vertex and fragment shader attached");
 
     MakeContextCurrent();
 
     gl->fLinkProgram(progname);
+    if (!program->NextGeneration())
+        return NS_ERROR_FAILURE;
 
     GLint ok;
     gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
     program->SetLinkStatus(ok ? PR_TRUE : PR_FALSE);
 
     return NS_OK;
 }
 
@@ -2248,16 +2266,18 @@ WebGLContext::DOMElementToImageSurface(n
 }
 
 #define OBTAIN_UNIFORM_LOCATION                                         \
     WebGLUniformLocation *location_object;                              \
     if (!GetConcreteObject(ploc, &location_object))                     \
         return ErrorInvalidValue("Invalid uniform location parameter"); \
     if (mCurrentProgram != location_object->Program())                  \
         return ErrorInvalidValue("This uniform location corresponds to another program"); \
+    if (mCurrentProgram->Generation() != location_object->ProgramGeneration())            \
+        return ErrorInvalidValue("This uniform location is obsolete since the program has been relinked"); \
     GLint location = location_object->Location();
 
 #define SIMPLE_ARRAY_METHOD_UNIFORM(name, cnt, arrayType, ptrType)      \
 NS_IMETHODIMP                                                           \
 WebGLContext::name(PRInt32 dummy) {                                     \
      return NS_ERROR_NOT_IMPLEMENTED;                                   \
 }                                                                       \
 NS_IMETHODIMP                                                           \