Backed out changeset b5c6dd9423cf (bug 1109945) for gl2 test failures on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book
2015-01-13 09:07:26 +01:00
parent c4100037f9
commit 2e0fe7d467
30 changed files with 2141 additions and 2461 deletions

View File

@@ -4,7 +4,7 @@
/////////////////// ///////////////////
// //
// Whitelisting this test. // Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejection should be fixed. // As part of bug 1077403, the leaking uncaught rejection should be fixed.
// //
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created."); thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
@@ -26,41 +26,35 @@ function ifWebGLSupported() {
let vsEditor = yield ShadersEditorsView._getEditor("vs"); let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs"); let fsEditor = yield ShadersEditorsView._getEditor("fs");
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(error, ok(error,
"The new vertex shader source was compiled with errors."); "The new vertex shader source was compiled with errors.");
is(error.compile, "",
// The implementation has the choice to defer all compile-time errors to link time. "The compilation status should be empty.");
let infoLog = (error.compile != "") ? error.compile : error.link; isnot(error.link, "",
"The linkage status should not be empty.");
isnot(infoLog, "", is(error.link.split("ERROR").length - 1, 2,
"The one of the compile or link info logs should not be empty."); "The linkage status contains two errors.");
is(infoLog.split("ERROR").length - 1, 2, ok(error.link.contains("ERROR: 0:8: 'constructor'"),
"The info log status contains two errors."); "A constructor error is contained in the linkage status.");
ok(infoLog.contains("ERROR: 0:8: 'constructor'"), ok(error.link.contains("ERROR: 0:8: 'assign'"),
"A constructor error is contained in the info log."); "An assignment error is contained in the linkage status.");
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
"An assignment error is contained in the info log.");
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
[, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(error, ok(error,
"The new fragment shader source was compiled with errors."); "The new fragment shader source was compiled with errors.");
is(error.compile, "",
infoLog = (error.compile != "") ? error.compile : error.link; "The compilation status should be empty.");
isnot(error.link, "",
isnot(infoLog, "", "The linkage status should not be empty.");
"The one of the compile or link info logs should not be empty."); is(error.link.split("ERROR").length - 1, 1,
is(infoLog.split("ERROR").length - 1, 1, "The linkage status contains one error.");
"The info log contains one error."); ok(error.link.contains("ERROR: 0:6: 'constructor'"),
ok(infoLog.contains("ERROR: 0:6: 'constructor'"), "A constructor error is contained in the linkage status.");
"A constructor error is contained in the info log.");
yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);

View File

@@ -23,18 +23,16 @@ function ifWebGLSupported() {
} catch (error) { } catch (error) {
ok(error, ok(error,
"The new vertex shader source was compiled with errors."); "The new vertex shader source was compiled with errors.");
is(error.compile, "",
// The implementation has the choice to defer all compile-time errors to link time. "The compilation status should be empty.");
let infoLog = (error.compile != "") ? error.compile : error.link; isnot(error.link, "",
"The linkage status should not be empty.");
isnot(infoLog, "", is(error.link.split("ERROR").length - 1, 2,
"The one of the compile or link info logs should not be empty."); "The linkage status contains two errors.");
is(infoLog.split("ERROR").length - 1, 2, ok(error.link.contains("ERROR: 0:8: 'constructor'"),
"The info log contains two errors."); "A constructor error is contained in the linkage status.");
ok(infoLog.contains("ERROR: 0:8: 'constructor'"), ok(error.link.contains("ERROR: 0:8: 'assign'"),
"A constructor error is contained in the info log."); "An assignment error is contained in the linkage status.");
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
"An assignment error is contained in the info log.");
} }
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
@@ -54,16 +52,14 @@ function ifWebGLSupported() {
} catch (error) { } catch (error) {
ok(error, ok(error,
"The new fragment shader source was compiled with errors."); "The new fragment shader source was compiled with errors.");
is(error.compile, "",
// The implementation has the choice to defer all compile-time errors to link time. "The compilation status should be empty.");
let infoLog = (error.compile != "") ? error.compile : error.link; isnot(error.link, "",
"The linkage status should not be empty.");
isnot(infoLog, "", is(error.link.split("ERROR").length - 1, 1,
"The one of the compile or link info logs should not be empty."); "The linkage status contains one error.");
is(infoLog.split("ERROR").length - 1, 1, ok(error.link.contains("ERROR: 0:6: 'constructor'"),
"The info log contains one error."); "A constructor error is contained in the linkage status.");
ok(infoLog.contains("ERROR: 0:6: 'constructor'"),
"A constructor error is contained in the info log.");
} }
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);

View File

@@ -152,8 +152,6 @@ WebGLContext::InitWebGL2()
auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs]; auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
mBoundTransformFeedbackBuffers.reset(xfBuffers); mBoundTransformFeedbackBuffers.reset(xfBuffers);
mBypassShaderValidation = true;
return true; return true;
} }

View File

@@ -212,13 +212,14 @@ WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]); tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
} }
GLuint progname = program->mGLName; GLuint progname = program->GLName();
MakeContextCurrent(); MakeContextCurrent();
gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode); gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings); NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
} }
already_AddRefed<WebGLActiveInfo> already_AddRefed<WebGLActiveInfo>
WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index) WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
{ {
@@ -231,7 +232,7 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
MakeContextCurrent(); MakeContextCurrent();
GLint len = 0; GLint len = 0;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len); gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
if (!len) if (!len)
return nullptr; return nullptr;
@@ -244,13 +245,10 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
if (len == 0 || tfsize == 0 || tftype == 0) if (len == 0 || tfsize == 0 || tftype == 0)
return nullptr; return nullptr;
MOZ_CRASH("todo"); // TODO(djg): Reverse lookup of name
/* // nsCString reverseMappedName;
// Reverse lookup of name // prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
nsCString reverseMappedName;
prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get())); nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get()));
return result.forget(); return result.forget();
*/
} }

View File

@@ -396,7 +396,7 @@ WebGL2Context::GetUniformIndices(WebGLProgram* program,
if (!uniformNames.Length()) if (!uniformNames.Length())
return; return;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
size_t count = uniformNames.Length(); size_t count = uniformNames.Length();
nsTArray<GLuint>& arr = retval.SetValue(); nsTArray<GLuint>& arr = retval.SetValue();
@@ -431,7 +431,7 @@ WebGL2Context::GetActiveUniforms(WebGLProgram* program,
if (!count) if (!count)
return; return;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
nsTArray<GLint>& arr = retval.SetValue(); nsTArray<GLint>& arr = retval.SetValue();
arr.SetLength(count); arr.SetLength(count);
@@ -450,14 +450,17 @@ WebGL2Context::GetUniformBlockIndex(WebGLProgram* program,
if (!ValidateObject("getUniformBlockIndex: program", program)) if (!ValidateObject("getUniformBlockIndex: program", program))
return 0; return 0;
// Leave this unchecked for now. if (!ValidateGLSLVariableName(uniformBlockName, "getUniformBlockIndex"))
return 0;
const NS_LossyConvertUTF16toASCII cname(uniformBlockName); NS_LossyConvertUTF16toASCII cname(uniformBlockName);
nsCString mappedName;
program->MapIdentifier(cname, &mappedName);
GLuint progname = program->mGLName; GLuint progname = program->GLName();
MakeContextCurrent(); MakeContextCurrent();
return gl->fGetUniformBlockIndex(progname, cname.BeginReading()); return gl->fGetUniformBlockIndex(progname, mappedName.get());
} }
static bool static bool
@@ -498,7 +501,7 @@ WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* progr
if (!ValidateObject("getActiveUniformBlockParameter: program", program)) if (!ValidateObject("getActiveUniformBlockParameter: program", program))
return; return;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
GLint param = 0; GLint param = 0;
MakeContextCurrent(); MakeContextCurrent();
@@ -548,7 +551,7 @@ WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBl
if (!ValidateObject("getActiveUniformBlockName: program", program)) if (!ValidateObject("getActiveUniformBlockName: program", program))
return; return;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH]; GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
GLsizei length = 0; GLsizei length = 0;
@@ -571,7 +574,7 @@ WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockInd
if (!ValidateObject("uniformBlockBinding: program", program)) if (!ValidateObject("uniformBlockBinding: program", program))
return; return;
GLuint progname = program->mGLName; GLuint progname = program->GLName();
MakeContextCurrent(); MakeContextCurrent();
gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding); gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);

View File

@@ -6,94 +6,15 @@
#include "WebGLActiveInfo.h" #include "WebGLActiveInfo.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h" #include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLTexture.h"
namespace mozilla { namespace mozilla {
static uint8_t
ElemSizeFromType(GLenum elemType)
{
switch (elemType) {
case LOCAL_GL_BOOL:
case LOCAL_GL_FLOAT:
case LOCAL_GL_INT:
case LOCAL_GL_INT_SAMPLER_2D:
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_INT_SAMPLER_3D:
case LOCAL_GL_INT_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_2D_ARRAY:
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
case LOCAL_GL_SAMPLER_2D_SHADOW:
case LOCAL_GL_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
return 1;
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_INT_VEC2:
return 2;
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_INT_VEC3:
return 3;
case LOCAL_GL_BOOL_VEC4:
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_VEC4:
case LOCAL_GL_INT_VEC4:
return 4;
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT3x2:
return 6;
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT4x2:
return 8;
case LOCAL_GL_FLOAT_MAT3:
return 9;
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4x3:
return 12;
case LOCAL_GL_FLOAT_MAT4:
return 16;
default:
MOZ_CRASH("Bad `elemType`.");
}
}
WebGLActiveInfo::WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
const nsACString& baseUserName,
const nsACString& baseMappedName)
: mElemCount(elemCount)
, mElemType(elemType)
, mBaseUserName(baseUserName)
, mIsArray(isArray)
, mElemSize(ElemSizeFromType(elemType))
, mBaseMappedName(baseMappedName)
{ }
////////////////////////////////////////////////////////////////////////////////
JSObject* JSObject*
WebGLActiveInfo::WrapObject(JSContext* js) WebGLActiveInfo::WrapObject(JSContext* cx)
{ {
return dom::WebGLActiveInfoBinding::Wrap(js, this); return dom::WebGLActiveInfoBinding::Wrap(cx, this);
} }
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLActiveInfo)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLActiveInfo, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLActiveInfo, Release)
} // namespace mozilla } // namespace mozilla

View File

@@ -6,76 +6,48 @@
#ifndef WEBGL_ACTIVE_INFO_H_ #ifndef WEBGL_ACTIVE_INFO_H_
#define WEBGL_ACTIVE_INFO_H_ #define WEBGL_ACTIVE_INFO_H_
#include "GLDefs.h"
#include "js/TypeDecls.h" #include "js/TypeDecls.h"
#include "mozilla/Attributes.h"
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
#include "nsString.h" #include "nsString.h"
#include "nsWrapperCache.h" #include "WebGLObjectModel.h"
namespace mozilla { namespace mozilla {
class WebGLActiveInfo MOZ_FINAL class WebGLActiveInfo MOZ_FINAL
: public nsWrapperCache
{ {
public: public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLActiveInfo) WebGLActiveInfo(GLint size, GLenum type, const nsACString& name)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLActiveInfo) : mSize(size)
, mType(type)
const GLint mElemCount; // `size` , mName(NS_ConvertASCIItoUTF16(name))
const GLenum mElemType; // `type` {}
const nsCString mBaseUserName; // `name`, but ASCII, and without any final "[0]".
// Not actually part of ActiveInfo:
const bool mIsArray;
const uint8_t mElemSize;
const nsCString mBaseMappedName; // Without any final "[0]".
WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
const nsACString& baseUserName, const nsACString& baseMappedName);
/* GLES 2.0.25, p33:
* This command will return as much information about active
* attributes as possible. If no information is available, length will
* be set to zero and name will be an empty string. This situation
* could arise if GetActiveAttrib is issued after a failed link.
*
* It's the same for GetActiveUniform.
*/
static WebGLActiveInfo* CreateInvalid() {
return new WebGLActiveInfo();
}
// WebIDL attributes // WebIDL attributes
GLint Size() const { GLint Size() const {
return mElemCount; return mSize;
} }
GLenum Type() const { GLenum Type() const {
return mElemType; return mType;
} }
void GetName(nsString& retval) const { void GetName(nsString& retval) const {
CopyASCIItoUTF16(mBaseUserName, retval); retval = mName;
if (mIsArray)
retval.AppendLiteral("[0]");
} }
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE; JSObject* WrapObject(JSContext* cx);
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
private: private:
WebGLActiveInfo()
: mElemCount(0)
, mElemType(0)
, mBaseUserName("")
, mIsArray(false)
, mElemSize(0)
, mBaseMappedName("")
{ }
// Private destructor, to discourage deletion outside of Release(): // Private destructor, to discourage deletion outside of Release():
~WebGLActiveInfo() { } ~WebGLActiveInfo()
{
}
GLint mSize;
GLenum mType;
nsString mName;
}; };
} // namespace mozilla } // namespace mozilla

View File

