Backed out changeset b5c6dd9423cf (bug 1109945) for gl2 test failures on a CLOSED TREE
This commit is contained in:
@@ -26,41 +26,35 @@ function ifWebGLSupported() {
|
||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||
|
||||
|
||||
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
|
||||
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
|
||||
ok(error,
|
||||
"The new vertex shader source was compiled with errors.");
|
||||
|
||||
// The implementation has the choice to defer all compile-time errors to link time.
|
||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
||||
|
||||
isnot(infoLog, "",
|
||||
"The one of the compile or link info logs should not be empty.");
|
||||
is(infoLog.split("ERROR").length - 1, 2,
|
||||
"The info log status contains two errors.");
|
||||
ok(infoLog.contains("ERROR: 0:8: 'constructor'"),
|
||||
"A constructor error is contained in the info log.");
|
||||
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
|
||||
"An assignment error is contained in the info log.");
|
||||
|
||||
is(error.compile, "",
|
||||
"The compilation status should be empty.");
|
||||
isnot(error.link, "",
|
||||
"The linkage status should not be empty.");
|
||||
is(error.link.split("ERROR").length - 1, 2,
|
||||
"The linkage status contains two errors.");
|
||||
ok(error.link.contains("ERROR: 0:8: 'constructor'"),
|
||||
"A constructor error is contained in the linkage status.");
|
||||
ok(error.link.contains("ERROR: 0:8: 'assign'"),
|
||||
"An assignment error is contained in the linkage status.");
|
||||
|
||||
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
|
||||
[, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
|
||||
ok(error,
|
||||
"The new fragment shader source was compiled with errors.");
|
||||
|
||||
infoLog = (error.compile != "") ? error.compile : error.link;
|
||||
|
||||
isnot(infoLog, "",
|
||||
"The one of the compile or link info logs should not be empty.");
|
||||
is(infoLog.split("ERROR").length - 1, 1,
|
||||
"The info log contains one error.");
|
||||
ok(infoLog.contains("ERROR: 0:6: 'constructor'"),
|
||||
"A constructor error is contained in the info log.");
|
||||
|
||||
is(error.compile, "",
|
||||
"The compilation status should be empty.");
|
||||
isnot(error.link, "",
|
||||
"The linkage status should not be empty.");
|
||||
is(error.link.split("ERROR").length - 1, 1,
|
||||
"The linkage status contains one error.");
|
||||
ok(error.link.contains("ERROR: 0:6: 'constructor'"),
|
||||
"A constructor error is contained in the linkage status.");
|
||||
|
||||
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);
|
||||
|
||||
@@ -23,18 +23,16 @@ function ifWebGLSupported() {
|
||||
} catch (error) {
|
||||
ok(error,
|
||||
"The new vertex shader source was compiled with errors.");
|
||||
|
||||
// The implementation has the choice to defer all compile-time errors to link time.
|
||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
||||
|
||||
isnot(infoLog, "",
|
||||
"The one of the compile or link info logs should not be empty.");
|
||||
is(infoLog.split("ERROR").length - 1, 2,
|
||||
"The info log contains two errors.");
|
||||
ok(infoLog.contains("ERROR: 0:8: 'constructor'"),
|
||||
"A constructor error is contained in the info log.");
|
||||
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
|
||||
"An assignment error is contained in the info log.");
|
||||
is(error.compile, "",
|
||||
"The compilation status should be empty.");
|
||||
isnot(error.link, "",
|
||||
"The linkage status should not be empty.");
|
||||
is(error.link.split("ERROR").length - 1, 2,
|
||||
"The linkage status contains two errors.");
|
||||
ok(error.link.contains("ERROR: 0:8: 'constructor'"),
|
||||
"A constructor error is contained in the linkage status.");
|
||||
ok(error.link.contains("ERROR: 0:8: 'assign'"),
|
||||
"An assignment error is contained in the linkage status.");
|
||||
}
|
||||
|
||||
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
@@ -54,16 +52,14 @@ function ifWebGLSupported() {
|
||||
} catch (error) {
|
||||
ok(error,
|
||||
"The new fragment shader source was compiled with errors.");
|
||||
|
||||
// The implementation has the choice to defer all compile-time errors to link time.
|
||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
||||
|
||||
isnot(infoLog, "",
|
||||
"The one of the compile or link info logs should not be empty.");
|
||||
is(infoLog.split("ERROR").length - 1, 1,
|
||||
"The info log contains one error.");
|
||||
ok(infoLog.contains("ERROR: 0:6: 'constructor'"),
|
||||
"A constructor error is contained in the info log.");
|
||||
is(error.compile, "",
|
||||
"The compilation status should be empty.");
|
||||
isnot(error.link, "",
|
||||
"The linkage status should not be empty.");
|
||||
is(error.link.split("ERROR").length - 1, 1,
|
||||
"The linkage status contains one error.");
|
||||
ok(error.link.contains("ERROR: 0:6: 'constructor'"),
|
||||
"A constructor error is contained in the linkage status.");
|
||||
}
|
||||
|
||||
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
|
||||
@@ -152,8 +152,6 @@ WebGLContext::InitWebGL2()
|
||||
auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
|
||||
mBoundTransformFeedbackBuffers.reset(xfBuffers);
|
||||
|
||||
mBypassShaderValidation = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,13 +212,14 @@ WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
|
||||
tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
|
||||
}
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
MakeContextCurrent();
|
||||
gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
|
||||
|
||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
|
||||
}
|
||||
|
||||
|
||||
already_AddRefed<WebGLActiveInfo>
|
||||
WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
||||
{
|
||||
@@ -231,7 +232,7 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
||||
MakeContextCurrent();
|
||||
|
||||
GLint len = 0;
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
|
||||
if (!len)
|
||||
return nullptr;
|
||||
@@ -244,13 +245,10 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
||||
if (len == 0 || tfsize == 0 || tftype == 0)
|
||||
return nullptr;
|
||||
|
||||
MOZ_CRASH("todo");
|
||||
/*
|
||||
// Reverse lookup of name
|
||||
nsCString reverseMappedName;
|
||||
prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
||||
// TODO(djg): Reverse lookup of name
|
||||
// nsCString reverseMappedName;
|
||||
// prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
||||
|
||||
nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get()));
|
||||
return result.forget();
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@ WebGL2Context::GetUniformIndices(WebGLProgram* program,
|
||||
if (!uniformNames.Length())
|
||||
return;
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
size_t count = uniformNames.Length();
|
||||
nsTArray<GLuint>& arr = retval.SetValue();
|
||||
|
||||
@@ -431,7 +431,7 @@ WebGL2Context::GetActiveUniforms(WebGLProgram* program,
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
nsTArray<GLint>& arr = retval.SetValue();
|
||||
arr.SetLength(count);
|
||||
|
||||
@@ -450,14 +450,17 @@ WebGL2Context::GetUniformBlockIndex(WebGLProgram* program,
|
||||
if (!ValidateObject("getUniformBlockIndex: program", program))
|
||||
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();
|
||||
return gl->fGetUniformBlockIndex(progname, cname.BeginReading());
|
||||
return gl->fGetUniformBlockIndex(progname, mappedName.get());
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -498,7 +501,7 @@ WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* progr
|
||||
if (!ValidateObject("getActiveUniformBlockParameter: program", program))
|
||||
return;
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
GLint param = 0;
|
||||
|
||||
MakeContextCurrent();
|
||||
@@ -548,7 +551,7 @@ WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBl
|
||||
if (!ValidateObject("getActiveUniformBlockName: program", program))
|
||||
return;
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
|
||||
GLsizei length = 0;
|
||||
|
||||
@@ -571,7 +574,7 @@ WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockInd
|
||||
if (!ValidateObject("uniformBlockBinding: program", program))
|
||||
return;
|
||||
|
||||
GLuint progname = program->mGLName;
|
||||
GLuint progname = program->GLName();
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
|
||||
|
||||
@@ -6,94 +6,15 @@
|
||||
#include "WebGLActiveInfo.h"
|
||||
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLTexture.h"
|
||||
|
||||
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*
|
||||
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
|
||||
|
||||
@@ -6,76 +6,48 @@
|
||||
#ifndef WEBGL_ACTIVE_INFO_H_
|
||||
#define WEBGL_ACTIVE_INFO_H_
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLActiveInfo MOZ_FINAL
|
||||
: public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLActiveInfo)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLActiveInfo)
|
||||
|
||||
const GLint mElemCount; // `size`
|
||||
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();
|
||||
}
|
||||
WebGLActiveInfo(GLint size, GLenum type, const nsACString& name)
|
||||
: mSize(size)
|
||||
, mType(type)
|
||||
, mName(NS_ConvertASCIItoUTF16(name))
|
||||
{}
|
||||
|
||||
// WebIDL attributes
|
||||
|
||||
GLint Size() const {
|
||||
return mElemCount;
|
||||
return mSize;
|
||||
}
|
||||
|
||||
GLenum Type() const {
|
||||
return mElemType;
|
||||
return mType;
|
||||
}
|
||||
|
||||
void GetName(nsString& retval) const {
|
||||
CopyASCIItoUTF16(mBaseUserName, retval);
|
||||
if (mIsArray)
|
||||
retval.AppendLiteral("[0]");
|
||||
retval = mName;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
|
||||
JSObject* WrapObject(JSContext* cx);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
|
||||
|
||||
private:
|
||||
WebGLActiveInfo()
|
||||
: mElemCount(0)
|
||||
, mElemType(0)
|
||||
, mBaseUserName("")
|
||||
, mIsArray(false)
|
||||
, mElemSize(0)
|
||||
, mBaseMappedName("")
|
||||
{ }
|
||||
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~WebGLActiveInfo() { }
|
||||
~WebGLActiveInfo()
|
||||
{
|
||||
}
|
||||
|
||||
GLint mSize;
|
||||
GLenum mType;
|
||||
nsString mName;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -202,7 +202,6 @@ WebGLContextOptions::WebGLContextOptions()
|
||||
|
||||
WebGLContext::WebGLContext()
|
||||
: WebGLContextUnchecked(nullptr)
|
||||
, mBypassShaderValidation(false)
|
||||
, mNeedsFakeNoAlpha(false)
|
||||
{
|
||||
mGeneration = 0;
|
||||
@@ -216,6 +215,8 @@ WebGLContext::WebGLContext()
|
||||
mPixelStorePremultiplyAlpha = false;
|
||||
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
|
||||
|
||||
mShaderValidation = true;
|
||||
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||
|
||||
mVertexAttrib0Vector[0] = 0;
|
||||
@@ -329,7 +330,6 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mBoundUniformBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
mActiveProgramLinkInfo = nullptr;
|
||||
mBoundDrawFramebuffer = nullptr;
|
||||
mBoundReadFramebuffer = nullptr;
|
||||
mActiveOcclusionQuery = nullptr;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLShaderValidator.h"
|
||||
#include "WebGLStrongTypes.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -97,10 +96,6 @@ namespace gfx {
|
||||
class SourceSurface;
|
||||
}
|
||||
|
||||
namespace webgl {
|
||||
struct LinkedProgramInfo;
|
||||
}
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
||||
|
||||
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
|
||||
@@ -380,9 +375,7 @@ public:
|
||||
void ClearStencil(GLint v);
|
||||
void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a);
|
||||
void CompileShader(WebGLShader* shader);
|
||||
void CompileShaderANGLE(WebGLShader* shader);
|
||||
void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
|
||||
void CompressedTexImage2D(GLenum target, GLint level,
|
||||
void CompressedTexImage2D(GLenum texImageTarget, GLint level,
|
||||
GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLint border,
|
||||
const dom::ArrayBufferView& view);
|
||||
@@ -844,10 +837,8 @@ public:
|
||||
const float* data);
|
||||
|
||||
void UseProgram(WebGLProgram* prog);
|
||||
|
||||
bool ValidateAttribArraySetter(const char* name, uint32_t count,
|
||||
uint32_t arrayLength);
|
||||
bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
|
||||
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
||||
GLenum setterType, const char* info,
|
||||
GLuint* out_rawLoc);
|
||||
@@ -1127,9 +1118,8 @@ protected:
|
||||
GLenum mUnderlyingGLError;
|
||||
GLenum GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
bool mBypassShaderValidation;
|
||||
|
||||
webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
|
||||
// whether shader validation is supported
|
||||
bool mShaderValidation;
|
||||
|
||||
// some GL constants
|
||||
int32_t mGLMaxVertexAttribs;
|
||||
@@ -1154,10 +1144,6 @@ public:
|
||||
return mGLMaxVertexAttribs;
|
||||
}
|
||||
|
||||
GLuint GLMaxTextureUnits() const {
|
||||
return mGLMaxTextureUnits;
|
||||
}
|
||||
|
||||
|
||||
bool IsFormatValidForFB(GLenum sizedFormat) const;
|
||||
|
||||
@@ -1239,6 +1225,10 @@ protected:
|
||||
WebGLintptr byteOffset, const char* info);
|
||||
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,
|
||||
WebGLTexDimensions dims);
|
||||
|
||||
@@ -1285,10 +1275,6 @@ protected:
|
||||
WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
|
||||
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
|
||||
WebGLProgram* program,
|
||||
const char* funcName);
|
||||
|
||||
void Invalidate();
|
||||
void DestroyResourcesAndContext();
|
||||
|
||||
@@ -1417,7 +1403,6 @@ protected:
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
||||
|
||||
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
||||
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
|
||||
|
||||
uint32_t mMaxFramebufferColorAttachments;
|
||||
|
||||
@@ -1610,7 +1595,7 @@ WebGLContext::ValidateObjectAssumeNonNull(const char* info, ObjectType* object)
|
||||
return false;
|
||||
|
||||
if (object->IsDeleted()) {
|
||||
ErrorInvalidValue("%s: Deleted object passed as argument.", info);
|
||||
ErrorInvalidValue("%s: deleted object passed as argument", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
@@ -409,15 +410,11 @@ void WebGLContext::Draw_cleanup()
|
||||
bool
|
||||
WebGLContext::ValidateBufferFetching(const char* info)
|
||||
{
|
||||
MOZ_ASSERT(mCurrentProgram);
|
||||
// Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
|
||||
MOZ_ASSERT(mActiveProgramLinkInfo);
|
||||
|
||||
#ifdef DEBUG
|
||||
GLint currentProgram = 0;
|
||||
MakeContextCurrent();
|
||||
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram);
|
||||
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName,
|
||||
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
|
||||
"WebGL: current program doesn't agree with GL state");
|
||||
#endif
|
||||
|
||||
@@ -444,7 +441,7 @@ WebGLContext::ValidateBufferFetching(const char* info)
|
||||
|
||||
// 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.
|
||||
if (!mActiveProgramLinkInfo->HasActiveAttrib(i))
|
||||
if (!mCurrentProgram->IsAttribInUse(i))
|
||||
continue;
|
||||
|
||||
// the base offset
|
||||
@@ -501,13 +498,12 @@ WebGLVertexAttrib0Status
|
||||
WebGLContext::WhatDoesVertexAttrib0Need()
|
||||
{
|
||||
MOZ_ASSERT(mCurrentProgram);
|
||||
MOZ_ASSERT(mActiveProgramLinkInfo);
|
||||
|
||||
// work around Mac OSX crash, see bug 631420
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
||||
!mActiveProgramLinkInfo->HasActiveAttrib(0))
|
||||
!mCurrentProgram->IsAttribInUse(0))
|
||||
{
|
||||
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
@@ -519,7 +515,7 @@ WebGLContext::WhatDoesVertexAttrib0Need()
|
||||
return WebGLVertexAttrib0Status::Default;
|
||||
}
|
||||
|
||||
return mActiveProgramLinkInfo->HasActiveAttrib(0)
|
||||
return mCurrentProgram->IsAttribInUse(0)
|
||||
? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
||||
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1043,7 +1043,7 @@ WebGLContext::AssertCachedBindings()
|
||||
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);
|
||||
|
||||
// Textures
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLValidateStrings.h"
|
||||
#include "WebGLVertexArray.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
|
||||
* be one of depth/stencil/depth_stencil/color attachment.
|
||||
@@ -1469,37 +1512,163 @@ WebGLContext::ValidateTexImage(TexImageTarget texImageTarget, GLint level,
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
|
||||
WebGLContext::ValidateUniformLocation(const char* info,
|
||||
WebGLUniformLocation* loc)
|
||||
{
|
||||
/* GLES 2.0.25, p38:
|
||||
* If the value of location is -1, the Uniform* commands will silently
|
||||
* ignore the data passed in, and the current uniform values will not be
|
||||
* changed.
|
||||
*/
|
||||
if (!ValidateObjectAllowNull(info, loc))
|
||||
return false;
|
||||
|
||||
if (!loc)
|
||||
return false;
|
||||
|
||||
if (!ValidateObject(funcName, loc))
|
||||
return false;
|
||||
|
||||
// The need to check specifically for !mCurrentProgram here is explained in
|
||||
// bug 657556.
|
||||
if (!mCurrentProgram) {
|
||||
ErrorInvalidOperation("%s: No program is currently bound.", funcName);
|
||||
ErrorInvalidOperation("%s: No program is currently bound.", info);
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (arrayLength < setterElemSize) {
|
||||
ErrorInvalidOperation("%s: Array must have >= %d elements.", name,
|
||||
setterElemSize);
|
||||
if (arrayLength < cnt) {
|
||||
ErrorInvalidOperation("%s: Array must be >= %d elements.", name, cnt);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1509,18 +1678,18 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
|
||||
bool
|
||||
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
const char* funcName, GLuint* out_rawLoc)
|
||||
const char* info, GLuint* out_rawLoc)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformLocation(loc, funcName))
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_rawLoc = loc->Location();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1529,24 +1698,27 @@ WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
const char* funcName,
|
||||
const char* info,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformLocation(loc, funcName))
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||
info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
|
||||
*out_rawLoc = loc->Location();
|
||||
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
@@ -1557,7 +1729,7 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* funcName,
|
||||
const char* info,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
{
|
||||
@@ -1566,22 +1738,25 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformLocation(loc, funcName))
|
||||
if (!ValidateUniformLocation(info, loc))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
return false;
|
||||
|
||||
if (setterTranspose) {
|
||||
ErrorInvalidValue("%s: `transpose` must be false.", funcName);
|
||||
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||
info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
|
||||
if (setterTranspose) {
|
||||
ErrorInvalidValue("%s: `transpose` must be false.", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rawLoc = loc->Location();
|
||||
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
@@ -1920,14 +2095,16 @@ WebGLContext::InitAndValidateGL()
|
||||
// Check the shader validator pref
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
||||
|
||||
mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation",
|
||||
mBypassShaderValidation);
|
||||
mShaderValidation = Preferences::GetBool("webgl.shader_validator",
|
||||
mShaderValidation);
|
||||
|
||||
// initialize shader translator
|
||||
if (mShaderValidation) {
|
||||
if (!ShInitialize()) {
|
||||
GenerateWarning("GLSL translator initialization failed!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Mesa can only be detected with the GL_VERSION string, of the form
|
||||
// "2.1 Mesa 7.11.0"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
|
||||
@@ -7,690 +7,364 @@
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "MurmurHash3.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLValidateStrings.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* If `name`: "foo[3]"
|
||||
* Then returns true, with
|
||||
* `out_baseName`: "foo"
|
||||
* `out_isArray`: true
|
||||
* `out_index`: 3
|
||||
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]"
|
||||
* in bracketPart.
|
||||
*
|
||||
* If `name`: "foo"
|
||||
* Then returns true, with
|
||||
* `out_baseName`: "foo"
|
||||
* `out_isArray`: false
|
||||
* `out_index`: <not written>
|
||||
* \param string input/output: The string to split, becomes the string without
|
||||
* the bracket part.
|
||||
* \param bracketPart output: Gets the bracket part.
|
||||
*
|
||||
* Notice that if there are multiple brackets like "foo[i].bar[j]", only the
|
||||
* last bracket is split.
|
||||
*/
|
||||
static bool
|
||||
ParseName(const nsCString& name, nsCString* const out_baseName,
|
||||
bool* const out_isArray, size_t* const out_arrayIndex)
|
||||
SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
|
||||
{
|
||||
int32_t indexEnd = name.RFind("]");
|
||||
if (indexEnd == -1 ||
|
||||
(uint32_t)indexEnd != name.Length() - 1)
|
||||
{
|
||||
*out_baseName = name;
|
||||
*out_isArray = false;
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(bracketPart.IsEmpty(),
|
||||
"SplitLastSquareBracket must be called with empty bracketPart"
|
||||
" string.");
|
||||
|
||||
int32_t indexOpenBracket = name.RFind("[");
|
||||
if (indexOpenBracket == -1)
|
||||
if (string.IsEmpty())
|
||||
return false;
|
||||
|
||||
uint32_t indexStart = indexOpenBracket + 1;
|
||||
uint32_t indexLen = indexEnd - indexStart;
|
||||
if (indexLen == 0)
|
||||
char* string_start = string.BeginWriting();
|
||||
char* s = string_start + string.Length() - 1;
|
||||
|
||||
if (*s != ']')
|
||||
return false;
|
||||
|
||||
const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
|
||||
while (*s != '[' && s != string_start)
|
||||
s--;
|
||||
|
||||
nsresult errorcode;
|
||||
int32_t indexNum = indexStr.ToInteger(&errorcode);
|
||||
if (NS_FAILED(errorcode))
|
||||
if (*s != '[')
|
||||
return false;
|
||||
|
||||
if (indexNum < 0)
|
||||
return false;
|
||||
|
||||
*out_baseName = StringHead(name, indexOpenBracket);
|
||||
*out_isArray = true;
|
||||
*out_arrayIndex = indexNum;
|
||||
bracketPart.Assign(s);
|
||||
*s = 0;
|
||||
string.EndWriting();
|
||||
string.SetLength(s - string_start);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
AddActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
|
||||
const nsACString& baseUserName, const nsACString& baseMappedName,
|
||||
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();
|
||||
JSObject*
|
||||
WebGLProgram::WrapObject(JSContext* cx) {
|
||||
return dom::WebGLProgramBinding::Wrap(cx, this);
|
||||
}
|
||||
|
||||
WebGLProgram::WebGLProgram(WebGLContext* 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);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLProgram::Delete()
|
||||
{
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
|
||||
gl->MakeCurrent();
|
||||
gl->fDeleteProgram(mGLName);
|
||||
|
||||
mVertShader = nullptr;
|
||||
mFragShader = nullptr;
|
||||
|
||||
mMostRecentLinkInfo = nullptr;
|
||||
|
||||
DetachShaders();
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteProgram(mGLName);
|
||||
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GL funcs
|
||||
|
||||
void
|
||||
bool
|
||||
WebGLProgram::AttachShader(WebGLShader* 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 (ContainsShader(shader))
|
||||
return false;
|
||||
|
||||
if (*shaderSlot) {
|
||||
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;
|
||||
mAttachedShaders.AppendElement(shader);
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fAttachShader(mGLName, shader->mGLName);
|
||||
mContext->gl->fAttachShader(GLName(), shader->GLName());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
bool
|
||||
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;
|
||||
if (!mAttachedShaders.RemoveElement(shader))
|
||||
return false;
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDetachShader(mGLName, shader->mGLName);
|
||||
}
|
||||
mContext->gl->fDetachShader(GLName(), shader->GLName());
|
||||
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::LinkProgram()
|
||||
WebGLProgram::HasAttachedShaderOfType(GLenum shaderType)
|
||||
{
|
||||
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;
|
||||
for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
|
||||
if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mFragShader || !mFragShader->IsCompiled()) {
|
||||
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::HasBadShaderAttached()
|
||||
{
|
||||
for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
|
||||
if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
size_t
|
||||
WebGLProgram::UpperBoundNumSamplerUniforms()
|
||||
{
|
||||
size_t numSamplerUniforms = 0;
|
||||
|
||||
// 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)
|
||||
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)
|
||||
{
|
||||
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
|
||||
" Mesa drivers to avoid crashing.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return false;
|
||||
numSamplerUniforms += u.arraySize;
|
||||
}
|
||||
|
||||
// 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 numSamplerUniforms;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLProgram::ValidateProgram() const
|
||||
WebGLProgram::MapIdentifier(const nsACString& name,
|
||||
nsCString* const out_mappedName)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
MOZ_ASSERT(mIdentifierMap);
|
||||
|
||||
#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.");
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
gl->fValidateProgram(mGLName);
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
WebGLProgram::LinkAndUpdate()
|
||||
void
|
||||
WebGLProgram::ReverseMapIdentifier(const nsACString& name,
|
||||
nsCString* const out_reverseMappedName)
|
||||
{
|
||||
mMostRecentLinkInfo = nullptr;
|
||||
MOZ_ASSERT(mIdentifierReverseMap);
|
||||
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
gl->fLinkProgram(mGLName);
|
||||
nsCString mutableName(name);
|
||||
nsCString bracketPart;
|
||||
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||
if (hadBracketPart)
|
||||
mutableName.AppendLiteral("[0]");
|
||||
|
||||
// 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);
|
||||
if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName)) {
|
||||
if (hadBracketPart) {
|
||||
nsCString reverseMappedBracketPart;
|
||||
bool reverseMappedHadBracketPart = SplitLastSquareBracket(*out_reverseMappedName,
|
||||
reverseMappedBracketPart);
|
||||
if (reverseMappedHadBracketPart)
|
||||
out_reverseMappedName->Append(bracketPart);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GLint ok = 0;
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
// 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;
|
||||
|
||||
mMostRecentLinkInfo = QueryProgramInfo(this, gl);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMostRecentLinkInfo);
|
||||
if (!mMostRecentLinkInfo)
|
||||
mLinkLog.AssignLiteral("Failed to gather program info.");
|
||||
WebGLUniformInfo
|
||||
WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name)
|
||||
{
|
||||
MOZ_ASSERT(mUniformInfoMap);
|
||||
|
||||
return mMostRecentLinkInfo;
|
||||
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::FindAttribUserNameByMappedName(const nsACString& mappedName,
|
||||
nsDependentCString* const out_userName) const
|
||||
WebGLProgram::UpdateInfo()
|
||||
{
|
||||
if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
|
||||
nsCString* const out_userName,
|
||||
bool* const out_isArray) const
|
||||
{
|
||||
if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
||||
return true;
|
||||
for (size_t i = 0; i < mAttribsInUse.Length(); i++)
|
||||
mAttribsInUse[i] = false;
|
||||
|
||||
if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
WebGLProgram::WrapObject(JSContext* js)
|
||||
/*static*/ uint64_t
|
||||
WebGLProgram::IdentifierHashFunction(const char* ident, size_t size)
|
||||
{
|
||||
return dom::WebGLProgramBinding::Wrap(js, this);
|
||||
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];
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
|
||||
/*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_UNROOT_NATIVE(WebGLProgram, Release)
|
||||
|
||||
@@ -9,74 +9,19 @@
|
||||
#include <map>
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
|
||||
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;
|
||||
struct WebGLUniformInfo;
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
|
||||
typedef nsDataHashtable<nsCStringHashKey,
|
||||
WebGLUniformInfo> CStringToUniformInfoMap;
|
||||
|
||||
class WebGLProgram MOZ_FINAL
|
||||
: public nsWrapperCache
|
||||
@@ -85,64 +30,107 @@ class WebGLProgram MOZ_FINAL
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
|
||||
|
||||
explicit WebGLProgram(WebGLContext* webgl);
|
||||
|
||||
void Delete();
|
||||
|
||||
// GL funcs
|
||||
void AttachShader(WebGLShader* shader);
|
||||
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();
|
||||
void DetachShaders() {
|
||||
mAttachedShaders.Clear();
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
bool LinkAndUpdate();
|
||||
GLuint mGLName;
|
||||
bool mLinkStatus;
|
||||
// attached shaders of the program object
|
||||
nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
|
||||
CheckedUint32 mGeneration;
|
||||
|
||||
public:
|
||||
const GLuint mGLName;
|
||||
|
||||
private:
|
||||
WebGLRefPtr<WebGLShader> mVertShader;
|
||||
WebGLRefPtr<WebGLShader> mFragShader;
|
||||
std::map<nsCString, GLuint> mBoundAttribLocs;
|
||||
nsCString mLinkLog;
|
||||
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
|
||||
// post-link data
|
||||
FallibleTArray<bool> mAttribsInUse;
|
||||
nsAutoPtr<CStringMap> mIdentifierMap, mIdentifierReverseMap;
|
||||
nsAutoPtr<CStringToUniformInfoMap> mUniformInfoMap;
|
||||
int mAttribMaxNameLength;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -9,376 +9,53 @@
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsString.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLShaderValidator.h"
|
||||
#include "WebGLValidateStrings.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// On success, writes to out_validator and out_translatedSource.
|
||||
// On failure, writes to out_translationLog.
|
||||
static bool
|
||||
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);
|
||||
JSObject*
|
||||
WebGLShader::WrapObject(JSContext* cx) {
|
||||
return dom::WebGLShaderBinding::Wrap(cx, this);
|
||||
}
|
||||
|
||||
WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mGLName(CreateShader(webgl->GL(), type))
|
||||
, mType(type)
|
||||
, mNeedsTranslation(true)
|
||||
, mAttribMaxNameLength(0)
|
||||
, mCompileStatus(false)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mGLName = mContext->gl->fCreateShader(mType);
|
||||
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
|
||||
WebGLShader::Delete()
|
||||
{
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
|
||||
gl->MakeCurrent();
|
||||
gl->fDeleteShader(mGLName);
|
||||
|
||||
mSource.Truncate();
|
||||
mTranslationLog.Truncate();
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteShader(mGLName);
|
||||
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_ROOT_NATIVE(WebGLShader, AddRef)
|
||||
|
||||
@@ -6,17 +6,25 @@
|
||||
#ifndef WEBGL_SHADER_H_
|
||||
#define WEBGL_SHADER_H_
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace webgl {
|
||||
class ShaderValidator;
|
||||
} // namespace webgl
|
||||
struct WebGLMappedIdentifier
|
||||
{
|
||||
// ASCII strings
|
||||
nsCString original;
|
||||
nsCString mapped;
|
||||
|
||||
WebGLMappedIdentifier(const nsACString& o, const nsACString& m)
|
||||
: original(o)
|
||||
, mapped(m)
|
||||
{}
|
||||
};
|
||||
|
||||
class WebGLShader MOZ_FINAL
|
||||
: public nsWrapperCache
|
||||
@@ -30,57 +38,67 @@ class WebGLShader MOZ_FINAL
|
||||
public:
|
||||
WebGLShader(WebGLContext* webgl, GLenum type);
|
||||
|
||||
protected:
|
||||
~WebGLShader();
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
public:
|
||||
// GL funcs
|
||||
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);
|
||||
GLuint GLName() { return mGLName; }
|
||||
sh::GLenum ShaderType() { return mType; }
|
||||
|
||||
// Util funcs
|
||||
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
|
||||
size_t CalcNumSamplerUniforms() const;
|
||||
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) 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 IsCompiled() const {
|
||||
return mTranslationSuccessful && mCompilationSuccessful;
|
||||
void SetSource(const nsAString& src) {
|
||||
// TODO: Do some quick gzip here maybe? Getting this will be very rare,
|
||||
// and we have to keep it forever.
|
||||
mSource.Assign(src);
|
||||
}
|
||||
|
||||
const nsString& Source() const { return mSource; }
|
||||
|
||||
void SetNeedsTranslation() { mNeedsTranslation = true; }
|
||||
bool NeedsTranslation() const { return mNeedsTranslation; }
|
||||
|
||||
void SetCompileStatus (bool status) {
|
||||
mCompileStatus = status;
|
||||
}
|
||||
|
||||
// Other funcs
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
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_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
|
||||
|
||||
public:
|
||||
const GLuint mGLName;
|
||||
const GLenum mType;
|
||||
protected:
|
||||
~WebGLShader() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
GLuint mGLName;
|
||||
GLenum mType;
|
||||
nsString mSource;
|
||||
nsCString mCleanSource;
|
||||
|
||||
UniquePtr<webgl::ShaderValidator> mValidator;
|
||||
nsCString mValidationLog;
|
||||
bool mTranslationSuccessful;
|
||||
nsCString mTranslatedSource;
|
||||
|
||||
bool mCompilationSuccessful;
|
||||
nsCString mCompilationLog;
|
||||
nsString mTranslatedSource;
|
||||
nsCString mTranslationLog; // The translation log should contain only ASCII characters
|
||||
bool mNeedsTranslation;
|
||||
nsTArray<WebGLMappedIdentifier> mAttributes;
|
||||
nsTArray<WebGLMappedIdentifier> mUniforms;
|
||||
nsTArray<WebGLUniformInfo> mUniformInfos;
|
||||
int mAttribMaxNameLength;
|
||||
bool mCompileStatus;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
82
dom/canvas/WebGLUniformInfo.h
Normal file
82
dom/canvas/WebGLUniformInfo.h
Normal 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
|
||||
@@ -5,272 +5,33 @@
|
||||
|
||||
#include "WebGLUniformLocation.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "WebGLActiveInfo.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLShader.h"
|
||||
|
||||
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*
|
||||
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_UNROOT_NATIVE(WebGLUniformLocation, Release)
|
||||
|
||||
@@ -6,56 +6,48 @@
|
||||
#ifndef WEBGL_UNIFORM_LOCATION_H_
|
||||
#define WEBGL_UNIFORM_LOCATION_H_
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
|
||||
struct JSContext;
|
||||
#include "WebGLUniformInfo.h"
|
||||
|
||||
namespace mozilla {
|
||||
class WebGLActiveInfo;
|
||||
class WebGLContext;
|
||||
|
||||
class WebGLProgram;
|
||||
|
||||
namespace webgl {
|
||||
struct LinkedProgramInfo;
|
||||
}
|
||||
|
||||
class WebGLUniformLocation MOZ_FINAL
|
||||
: public nsWrapperCache
|
||||
, public WebGLContextBoundObject
|
||||
: public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLUniformLocation)
|
||||
WebGLUniformLocation(WebGLContext* context, WebGLProgram* program,
|
||||
GLint location, const WebGLUniformInfo& info);
|
||||
|
||||
const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
|
||||
const GLuint mLoc;
|
||||
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.
|
||||
// needed for certain helper functions like ValidateObject.
|
||||
// WebGLUniformLocation's can't be 'Deleted' in the WebGL sense.
|
||||
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:
|
||||
~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
|
||||
|
||||
@@ -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
|
||||
@@ -27,23 +27,38 @@
|
||||
#ifndef WEBGL_VALIDATE_STRINGS_H_
|
||||
#define WEBGL_VALIDATE_STRINGS_H_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLContext;
|
||||
|
||||
// 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 ******/
|
||||
// Strips comments from shader text. This allows non-ASCII characters
|
||||
// to be used in comments without potentially breaking OpenGL
|
||||
// implementations not expecting characters outside the GLSL ES set.
|
||||
class StripComments {
|
||||
public:
|
||||
bool WebGLContext::ValidateGLSLCharacter(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;
|
||||
}
|
||||
|
||||
// Strips comments from shader text. This allows non-ASCII characters
|
||||
// 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())
|
||||
@@ -64,7 +79,7 @@ public:
|
||||
return m_position;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
bool hasMoreCharacters()
|
||||
{
|
||||
return (m_current < m_end);
|
||||
@@ -141,16 +156,97 @@ private:
|
||||
const char16_t* m_current;
|
||||
size_t m_position;
|
||||
nsTArray<char16_t> m_result;
|
||||
};
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl,
|
||||
const char* funcName);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGL_VALIDATE_STRINGS_H_
|
||||
|
||||
@@ -108,13 +108,11 @@ UNIFIED_SOURCES += [
|
||||
'WebGLSampler.cpp',
|
||||
'WebGLShader.cpp',
|
||||
'WebGLShaderPrecisionFormat.cpp',
|
||||
'WebGLShaderValidator.cpp',
|
||||
'WebGLSync.cpp',
|
||||
'WebGLTexelConversions.cpp',
|
||||
'WebGLTexture.cpp',
|
||||
'WebGLTransformFeedback.cpp',
|
||||
'WebGLUniformLocation.cpp',
|
||||
'WebGLValidateStrings.cpp',
|
||||
'WebGLVertexArray.cpp',
|
||||
'WebGLVertexArrayFake.cpp',
|
||||
'WebGLVertexArrayGL.cpp',
|
||||
|
||||
@@ -68,13 +68,15 @@ function shouldBeEmptyString(command) {
|
||||
}
|
||||
|
||||
for (var i = 0; i < arguments.length; ++i) {
|
||||
var func, func2;
|
||||
var func, func2, func3;
|
||||
if (arguments[i].throws) {
|
||||
func = shouldThrow;
|
||||
func2 = shouldThrow;
|
||||
func3 = shouldThrow;
|
||||
} else {
|
||||
func = shouldBeUndefined;
|
||||
func2 = shouldBeNull;
|
||||
func3 = shouldBeEmptyString;
|
||||
}
|
||||
argument = arguments[i].value;
|
||||
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.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
|
||||
|
||||
func2("context.getProgramInfoLog(argument)");
|
||||
func2("context.getProgramParameter(argument, 0)");
|
||||
func2("context.getShaderInfoLog(argument)");
|
||||
func2("context.getShaderParameter(argument, 0)");
|
||||
func2("context.getShaderSource(argument)");
|
||||
func2("context.getUniform(argument, loc)");
|
||||
func2("context.getUniform(program, argument)");
|
||||
func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
|
||||
|
||||
func3("context.getProgramInfoLog(argument)");
|
||||
func3("context.getShaderInfoLog(argument)");
|
||||
func3("context.getShaderSource(argument)");
|
||||
}
|
||||
|
||||
successfullyParsed = true;
|
||||
|
||||
@@ -2015,7 +2015,7 @@ public:
|
||||
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;
|
||||
mSymbols.fShaderSource(shader, count, strings, lengths);
|
||||
AFTER_GL_CALL;
|
||||
|
||||
@@ -308,7 +308,7 @@ struct GLContextSymbols
|
||||
PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat;
|
||||
typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source);
|
||||
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;
|
||||
|
||||
typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);
|
||||
|
||||
@@ -3841,6 +3841,7 @@ pref("gl.msaa-level", 2);
|
||||
#endif
|
||||
pref("webgl.force-enabled", false);
|
||||
pref("webgl.disabled", false);
|
||||
pref("webgl.shader_validator", true);
|
||||
pref("webgl.disable-angle", false);
|
||||
pref("webgl.min_capability_mode", 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.enable-draft-extensions", false);
|
||||
pref("webgl.enable-privileged-extensions", false);
|
||||
pref("webgl.bypass-shader-validation", false);
|
||||
#ifdef XP_WIN
|
||||
pref("webgl.angle.try-d3d11", true);
|
||||
pref("webgl.angle.force-d3d11", false);
|
||||
|
||||
Reference in New Issue
Block a user