@@ -202,7 +202,6 @@ WebGLContextOptions::WebGLContextOptions()
WebGLContext::WebGLContext() WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr) : WebGLContextUnchecked(nullptr)
, mBypassShaderValidation(false)
, mNeedsFakeNoAlpha(false) , mNeedsFakeNoAlpha(false)
{ {
mGeneration = 0; mGeneration = 0;
@@ -216,6 +215,8 @@ WebGLContext::WebGLContext()
mPixelStorePremultiplyAlpha = false; mPixelStorePremultiplyAlpha = false;
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL; mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
mShaderValidation = true;
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded; mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
mVertexAttrib0Vector[0] = 0; mVertexAttrib0Vector[0] = 0;
@@ -329,7 +330,6 @@ WebGLContext::DestroyResourcesAndContext()
mBoundTransformFeedbackBuffer = nullptr; mBoundTransformFeedbackBuffer = nullptr;
mBoundUniformBuffer = nullptr; mBoundUniformBuffer = nullptr;
mCurrentProgram = nullptr; mCurrentProgram = nullptr;
mActiveProgramLinkInfo = nullptr;
mBoundDrawFramebuffer = nullptr; mBoundDrawFramebuffer = nullptr;
mBoundReadFramebuffer = nullptr; mBoundReadFramebuffer = nullptr;
mActiveOcclusionQuery = nullptr; mActiveOcclusionQuery = nullptr;

View File

@@ -19,7 +19,6 @@
#include "WebGLObjectModel.h" #include "WebGLObjectModel.h"
#include "WebGLRenderbuffer.h" #include "WebGLRenderbuffer.h"
#include "WebGLTexture.h" #include "WebGLTexture.h"
#include "WebGLShaderValidator.h"
#include "WebGLStrongTypes.h" #include "WebGLStrongTypes.h"
#include <stdarg.h> #include <stdarg.h>
@@ -97,10 +96,6 @@ namespace gfx {
class SourceSurface; class SourceSurface;
} }
namespace webgl {
struct LinkedProgramInfo;
}
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format); WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow); void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
@@ -380,9 +375,7 @@ public:
void ClearStencil(GLint v); void ClearStencil(GLint v);
void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a); void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a);
void CompileShader(WebGLShader* shader); void CompileShader(WebGLShader* shader);
void CompileShaderANGLE(WebGLShader* shader); void CompressedTexImage2D(GLenum texImageTarget, GLint level,
void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
void CompressedTexImage2D(GLenum target, GLint level,
GLenum internalformat, GLsizei width, GLenum internalformat, GLsizei width,
GLsizei height, GLint border, GLsizei height, GLint border,
const dom::ArrayBufferView& view); const dom::ArrayBufferView& view);
@@ -844,10 +837,8 @@ public:
const float* data); const float* data);
void UseProgram(WebGLProgram* prog); void UseProgram(WebGLProgram* prog);
bool ValidateAttribArraySetter(const char* name, uint32_t count, bool ValidateAttribArraySetter(const char* name, uint32_t count,
uint32_t arrayLength); uint32_t arrayLength);
bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize, bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
GLenum setterType, const char* info, GLenum setterType, const char* info,
GLuint* out_rawLoc); GLuint* out_rawLoc);
@@ -1127,9 +1118,8 @@ protected:
GLenum mUnderlyingGLError; GLenum mUnderlyingGLError;
GLenum GetAndFlushUnderlyingGLErrors(); GLenum GetAndFlushUnderlyingGLErrors();
bool mBypassShaderValidation; // whether shader validation is supported
bool mShaderValidation;
webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
// some GL constants // some GL constants
int32_t mGLMaxVertexAttribs; int32_t mGLMaxVertexAttribs;
@@ -1154,10 +1144,6 @@ public:
return mGLMaxVertexAttribs; return mGLMaxVertexAttribs;
} }
GLuint GLMaxTextureUnits() const {
return mGLMaxTextureUnits;
}
bool IsFormatValidForFB(GLenum sizedFormat) const; bool IsFormatValidForFB(GLenum sizedFormat) const;
@@ -1239,6 +1225,10 @@ protected:
WebGLintptr byteOffset, const char* info); WebGLintptr byteOffset, const char* info);
bool ValidateStencilParamsForDrawCall(); bool ValidateStencilParamsForDrawCall();
bool ValidateGLSLVariableName(const nsAString& name, const char* info);
bool ValidateGLSLCharacter(char16_t c);
bool ValidateGLSLString(const nsAString& string, const char* info);
bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func, bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func,
WebGLTexDimensions dims); WebGLTexDimensions dims);
@@ -1285,10 +1275,6 @@ protected:
WebGLTexImageFunc func, WebGLTexImageFunc func,
WebGLTexDimensions dims); WebGLTexDimensions dims);
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
WebGLProgram* program,
const char* funcName);
void Invalidate(); void Invalidate();
void DestroyResourcesAndContext(); void DestroyResourcesAndContext();
@@ -1417,7 +1403,6 @@ protected:
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures; nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
WebGLRefPtr<WebGLProgram> mCurrentProgram; WebGLRefPtr<WebGLProgram> mCurrentProgram;
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
uint32_t mMaxFramebufferColorAttachments; uint32_t mMaxFramebufferColorAttachments;
@@ -1610,7 +1595,7 @@ WebGLContext::ValidateObjectAssumeNonNull(const char* info, ObjectType* object)
return false; return false;
if (object->IsDeleted()) { if (object->IsDeleted()) {
ErrorInvalidValue("%s: Deleted object passed as argument.", info); ErrorInvalidValue("%s: deleted object passed as argument", info);
return false; return false;
} }

View File

@@ -14,6 +14,7 @@
#include "WebGLRenderbuffer.h" #include "WebGLRenderbuffer.h"
#include "WebGLShader.h" #include "WebGLShader.h"
#include "WebGLTexture.h" #include "WebGLTexture.h"
#include "WebGLUniformInfo.h"
#include "WebGLVertexArray.h" #include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h" #include "WebGLVertexAttribData.h"
@@ -409,15 +410,11 @@ void WebGLContext::Draw_cleanup()
bool bool
WebGLContext::ValidateBufferFetching(const char* info) WebGLContext::ValidateBufferFetching(const char* info)
{ {
MOZ_ASSERT(mCurrentProgram);
// Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
MOZ_ASSERT(mActiveProgramLinkInfo);
#ifdef DEBUG #ifdef DEBUG
GLint currentProgram = 0; GLint currentProgram = 0;
MakeContextCurrent(); MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram); gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName, MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
"WebGL: current program doesn't agree with GL state"); "WebGL: current program doesn't agree with GL state");
#endif #endif
@@ -444,7 +441,7 @@ WebGLContext::ValidateBufferFetching(const char* info)
// If the attrib is not in use, then we don't have to validate // If the attrib is not in use, then we don't have to validate
// it, just need to make sure that the binding is non-null. // it, just need to make sure that the binding is non-null.
if (!mActiveProgramLinkInfo->HasActiveAttrib(i)) if (!mCurrentProgram->IsAttribInUse(i))
continue; continue;
// the base offset // the base offset
@@ -501,13 +498,12 @@ WebGLVertexAttrib0Status
WebGLContext::WhatDoesVertexAttrib0Need() WebGLContext::WhatDoesVertexAttrib0Need()
{ {
MOZ_ASSERT(mCurrentProgram); MOZ_ASSERT(mCurrentProgram);
MOZ_ASSERT(mActiveProgramLinkInfo);
// work around Mac OSX crash, see bug 631420 // work around Mac OSX crash, see bug 631420
#ifdef XP_MACOSX #ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs() && if (gl->WorkAroundDriverBugs() &&
mBoundVertexArray->IsAttribArrayEnabled(0) && mBoundVertexArray->IsAttribArrayEnabled(0) &&
!mActiveProgramLinkInfo->HasActiveAttrib(0)) !mCurrentProgram->IsAttribInUse(0))
{ {
return WebGLVertexAttrib0Status::EmulatedUninitializedArray; return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
} }
@@ -519,7 +515,7 @@ WebGLContext::WhatDoesVertexAttrib0Need()
return WebGLVertexAttrib0Status::Default; return WebGLVertexAttrib0Status::Default;
} }
return mActiveProgramLinkInfo->HasActiveAttrib(0) return mCurrentProgram->IsAttribInUse(0)
? WebGLVertexAttrib0Status::EmulatedInitializedArray ? WebGLVertexAttrib0Status::EmulatedInitializedArray
: WebGLVertexAttrib0Status::EmulatedUninitializedArray; : WebGLVertexAttrib0Status::EmulatedUninitializedArray;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1043,7 +1043,7 @@ WebGLContext::AssertCachedBindings()
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound); AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
} }
GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0; GLuint bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
// Textures // Textures

View File

@@ -22,7 +22,6 @@
#include "WebGLShader.h" #include "WebGLShader.h"
#include "WebGLTexture.h" #include "WebGLTexture.h"
#include "WebGLUniformLocation.h" #include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
#include "WebGLVertexArray.h" #include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h" #include "WebGLVertexAttribData.h"
@@ -368,6 +367,50 @@ WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
} }
} }
bool
WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char* info)
{
if (name.IsEmpty())
return false;
const uint32_t maxSize = 256;
if (name.Length() > maxSize) {
ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
" maximum allowed length of %d characters.", info,
name.Length(), maxSize);
return false;
}
if (!ValidateGLSLString(name, info))
return false;
nsString prefix1 = NS_LITERAL_STRING("webgl_");
nsString prefix2 = NS_LITERAL_STRING("_webgl_");
if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
Substring(name, 0, prefix2.Length()).Equals(prefix2))
{
ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
info);
return false;
}
return true;
}
bool WebGLContext::ValidateGLSLString(const nsAString& string, const char* info)
{
for (uint32_t i = 0; i < string.Length(); ++i) {
if (!ValidateGLSLCharacter(string.CharAt(i))) {
ErrorInvalidValue("%s: String contains the illegal character"
" '%d'.", info, string.CharAt(i));
return false;
}
}
return true;
}
/** /**
* Return true if the framebuffer attachment is valid. Attachment must * Return true if the framebuffer attachment is valid. Attachment must
* be one of depth/stencil/depth_stencil/color attachment. * be one of depth/stencil/depth_stencil/color attachment.
@@ -1469,37 +1512,163 @@ WebGLContext::ValidateTexImage(TexImageTarget texImageTarget, GLint level,
} }
bool bool
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName) WebGLContext::ValidateUniformLocation(const char* info,
WebGLUniformLocation* loc)
{ {
/* GLES 2.0.25, p38: if (!ValidateObjectAllowNull(info, loc))
* If the value of location is -1, the Uniform* commands will silently return false;
* ignore the data passed in, and the current uniform values will not be
* changed.
*/
if (!loc) if (!loc)
return false; return false;
if (!ValidateObject(funcName, loc)) // The need to check specifically for !mCurrentProgram here is explained in
return false; // bug 657556.
if (!mCurrentProgram) { if (!mCurrentProgram) {
ErrorInvalidOperation("%s: No program is currently bound.", funcName); ErrorInvalidOperation("%s: No program is currently bound.", info);
return false; return false;
} }
return loc->ValidateForProgram(mCurrentProgram, this, funcName); if (mCurrentProgram != loc->Program()) {
ErrorInvalidOperation("%s: This uniform location doesn't correspond to"
" the current program.", info);
return false;
}
if (mCurrentProgram->Generation() != loc->ProgramGeneration()) {
ErrorInvalidOperation("%s: This uniform location is obsolete since the"
" program has been relinked.", info);
return false;
}
return true;
} }
bool bool
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSize, WebGLContext::ValidateSamplerUniformSetter(const char* info,
WebGLUniformLocation* loc,
GLint value)
{
if (loc->Info().type != LOCAL_GL_SAMPLER_2D &&
loc->Info().type != LOCAL_GL_SAMPLER_CUBE)
{
return true;
}
if (value >= 0 && value < mGLMaxTextureUnits)
return true;
ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
" valid texture unit.", info, value);
return false;
}
bool
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt,
uint32_t arrayLength) uint32_t arrayLength)
{ {
if (IsContextLost()) if (IsContextLost())
return false; return false;
if (arrayLength < setterElemSize) { if (arrayLength < cnt) {
ErrorInvalidOperation("%s: Array must have >= %d elements.", name, ErrorInvalidOperation("%s: Array must be >= %d elements.", name, cnt);
setterElemSize); return false;
}
return true;
}
static bool
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
{
switch (uniformType) {
case LOCAL_GL_BOOL:
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_BOOL_VEC4:
return true; // GLfloat(0.0) sets a bool to false.
case LOCAL_GL_INT:
case LOCAL_GL_INT_SAMPLER_2D:
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_INT_SAMPLER_3D:
case LOCAL_GL_INT_SAMPLER_CUBE:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_2D_ARRAY:
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
case LOCAL_GL_SAMPLER_2D_SHADOW:
case LOCAL_GL_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
return setterType == LOCAL_GL_INT;
case LOCAL_GL_FLOAT:
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT3x2:
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4:
case LOCAL_GL_FLOAT_MAT4x2:
case LOCAL_GL_FLOAT_MAT4x3:
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_FLOAT_VEC4:
return setterType == LOCAL_GL_FLOAT;
default:
MOZ_ASSERT(false); // should never get here
return false;
}
}
static bool
CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
uint8_t setterElemSize, GLenum setterType,
const char* info)
{
if (setterElemSize != loc->ElementSize()) {
webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
loc->ElementSize());
return false;
}
if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
loc->Info().type);
return false;
}
return true;
}
static bool
CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
uint8_t setterElemSize, size_t setterArraySize,
const char* info)
{
if (setterArraySize == 0 ||
setterArraySize % setterElemSize)
{
webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
" %d, got an array of length %d.", info,
setterElemSize, setterArraySize);
return false;
}
if (!loc->Info().isArray &&
setterArraySize != setterElemSize)
{
webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
" (since this uniform is not an array"
" uniform), got an array of length %d.",
info, setterElemSize, setterArraySize);
return false; return false;
} }
@@ -1509,18 +1678,18 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
bool bool
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc, WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
uint8_t setterElemSize, GLenum setterType, uint8_t setterElemSize, GLenum setterType,
const char* funcName, GLuint* out_rawLoc) const char* info, GLuint* out_rawLoc)
{ {
if (IsContextLost()) if (IsContextLost())
return false; return false;
if (!ValidateUniformLocation(loc, funcName)) if (!ValidateUniformLocation(info, loc))
return false; return false;
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName)) if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
return false; return false;
*out_rawLoc = loc->mLoc; *out_rawLoc = loc->Location();
return true; return true;
} }
@@ -1529,24 +1698,27 @@ WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
uint8_t setterElemSize, uint8_t setterElemSize,
GLenum setterType, GLenum setterType,
size_t setterArraySize, size_t setterArraySize,
const char* funcName, const char* info,
GLuint* const out_rawLoc, GLuint* const out_rawLoc,
GLsizei* const out_numElementsToUpload) GLsizei* const out_numElementsToUpload)
{ {
if (IsContextLost()) if (IsContextLost())
return false; return false;
if (!ValidateUniformLocation(loc, funcName)) if (!ValidateUniformLocation(info, loc))
return false; return false;
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName)) if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
return false; return false;
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName)) if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
info))
{
return false; return false;
}
*out_rawLoc = loc->mLoc; *out_rawLoc = loc->Location();
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount, *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
setterArraySize / setterElemSize); setterArraySize / setterElemSize);
return true; return true;
} }
@@ -1557,7 +1729,7 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
GLenum setterType, GLenum setterType,
size_t setterArraySize, size_t setterArraySize,
bool setterTranspose, bool setterTranspose,
const char* funcName, const char* info,
GLuint* const out_rawLoc, GLuint* const out_rawLoc,
GLsizei* const out_numElementsToUpload) GLsizei* const out_numElementsToUpload)
{ {
@@ -1566,22 +1738,25 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
if (IsContextLost()) if (IsContextLost())
return false; return false;
if (!ValidateUniformLocation(loc, funcName)) if (!ValidateUniformLocation(info, loc))
return false; return false;
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName)) if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
return false; return false;
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName)) if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
return false; info))
{
if (setterTranspose) {
ErrorInvalidValue("%s: `transpose` must be false.", funcName);
return false; return false;
} }
*out_rawLoc = loc->mLoc; if (setterTranspose) {
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount, ErrorInvalidValue("%s: `transpose` must be false.", info);
return false;
}
*out_rawLoc = loc->Location();
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
setterArraySize / setterElemSize); setterArraySize / setterElemSize);
return true; return true;
} }
@@ -1920,13 +2095,15 @@ WebGLContext::InitAndValidateGL()
// Check the shader validator pref // Check the shader validator pref
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false); NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation", mShaderValidation = Preferences::GetBool("webgl.shader_validator",
mBypassShaderValidation); mShaderValidation);
// initialize shader translator // initialize shader translator
if (!ShInitialize()) { if (mShaderValidation) {
GenerateWarning("GLSL translator initialization failed!"); if (!ShInitialize()) {
return false; GenerateWarning("GLSL translator initialization failed!");
return false;
}
} }
// Mesa can only be detected with the GL_VERSION string, of the form // Mesa can only be detected with the GL_VERSION string, of the form

View File

@@ -13,6 +13,7 @@
#include "WebGLRenderbuffer.h" #include "WebGLRenderbuffer.h"
#include "WebGLShader.h" #include "WebGLShader.h"
#include "WebGLTexture.h" #include "WebGLTexture.h"
#include "WebGLUniformInfo.h"
#include "WebGLVertexArray.h" #include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h" #include "WebGLVertexAttribData.h"

View File

@@ -7,690 +7,364 @@
#include "GLContext.h" #include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h" #include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "MurmurHash3.h"
#include "WebGLContext.h" #include "WebGLContext.h"
#include "WebGLShader.h" #include "WebGLShader.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
namespace mozilla { namespace mozilla {
/* If `name`: "foo[3]" /** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]"
* Then returns true, with * in bracketPart.
* `out_baseName`: "foo" *
* `out_isArray`: true * \param string input/output: The string to split, becomes the string without
* `out_index`: 3 * the bracket part.
* * \param bracketPart output: Gets the bracket part.
* If `name`: "foo" *
* Then returns true, with * Notice that if there are multiple brackets like "foo[i].bar[j]", only the
* `out_baseName`: "foo" * last bracket is split.
* `out_isArray`: false */
* `out_index`: <not written>
*/
static bool static bool
ParseName(const nsCString& name, nsCString* const out_baseName, SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
bool* const out_isArray, size_t* const out_arrayIndex)
{ {
int32_t indexEnd = name.RFind("]"); MOZ_ASSERT(bracketPart.IsEmpty(),
if (indexEnd == -1 || "SplitLastSquareBracket must be called with empty bracketPart"
(uint32_t)indexEnd != name.Length() - 1) " string.");
{
*out_baseName = name;
*out_isArray = false;
return true;
}
int32_t indexOpenBracket = name.RFind("["); if (string.IsEmpty())
if (indexOpenBracket == -1)
return false; return false;
uint32_t indexStart = indexOpenBracket + 1; char* string_start = string.BeginWriting();
uint32_t indexLen = indexEnd - indexStart; char* s = string_start + string.Length() - 1;
if (indexLen == 0)
if (*s != ']')
return false; return false;
const nsAutoCString indexStr(Substring(name, indexStart, indexLen)); while (*s != '[' && s != string_start)
s--;
nsresult errorcode; if (*s != '[')
int32_t indexNum = indexStr.ToInteger(&errorcode);
if (NS_FAILED(errorcode))
return false; return false;
if (indexNum < 0) bracketPart.Assign(s);
return false; *s = 0;
string.EndWriting();
*out_baseName = StringHead(name, indexOpenBracket); string.SetLength(s - string_start);
*out_isArray = true;
*out_arrayIndex = indexNum;
return true; return true;
} }
static void JSObject*
AddActiveInfo(GLint elemCount, GLenum elemType, bool isArray, WebGLProgram::WrapObject(JSContext* cx) {
const nsACString& baseUserName, const nsACString& baseMappedName, return dom::WebGLProgramBinding::Wrap(cx, this);
std::vector<nsRefPtr<WebGLActiveInfo>>* activeInfoList,
std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
{
nsRefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(elemCount, elemType, isArray,
baseUserName, baseMappedName);
activeInfoList->push_back(info);
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
}
//#define DUMP_SHADERVAR_MAPPINGS
static TemporaryRef<const webgl::LinkedProgramInfo>
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
{
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
GLuint maxAttribLenWithNull = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
(GLint*)&maxAttribLenWithNull);
if (maxAttribLenWithNull < 1)
maxAttribLenWithNull = 1;
GLuint maxUniformLenWithNull = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
(GLint*)&maxUniformLenWithNull);
if (maxUniformLenWithNull < 1)
maxUniformLenWithNull = 1;
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
#endif
// Attribs
GLuint numActiveAttribs = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
(GLint*)&numActiveAttribs);
for (GLuint i = 0; i < numActiveAttribs; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxAttribLenWithNull - 1);
GLsizei lengthWithoutNull = 0;
GLint elemCount = 0; // `size`
GLenum elemType = 0; // `type`
gl->fGetActiveAttrib(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
&elemCount, &elemType, mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
// Collect ActiveInfos:
// Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
// path.
nsDependentCString userName;
if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
userName.Rebind(mappedName, 0);
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
userName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
#endif
const bool isArray = false;
AddActiveInfo(elemCount, elemType, isArray, userName, mappedName,
&info->activeAttribs, &info->attribMap);
// Collect active locations:
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
if (loc == -1)
MOZ_CRASH("Active attrib has no location.");
info->activeAttribLocs.insert(loc);
}
// Uniforms
const bool needsCheckForArrays = true;
GLuint numActiveUniforms = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
(GLint*)&numActiveUniforms);
for (GLuint i = 0; i < numActiveUniforms; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxUniformLenWithNull - 1);
GLsizei lengthWithoutNull = 0;
GLint elemCount = 0; // `size`
GLenum elemType = 0; // `type`
gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
&elemCount, &elemType, mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
nsAutoCString baseMappedName;
bool isArray;
size_t arrayIndex;
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
MOZ_CRASH("Failed to parse `mappedName` received from driver.");
// Note that for good drivers, `isArray` should already be correct.
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
nsAutoCString baseUserName;
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
baseUserName = baseMappedName;
if (needsCheckForArrays && !isArray) {
// By GLES 3, GetUniformLocation("foo[0]") should return -1 if `foo` is
// not an array. Our current linux Try slaves return the location of `foo`
// anyways, though.
std::string mappedName = baseMappedName.BeginReading();
mappedName += "[0]";
GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedName.c_str());
if (loc != -1)
isArray = true;
}
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
(int)isArray, baseMappedName.BeginReading(),
baseUserName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
AddActiveInfo(elemCount, elemType, isArray, baseUserName, baseMappedName,
&info->activeUniforms, &info->uniformMap);
}
return info.forget();
}
////////////////////////////////////////////////////////////////////////////////
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* aProg)
: prog(aProg)
{ }
////////////////////////////////////////////////////////////////////////////////
// WebGLProgram
static GLuint
CreateProgram(gl::GLContext* gl)
{
gl->MakeCurrent();
return gl->fCreateProgram();
} }
WebGLProgram::WebGLProgram(WebGLContext* webgl) WebGLProgram::WebGLProgram(WebGLContext* webgl)
: WebGLContextBoundObject(webgl) : WebGLContextBoundObject(webgl)
, mGLName(CreateProgram(webgl->GL())) , mLinkStatus(false)
, mGeneration(0)
, mIdentifierMap(new CStringMap)
, mIdentifierReverseMap(new CStringMap)
, mUniformInfoMap(new CStringToUniformInfoMap)
, mAttribMaxNameLength(0)
{ {
mContext->MakeContextCurrent();
mGLName = mContext->gl->fCreateProgram();
mContext->mPrograms.insertBack(this); mContext->mPrograms.insertBack(this);
} }
void void
WebGLProgram::Delete() WebGLProgram::Delete()
{ {
gl::GLContext* gl = mContext->GL(); DetachShaders();
mContext->MakeContextCurrent();
gl->MakeCurrent(); mContext->gl->fDeleteProgram(mGLName);
gl->fDeleteProgram(mGLName);
mVertShader = nullptr;
mFragShader = nullptr;
mMostRecentLinkInfo = nullptr;
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms); LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
} }
//////////////////////////////////////////////////////////////////////////////// bool
// GL funcs
void
WebGLProgram::AttachShader(WebGLShader* shader) WebGLProgram::AttachShader(WebGLShader* shader)
{ {
WebGLRefPtr<WebGLShader>* shaderSlot; if (ContainsShader(shader))
switch (shader->mType) { return false;
case LOCAL_GL_VERTEX_SHADER:
shaderSlot = &mVertShader;
break;
case LOCAL_GL_FRAGMENT_SHADER:
shaderSlot = &mFragShader;
break;
default:
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
return;
}
if (*shaderSlot) { mAttachedShaders.AppendElement(shader);
if (shader == *shaderSlot) {
mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
} else {
mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
" shader may be attached to a program.");
}
return;
}
*shaderSlot = shader;
mContext->MakeContextCurrent(); mContext->MakeContextCurrent();
mContext->gl->fAttachShader(mGLName, shader->mGLName); mContext->gl->fAttachShader(GLName(), shader->GLName());
}
void
WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
{
if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
return;
if (loc >= mContext->MaxVertexAttribs()) {
mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
" MAX_VERTEX_ATTRIBS.");
return;
}
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
" name that starts with 'gl_'.");
return;
}
NS_LossyConvertUTF16toASCII asciiName(name);
auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
const bool wasInserted = res.second;
if (!wasInserted) {
auto itr = res.first;
itr->second = loc;
}
}
void
WebGLProgram::DetachShader(WebGLShader* shader)
{
MOZ_ASSERT(shader);
WebGLRefPtr<WebGLShader>* shaderSlot;
switch (shader->mType) {
case LOCAL_GL_VERTEX_SHADER:
shaderSlot = &mVertShader;
break;
case LOCAL_GL_FRAGMENT_SHADER:
shaderSlot = &mFragShader;
break;
default:
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
return;
}
if (*shaderSlot != shader) {
mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
return;
}
*shaderSlot = nullptr;
mContext->MakeContextCurrent();
mContext->gl->fDetachShader(mGLName, shader->mGLName);
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetActiveAttrib(GLuint index) const
{
if (!mMostRecentLinkInfo) {
nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
return ret.forget();
}
const auto& activeList = mMostRecentLinkInfo->activeAttribs;
if (index >= activeList.size()) {
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
index, "ACTIVE_ATTRIBS", activeList.size());
return nullptr;
}
nsRefPtr<WebGLActiveInfo> ret = activeList[index];
return ret.forget();
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetActiveUniform(GLuint index) const
{
if (!mMostRecentLinkInfo) {
nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
return ret.forget();
}
const auto& activeList = mMostRecentLinkInfo->activeUniforms;
if (index >= activeList.size()) {
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
index, "ACTIVE_UNIFORMS", activeList.size());
return nullptr;
}
nsRefPtr<WebGLActiveInfo> ret = activeList[index];
return ret.forget();
}
void
WebGLProgram::GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const
{
out->TruncateLength(0);
if (mVertShader)
out->AppendElement(mVertShader);
if (mFragShader)
out->AppendElement(mFragShader);
}
GLint
WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getAttribLocation"))
return -1;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getAttribLocation: `program` must be linked.");
return -1;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
const WebGLActiveInfo* info;
if (!LinkInfo()->FindAttrib(userName, &info))
return -1;
const nsCString& mappedName = info->mBaseMappedName;
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
}
void
WebGLProgram::GetProgramInfoLog(nsAString* const out) const
{
CopyASCIItoUTF16(mLinkLog, *out);
}
static GLint
GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname)
{
GLint ret = 0;
gl->fGetProgramiv(program, pname, &ret);
return ret;
}
JS::Value
WebGLProgram::GetProgramParameter(GLenum pname) const
{
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
}
}
switch (pname) {
case LOCAL_GL_ATTACHED_SHADERS:
case LOCAL_GL_ACTIVE_UNIFORMS:
case LOCAL_GL_ACTIVE_ATTRIBUTES:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_DELETE_STATUS:
return JS::BooleanValue(IsDeleteRequested());
case LOCAL_GL_LINK_STATUS:
return JS::BooleanValue(IsLinked());
case LOCAL_GL_VALIDATE_STATUS:
#ifdef XP_MACOSX
// See comment in ValidateProgram.
if (gl->WorkAroundDriverBugs())
return JS::BooleanValue(true);
#endif
return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
default:
mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
pname);
return JS::NullValue();
}
}
already_AddRefed<WebGLUniformLocation>
WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
return nullptr;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
return nullptr;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
nsDependentCString baseUserName;
bool isArray;
size_t arrayIndex;
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
return nullptr;
const WebGLActiveInfo* activeInfo;
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
return nullptr;
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
nsAutoCString mappedName(baseMappedName);
if (isArray) {
mappedName.AppendLiteral("[");
mappedName.AppendInt(uint32_t(arrayIndex));
mappedName.AppendLiteral("]");
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
if (loc == -1)
return nullptr;
nsRefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
loc, activeInfo);
return locObj.forget();
}
bool
WebGLProgram::LinkProgram()
{
mContext->InvalidateBufferFetching(); // we do it early in this function
// as some of the validation below changes program state
mLinkLog.Truncate();
mMostRecentLinkInfo = nullptr;
if (!mVertShader || !mVertShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
if (!mFragShader || !mFragShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
// Bug 777028: Mesa can't handle more than 16 samplers per program,
// counting each array entry.
size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
mFragShader->CalcNumSamplerUniforms();
if (gl->WorkAroundDriverBugs() &&
mContext->mIsMesa &&
numSamplerUniforms_upperBound > 16)
{
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
" Mesa drivers to avoid crashing.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
// Bind the attrib locations.
// This can't be done trivially, because we have to deal with mapped attrib names.
for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
const nsCString& name = itr->first;
GLuint index = itr->second;
mVertShader->BindAttribLocation(mGLName, name, index);
}
if (LinkAndUpdate())
return true;
// Failed link.
if (mContext->ShouldGenerateWarnings()) {
// report shader/program infoLogs as warnings.
// note that shader compilation errors can be deferred to linkProgram,
// which is why we can't do anything in compileShader. In practice we could
// report in compileShader the translation errors generated by ANGLE,
// but it seems saner to keep a single way of obtaining shader infologs.
if (!mLinkLog.IsEmpty()) {
mContext->GenerateWarning("linkProgram: Failed to link, leaving the following"
" log:\n%s\n",
mLinkLog.BeginReading());
}
}
return false;
}
bool
WebGLProgram::UseProgram() const
{
if (!mMostRecentLinkInfo) {
mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
" linked.");
return false;
}
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching();
mContext->gl->fUseProgram(mGLName);
return true; return true;
} }
void
WebGLProgram::ValidateProgram() const
{
mContext->MakeContextCurrent();
gl::GLContext* gl = mContext->gl;
#ifdef XP_MACOSX
// See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
// with Mac OS 10.6.7.
if (gl->WorkAroundDriverBugs()) {
mContext->GenerateWarning("validateProgram: Implemented as a no-op on"
" Mac to work around crashes.");
return;
}
#endif
gl->fValidateProgram(mGLName);
}
////////////////////////////////////////////////////////////////////////////////
bool bool
WebGLProgram::LinkAndUpdate() WebGLProgram::DetachShader(WebGLShader* shader)
{ {
mMostRecentLinkInfo = nullptr; if (!mAttachedShaders.RemoveElement(shader))
gl::GLContext* gl = mContext->gl;
gl->fLinkProgram(mGLName);
// Grab the program log.
GLuint logLenWithNull = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
if (logLenWithNull > 1) {
mLinkLog.SetLength(logLenWithNull - 1);
gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
} else {
mLinkLog.SetLength(0);
}
GLint ok = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
if (!ok)
return false; return false;
mMostRecentLinkInfo = QueryProgramInfo(this, gl); mContext->MakeContextCurrent();
mContext->gl->fDetachShader(GLName(), shader->GLName());
MOZ_ASSERT(mMostRecentLinkInfo); return true;
if (!mMostRecentLinkInfo)
mLinkLog.AssignLiteral("Failed to gather program info.");
return mMostRecentLinkInfo;
} }
bool bool
WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName, WebGLProgram::HasAttachedShaderOfType(GLenum shaderType)
nsDependentCString* const out_userName) const
{ {
if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName)) for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
return true; if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType)
return true;
}
return false; return false;
} }
bool bool
WebGLProgram::FindUniformByMappedName(const nsACString& mappedName, WebGLProgram::HasBadShaderAttached()
nsCString* const out_userName,
bool* const out_isArray) const
{ {
if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray)) for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
return true; if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus())
return true;
if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray)) }
return true;
return false; return false;
} }
//////////////////////////////////////////////////////////////////////////////// size_t
WebGLProgram::UpperBoundNumSamplerUniforms()
JSObject*
WebGLProgram::WrapObject(JSContext* js)
{ {
return dom::WebGLProgramBinding::Wrap(js, this); size_t numSamplerUniforms = 0;
for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
const WebGLShader* shader = mAttachedShaders[i];
if (!shader)
continue;
for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
WebGLUniformInfo u = shader->mUniformInfos[j];
if (u.type == LOCAL_GL_SAMPLER_2D ||
u.type == LOCAL_GL_SAMPLER_CUBE)
{
numSamplerUniforms += u.arraySize;
}
}
}
return numSamplerUniforms;
} }
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader) void
WebGLProgram::MapIdentifier(const nsACString& name,
nsCString* const out_mappedName)
{
MOZ_ASSERT(mIdentifierMap);
nsCString mutableName(name);
nsCString bracketPart;
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
if (hadBracketPart)
mutableName.AppendLiteral("[0]");
if (mIdentifierMap->Get(mutableName, out_mappedName)) {
if (hadBracketPart) {
nsCString mappedBracketPart;
bool mappedHadBracketPart = SplitLastSquareBracket(*out_mappedName,
mappedBracketPart);
if (mappedHadBracketPart)
out_mappedName->Append(bracketPart);
}
return;
}
// Not found? We might be in the situation we have a uniform array name and
// the GL's glGetActiveUniform returned its name without [0], as is allowed
// by desktop GL but not in ES. Let's then try with [0].
mutableName.AppendLiteral("[0]");
if (mIdentifierMap->Get(mutableName, out_mappedName))
return;
/* Not found? Return name unchanged. This case happens e.g. on bad user
* input, or when we're not using identifier mapping, or if we didn't store
* an identifier in the map because e.g. its mapping is trivial. (as happens
* for short identifiers)
*/
out_mappedName->Assign(name);
}
void
WebGLProgram::ReverseMapIdentifier(const nsACString& name,
nsCString* const out_reverseMappedName)
{
MOZ_ASSERT(mIdentifierReverseMap);
nsCString mutableName(name);
nsCString bracketPart;
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
if (hadBracketPart)
mutableName.AppendLiteral("[0]");
if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName)) {
if (hadBracketPart) {
nsCString reverseMappedBracketPart;
bool reverseMappedHadBracketPart = SplitLastSquareBracket(*out_reverseMappedName,
reverseMappedBracketPart);
if (reverseMappedHadBracketPart)
out_reverseMappedName->Append(bracketPart);
}
return;
}
// Not found? We might be in the situation we have a uniform array name and
// the GL's glGetActiveUniform returned its name without [0], as is allowed
// by desktop GL but not in ES. Let's then try with [0].
mutableName.AppendLiteral("[0]");
if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName))
return;
/* Not found? Return name unchanged. This case happens e.g. on bad user
* input, or when we're not using identifier mapping, or if we didn't store
* an identifier in the map because e.g. its mapping is trivial. (as happens
* for short identifiers)
*/
out_reverseMappedName->Assign(name);
}
WebGLUniformInfo
WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name)
{
MOZ_ASSERT(mUniformInfoMap);
nsCString mutableName(name);
nsCString bracketPart;
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
// If there is a bracket, we're either an array or an entry in an array.
if (hadBracketPart)
mutableName.AppendLiteral("[0]");
WebGLUniformInfo info;
mUniformInfoMap->Get(mutableName, &info);
// We don't check if that Get failed, as if it did, it left info with
// default values.
return info;
}
bool
WebGLProgram::UpdateInfo()
{
mAttribMaxNameLength = 0;
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
mAttribMaxNameLength = std::max(mAttribMaxNameLength,
mAttachedShaders[i]->mAttribMaxNameLength);
}
GLint attribCount;
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
mContext->ErrorOutOfMemory("updateInfo: Out of memory to allocate %d"
" attribs.", mContext->mGLMaxVertexAttribs);
return false;
}
for (size_t i = 0; i < mAttribsInUse.Length(); i++)
mAttribsInUse[i] = false;
nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
for (int i = 0; i < attribCount; ++i) {
GLint attrnamelen;
GLint attrsize;
GLenum attrtype;
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength,
&attrnamelen, &attrsize, &attrtype,
nameBuf);
if (attrnamelen > 0) {
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
MOZ_ASSERT(loc >= 0, "Major oops in managing the attributes of a"
" WebGL program.");
if (loc < mContext->mGLMaxVertexAttribs) {
mAttribsInUse[loc] = true;
} else {
mContext->GenerateWarning("Program exceeds MAX_VERTEX_ATTRIBS.");
return false;
}
}
}
// nsAutoPtr will delete old version first
mIdentifierMap = new CStringMap;
mIdentifierReverseMap = new CStringMap;
mUniformInfoMap = new CStringToUniformInfoMap;
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
// Loop through ATTRIBUTES
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
// FORWARD MAPPING
mIdentifierMap->Put(attrib.original, attrib.mapped);
// REVERSE MAPPING
mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
}
// Loop through UNIFORMS
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
// Add the uniforms name mapping to mIdentifier[Reverse]Map
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
// FOWARD MAPPING
mIdentifierMap->Put(uniform.original, uniform.mapped);
// REVERSE MAPPING
mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
// Add uniform info to mUniformInfoMap
const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
mUniformInfoMap->Put(uniform.mapped, info);
}
}
mActiveAttribMap.clear();
GLint numActiveAttrs = 0;
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
// Spec says the maximum attrib name length is 256 chars, so this is
// sufficient to hold any attrib name.
char attrName[257];
GLint dummySize;
GLenum dummyType;
for (GLint i = 0; i < numActiveAttrs; i++) {
mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
&dummyType, attrName);
GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
MOZ_ASSERT(attrLoc >= 0);
mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
}
return true;
}
/*static*/ uint64_t
WebGLProgram::IdentifierHashFunction(const char* ident, size_t size)
{
uint64_t outhash[2];
// NB: we use the x86 function everywhere, even though it's suboptimal perf
// on x64. They return different results; not sure if that's a requirement.
MurmurHash3_x86_128(ident, size, 0, &outhash[0]);
return outhash[0];
}
/*static*/ void
WebGLProgram::HashMapIdentifier(const nsACString& name,
nsCString* const out_hashedName)
{
uint64_t hash = IdentifierHashFunction(name.BeginReading(), name.Length());
out_hashedName->Truncate();
// This MUST MATCH HASHED_NAME_PREFIX from
// angle/src/compiler/translator/HashNames.h .
out_hashedName->AppendPrintf("webgl_%llx", hash);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)

View File

@@ -9,74 +9,19 @@
#include <map> #include <map>
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/LinkedList.h" #include "mozilla/LinkedList.h"
#include "nsString.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include <set>
#include <vector>
#include "WebGLObjectModel.h" #include "WebGLObjectModel.h"
#include "WebGLShader.h" #include "WebGLShader.h"
#include "WebGLUniformInfo.h"
namespace mozilla { namespace mozilla {
class WebGLActiveInfo;
class WebGLProgram;
class WebGLUniformLocation;
namespace webgl {
struct LinkedProgramInfo MOZ_FINAL
: public RefCounted<LinkedProgramInfo>
, public SupportsWeakPtr<LinkedProgramInfo>
{
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
WebGLProgram* const prog;
std::vector<nsRefPtr<WebGLActiveInfo>> activeAttribs;
std::vector<nsRefPtr<WebGLActiveInfo>> activeUniforms;
// Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
// user-facing `GLActiveInfo::name`s, without any final "[0]".
std::map<nsCString, const WebGLActiveInfo*> attribMap;
std::map<nsCString, const WebGLActiveInfo*> uniformMap;
// Needed for draw call validation.
std::set<GLuint> activeAttribLocs;
explicit LinkedProgramInfo(WebGLProgram* aProg);
bool FindAttrib(const nsCString& baseUserName,
const WebGLActiveInfo** const out_activeInfo) const
{
auto itr = attribMap.find(baseUserName);
if (itr == attribMap.end())
return false;
*out_activeInfo = itr->second;
return true;
}
bool FindUniform(const nsCString& baseUserName,
const WebGLActiveInfo** const out_activeInfo) const
{
auto itr = uniformMap.find(baseUserName);
if (itr == uniformMap.end())
return false;
*out_activeInfo = itr->second;
return true;
}
bool HasActiveAttrib(GLuint loc) const {
auto itr = activeAttribLocs.find(loc);
return itr != activeAttribLocs.end();
}
};
} // namespace webgl
class WebGLShader; class WebGLShader;
struct WebGLUniformInfo;
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap; typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
typedef nsDataHashtable<nsCStringHashKey,
WebGLUniformInfo> CStringToUniformInfoMap;
class WebGLProgram MOZ_FINAL class WebGLProgram MOZ_FINAL
: public nsWrapperCache : public nsWrapperCache
@@ -85,64 +30,107 @@ class WebGLProgram MOZ_FINAL
, public WebGLContextBoundObject , public WebGLContextBoundObject
{ {
public: public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
explicit WebGLProgram(WebGLContext* webgl); explicit WebGLProgram(WebGLContext* webgl);
void Delete(); void Delete();
// GL funcs void DetachShaders() {
void AttachShader(WebGLShader* shader); mAttachedShaders.Clear();
void BindAttribLocation(GLuint index, const nsAString& name);
void DetachShader(WebGLShader* shader);
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(GLuint index) const;
already_AddRefed<WebGLActiveInfo> GetActiveUniform(GLuint index) const;
void GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const;
GLint GetAttribLocation(const nsAString& name) const;
void GetProgramInfoLog(nsAString* const out) const;
JS::Value GetProgramParameter(GLenum pname) const;
already_AddRefed<WebGLUniformLocation> GetUniformLocation(const nsAString& name) const;
bool LinkProgram();
bool UseProgram() const;
void ValidateProgram() const;
////////////////
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
nsDependentCString* const out_userName) const;
bool FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool IsLinked() const { return mMostRecentLinkInfo; }
const webgl::LinkedProgramInfo* LinkInfo() const {
return mMostRecentLinkInfo.get();
} }
GLuint GLName() { return mGLName; }
const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const {
return mAttachedShaders;
}
bool LinkStatus() { return mLinkStatus; }
uint32_t Generation() const { return mGeneration.value(); }
void SetLinkStatus(bool val) { mLinkStatus = val; }
bool ContainsShader(WebGLShader* shader) {
return mAttachedShaders.Contains(shader);
}
// return true if the shader wasn't already attached
bool AttachShader(WebGLShader* shader);
// return true if the shader was found and removed
bool DetachShader(WebGLShader* shader);
bool HasAttachedShaderOfType(GLenum shaderType);
bool HasBothShaderTypesAttached() {
return HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) &&
HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
}
bool HasBadShaderAttached();
size_t UpperBoundNumSamplerUniforms();
bool NextGeneration() {
if (!(mGeneration + 1).isValid())
return false; // must exit without changing mGeneration
++mGeneration;
return true;
}
// Called only after LinkProgram
bool UpdateInfo();
// Getters for cached program info
bool IsAttribInUse(uint32_t i) const { return mAttribsInUse[i]; }
// Maps identifier |name| to the mapped identifier |*mappedName|
// Both are ASCII strings.
void MapIdentifier(const nsACString& name, nsCString* out_mappedName);
// Un-maps mapped identifier |name| to the original identifier
// |*reverseMappedName|.
// Both are ASCII strings.
void ReverseMapIdentifier(const nsACString& name,
nsCString* out_reverseMappedName);
/* Returns the uniform array size (or 1 if the uniform is not an array) of
* the uniform with given mapped identifier.
*
* Note: The input string |name| is the mapped identifier, not the original
* identifier.
*/
WebGLUniformInfo GetUniformInfoForMappedIdentifier(const nsACString& name);
WebGLContext* GetParentObject() const { WebGLContext* GetParentObject() const {
return Context(); return Context();
} }
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE; virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
private: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
// public post-link data
std::map<GLint, nsCString> mActiveAttribMap;
static uint64_t IdentifierHashFunction(const char* ident, size_t size);
static void HashMapIdentifier(const nsACString& name,
nsCString* const out_hashedName);
protected:
~WebGLProgram() { ~WebGLProgram() {
DeleteOnce(); DeleteOnce();
} }
bool LinkAndUpdate(); GLuint mGLName;
bool mLinkStatus;
// attached shaders of the program object
nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
CheckedUint32 mGeneration;
public: // post-link data
const GLuint mGLName; FallibleTArray<bool> mAttribsInUse;
nsAutoPtr<CStringMap> mIdentifierMap, mIdentifierReverseMap;
private: nsAutoPtr<CStringToUniformInfoMap> mUniformInfoMap;
WebGLRefPtr<WebGLShader> mVertShader; int mAttribMaxNameLength;
WebGLRefPtr<WebGLShader> mFragShader;
std::map<nsCString, GLuint> mBoundAttribLocs;
nsCString mLinkLog;
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
}; };
} // namespace mozilla } // namespace mozilla

View File

@@ -9,376 +9,53 @@
#include "GLContext.h" #include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h" #include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "WebGLContext.h" #include "WebGLContext.h"
#include "WebGLObjectModel.h" #include "WebGLObjectModel.h"
#include "WebGLShaderValidator.h"
#include "WebGLValidateStrings.h"
namespace mozilla { namespace mozilla {
// On success, writes to out_validator and out_translatedSource. JSObject*
// On failure, writes to out_translationLog. WebGLShader::WrapObject(JSContext* cx) {
static bool return dom::WebGLShaderBinding::Wrap(cx, this);
Translate(const nsACString& source, webgl::ShaderValidator* validator,
nsACString* const out_translationLog, nsACString* const out_translatedSource)
{
if (!validator->ValidateAndTranslate(source.BeginReading())) {
validator->GetInfoLog(out_translationLog);
return false;
}
// Success
validator->GetOutput(out_translatedSource);
return true;
}
template<size_t N>
static bool
SubstringStartsWith(const std::string& testStr, size_t offset, const char (& refStr)[N])
{
for (size_t i = 0; i < N-1; i++) {
if (testStr[offset + i] != refStr[i])
return false;
}
return true;
}
/* On success, writes to out_translatedSource.
* On failure, writes to out_translationLog.
*
* Requirements:
* #version is either omitted, `#version 100`, or `version 300 es`.
*/
static bool
TranslateWithoutValidation(const nsACString& sourceNS, bool isWebGL2,
nsACString* const out_translationLog,
nsACString* const out_translatedSource)
{
std::string source = sourceNS.BeginReading();
size_t versionStrStart = source.find("#version");
size_t versionStrLen;
uint32_t glesslVersion;
if (versionStrStart != std::string::npos) {
static const char versionStr100[] = "#version 100\n";
static const char versionStr300es[] = "#version 300 es\n";
if (isWebGL2 && SubstringStartsWith(source, versionStrStart, versionStr300es)) {
glesslVersion = 300;
versionStrLen = strlen(versionStr300es);
} else if (SubstringStartsWith(source, versionStrStart, versionStr100)) {
glesslVersion = 100;
versionStrLen = strlen(versionStr100);
} else {
nsPrintfCString error("#version, if declared, must be %s.",
isWebGL2 ? "`100` or `300 es`"
: "`100`");
*out_translationLog = error;
return false;
}
} else {
versionStrStart = 0;
versionStrLen = 0;
glesslVersion = 100;
}
std::string reversionedSource = source;
reversionedSource.erase(versionStrStart, versionStrLen);
switch (glesslVersion) {
case 100:
break;
case 300:
reversionedSource.insert(versionStrStart, "#version 330\n");
break;
default:
MOZ_CRASH("Bad `glesslVersion`.");
}
out_translatedSource->Assign(reversionedSource.c_str(),
reversionedSource.length());
return true;
}
static void
GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader, bool* const out_success,
nsACString* const out_log)
{
GLint compileStatus = LOCAL_GL_FALSE;
gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
// It's simpler if we always get the log.
GLint lenWithNull = 0;
gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
if (lenWithNull > 1) {
// SetLength takes the length without the null.
out_log->SetLength(lenWithNull - 1);
gl->fGetShaderInfoLog(shader, lenWithNull, nullptr, out_log->BeginWriting());
} else {
out_log->SetLength(0);
}
*out_success = (compileStatus == LOCAL_GL_TRUE);
}
////////////////////////////////////////////////////////////////////////////////
static GLuint
CreateShader(gl::GLContext* gl, GLenum type)
{
gl->MakeCurrent();
return gl->fCreateShader(type);
} }
WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type) WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
: WebGLContextBoundObject(webgl) : WebGLContextBoundObject(webgl)
, mGLName(CreateShader(webgl->GL(), type))
, mType(type) , mType(type)
, mNeedsTranslation(true)
, mAttribMaxNameLength(0)
, mCompileStatus(false)
{ {
mContext->MakeContextCurrent();
mGLName = mContext->gl->fCreateShader(mType);
mContext->mShaders.insertBack(this); mContext->mShaders.insertBack(this);
} }
WebGLShader::~WebGLShader()
{
DeleteOnce();
}
void
WebGLShader::ShaderSource(const nsAString& source)
{
StripComments stripComments(source);
const nsAString& cleanSource = Substring(stripComments.result().Elements(),
stripComments.length());
if (!ValidateGLSLString(cleanSource, mContext, "shaderSource"))
return;
// We checked that the source stripped of comments is in the
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
if (mContext->gl->WorkAroundDriverBugs()) {
const size_t maxSourceLength = 0x3ffff;
if (sourceCString.Length() > maxSourceLength) {
mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
" characters. (Driver workaround)",
maxSourceLength);
return;
}
}
// HACK - dump shader source
{
/*
printf_stderr("//-*- glsl -*-\n");
// Wow - Roll Your Own For Each Lines because printf_stderr has a hard-coded internal size, so long strings are truncated.
const nsString& src = shader->Source();
int32_t start = 0;
int32_t end = src.Find("\n", false, start, -1);
while (end > -1) {
printf_stderr("%s\n", NS_ConvertUTF16toUTF8(nsDependentSubstring(src, start, end - start)).get());
start = end + 1;
end = src.Find("\n", false, start, -1);
}
printf_stderr("//\n");
*/
}
// HACK
mSource = source;
mCleanSource = sourceCString;
}
void
WebGLShader::CompileShader()
{
mValidator = nullptr;
mTranslationSuccessful = false;
mCompilationSuccessful = false;
gl::GLContext* gl = mContext->gl;
mValidator.reset(mContext->CreateShaderValidator(mType));
bool success;
if (mValidator) {
success = Translate(mCleanSource, mValidator.get(), &mValidationLog,
&mTranslatedSource);
} else {
success = TranslateWithoutValidation(mCleanSource, mContext->IsWebGL2(),
&mValidationLog, &mTranslatedSource);
}
if (!success)
return;
mTranslationSuccessful = true;
gl->MakeCurrent();
const char* const parts[] = {
mTranslatedSource.BeginReading()
};
gl->fShaderSource(mGLName, ArrayLength(parts), parts, nullptr);
gl->fCompileShader(mGLName);
GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful, &mCompilationLog);
}
void
WebGLShader::GetShaderInfoLog(nsAString* out) const
{
const nsCString& log = !mTranslationSuccessful ? mValidationLog
: mCompilationLog;
CopyASCIItoUTF16(log, *out);
}
JS::Value
WebGLShader::GetShaderParameter(GLenum pname) const
{
switch (pname) {
case LOCAL_GL_SHADER_TYPE:
return JS::NumberValue(mType);
case LOCAL_GL_DELETE_STATUS:
return JS::BooleanValue(IsDeleteRequested());
case LOCAL_GL_COMPILE_STATUS:
return JS::BooleanValue(mCompilationSuccessful);
default:
mContext->ErrorInvalidEnumInfo("getShaderParameter: `pname`", pname);
return JS::NullValue();
}
}
void
WebGLShader::GetShaderSource(nsAString* out) const
{
out->SetIsVoid(false);
*out = mSource;
}
void
WebGLShader::GetShaderTranslatedSource(nsAString* out) const
{
if (!mCompilationSuccessful) {
mContext->ErrorInvalidOperation("getShaderTranslatedSource: Shader has"
" not been successfully compiled.");
return;
}
out->SetIsVoid(false);
CopyASCIItoUTF16(mTranslatedSource, *out);
}
////////////////////////////////////////////////////////////////////////////////
bool
WebGLShader::CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const
{
if (!mValidator)
return true;
return mValidator->CanLinkTo(prev->mValidator.get(), out_log);
}
size_t
WebGLShader::CalcNumSamplerUniforms() const
{
if (mValidator)
return mValidator->CalcNumSamplerUniforms();
// TODO
return 0;
}
void
WebGLShader::BindAttribLocation(GLuint prog, const nsCString& userName,
GLuint index) const
{
std::string userNameStr(userName.BeginReading());
const std::string* mappedNameStr = &userNameStr;
if (mValidator)
mValidator->FindAttribMappedNameByUserName(userNameStr, &mappedNameStr);
mContext->gl->fBindAttribLocation(prog, index, mappedNameStr->c_str());
}
bool
WebGLShader::FindAttribUserNameByMappedName(const nsACString& mappedName,
nsDependentCString* const out_userName) const
{
if (!mValidator)
return false;
const std::string mappedNameStr(mappedName.BeginReading());
const std::string* userNameStr;
if (!mValidator->FindAttribUserNameByMappedName(mappedNameStr, &userNameStr))
return false;
out_userName->Rebind(userNameStr->c_str());
return true;
}
bool
WebGLShader::FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
if (!mValidator)
return false;
const std::string mappedNameStr(mappedName.BeginReading(), mappedName.Length());
std::string userNameStr;
if (!mValidator->FindUniformByMappedName(mappedNameStr, &userNameStr, out_isArray))
return false;
*out_userName = userNameStr.c_str();
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Boilerplate
JSObject*
WebGLShader::WrapObject(JSContext* js)
{
return dom::WebGLShaderBinding::Wrap(js, this);
}
size_t
WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
{
size_t validatorSize = mValidator ? mallocSizeOf(mValidator.get())
: 0;
return mallocSizeOf(this) +
mSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
mCleanSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
validatorSize +
mValidationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
mTranslatedSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
mCompilationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
}
void void
WebGLShader::Delete() WebGLShader::Delete()
{ {
gl::GLContext* gl = mContext->GL(); mSource.Truncate();
mTranslationLog.Truncate();
gl->MakeCurrent(); mContext->MakeContextCurrent();
gl->fDeleteShader(mGLName); mContext->gl->fDeleteShader(mGLName);
LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders); LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders);
} }
size_t
WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(this) +
mSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
mTranslationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
}
void
WebGLShader::SetTranslationSuccess()
{
mTranslationLog.SetIsVoid(true);
mNeedsTranslation = false;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)

View File

@@ -6,17 +6,25 @@
#ifndef WEBGL_SHADER_H_ #ifndef WEBGL_SHADER_H_
#define WEBGL_SHADER_H_ #define WEBGL_SHADER_H_
#include "GLDefs.h"
#include "mozilla/LinkedList.h" #include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include "WebGLObjectModel.h" #include "WebGLObjectModel.h"
#include "WebGLUniformInfo.h"
namespace mozilla { namespace mozilla {
namespace webgl { struct WebGLMappedIdentifier
class ShaderValidator; {
} // namespace webgl // ASCII strings
nsCString original;
nsCString mapped;
WebGLMappedIdentifier(const nsACString& o, const nsACString& m)
: original(o)
, mapped(m)
{}
};
class WebGLShader MOZ_FINAL class WebGLShader MOZ_FINAL
: public nsWrapperCache : public nsWrapperCache
@@ -30,57 +38,67 @@ class WebGLShader MOZ_FINAL
public: public:
WebGLShader(WebGLContext* webgl, GLenum type); WebGLShader(WebGLContext* webgl, GLenum type);
protected: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
~WebGLShader();
public: GLuint GLName() { return mGLName; }
// GL funcs sh::GLenum ShaderType() { return mType; }
void CompileShader();
JS::Value GetShaderParameter(GLenum pname) const;
void GetShaderInfoLog(nsAString* out) const;
void GetShaderSource(nsAString* out) const;
void GetShaderTranslatedSource(nsAString* out) const;
void ShaderSource(const nsAString& source);
// Util funcs void SetSource(const nsAString& src) {
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const; // TODO: Do some quick gzip here maybe? Getting this will be very rare,
size_t CalcNumSamplerUniforms() const; // and we have to keep it forever.
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const; mSource.Assign(src);
bool FindAttribUserNameByMappedName(const nsACString& mappedName, }
nsDependentCString* const out_userName) const;
bool FindUniformByMappedName(const nsACString& mappedName, const nsString& Source() const { return mSource; }
nsCString* const out_userName,
bool* const out_isArray) const; void SetNeedsTranslation() { mNeedsTranslation = true; }
bool NeedsTranslation() const { return mNeedsTranslation; }
bool IsCompiled() const {
return mTranslationSuccessful && mCompilationSuccessful; void SetCompileStatus (bool status) {
mCompileStatus = status;
} }
// Other funcs
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
void Delete(); void Delete();
WebGLContext* GetParentObject() const { return Context(); } bool CompileStatus() const {
return mCompileStatus;
}
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE; void SetTranslationSuccess();
void SetTranslationFailure(const nsCString& msg) {
mTranslationLog.Assign(msg);
}
const nsCString& TranslationLog() const { return mTranslationLog; }
const nsString& TranslatedSource() const { return mTranslatedSource; }
WebGLContext* GetParentObject() const {
return Context();
}
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader) NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
public:
const GLuint mGLName;
const GLenum mType;
protected: protected:
~WebGLShader() {
DeleteOnce();
}
GLuint mGLName;
GLenum mType;
nsString mSource; nsString mSource;
nsCString mCleanSource; nsString mTranslatedSource;
nsCString mTranslationLog; // The translation log should contain only ASCII characters
UniquePtr<webgl::ShaderValidator> mValidator; bool mNeedsTranslation;
nsCString mValidationLog; nsTArray<WebGLMappedIdentifier> mAttributes;
bool mTranslationSuccessful; nsTArray<WebGLMappedIdentifier> mUniforms;
nsCString mTranslatedSource; nsTArray<WebGLUniformInfo> mUniformInfos;
int mAttribMaxNameLength;
bool mCompilationSuccessful; bool mCompileStatus;
nsCString mCompilationLog;
}; };
} // namespace mozilla } // namespace mozilla

View File

@@ -1,349 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLShaderValidator.h"
#include "angle/ShaderLang.h"
#include "GLContext.h"
#include "MurmurHash3.h"
#include "nsPrintfCString.h"
#include <string>
#include <vector>
#include "WebGLContext.h"
namespace mozilla {
namespace webgl {
uint64_t
IdentifierHashFunc(const char* name, size_t len)
{
// NB: we use the x86 function everywhere, even though it's suboptimal perf
// on x64. They return different results; not sure if that's a requirement.
uint64_t hash[2];
MurmurHash3_x86_128(name, len, 0, hash);
return hash[0];
}
static int
ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
const mozilla::gl::GLContext* gl)
{
int options = SH_VARIABLES |
SH_ENFORCE_PACKING_RESTRICTIONS |
SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
SH_OBJECT_CODE |
SH_LIMIT_CALL_STACK_DEPTH;
if (resources.MaxExpressionComplexity > 0) {
options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
}
#ifndef XP_MACOSX
// We want to do this everywhere, but to do this on Mac, we need
// to do it only on Mac OSX > 10.6 as this causes the shader
// compiler in 10.6 to crash
options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
#endif
#ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs()) {
// Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
// https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
options |= SH_UNFOLD_SHORT_CIRCUIT;
// Work around bug 665578 and bug 769810
if (gl->Vendor() == gl::GLVendor::ATI) {
options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
}
// Work around bug 735560
if (gl->Vendor() == gl::GLVendor::Intel) {
options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
}
// Work around bug 636926
if (gl->Vendor() == gl::GLVendor::NVIDIA) {
options |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
}
}
#endif
return options;
}
} // namespace webgl
////////////////////////////////////////
webgl::ShaderValidator*
WebGLContext::CreateShaderValidator(GLenum shaderType) const
{
if (mBypassShaderValidation)
return nullptr;
ShShaderSpec spec = SH_WEBGL_SPEC;
ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT;
ShBuiltInResources resources;
memset(&resources, 0, sizeof(resources));
ShInitBuiltInResources(&resources);
resources.HashFunction = webgl::IdentifierHashFunc;
resources.MaxVertexAttribs = mGLMaxVertexAttribs;
resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
resources.MaxVaryingVectors = mGLMaxVaryingVectors;
resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
resources.MaxDrawBuffers = mGLMaxDrawBuffers;
if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
resources.EXT_frag_depth = 1;
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
resources.OES_standard_derivatives = 1;
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
resources.EXT_draw_buffers = 1;
if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
resources.EXT_shader_texture_lod = 1;
// Tell ANGLE to allow highp in frag shaders. (unless disabled)
// If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
if (gl->WorkAroundDriverBugs()) {
#ifdef XP_MACOSX
if (gl->Vendor() == gl::GLVendor::NVIDIA) {
// Work around bug 890432
resources.MaxExpressionComplexity = 1000;
}
#endif
}
int compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl);
return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources,
compileOptions);
}
////////////////////////////////////////
namespace webgl {
/*static*/ ShaderValidator*
ShaderValidator::Create(GLenum shaderType, ShShaderSpec spec,
ShShaderOutput outputLanguage,
const ShBuiltInResources& resources, int compileOptions)
{
ShHandle handle = ShConstructCompiler(shaderType, spec, outputLanguage, &resources);
if (!handle)
return nullptr;
return new ShaderValidator(handle, compileOptions);
}
ShaderValidator::~ShaderValidator()
{
ShDestruct(mHandle);
}
bool
ShaderValidator::ValidateAndTranslate(const char* source)
{
MOZ_ASSERT(!mHasRun);
mHasRun = true;
const char* const parts[] = {
source
};
return ShCompile(mHandle, parts, ArrayLength(parts), mCompileOptions);
}
void
ShaderValidator::GetInfo(ShShaderInfo pname, size_t* params) const
{
MOZ_ASSERT(mHasRun);
ShGetInfo(mHandle, pname, params);
}
void
ShaderValidator::GetInfoLog(nsACString* out) const
{
MOZ_ASSERT(mHasRun);
size_t lenWithNull = 0;
GetInfo(SH_INFO_LOG_LENGTH, &lenWithNull);
MOZ_ASSERT(lenWithNull >= 1);
// SetLength allocates len+1, for the null-term.
out->SetLength(lenWithNull - 1);
ShGetInfoLog(mHandle, out->BeginWriting());
}
void
ShaderValidator::GetOutput(nsACString* out) const
{
MOZ_ASSERT(mHasRun);
size_t lenWithNull = 0;
GetInfo(SH_OBJECT_CODE_LENGTH, &lenWithNull);
MOZ_ASSERT(lenWithNull >= 1);
// SetLength allocates len+1, for the null-term.
out->SetLength(lenWithNull - 1);
ShGetObjectCode(mHandle, out->BeginWriting());
}
template<size_t N>
static bool
StartsWith(const std::string& haystack, const char (&needle)[N])
{
return haystack.compare(0, N - 1, needle) == 0;
}
bool
ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const
{
{
const std::vector<sh::Uniform>& vertList = *ShGetUniforms(prev->mHandle);
const std::vector<sh::Uniform>& fragList = *ShGetUniforms(mHandle);
for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
if (itrVert->name != itrFrag->name)
continue;
if (!itrVert->isSameUniformAtLinkTime(*itrFrag)) {
nsPrintfCString error("Uniform `%s`is not linkable between"
" attached shaders.",
itrFrag->name.c_str());
*out_log = error;
return false;
}
break;
}
}
}
{
const std::vector<sh::Varying>& vertList = *ShGetVaryings(prev->mHandle);
const std::vector<sh::Varying>& fragList = *ShGetVaryings(mHandle);
for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
static const char prefix[] = "gl_";
if (StartsWith(itrFrag->name, prefix))
continue;
bool definedInVertShader = false;
for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
if (itrVert->name != itrFrag->name)
continue;
if (!itrVert->isSameVaryingAtLinkTime(*itrFrag)) {
nsPrintfCString error("Varying `%s`is not linkable between"
" attached shaders.",
itrFrag->name.c_str());
*out_log = error;
return false;
}
definedInVertShader = true;
break;
}
if (!definedInVertShader && itrFrag->staticUse) {
nsPrintfCString error("Varying `%s` has static-use in the frag"
" shader, but is undeclared in the vert"
" shader.", itrFrag->name.c_str());
*out_log = error;
return false;
}
}
}
return true;
}
size_t
ShaderValidator::CalcNumSamplerUniforms() const
{
size_t accum = 0;
const std::vector<sh::Uniform>& uniforms = *ShGetUniforms(mHandle);
for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) {
GLenum type = itr->type;
if (type == LOCAL_GL_SAMPLER_2D ||
type == LOCAL_GL_SAMPLER_CUBE)
{
accum += itr->arraySize;
}
}
return accum;
}
// Attribs cannot be structs or arrays, and neither can vertex inputs in ES3.
// Therefore, attrib names are always simple.
bool
ShaderValidator::FindAttribUserNameByMappedName(const std::string& mappedName,
const std::string** const out_userName) const
{
const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
if (itr->mappedName == mappedName) {
*out_userName = &(itr->name);
return true;
}
}
return false;
}
bool
ShaderValidator::FindAttribMappedNameByUserName(const std::string& userName,
const std::string** const out_mappedName) const
{
const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
if (itr->name == userName) {
*out_mappedName = &(itr->mappedName);
return true;
}
}
return false;
}
// This must handle names like "foo.bar[0]".
bool
ShaderValidator::FindUniformByMappedName(const std::string& mappedName,
std::string* const out_userName,
bool* const out_isArray) const
{
const std::vector<sh::Uniform>& uniforms = *ShGetUniforms(mHandle);
for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) {
const sh::ShaderVariable* found;
if (!itr->findInfoByMappedName(mappedName, &found, out_userName))
continue;
*out_isArray = found->isArray();
return true;
}
return false;
}
} // namespace webgl
} // namespace mozilla

View File

@@ -1,60 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGL_SHADER_VALIDATOR_H_
#define WEBGL_SHADER_VALIDATOR_H_
#include "angle/ShaderLang.h"
#include "GLDefs.h"
#include "nsString.h"
#include <string>
namespace mozilla {
namespace webgl {
class ShaderValidator MOZ_FINAL
{
const ShHandle mHandle;
const int mCompileOptions;
bool mHasRun;
public:
static ShaderValidator* Create(GLenum shaderType, ShShaderSpec spec,
ShShaderOutput outputLanguage,
const ShBuiltInResources& resources,
int compileOptions);
private:
ShaderValidator(ShHandle handle, int compileOptions)
: mHandle(handle)
, mCompileOptions(compileOptions)
, mHasRun(false)
{ }
public:
~ShaderValidator();
bool ValidateAndTranslate(const char* source);
void GetInfo(ShShaderInfo pname, size_t* params) const;
void GetInfoLog(nsACString* out) const;
void GetOutput(nsACString* out) const;
bool CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const;
size_t CalcNumSamplerUniforms() const;
bool FindAttribUserNameByMappedName(const std::string& mappedName,
const std::string** const out_userName) const;
bool FindAttribMappedNameByUserName(const std::string& userName,
const std::string** const out_mappedName) const;
bool FindUniformByMappedName(const std::string& mappedName,
std::string* const out_userName,
bool* const out_isArray) const;
};
} // namespace webgl
} // namespace mozilla
#endif // WEBGL_SHADER_VALIDATOR_H_

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGLUNIFORMINFO_H_
#define WEBGLUNIFORMINFO_H_
#include "GLDefs.h"
#include "angle/ShaderLang.h"
namespace mozilla {
struct WebGLUniformInfo {
uint32_t arraySize;
bool isArray;
sh::GLenum type;
explicit WebGLUniformInfo(uint32_t s = 0, bool a = false, sh::GLenum t = LOCAL_GL_NONE)
: arraySize(s), isArray(a), type(t) {}
int ElementSize() const {
switch (type) {
case LOCAL_GL_FLOAT:
case LOCAL_GL_INT:
case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_BOOL:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_3D:
case LOCAL_GL_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_2D_SHADOW:
case LOCAL_GL_SAMPLER_2D_ARRAY:
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
case LOCAL_GL_INT_SAMPLER_2D:
case LOCAL_GL_INT_SAMPLER_3D:
case LOCAL_GL_INT_SAMPLER_CUBE:
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
return 1;
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_UNSIGNED_INT_VEC2:
case LOCAL_GL_BOOL_VEC2:
return 2;
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_UNSIGNED_INT_VEC3:
case LOCAL_GL_BOOL_VEC3:
return 3;
case LOCAL_GL_FLOAT_VEC4:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_UNSIGNED_INT_VEC4:
case LOCAL_GL_BOOL_VEC4:
case LOCAL_GL_FLOAT_MAT2:
return 4;
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT3x2:
return 6;
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT4x2:
return 8;
case LOCAL_GL_FLOAT_MAT3:
return 9;
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4x3:
return 12;
case LOCAL_GL_FLOAT_MAT4:
return 16;
default:
MOZ_ASSERT(false); // should never get here
return 0;
}
}
};
} // namespace mozilla
#endif

View File

@@ -5,272 +5,33 @@
#include "WebGLUniformLocation.h" #include "WebGLUniformLocation.h"
#include "GLContext.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h" #include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLActiveInfo.h"
#include "WebGLContext.h" #include "WebGLContext.h"
#include "WebGLProgram.h" #include "WebGLProgram.h"
#include "WebGLShader.h"
namespace mozilla { namespace mozilla {
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
const webgl::LinkedProgramInfo* linkInfo,
GLuint loc, const WebGLActiveInfo* activeInfo)
: WebGLContextBoundObject(webgl)
, mLinkInfo(linkInfo)
, mLoc(loc)
, mActiveInfo(activeInfo)
{ }
WebGLUniformLocation::~WebGLUniformLocation()
{ }
bool
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
const char* funcName) const
{
// Check the weak-pointer.
if (!mLinkInfo) {
webgl->ErrorInvalidOperation("%s: This uniform location is obsolete because its"
" program has been successfully relinked.",
funcName);
return false;
}
if (mLinkInfo->prog != prog) {
webgl->ErrorInvalidOperation("%s: This uniform location corresponds to a"
" different program.", funcName);
return false;
}
return true;
}
static bool
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
{
switch (uniformType) {
case LOCAL_GL_BOOL:
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_BOOL_VEC4:
return setterType == LOCAL_GL_INT ||
setterType == LOCAL_GL_FLOAT; // GLfloat(0.0) sets a bool to false.
case LOCAL_GL_INT:
case LOCAL_GL_INT_SAMPLER_2D:
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_INT_SAMPLER_3D:
case LOCAL_GL_INT_SAMPLER_CUBE:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_2D_ARRAY:
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
case LOCAL_GL_SAMPLER_2D_SHADOW:
case LOCAL_GL_SAMPLER_CUBE:
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
return setterType == LOCAL_GL_INT;
case LOCAL_GL_FLOAT:
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT3x2:
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4:
case LOCAL_GL_FLOAT_MAT4x2:
case LOCAL_GL_FLOAT_MAT4x3:
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_FLOAT_VEC4:
return setterType == LOCAL_GL_FLOAT;
default:
MOZ_CRASH("Bad `uniformType`.");
}
}
bool
WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
WebGLContext* webgl, const char* funcName) const
{
MOZ_ASSERT(mLinkInfo);
if (setterElemSize != mActiveInfo->mElemSize) {
webgl->ErrorInvalidOperation("%s: Bad uniform size: %i", funcName,
mActiveInfo->mElemSize);
return false;
}
if (!IsUniformSetterTypeValid(setterType, mActiveInfo->mElemType)) {
webgl->ErrorInvalidOperation("%s: Bad uniform type: %i", funcName,
mActiveInfo->mElemSize);
return false;
}
return true;
}
bool
WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
WebGLContext* webgl, const char* funcName) const
{
MOZ_ASSERT(mLinkInfo);
if (setterArraySize == 0 ||
setterArraySize % setterElemSize)
{
webgl->ErrorInvalidValue("%s: expected an array of length a multiple of"
" %d, got an array of length %d.",
funcName, setterElemSize, setterArraySize);
return false;
}
/* GLES 2.0.25, Section 2.10, p38
* When loading `N` elements starting at an arbitrary position `k` in a uniform
* declared as an array, elements `k` through `k + N - 1` in the array will be
* replaced with the new values. Values for any array element that exceeds the
* highest array element index used, as reported by `GetActiveUniform`, will be
* ignored by GL.
*/
if (!mActiveInfo->mIsArray &&
setterArraySize != setterElemSize)
{
webgl->ErrorInvalidOperation("%s: expected an array of length exactly %d"
" (since this uniform is not an array"
" uniform), got an array of length %d.",
funcName, setterElemSize, setterArraySize);
return false;
}
return true;
}
bool
WebGLUniformLocation::ValidateSamplerSetter(GLint value, WebGLContext* webgl,
const char* funcName) const
{
MOZ_ASSERT(mLinkInfo);
if (mActiveInfo->mElemType != LOCAL_GL_SAMPLER_2D &&
mActiveInfo->mElemType != LOCAL_GL_SAMPLER_CUBE)
{
return true;
}
if (value >= 0 && value < (GLint)webgl->GLMaxTextureUnits())
return true;
webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
" valid texture unit.",
funcName, value);
return false;
}
JS::Value
WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
{
MOZ_ASSERT(mLinkInfo);
uint8_t elemSize = mActiveInfo->mElemSize;
static const uint8_t kMaxElemSize = 16;
MOZ_ASSERT(elemSize <= kMaxElemSize);
GLuint prog = mLinkInfo->prog->mGLName;
gl::GLContext* gl = webgl->GL();
gl->MakeCurrent();
switch (mActiveInfo->mElemType) {
case LOCAL_GL_INT:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_SAMPLER_2D:
case LOCAL_GL_SAMPLER_CUBE:
{
GLint buffer[kMaxElemSize] = {0};
gl->fGetUniformiv(prog, mLoc, buffer);
if (elemSize == 1)
return JS::Int32Value(buffer[0]);
JSObject* obj = dom::Int32Array::Create(js, webgl, elemSize, buffer);
if (!obj) {
webgl->ErrorOutOfMemory("getUniform: out of memory");
return JS::NullValue();
}
return JS::ObjectOrNullValue(obj);
}
case LOCAL_GL_BOOL:
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_BOOL_VEC4:
{
GLint buffer[kMaxElemSize] = {0};
gl->fGetUniformiv(prog, mLoc, buffer);
if (elemSize == 1)
return JS::BooleanValue(buffer[0]);
bool boolBuffer[kMaxElemSize];
for (uint8_t i = 0; i < kMaxElemSize; i++)
boolBuffer[i] = buffer[i];
JS::RootedValue val(js);
// Be careful: we don't want to convert all of |uv|!
if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
webgl->ErrorOutOfMemory("getUniform: out of memory");
return JS::NullValue();
}
return val;
}
case LOCAL_GL_FLOAT:
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_FLOAT_VEC4:
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT4:
{
GLfloat buffer[16] = {0.0f};
gl->fGetUniformfv(prog, mLoc, buffer);
if (elemSize == 1)
return JS::DoubleValue(buffer[0]);
JSObject* obj = dom::Float32Array::Create(js, webgl, elemSize, buffer);
if (!obj) {
webgl->ErrorOutOfMemory("getUniform: out of memory");
return JS::NullValue();
}
return JS::ObjectOrNullValue(obj);
}
default:
MOZ_CRASH("Invalid elemType.");
}
}
////////////////////////////////////////////////////////////////////////////////
JSObject* JSObject*
WebGLUniformLocation::WrapObject(JSContext* js) WebGLUniformLocation::WrapObject(JSContext* cx)
{ {
return dom::WebGLUniformLocationBinding::Wrap(js, this); return dom::WebGLUniformLocationBinding::Wrap(cx, this);
} }
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLUniformLocation) WebGLUniformLocation::WebGLUniformLocation(WebGLContext* context,
WebGLProgram* program,
GLint location,
const WebGLUniformInfo& info)
: WebGLContextBoundObject(context)
, mProgram(program)
, mProgramGeneration(program->Generation())
, mLocation(location)
, mInfo(info)
{
mElementSize = info.ElementSize();
}
NS_IMPL_CYCLE_COLLECTION(WebGLUniformLocation, mProgram)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)

View File

@@ -6,56 +6,48 @@
#ifndef WEBGL_UNIFORM_LOCATION_H_ #ifndef WEBGL_UNIFORM_LOCATION_H_
#define WEBGL_UNIFORM_LOCATION_H_ #define WEBGL_UNIFORM_LOCATION_H_
#include "GLDefs.h"
#include "mozilla/WeakPtr.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h" #include "WebGLObjectModel.h"
#include "WebGLUniformInfo.h"
struct JSContext;
namespace mozilla { namespace mozilla {
class WebGLActiveInfo;
class WebGLContext;
class WebGLProgram; class WebGLProgram;
namespace webgl {
struct LinkedProgramInfo;
}
class WebGLUniformLocation MOZ_FINAL class WebGLUniformLocation MOZ_FINAL
: public nsWrapperCache : public WebGLContextBoundObject
, public WebGLContextBoundObject
{ {
public: public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation) WebGLUniformLocation(WebGLContext* context, WebGLProgram* program,
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLUniformLocation) GLint location, const WebGLUniformInfo& info);
const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo; // needed for certain helper functions like ValidateObject.
const GLuint mLoc; // WebGLUniformLocation's can't be 'Deleted' in the WebGL sense.
const WebGLActiveInfo* const mActiveInfo;
WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
GLuint loc, const WebGLActiveInfo* activeInfo);
bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
const char* funcName) const;
bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
const char* funcName) const;
bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
WebGLContext* webgl, const char* funcName) const;
bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
WebGLContext* webgl, const char* funcName) const;
JS::Value GetUniform(JSContext* js, WebGLContext* webgl) const;
// Needed for certain helper functions like ValidateObject.
// `WebGLUniformLocation`s can't be 'Deleted' in the WebGL sense.
bool IsDeleted() const { return false; } bool IsDeleted() const { return false; }
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE; const WebGLUniformInfo& Info() const { return mInfo; }
WebGLProgram* Program() const { return mProgram; }
GLint Location() const { return mLocation; }
uint32_t ProgramGeneration() const { return mProgramGeneration; }
int ElementSize() const { return mElementSize; }
JSObject* WrapObject(JSContext* cx);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
protected: protected:
~WebGLUniformLocation(); ~WebGLUniformLocation() { }
// nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
// we just want to avoid having a dangling pointer.
nsRefPtr<WebGLProgram> mProgram;
uint32_t mProgramGeneration;
GLint mLocation;
WebGLUniformInfo mInfo;
int mElementSize;
friend class WebGLProgram;
}; };
} // namespace mozilla } // namespace mozilla

View File

@@ -1,169 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLValidateStrings.h"
#include "nsString.h"
#include "WebGLContext.h"
namespace mozilla {
// The following code was taken from the WebKit WebGL implementation,
// which can be found here:
// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
// Note that some modifications were done to adapt it to Mozilla.
/****** BEGIN CODE TAKEN FROM WEBKIT ******/
bool IsValidGLSLCharacter(char16_t c)
{
// Printing characters are valid except " $ ` @ \ ' DEL.
if (c >= 32 && c <= 126 &&
c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
{
return true;
}
// Horizontal tab, line feed, vertical tab, form feed, carriage return
// are also valid.
if (c >= 9 && c <= 13) {
return true;
}
return false;
}
void StripComments::process(char16_t c)
{
if (isNewline(c)) {
// No matter what state we are in, pass through newlines
// so we preserve line numbers.
emit(c);
if (m_parseState != InMultiLineComment)
m_parseState = BeginningOfLine;
return;
}
char16_t temp = 0;
switch (m_parseState) {
case BeginningOfLine:
// If it's an ASCII space.
if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
emit(c);
break;
}
if (c == '#') {
m_parseState = InPreprocessorDirective;
emit(c);
break;
}
// Transition to normal state and re-handle character.
m_parseState = MiddleOfLine;
process(c);
break;
case MiddleOfLine:
if (c == '/' && peek(temp)) {
if (temp == '/') {
m_parseState = InSingleLineComment;
emit(' ');
advance();
break;
}
if (temp == '*') {
m_parseState = InMultiLineComment;
// Emit the comment start in case the user has
// an unclosed comment and we want to later
// signal an error.
emit('/');
emit('*');
advance();
break;
}
}
emit(c);
break;
case InPreprocessorDirective:
// No matter what the character is, just pass it
// through. Do not parse comments in this state. This
// might not be the right thing to do long term, but it
// should handle the #error preprocessor directive.
emit(c);
break;
case InSingleLineComment:
// The newline code at the top of this function takes care
// of resetting our state when we get out of the
// single-line comment. Swallow all other characters.
break;
case InMultiLineComment:
if (c == '*' && peek(temp) && temp == '/') {
emit('*');
emit('/');
m_parseState = MiddleOfLine;
advance();
break;
}
// Swallow all other characters. Unclear whether we may
// want or need to just emit a space per character to try
// to preserve column numbers for debugging purposes.
break;
}
}
/****** END CODE TAKEN FROM WEBKIT ******/
bool
ValidateGLSLString(const nsAString& string, WebGLContext* webgl, const char* funcName)
{
for (size_t i = 0; i < string.Length(); ++i) {
if (!IsValidGLSLCharacter(string.CharAt(i))) {
webgl->ErrorInvalidValue("%s: String contains the illegal character '%d'",
funcName, string.CharAt(i));
return false;
}
}
return true;
}
bool
ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char* funcName)
{
if (name.IsEmpty())
return false;
const uint32_t maxSize = 256;
if (name.Length() > maxSize) {
webgl->ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
" maximum allowed length of %d characters.",
funcName, name.Length(), maxSize);
return false;
}
if (!ValidateGLSLString(name, webgl, funcName))
return false;
nsString prefix1 = NS_LITERAL_STRING("webgl_");
nsString prefix2 = NS_LITERAL_STRING("_webgl_");
if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
Substring(name, 0, prefix2.Length()).Equals(prefix2))
{
webgl->ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
funcName);
return false;
}
return true;
}
} // namespace mozilla

View File

@@ -27,130 +27,226 @@
#ifndef WEBGL_VALIDATE_STRINGS_H_ #ifndef WEBGL_VALIDATE_STRINGS_H_
#define WEBGL_VALIDATE_STRINGS_H_ #define WEBGL_VALIDATE_STRINGS_H_
#include "nsString.h" #include "WebGLContext.h"
#include "nsTArray.h"
namespace mozilla { namespace mozilla {
class WebGLContext;
// The following code was taken from the WebKit WebGL implementation, // The following code was taken from the WebKit WebGL implementation,
// which can be found here: // which can be found here:
// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121 // http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
// Note that some modifications were done to adapt it to Mozilla. // Note that some modifications were done to adapt it to Mozilla.
/****** BEGIN CODE TAKEN FROM WEBKIT ******/ /****** BEGIN CODE TAKEN FROM WEBKIT ******/
// Strips comments from shader text. This allows non-ASCII characters bool WebGLContext::ValidateGLSLCharacter(char16_t c)
// to be used in comments without potentially breaking OpenGL
// implementations not expecting characters outside the GLSL ES set.
class StripComments {
public:
explicit StripComments(const nsAString& str)
: m_parseState(BeginningOfLine)
, m_end(str.EndReading())
, m_current(str.BeginReading())
, m_position(0)
{ {
m_result.SetLength(str.Length()); // Printing characters are valid except " $ ` @ \ ' DEL.
parse(); if (c >= 32 && c <= 126 &&
c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
{
return true;
}
// Horizontal tab, line feed, vertical tab, form feed, carriage return
// are also valid.
if (c >= 9 && c <= 13) {
return true;
}
return false;
} }
const nsTArray<char16_t>& result() // Strips comments from shader text. This allows non-ASCII characters
{ // to be used in comments without potentially breaking OpenGL
return m_result; // implementations not expecting characters outside the GLSL ES set.
} class StripComments {
public:
explicit StripComments(const nsAString& str)
: m_parseState(BeginningOfLine)
, m_end(str.EndReading())
, m_current(str.BeginReading())
, m_position(0)
{
m_result.SetLength(str.Length());
parse();
}
size_t length() const nsTArray<char16_t>& result()
{ {
return m_position; return m_result;
} }
private: size_t length()
bool hasMoreCharacters() {
{ return m_position;
return (m_current < m_end); }
}
void parse() private:
bool hasMoreCharacters()
{
return (m_current < m_end);
}
void parse()
{
while (hasMoreCharacters()) {
process(current());
// process() might advance the position.
if (hasMoreCharacters())
advance();
}
}
void process(char16_t);
bool peek(char16_t& character)
{
if (m_current + 1 >= m_end)
return false;
character = *(m_current + 1);
return true;
}
char16_t current()
{
//ASSERT(m_position < m_length);
return *m_current;
}
void advance()
{
++m_current;
}
bool isNewline(char16_t character)
{
// Don't attempt to canonicalize newline related characters.
return (character == '\n' || character == '\r');
}
void emit(char16_t character)
{
m_result[m_position++] = character;
}
enum ParseState {
// Have not seen an ASCII non-whitespace character yet on
// this line. Possible that we might see a preprocessor
// directive.
BeginningOfLine,
// Have seen at least one ASCII non-whitespace character
// on this line.
MiddleOfLine,
// Handling a preprocessor directive. Passes through all
// characters up to the end of the line. Disables comment
// processing.
InPreprocessorDirective,
// Handling a single-line comment. The comment text is
// replaced with a single space.
InSingleLineComment,
// Handling a multi-line comment. Newlines are passed
// through to preserve line numbers.
InMultiLineComment
};
ParseState m_parseState;
const char16_t* m_end;
const char16_t* m_current;
size_t m_position;
nsTArray<char16_t> m_result;
};
void StripComments::process(char16_t c)
{ {
while (hasMoreCharacters()) { if (isNewline(c)) {
process(current()); // No matter what state we are in, pass through newlines
// process() might advance the position. // so we preserve line numbers.
if (hasMoreCharacters()) emit(c);
if (m_parseState != InMultiLineComment)
m_parseState = BeginningOfLine;
return;
}
char16_t temp = 0;
switch (m_parseState) {
case BeginningOfLine:
// If it's an ASCII space.
if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
emit(c);
break;
}
if (c == '#') {
m_parseState = InPreprocessorDirective;
emit(c);
break;
}
// Transition to normal state and re-handle character.
m_parseState = MiddleOfLine;
process(c);
break;
case MiddleOfLine:
if (c == '/' && peek(temp)) {
if (temp == '/') {
m_parseState = InSingleLineComment;
emit(' ');
advance();
break;
}
if (temp == '*') {
m_parseState = InMultiLineComment;
// Emit the comment start in case the user has
// an unclosed comment and we want to later
// signal an error.
emit('/');
emit('*');
advance();
break;
}
}
emit(c);
break;
case InPreprocessorDirective:
// No matter what the character is, just pass it
// through. Do not parse comments in this state. This
// might not be the right thing to do long term, but it
// should handle the #error preprocessor directive.
emit(c);
break;
case InSingleLineComment:
// The newline code at the top of this function takes care
// of resetting our state when we get out of the
// single-line comment. Swallow all other characters.
break;
case InMultiLineComment:
if (c == '*' && peek(temp) && temp == '/') {
emit('*');
emit('/');
m_parseState = MiddleOfLine;
advance(); advance();
break;
}
// Swallow all other characters. Unclear whether we may
// want or need to just emit a space per character to try
// to preserve column numbers for debugging purposes.
break;
} }
} }
void process(char16_t);
bool peek(char16_t& character)
{
if (m_current + 1 >= m_end)
return false;
character = *(m_current + 1);
return true;
}
char16_t current()
{
//ASSERT(m_position < m_length);
return *m_current;
}
void advance()
{
++m_current;
}
bool isNewline(char16_t character)
{
// Don't attempt to canonicalize newline related characters.
return (character == '\n' || character == '\r');
}
void emit(char16_t character)
{
m_result[m_position++] = character;
}
enum ParseState {
// Have not seen an ASCII non-whitespace character yet on
// this line. Possible that we might see a preprocessor
// directive.
BeginningOfLine,
// Have seen at least one ASCII non-whitespace character
// on this line.
MiddleOfLine,
// Handling a preprocessor directive. Passes through all
// characters up to the end of the line. Disables comment
// processing.
InPreprocessorDirective,
// Handling a single-line comment. The comment text is
// replaced with a single space.
InSingleLineComment,
// Handling a multi-line comment. Newlines are passed
// through to preserve line numbers.
InMultiLineComment
};
ParseState m_parseState;
const char16_t* m_end;
const char16_t* m_current;
size_t m_position;
nsTArray<char16_t> m_result;
};
/****** END CODE TAKEN FROM WEBKIT ******/ /****** END CODE TAKEN FROM WEBKIT ******/
bool ValidateGLSLString(const nsAString& string, WebGLContext* webgl,
const char* funcName);
bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl,
const char* funcName);
} // namespace mozilla } // namespace mozilla
#endif // WEBGL_VALIDATE_STRINGS_H_ #endif // WEBGL_VALIDATE_STRINGS_H_

View File

@@ -108,13 +108,11 @@ UNIFIED_SOURCES += [
'WebGLSampler.cpp', 'WebGLSampler.cpp',
'WebGLShader.cpp', 'WebGLShader.cpp',
'WebGLShaderPrecisionFormat.cpp', 'WebGLShaderPrecisionFormat.cpp',
'WebGLShaderValidator.cpp',
'WebGLSync.cpp', 'WebGLSync.cpp',
'WebGLTexelConversions.cpp', 'WebGLTexelConversions.cpp',
'WebGLTexture.cpp', 'WebGLTexture.cpp',
'WebGLTransformFeedback.cpp', 'WebGLTransformFeedback.cpp',
'WebGLUniformLocation.cpp', 'WebGLUniformLocation.cpp',
'WebGLValidateStrings.cpp',
'WebGLVertexArray.cpp', 'WebGLVertexArray.cpp',
'WebGLVertexArrayFake.cpp', 'WebGLVertexArrayFake.cpp',
'WebGLVertexArrayGL.cpp', 'WebGLVertexArrayGL.cpp',

View File

@@ -68,13 +68,15 @@ function shouldBeEmptyString(command) {
} }
for (var i = 0; i < arguments.length; ++i) { for (var i = 0; i < arguments.length; ++i) {
var func, func2; var func, func2, func3;
if (arguments[i].throws) { if (arguments[i].throws) {
func = shouldThrow; func = shouldThrow;
func2 = shouldThrow; func2 = shouldThrow;
func3 = shouldThrow;
} else { } else {
func = shouldBeUndefined; func = shouldBeUndefined;
func2 = shouldBeNull; func2 = shouldBeNull;
func3 = shouldBeEmptyString;
} }
argument = arguments[i].value; argument = arguments[i].value;
func("context.compileShader(argument)"); func("context.compileShader(argument)");
@@ -96,14 +98,15 @@ for (var i = 0; i < arguments.length; ++i) {
func("context.uniform2iv(argument, new Int32Array([0, 0]))"); func("context.uniform2iv(argument, new Int32Array([0, 0]))");
func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))"); func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
func2("context.getProgramInfoLog(argument)");
func2("context.getProgramParameter(argument, 0)"); func2("context.getProgramParameter(argument, 0)");
func2("context.getShaderInfoLog(argument)");
func2("context.getShaderParameter(argument, 0)"); func2("context.getShaderParameter(argument, 0)");
func2("context.getShaderSource(argument)");
func2("context.getUniform(argument, loc)"); func2("context.getUniform(argument, loc)");
func2("context.getUniform(program, argument)"); func2("context.getUniform(program, argument)");
func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')"); func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
func3("context.getProgramInfoLog(argument)");
func3("context.getShaderInfoLog(argument)");
func3("context.getShaderSource(argument)");
} }
successfullyParsed = true; successfullyParsed = true;

View File

@@ -2015,7 +2015,7 @@ public:
AFTER_GL_CALL; AFTER_GL_CALL;
} }
void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths) { void fShaderSource(GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths) {
BEFORE_GL_CALL; BEFORE_GL_CALL;
mSymbols.fShaderSource(shader, count, strings, lengths); mSymbols.fShaderSource(shader, count, strings, lengths);
AFTER_GL_CALL; AFTER_GL_CALL;

View File

@@ -308,7 +308,7 @@ struct GLContextSymbols
PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat; PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat;
typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source); typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source);
PFNGLGETSHADERSOURCEPROC fGetShaderSource; PFNGLGETSHADERSOURCEPROC fGetShaderSource;
typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths); typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths);
PFNGLSHADERSOURCEPROC fShaderSource; PFNGLSHADERSOURCEPROC fShaderSource;
typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer); typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);

View File

@@ -3841,6 +3841,7 @@ pref("gl.msaa-level", 2);
#endif #endif
pref("webgl.force-enabled", false); pref("webgl.force-enabled", false);
pref("webgl.disabled", false); pref("webgl.disabled", false);
pref("webgl.shader_validator", true);
pref("webgl.disable-angle", false); pref("webgl.disable-angle", false);
pref("webgl.min_capability_mode", false); pref("webgl.min_capability_mode", false);
pref("webgl.disable-extensions", false); pref("webgl.disable-extensions", false);
@@ -3854,7 +3855,6 @@ pref("webgl.restore-context-when-visible", true);
pref("webgl.max-warnings-per-context", 32); pref("webgl.max-warnings-per-context", 32);
pref("webgl.enable-draft-extensions", false); pref("webgl.enable-draft-extensions", false);
pref("webgl.enable-privileged-extensions", false); pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
#ifdef XP_WIN #ifdef XP_WIN
pref("webgl.angle.try-d3d11", true); pref("webgl.angle.try-d3d11", true);
pref("webgl.angle.force-d3d11", false); pref("webgl.angle.force-d3d11", false);