Backed out changeset b5c6dd9423cf (bug 1109945) for gl2 test failures on a CLOSED TREE
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
///////////////////
|
///////////////////
|
||||||
//
|
//
|
||||||
// Whitelisting this test.
|
// Whitelisting this test.
|
||||||
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
|
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
|
||||||
//
|
//
|
||||||
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
|
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
|
||||||
|
|
||||||
@@ -26,41 +26,35 @@ function ifWebGLSupported() {
|
|||||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||||
|
|
||||||
|
|
||||||
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
|
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
|
||||||
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||||
|
|
||||||
ok(error,
|
ok(error,
|
||||||
"The new vertex shader source was compiled with errors.");
|
"The new vertex shader source was compiled with errors.");
|
||||||
|
is(error.compile, "",
|
||||||
// The implementation has the choice to defer all compile-time errors to link time.
|
"The compilation status should be empty.");
|
||||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
isnot(error.link, "",
|
||||||
|
"The linkage status should not be empty.");
|
||||||
isnot(infoLog, "",
|
is(error.link.split("ERROR").length - 1, 2,
|
||||||
"The one of the compile or link info logs should not be empty.");
|
"The linkage status contains two errors.");
|
||||||
is(infoLog.split("ERROR").length - 1, 2,
|
ok(error.link.contains("ERROR: 0:8: 'constructor'"),
|
||||||
"The info log status contains two errors.");
|
"A constructor error is contained in the linkage status.");
|
||||||
ok(infoLog.contains("ERROR: 0:8: 'constructor'"),
|
ok(error.link.contains("ERROR: 0:8: 'assign'"),
|
||||||
"A constructor error is contained in the info log.");
|
"An assignment error is contained in the linkage status.");
|
||||||
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
|
|
||||||
"An assignment error is contained in the info log.");
|
|
||||||
|
|
||||||
|
|
||||||
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
|
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
|
||||||
[, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
[, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||||
|
|
||||||
ok(error,
|
ok(error,
|
||||||
"The new fragment shader source was compiled with errors.");
|
"The new fragment shader source was compiled with errors.");
|
||||||
|
is(error.compile, "",
|
||||||
infoLog = (error.compile != "") ? error.compile : error.link;
|
"The compilation status should be empty.");
|
||||||
|
isnot(error.link, "",
|
||||||
isnot(infoLog, "",
|
"The linkage status should not be empty.");
|
||||||
"The one of the compile or link info logs should not be empty.");
|
is(error.link.split("ERROR").length - 1, 1,
|
||||||
is(infoLog.split("ERROR").length - 1, 1,
|
"The linkage status contains one error.");
|
||||||
"The info log contains one error.");
|
ok(error.link.contains("ERROR: 0:6: 'constructor'"),
|
||||||
ok(infoLog.contains("ERROR: 0:6: 'constructor'"),
|
"A constructor error is contained in the linkage status.");
|
||||||
"A constructor error is contained in the info log.");
|
|
||||||
|
|
||||||
|
|
||||||
yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||||
yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
|
yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
|
||||||
|
|||||||
@@ -23,18 +23,16 @@ function ifWebGLSupported() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
ok(error,
|
ok(error,
|
||||||
"The new vertex shader source was compiled with errors.");
|
"The new vertex shader source was compiled with errors.");
|
||||||
|
is(error.compile, "",
|
||||||
// The implementation has the choice to defer all compile-time errors to link time.
|
"The compilation status should be empty.");
|
||||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
isnot(error.link, "",
|
||||||
|
"The linkage status should not be empty.");
|
||||||
isnot(infoLog, "",
|
is(error.link.split("ERROR").length - 1, 2,
|
||||||
"The one of the compile or link info logs should not be empty.");
|
"The linkage status contains two errors.");
|
||||||
is(infoLog.split("ERROR").length - 1, 2,
|
ok(error.link.contains("ERROR: 0:8: 'constructor'"),
|
||||||
"The info log contains two errors.");
|
"A constructor error is contained in the linkage status.");
|
||||||
ok(infoLog.contains("ERROR: 0:8: 'constructor'"),
|
ok(error.link.contains("ERROR: 0:8: 'assign'"),
|
||||||
"A constructor error is contained in the info log.");
|
"An assignment error is contained in the linkage status.");
|
||||||
ok(infoLog.contains("ERROR: 0:8: 'assign'"),
|
|
||||||
"An assignment error is contained in the info log.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||||
@@ -54,16 +52,14 @@ function ifWebGLSupported() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
ok(error,
|
ok(error,
|
||||||
"The new fragment shader source was compiled with errors.");
|
"The new fragment shader source was compiled with errors.");
|
||||||
|
is(error.compile, "",
|
||||||
// The implementation has the choice to defer all compile-time errors to link time.
|
"The compilation status should be empty.");
|
||||||
let infoLog = (error.compile != "") ? error.compile : error.link;
|
isnot(error.link, "",
|
||||||
|
"The linkage status should not be empty.");
|
||||||
isnot(infoLog, "",
|
is(error.link.split("ERROR").length - 1, 1,
|
||||||
"The one of the compile or link info logs should not be empty.");
|
"The linkage status contains one error.");
|
||||||
is(infoLog.split("ERROR").length - 1, 1,
|
ok(error.link.contains("ERROR: 0:6: 'constructor'"),
|
||||||
"The info log contains one error.");
|
"A constructor error is contained in the linkage status.");
|
||||||
ok(infoLog.contains("ERROR: 0:6: 'constructor'"),
|
|
||||||
"A constructor error is contained in the info log.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||||
|
|||||||
@@ -152,8 +152,6 @@ WebGLContext::InitWebGL2()
|
|||||||
auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
|
auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
|
||||||
mBoundTransformFeedbackBuffers.reset(xfBuffers);
|
mBoundTransformFeedbackBuffers.reset(xfBuffers);
|
||||||
|
|
||||||
mBypassShaderValidation = true;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,13 +212,14 @@ WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
|
|||||||
tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
|
tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
|
gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
|
||||||
|
|
||||||
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
already_AddRefed<WebGLActiveInfo>
|
already_AddRefed<WebGLActiveInfo>
|
||||||
WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
||||||
{
|
{
|
||||||
@@ -231,7 +232,7 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
|||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
|
|
||||||
GLint len = 0;
|
GLint len = 0;
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
|
gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
|
||||||
if (!len)
|
if (!len)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -244,13 +245,10 @@ WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
|
|||||||
if (len == 0 || tfsize == 0 || tftype == 0)
|
if (len == 0 || tfsize == 0 || tftype == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
MOZ_CRASH("todo");
|
// TODO(djg): Reverse lookup of name
|
||||||
/*
|
// nsCString reverseMappedName;
|
||||||
// Reverse lookup of name
|
// prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
||||||
nsCString reverseMappedName;
|
|
||||||
prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
|
||||||
|
|
||||||
nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get()));
|
nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get()));
|
||||||
return result.forget();
|
return result.forget();
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ WebGL2Context::GetUniformIndices(WebGLProgram* program,
|
|||||||
if (!uniformNames.Length())
|
if (!uniformNames.Length())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
size_t count = uniformNames.Length();
|
size_t count = uniformNames.Length();
|
||||||
nsTArray<GLuint>& arr = retval.SetValue();
|
nsTArray<GLuint>& arr = retval.SetValue();
|
||||||
|
|
||||||
@@ -431,7 +431,7 @@ WebGL2Context::GetActiveUniforms(WebGLProgram* program,
|
|||||||
if (!count)
|
if (!count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
nsTArray<GLint>& arr = retval.SetValue();
|
nsTArray<GLint>& arr = retval.SetValue();
|
||||||
arr.SetLength(count);
|
arr.SetLength(count);
|
||||||
|
|
||||||
@@ -450,14 +450,17 @@ WebGL2Context::GetUniformBlockIndex(WebGLProgram* program,
|
|||||||
if (!ValidateObject("getUniformBlockIndex: program", program))
|
if (!ValidateObject("getUniformBlockIndex: program", program))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Leave this unchecked for now.
|
if (!ValidateGLSLVariableName(uniformBlockName, "getUniformBlockIndex"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
const NS_LossyConvertUTF16toASCII cname(uniformBlockName);
|
NS_LossyConvertUTF16toASCII cname(uniformBlockName);
|
||||||
|
nsCString mappedName;
|
||||||
|
program->MapIdentifier(cname, &mappedName);
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
|
|
||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
return gl->fGetUniformBlockIndex(progname, cname.BeginReading());
|
return gl->fGetUniformBlockIndex(progname, mappedName.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -498,7 +501,7 @@ WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* progr
|
|||||||
if (!ValidateObject("getActiveUniformBlockParameter: program", program))
|
if (!ValidateObject("getActiveUniformBlockParameter: program", program))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
GLint param = 0;
|
GLint param = 0;
|
||||||
|
|
||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
@@ -548,7 +551,7 @@ WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBl
|
|||||||
if (!ValidateObject("getActiveUniformBlockName: program", program))
|
if (!ValidateObject("getActiveUniformBlockName: program", program))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
|
GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
|
||||||
GLsizei length = 0;
|
GLsizei length = 0;
|
||||||
|
|
||||||
@@ -571,7 +574,7 @@ WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockInd
|
|||||||
if (!ValidateObject("uniformBlockBinding: program", program))
|
if (!ValidateObject("uniformBlockBinding: program", program))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint progname = program->mGLName;
|
GLuint progname = program->GLName();
|
||||||
|
|
||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
|
gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
|
||||||
|
|||||||
@@ -6,94 +6,15 @@
|
|||||||
#include "WebGLActiveInfo.h"
|
#include "WebGLActiveInfo.h"
|
||||||
|
|
||||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||||
|
#include "WebGLContext.h"
|
||||||
|
#include "WebGLTexture.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
ElemSizeFromType(GLenum elemType)
|
|
||||||
{
|
|
||||||
switch (elemType) {
|
|
||||||
case LOCAL_GL_BOOL:
|
|
||||||
case LOCAL_GL_FLOAT:
|
|
||||||
case LOCAL_GL_INT:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_3D:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
|
||||||
case LOCAL_GL_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
|
||||||
case LOCAL_GL_SAMPLER_CUBE:
|
|
||||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case LOCAL_GL_BOOL_VEC2:
|
|
||||||
case LOCAL_GL_FLOAT_VEC2:
|
|
||||||
case LOCAL_GL_INT_VEC2:
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case LOCAL_GL_BOOL_VEC3:
|
|
||||||
case LOCAL_GL_FLOAT_VEC3:
|
|
||||||
case LOCAL_GL_INT_VEC3:
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
|
|
||||||
case LOCAL_GL_BOOL_VEC4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT2:
|
|
||||||
case LOCAL_GL_FLOAT_VEC4:
|
|
||||||
case LOCAL_GL_INT_VEC4:
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT_MAT2x3:
|
|
||||||
case LOCAL_GL_FLOAT_MAT3x2:
|
|
||||||
return 6;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT_MAT2x4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4x2:
|
|
||||||
return 8;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT_MAT3:
|
|
||||||
return 9;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT_MAT3x4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4x3:
|
|
||||||
return 12;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT_MAT4:
|
|
||||||
return 16;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Bad `elemType`.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGLActiveInfo::WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
|
|
||||||
const nsACString& baseUserName,
|
|
||||||
const nsACString& baseMappedName)
|
|
||||||
: mElemCount(elemCount)
|
|
||||||
, mElemType(elemType)
|
|
||||||
, mBaseUserName(baseUserName)
|
|
||||||
, mIsArray(isArray)
|
|
||||||
, mElemSize(ElemSizeFromType(elemType))
|
|
||||||
, mBaseMappedName(baseMappedName)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
WebGLActiveInfo::WrapObject(JSContext* js)
|
WebGLActiveInfo::WrapObject(JSContext* cx)
|
||||||
{
|
{
|
||||||
return dom::WebGLActiveInfoBinding::Wrap(js, this);
|
return dom::WebGLActiveInfoBinding::Wrap(cx, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLActiveInfo)
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLActiveInfo, AddRef)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLActiveInfo, Release)
|
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -6,76 +6,48 @@
|
|||||||
#ifndef WEBGL_ACTIVE_INFO_H_
|
#ifndef WEBGL_ACTIVE_INFO_H_
|
||||||
#define WEBGL_ACTIVE_INFO_H_
|
#define WEBGL_ACTIVE_INFO_H_
|
||||||
|
|
||||||
#include "GLDefs.h"
|
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
|
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "WebGLObjectModel.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class WebGLActiveInfo MOZ_FINAL
|
class WebGLActiveInfo MOZ_FINAL
|
||||||
: public nsWrapperCache
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLActiveInfo)
|
WebGLActiveInfo(GLint size, GLenum type, const nsACString& name)
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLActiveInfo)
|
: mSize(size)
|
||||||
|
, mType(type)
|
||||||
const GLint mElemCount; // `size`
|
, mName(NS_ConvertASCIItoUTF16(name))
|
||||||
const GLenum mElemType; // `type`
|
{}
|
||||||
const nsCString mBaseUserName; // `name`, but ASCII, and without any final "[0]".
|
|
||||||
|
|
||||||
// Not actually part of ActiveInfo:
|
|
||||||
const bool mIsArray;
|
|
||||||
const uint8_t mElemSize;
|
|
||||||
const nsCString mBaseMappedName; // Without any final "[0]".
|
|
||||||
|
|
||||||
WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
|
|
||||||
const nsACString& baseUserName, const nsACString& baseMappedName);
|
|
||||||
|
|
||||||
|
|
||||||
/* GLES 2.0.25, p33:
|
|
||||||
* This command will return as much information about active
|
|
||||||
* attributes as possible. If no information is available, length will
|
|
||||||
* be set to zero and name will be an empty string. This situation
|
|
||||||
* could arise if GetActiveAttrib is issued after a failed link.
|
|
||||||
*
|
|
||||||
* It's the same for GetActiveUniform.
|
|
||||||
*/
|
|
||||||
static WebGLActiveInfo* CreateInvalid() {
|
|
||||||
return new WebGLActiveInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebIDL attributes
|
// WebIDL attributes
|
||||||
|
|
||||||
GLint Size() const {
|
GLint Size() const {
|
||||||
return mElemCount;
|
return mSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum Type() const {
|
GLenum Type() const {
|
||||||
return mElemType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetName(nsString& retval) const {
|
void GetName(nsString& retval) const {
|
||||||
CopyASCIItoUTF16(mBaseUserName, retval);
|
retval = mName;
|
||||||
if (mIsArray)
|
|
||||||
retval.AppendLiteral("[0]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
|
JSObject* WrapObject(JSContext* cx);
|
||||||
|
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WebGLActiveInfo()
|
|
||||||
: mElemCount(0)
|
|
||||||
, mElemType(0)
|
|
||||||
, mBaseUserName("")
|
|
||||||
, mIsArray(false)
|
|
||||||
, mElemSize(0)
|
|
||||||
, mBaseMappedName("")
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// Private destructor, to discourage deletion outside of Release():
|
// Private destructor, to discourage deletion outside of Release():
|
||||||
~WebGLActiveInfo() { }
|
~WebGLActiveInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint mSize;
|
||||||
|
GLenum mType;
|
||||||
|
nsString mName;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ WebGLContextOptions::WebGLContextOptions()
|
|||||||
|
|
||||||
WebGLContext::WebGLContext()
|
WebGLContext::WebGLContext()
|
||||||
: WebGLContextUnchecked(nullptr)
|
: WebGLContextUnchecked(nullptr)
|
||||||
, mBypassShaderValidation(false)
|
|
||||||
, mNeedsFakeNoAlpha(false)
|
, mNeedsFakeNoAlpha(false)
|
||||||
{
|
{
|
||||||
mGeneration = 0;
|
mGeneration = 0;
|
||||||
@@ -216,6 +215,8 @@ WebGLContext::WebGLContext()
|
|||||||
mPixelStorePremultiplyAlpha = false;
|
mPixelStorePremultiplyAlpha = false;
|
||||||
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
|
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
|
||||||
|
|
||||||
|
mShaderValidation = true;
|
||||||
|
|
||||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||||
|
|
||||||
mVertexAttrib0Vector[0] = 0;
|
mVertexAttrib0Vector[0] = 0;
|
||||||
@@ -329,7 +330,6 @@ WebGLContext::DestroyResourcesAndContext()
|
|||||||
mBoundTransformFeedbackBuffer = nullptr;
|
mBoundTransformFeedbackBuffer = nullptr;
|
||||||
mBoundUniformBuffer = nullptr;
|
mBoundUniformBuffer = nullptr;
|
||||||
mCurrentProgram = nullptr;
|
mCurrentProgram = nullptr;
|
||||||
mActiveProgramLinkInfo = nullptr;
|
|
||||||
mBoundDrawFramebuffer = nullptr;
|
mBoundDrawFramebuffer = nullptr;
|
||||||
mBoundReadFramebuffer = nullptr;
|
mBoundReadFramebuffer = nullptr;
|
||||||
mActiveOcclusionQuery = nullptr;
|
mActiveOcclusionQuery = nullptr;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include "WebGLObjectModel.h"
|
#include "WebGLObjectModel.h"
|
||||||
#include "WebGLRenderbuffer.h"
|
#include "WebGLRenderbuffer.h"
|
||||||
#include "WebGLTexture.h"
|
#include "WebGLTexture.h"
|
||||||
#include "WebGLShaderValidator.h"
|
|
||||||
#include "WebGLStrongTypes.h"
|
#include "WebGLStrongTypes.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@@ -97,10 +96,6 @@ namespace gfx {
|
|||||||
class SourceSurface;
|
class SourceSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace webgl {
|
|
||||||
struct LinkedProgramInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
||||||
|
|
||||||
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
|
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
|
||||||
@@ -380,9 +375,7 @@ public:
|
|||||||
void ClearStencil(GLint v);
|
void ClearStencil(GLint v);
|
||||||
void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a);
|
void ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a);
|
||||||
void CompileShader(WebGLShader* shader);
|
void CompileShader(WebGLShader* shader);
|
||||||
void CompileShaderANGLE(WebGLShader* shader);
|
void CompressedTexImage2D(GLenum texImageTarget, GLint level,
|
||||||
void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
|
|
||||||
void CompressedTexImage2D(GLenum target, GLint level,
|
|
||||||
GLenum internalformat, GLsizei width,
|
GLenum internalformat, GLsizei width,
|
||||||
GLsizei height, GLint border,
|
GLsizei height, GLint border,
|
||||||
const dom::ArrayBufferView& view);
|
const dom::ArrayBufferView& view);
|
||||||
@@ -844,10 +837,8 @@ public:
|
|||||||
const float* data);
|
const float* data);
|
||||||
|
|
||||||
void UseProgram(WebGLProgram* prog);
|
void UseProgram(WebGLProgram* prog);
|
||||||
|
|
||||||
bool ValidateAttribArraySetter(const char* name, uint32_t count,
|
bool ValidateAttribArraySetter(const char* name, uint32_t count,
|
||||||
uint32_t arrayLength);
|
uint32_t arrayLength);
|
||||||
bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
|
|
||||||
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
||||||
GLenum setterType, const char* info,
|
GLenum setterType, const char* info,
|
||||||
GLuint* out_rawLoc);
|
GLuint* out_rawLoc);
|
||||||
@@ -1127,9 +1118,8 @@ protected:
|
|||||||
GLenum mUnderlyingGLError;
|
GLenum mUnderlyingGLError;
|
||||||
GLenum GetAndFlushUnderlyingGLErrors();
|
GLenum GetAndFlushUnderlyingGLErrors();
|
||||||
|
|
||||||
bool mBypassShaderValidation;
|
// whether shader validation is supported
|
||||||
|
bool mShaderValidation;
|
||||||
webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
|
|
||||||
|
|
||||||
// some GL constants
|
// some GL constants
|
||||||
int32_t mGLMaxVertexAttribs;
|
int32_t mGLMaxVertexAttribs;
|
||||||
@@ -1154,10 +1144,6 @@ public:
|
|||||||
return mGLMaxVertexAttribs;
|
return mGLMaxVertexAttribs;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint GLMaxTextureUnits() const {
|
|
||||||
return mGLMaxTextureUnits;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool IsFormatValidForFB(GLenum sizedFormat) const;
|
bool IsFormatValidForFB(GLenum sizedFormat) const;
|
||||||
|
|
||||||
@@ -1239,6 +1225,10 @@ protected:
|
|||||||
WebGLintptr byteOffset, const char* info);
|
WebGLintptr byteOffset, const char* info);
|
||||||
bool ValidateStencilParamsForDrawCall();
|
bool ValidateStencilParamsForDrawCall();
|
||||||
|
|
||||||
|
bool ValidateGLSLVariableName(const nsAString& name, const char* info);
|
||||||
|
bool ValidateGLSLCharacter(char16_t c);
|
||||||
|
bool ValidateGLSLString(const nsAString& string, const char* info);
|
||||||
|
|
||||||
bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func,
|
bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func,
|
||||||
WebGLTexDimensions dims);
|
WebGLTexDimensions dims);
|
||||||
|
|
||||||
@@ -1285,10 +1275,6 @@ protected:
|
|||||||
WebGLTexImageFunc func,
|
WebGLTexImageFunc func,
|
||||||
WebGLTexDimensions dims);
|
WebGLTexDimensions dims);
|
||||||
|
|
||||||
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
|
|
||||||
WebGLProgram* program,
|
|
||||||
const char* funcName);
|
|
||||||
|
|
||||||
void Invalidate();
|
void Invalidate();
|
||||||
void DestroyResourcesAndContext();
|
void DestroyResourcesAndContext();
|
||||||
|
|
||||||
@@ -1417,7 +1403,6 @@ protected:
|
|||||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
||||||
|
|
||||||
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
||||||
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
|
|
||||||
|
|
||||||
uint32_t mMaxFramebufferColorAttachments;
|
uint32_t mMaxFramebufferColorAttachments;
|
||||||
|
|
||||||
@@ -1610,7 +1595,7 @@ WebGLContext::ValidateObjectAssumeNonNull(const char* info, ObjectType* object)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (object->IsDeleted()) {
|
if (object->IsDeleted()) {
|
||||||
ErrorInvalidValue("%s: Deleted object passed as argument.", info);
|
ErrorInvalidValue("%s: deleted object passed as argument", info);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "WebGLRenderbuffer.h"
|
#include "WebGLRenderbuffer.h"
|
||||||
#include "WebGLShader.h"
|
#include "WebGLShader.h"
|
||||||
#include "WebGLTexture.h"
|
#include "WebGLTexture.h"
|
||||||
|
#include "WebGLUniformInfo.h"
|
||||||
#include "WebGLVertexArray.h"
|
#include "WebGLVertexArray.h"
|
||||||
#include "WebGLVertexAttribData.h"
|
#include "WebGLVertexAttribData.h"
|
||||||
|
|
||||||
@@ -409,15 +410,11 @@ void WebGLContext::Draw_cleanup()
|
|||||||
bool
|
bool
|
||||||
WebGLContext::ValidateBufferFetching(const char* info)
|
WebGLContext::ValidateBufferFetching(const char* info)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mCurrentProgram);
|
|
||||||
// Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
|
|
||||||
MOZ_ASSERT(mActiveProgramLinkInfo);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
GLint currentProgram = 0;
|
GLint currentProgram = 0;
|
||||||
MakeContextCurrent();
|
MakeContextCurrent();
|
||||||
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram);
|
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");
|
"WebGL: current program doesn't agree with GL state");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -444,7 +441,7 @@ WebGLContext::ValidateBufferFetching(const char* info)
|
|||||||
|
|
||||||
// If the attrib is not in use, then we don't have to validate
|
// If the attrib is not in use, then we don't have to validate
|
||||||
// it, just need to make sure that the binding is non-null.
|
// it, just need to make sure that the binding is non-null.
|
||||||
if (!mActiveProgramLinkInfo->HasActiveAttrib(i))
|
if (!mCurrentProgram->IsAttribInUse(i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// the base offset
|
// the base offset
|
||||||
@@ -501,13 +498,12 @@ WebGLVertexAttrib0Status
|
|||||||
WebGLContext::WhatDoesVertexAttrib0Need()
|
WebGLContext::WhatDoesVertexAttrib0Need()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mCurrentProgram);
|
MOZ_ASSERT(mCurrentProgram);
|
||||||
MOZ_ASSERT(mActiveProgramLinkInfo);
|
|
||||||
|
|
||||||
// work around Mac OSX crash, see bug 631420
|
// work around Mac OSX crash, see bug 631420
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
if (gl->WorkAroundDriverBugs() &&
|
if (gl->WorkAroundDriverBugs() &&
|
||||||
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
||||||
!mActiveProgramLinkInfo->HasActiveAttrib(0))
|
!mCurrentProgram->IsAttribInUse(0))
|
||||||
{
|
{
|
||||||
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||||
}
|
}
|
||||||
@@ -519,7 +515,7 @@ WebGLContext::WhatDoesVertexAttrib0Need()
|
|||||||
return WebGLVertexAttrib0Status::Default;
|
return WebGLVertexAttrib0Status::Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mActiveProgramLinkInfo->HasActiveAttrib(0)
|
return mCurrentProgram->IsAttribInUse(0)
|
||||||
? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
||||||
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1043,7 +1043,7 @@ WebGLContext::AssertCachedBindings()
|
|||||||
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
|
GLuint bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
|
||||||
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
|
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "WebGLShader.h"
|
#include "WebGLShader.h"
|
||||||
#include "WebGLTexture.h"
|
#include "WebGLTexture.h"
|
||||||
#include "WebGLUniformLocation.h"
|
#include "WebGLUniformLocation.h"
|
||||||
#include "WebGLValidateStrings.h"
|
|
||||||
#include "WebGLVertexArray.h"
|
#include "WebGLVertexArray.h"
|
||||||
#include "WebGLVertexAttribData.h"
|
#include "WebGLVertexAttribData.h"
|
||||||
|
|
||||||
@@ -368,6 +367,50 @@ WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char* info)
|
||||||
|
{
|
||||||
|
if (name.IsEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const uint32_t maxSize = 256;
|
||||||
|
if (name.Length() > maxSize) {
|
||||||
|
ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
|
||||||
|
" maximum allowed length of %d characters.", info,
|
||||||
|
name.Length(), maxSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ValidateGLSLString(name, info))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nsString prefix1 = NS_LITERAL_STRING("webgl_");
|
||||||
|
nsString prefix2 = NS_LITERAL_STRING("_webgl_");
|
||||||
|
|
||||||
|
if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
|
||||||
|
Substring(name, 0, prefix2.Length()).Equals(prefix2))
|
||||||
|
{
|
||||||
|
ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
|
||||||
|
info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebGLContext::ValidateGLSLString(const nsAString& string, const char* info)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < string.Length(); ++i) {
|
||||||
|
if (!ValidateGLSLCharacter(string.CharAt(i))) {
|
||||||
|
ErrorInvalidValue("%s: String contains the illegal character"
|
||||||
|
" '%d'.", info, string.CharAt(i));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the framebuffer attachment is valid. Attachment must
|
* Return true if the framebuffer attachment is valid. Attachment must
|
||||||
* be one of depth/stencil/depth_stencil/color attachment.
|
* be one of depth/stencil/depth_stencil/color attachment.
|
||||||
@@ -1469,37 +1512,163 @@ WebGLContext::ValidateTexImage(TexImageTarget texImageTarget, GLint level,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
|
WebGLContext::ValidateUniformLocation(const char* info,
|
||||||
|
WebGLUniformLocation* loc)
|
||||||
{
|
{
|
||||||
/* GLES 2.0.25, p38:
|
if (!ValidateObjectAllowNull(info, loc))
|
||||||
* If the value of location is -1, the Uniform* commands will silently
|
return false;
|
||||||
* ignore the data passed in, and the current uniform values will not be
|
|
||||||
* changed.
|
|
||||||
*/
|
|
||||||
if (!loc)
|
if (!loc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ValidateObject(funcName, loc))
|
// The need to check specifically for !mCurrentProgram here is explained in
|
||||||
return false;
|
// bug 657556.
|
||||||
|
|
||||||
if (!mCurrentProgram) {
|
if (!mCurrentProgram) {
|
||||||
ErrorInvalidOperation("%s: No program is currently bound.", funcName);
|
ErrorInvalidOperation("%s: No program is currently bound.", info);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loc->ValidateForProgram(mCurrentProgram, this, funcName);
|
if (mCurrentProgram != loc->Program()) {
|
||||||
|
ErrorInvalidOperation("%s: This uniform location doesn't correspond to"
|
||||||
|
" the current program.", info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentProgram->Generation() != loc->ProgramGeneration()) {
|
||||||
|
ErrorInvalidOperation("%s: This uniform location is obsolete since the"
|
||||||
|
" program has been relinked.", info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSize,
|
WebGLContext::ValidateSamplerUniformSetter(const char* info,
|
||||||
|
WebGLUniformLocation* loc,
|
||||||
|
GLint value)
|
||||||
|
{
|
||||||
|
if (loc->Info().type != LOCAL_GL_SAMPLER_2D &&
|
||||||
|
loc->Info().type != LOCAL_GL_SAMPLER_CUBE)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value >= 0 && value < mGLMaxTextureUnits)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
|
||||||
|
" valid texture unit.", info, value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt,
|
||||||
uint32_t arrayLength)
|
uint32_t arrayLength)
|
||||||
{
|
{
|
||||||
if (IsContextLost())
|
if (IsContextLost())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (arrayLength < setterElemSize) {
|
if (arrayLength < cnt) {
|
||||||
ErrorInvalidOperation("%s: Array must have >= %d elements.", name,
|
ErrorInvalidOperation("%s: Array must be >= %d elements.", name, cnt);
|
||||||
setterElemSize);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
||||||
|
{
|
||||||
|
switch (uniformType) {
|
||||||
|
case LOCAL_GL_BOOL:
|
||||||
|
case LOCAL_GL_BOOL_VEC2:
|
||||||
|
case LOCAL_GL_BOOL_VEC3:
|
||||||
|
case LOCAL_GL_BOOL_VEC4:
|
||||||
|
return true; // GLfloat(0.0) sets a bool to false.
|
||||||
|
|
||||||
|
case LOCAL_GL_INT:
|
||||||
|
case LOCAL_GL_INT_SAMPLER_2D:
|
||||||
|
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case LOCAL_GL_INT_SAMPLER_3D:
|
||||||
|
case LOCAL_GL_INT_SAMPLER_CUBE:
|
||||||
|
case LOCAL_GL_INT_VEC2:
|
||||||
|
case LOCAL_GL_INT_VEC3:
|
||||||
|
case LOCAL_GL_INT_VEC4:
|
||||||
|
case LOCAL_GL_SAMPLER_2D:
|
||||||
|
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
||||||
|
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||||
|
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
||||||
|
case LOCAL_GL_SAMPLER_CUBE:
|
||||||
|
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
||||||
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
||||||
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
||||||
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||||
|
return setterType == LOCAL_GL_INT;
|
||||||
|
|
||||||
|
case LOCAL_GL_FLOAT:
|
||||||
|
case LOCAL_GL_FLOAT_MAT2:
|
||||||
|
case LOCAL_GL_FLOAT_MAT2x3:
|
||||||
|
case LOCAL_GL_FLOAT_MAT2x4:
|
||||||
|
case LOCAL_GL_FLOAT_MAT3:
|
||||||
|
case LOCAL_GL_FLOAT_MAT3x2:
|
||||||
|
case LOCAL_GL_FLOAT_MAT3x4:
|
||||||
|
case LOCAL_GL_FLOAT_MAT4:
|
||||||
|
case LOCAL_GL_FLOAT_MAT4x2:
|
||||||
|
case LOCAL_GL_FLOAT_MAT4x3:
|
||||||
|
case LOCAL_GL_FLOAT_VEC2:
|
||||||
|
case LOCAL_GL_FLOAT_VEC3:
|
||||||
|
case LOCAL_GL_FLOAT_VEC4:
|
||||||
|
return setterType == LOCAL_GL_FLOAT;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT(false); // should never get here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
|
||||||
|
uint8_t setterElemSize, GLenum setterType,
|
||||||
|
const char* info)
|
||||||
|
{
|
||||||
|
if (setterElemSize != loc->ElementSize()) {
|
||||||
|
webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
|
||||||
|
loc->ElementSize());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
|
||||||
|
webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
|
||||||
|
loc->Info().type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
|
||||||
|
uint8_t setterElemSize, size_t setterArraySize,
|
||||||
|
const char* info)
|
||||||
|
{
|
||||||
|
if (setterArraySize == 0 ||
|
||||||
|
setterArraySize % setterElemSize)
|
||||||
|
{
|
||||||
|
webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
|
||||||
|
" %d, got an array of length %d.", info,
|
||||||
|
setterElemSize, setterArraySize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loc->Info().isArray &&
|
||||||
|
setterArraySize != setterElemSize)
|
||||||
|
{
|
||||||
|
webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
||||||
|
" (since this uniform is not an array"
|
||||||
|
" uniform), got an array of length %d.",
|
||||||
|
info, setterElemSize, setterArraySize);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1509,18 +1678,18 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
|
|||||||
bool
|
bool
|
||||||
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
||||||
uint8_t setterElemSize, GLenum setterType,
|
uint8_t setterElemSize, GLenum setterType,
|
||||||
const char* funcName, GLuint* out_rawLoc)
|
const char* info, GLuint* out_rawLoc)
|
||||||
{
|
{
|
||||||
if (IsContextLost())
|
if (IsContextLost())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ValidateUniformLocation(loc, funcName))
|
if (!ValidateUniformLocation(info, loc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*out_rawLoc = loc->mLoc;
|
*out_rawLoc = loc->Location();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1529,24 +1698,27 @@ WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
|||||||
uint8_t setterElemSize,
|
uint8_t setterElemSize,
|
||||||
GLenum setterType,
|
GLenum setterType,
|
||||||
size_t setterArraySize,
|
size_t setterArraySize,
|
||||||
const char* funcName,
|
const char* info,
|
||||||
GLuint* const out_rawLoc,
|
GLuint* const out_rawLoc,
|
||||||
GLsizei* const out_numElementsToUpload)
|
GLsizei* const out_numElementsToUpload)
|
||||||
{
|
{
|
||||||
if (IsContextLost())
|
if (IsContextLost())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ValidateUniformLocation(loc, funcName))
|
if (!ValidateUniformLocation(info, loc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||||
|
info))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*out_rawLoc = loc->mLoc;
|
*out_rawLoc = loc->Location();
|
||||||
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
|
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||||
setterArraySize / setterElemSize);
|
setterArraySize / setterElemSize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1557,7 +1729,7 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||||||
GLenum setterType,
|
GLenum setterType,
|
||||||
size_t setterArraySize,
|
size_t setterArraySize,
|
||||||
bool setterTranspose,
|
bool setterTranspose,
|
||||||
const char* funcName,
|
const char* info,
|
||||||
GLuint* const out_rawLoc,
|
GLuint* const out_rawLoc,
|
||||||
GLsizei* const out_numElementsToUpload)
|
GLsizei* const out_numElementsToUpload)
|
||||||
{
|
{
|
||||||
@@ -1566,22 +1738,25 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||||||
if (IsContextLost())
|
if (IsContextLost())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ValidateUniformLocation(loc, funcName))
|
if (!ValidateUniformLocation(info, loc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
||||||
return false;
|
info))
|
||||||
|
{
|
||||||
if (setterTranspose) {
|
|
||||||
ErrorInvalidValue("%s: `transpose` must be false.", funcName);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_rawLoc = loc->mLoc;
|
if (setterTranspose) {
|
||||||
*out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
|
ErrorInvalidValue("%s: `transpose` must be false.", info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_rawLoc = loc->Location();
|
||||||
|
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
||||||
setterArraySize / setterElemSize);
|
setterArraySize / setterElemSize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1920,13 +2095,15 @@ WebGLContext::InitAndValidateGL()
|
|||||||
// Check the shader validator pref
|
// Check the shader validator pref
|
||||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
||||||
|
|
||||||
mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation",
|
mShaderValidation = Preferences::GetBool("webgl.shader_validator",
|
||||||
mBypassShaderValidation);
|
mShaderValidation);
|
||||||
|
|
||||||
// initialize shader translator
|
// initialize shader translator
|
||||||
if (!ShInitialize()) {
|
if (mShaderValidation) {
|
||||||
GenerateWarning("GLSL translator initialization failed!");
|
if (!ShInitialize()) {
|
||||||
return false;
|
GenerateWarning("GLSL translator initialization failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mesa can only be detected with the GL_VERSION string, of the form
|
// Mesa can only be detected with the GL_VERSION string, of the form
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "WebGLRenderbuffer.h"
|
#include "WebGLRenderbuffer.h"
|
||||||
#include "WebGLShader.h"
|
#include "WebGLShader.h"
|
||||||
#include "WebGLTexture.h"
|
#include "WebGLTexture.h"
|
||||||
|
#include "WebGLUniformInfo.h"
|
||||||
#include "WebGLVertexArray.h"
|
#include "WebGLVertexArray.h"
|
||||||
#include "WebGLVertexAttribData.h"
|
#include "WebGLVertexAttribData.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,690 +7,364 @@
|
|||||||
|
|
||||||
#include "GLContext.h"
|
#include "GLContext.h"
|
||||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||||
|
#include "MurmurHash3.h"
|
||||||
#include "WebGLContext.h"
|
#include "WebGLContext.h"
|
||||||
#include "WebGLShader.h"
|
#include "WebGLShader.h"
|
||||||
#include "WebGLUniformLocation.h"
|
|
||||||
#include "WebGLValidateStrings.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
/* If `name`: "foo[3]"
|
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]"
|
||||||
* Then returns true, with
|
* in bracketPart.
|
||||||
* `out_baseName`: "foo"
|
*
|
||||||
* `out_isArray`: true
|
* \param string input/output: The string to split, becomes the string without
|
||||||
* `out_index`: 3
|
* the bracket part.
|
||||||
*
|
* \param bracketPart output: Gets the bracket part.
|
||||||
* If `name`: "foo"
|
*
|
||||||
* Then returns true, with
|
* Notice that if there are multiple brackets like "foo[i].bar[j]", only the
|
||||||
* `out_baseName`: "foo"
|
* last bracket is split.
|
||||||
* `out_isArray`: false
|
*/
|
||||||
* `out_index`: <not written>
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
ParseName(const nsCString& name, nsCString* const out_baseName,
|
SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
|
||||||
bool* const out_isArray, size_t* const out_arrayIndex)
|
|
||||||
{
|
{
|
||||||
int32_t indexEnd = name.RFind("]");
|
MOZ_ASSERT(bracketPart.IsEmpty(),
|
||||||
if (indexEnd == -1 ||
|
"SplitLastSquareBracket must be called with empty bracketPart"
|
||||||
(uint32_t)indexEnd != name.Length() - 1)
|
" string.");
|
||||||
{
|
|
||||||
*out_baseName = name;
|
|
||||||
*out_isArray = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t indexOpenBracket = name.RFind("[");
|
if (string.IsEmpty())
|
||||||
if (indexOpenBracket == -1)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32_t indexStart = indexOpenBracket + 1;
|
char* string_start = string.BeginWriting();
|
||||||
uint32_t indexLen = indexEnd - indexStart;
|
char* s = string_start + string.Length() - 1;
|
||||||
if (indexLen == 0)
|
|
||||||
|
if (*s != ']')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
|
while (*s != '[' && s != string_start)
|
||||||
|
s--;
|
||||||
|
|
||||||
nsresult errorcode;
|
if (*s != '[')
|
||||||
int32_t indexNum = indexStr.ToInteger(&errorcode);
|
|
||||||
if (NS_FAILED(errorcode))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (indexNum < 0)
|
bracketPart.Assign(s);
|
||||||
return false;
|
*s = 0;
|
||||||
|
string.EndWriting();
|
||||||
*out_baseName = StringHead(name, indexOpenBracket);
|
string.SetLength(s - string_start);
|
||||||
*out_isArray = true;
|
|
||||||
*out_arrayIndex = indexNum;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
JSObject*
|
||||||
AddActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
|
WebGLProgram::WrapObject(JSContext* cx) {
|
||||||
const nsACString& baseUserName, const nsACString& baseMappedName,
|
return dom::WebGLProgramBinding::Wrap(cx, this);
|
||||||
std::vector<nsRefPtr<WebGLActiveInfo>>* activeInfoList,
|
|
||||||
std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
|
|
||||||
{
|
|
||||||
nsRefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(elemCount, elemType, isArray,
|
|
||||||
baseUserName, baseMappedName);
|
|
||||||
activeInfoList->push_back(info);
|
|
||||||
|
|
||||||
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//#define DUMP_SHADERVAR_MAPPINGS
|
|
||||||
|
|
||||||
static TemporaryRef<const webgl::LinkedProgramInfo>
|
|
||||||
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|
||||||
{
|
|
||||||
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
|
|
||||||
|
|
||||||
GLuint maxAttribLenWithNull = 0;
|
|
||||||
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
|
|
||||||
(GLint*)&maxAttribLenWithNull);
|
|
||||||
if (maxAttribLenWithNull < 1)
|
|
||||||
maxAttribLenWithNull = 1;
|
|
||||||
|
|
||||||
GLuint maxUniformLenWithNull = 0;
|
|
||||||
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
|
|
||||||
(GLint*)&maxUniformLenWithNull);
|
|
||||||
if (maxUniformLenWithNull < 1)
|
|
||||||
maxUniformLenWithNull = 1;
|
|
||||||
|
|
||||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
|
||||||
printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
|
|
||||||
printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Attribs
|
|
||||||
|
|
||||||
GLuint numActiveAttribs = 0;
|
|
||||||
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
|
|
||||||
(GLint*)&numActiveAttribs);
|
|
||||||
|
|
||||||
for (GLuint i = 0; i < numActiveAttribs; i++) {
|
|
||||||
nsAutoCString mappedName;
|
|
||||||
mappedName.SetLength(maxAttribLenWithNull - 1);
|
|
||||||
|
|
||||||
GLsizei lengthWithoutNull = 0;
|
|
||||||
GLint elemCount = 0; // `size`
|
|
||||||
GLenum elemType = 0; // `type`
|
|
||||||
gl->fGetActiveAttrib(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
|
|
||||||
&elemCount, &elemType, mappedName.BeginWriting());
|
|
||||||
|
|
||||||
mappedName.SetLength(lengthWithoutNull);
|
|
||||||
|
|
||||||
// Collect ActiveInfos:
|
|
||||||
|
|
||||||
// Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
|
|
||||||
// path.
|
|
||||||
nsDependentCString userName;
|
|
||||||
if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
|
|
||||||
userName.Rebind(mappedName, 0);
|
|
||||||
|
|
||||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
|
||||||
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
|
|
||||||
userName.BeginReading());
|
|
||||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const bool isArray = false;
|
|
||||||
AddActiveInfo(elemCount, elemType, isArray, userName, mappedName,
|
|
||||||
&info->activeAttribs, &info->attribMap);
|
|
||||||
|
|
||||||
// Collect active locations:
|
|
||||||
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
|
|
||||||
if (loc == -1)
|
|
||||||
MOZ_CRASH("Active attrib has no location.");
|
|
||||||
|
|
||||||
info->activeAttribLocs.insert(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uniforms
|
|
||||||
|
|
||||||
const bool needsCheckForArrays = true;
|
|
||||||
|
|
||||||
GLuint numActiveUniforms = 0;
|
|
||||||
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
|
|
||||||
(GLint*)&numActiveUniforms);
|
|
||||||
|
|
||||||
for (GLuint i = 0; i < numActiveUniforms; i++) {
|
|
||||||
nsAutoCString mappedName;
|
|
||||||
mappedName.SetLength(maxUniformLenWithNull - 1);
|
|
||||||
|
|
||||||
GLsizei lengthWithoutNull = 0;
|
|
||||||
GLint elemCount = 0; // `size`
|
|
||||||
GLenum elemType = 0; // `type`
|
|
||||||
gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
|
|
||||||
&elemCount, &elemType, mappedName.BeginWriting());
|
|
||||||
|
|
||||||
mappedName.SetLength(lengthWithoutNull);
|
|
||||||
|
|
||||||
nsAutoCString baseMappedName;
|
|
||||||
bool isArray;
|
|
||||||
size_t arrayIndex;
|
|
||||||
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
|
|
||||||
MOZ_CRASH("Failed to parse `mappedName` received from driver.");
|
|
||||||
|
|
||||||
// Note that for good drivers, `isArray` should already be correct.
|
|
||||||
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
|
|
||||||
|
|
||||||
nsAutoCString baseUserName;
|
|
||||||
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
|
|
||||||
baseUserName = baseMappedName;
|
|
||||||
|
|
||||||
if (needsCheckForArrays && !isArray) {
|
|
||||||
// By GLES 3, GetUniformLocation("foo[0]") should return -1 if `foo` is
|
|
||||||
// not an array. Our current linux Try slaves return the location of `foo`
|
|
||||||
// anyways, though.
|
|
||||||
std::string mappedName = baseMappedName.BeginReading();
|
|
||||||
mappedName += "[0]";
|
|
||||||
|
|
||||||
GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedName.c_str());
|
|
||||||
if (loc != -1)
|
|
||||||
isArray = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
|
||||||
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
|
|
||||||
(int)isArray, baseMappedName.BeginReading(),
|
|
||||||
baseUserName.BeginReading());
|
|
||||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
|
||||||
printf_stderr(" isArray: %d\n", (int)isArray);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AddActiveInfo(elemCount, elemType, isArray, baseUserName, baseMappedName,
|
|
||||||
&info->activeUniforms, &info->uniformMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return info.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* aProg)
|
|
||||||
: prog(aProg)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// WebGLProgram
|
|
||||||
|
|
||||||
static GLuint
|
|
||||||
CreateProgram(gl::GLContext* gl)
|
|
||||||
{
|
|
||||||
gl->MakeCurrent();
|
|
||||||
return gl->fCreateProgram();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGLProgram::WebGLProgram(WebGLContext* webgl)
|
WebGLProgram::WebGLProgram(WebGLContext* webgl)
|
||||||
: WebGLContextBoundObject(webgl)
|
: WebGLContextBoundObject(webgl)
|
||||||
, mGLName(CreateProgram(webgl->GL()))
|
, mLinkStatus(false)
|
||||||
|
, mGeneration(0)
|
||||||
|
, mIdentifierMap(new CStringMap)
|
||||||
|
, mIdentifierReverseMap(new CStringMap)
|
||||||
|
, mUniformInfoMap(new CStringToUniformInfoMap)
|
||||||
|
, mAttribMaxNameLength(0)
|
||||||
{
|
{
|
||||||
|
mContext->MakeContextCurrent();
|
||||||
|
mGLName = mContext->gl->fCreateProgram();
|
||||||
mContext->mPrograms.insertBack(this);
|
mContext->mPrograms.insertBack(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WebGLProgram::Delete()
|
WebGLProgram::Delete()
|
||||||
{
|
{
|
||||||
gl::GLContext* gl = mContext->GL();
|
DetachShaders();
|
||||||
|
mContext->MakeContextCurrent();
|
||||||
gl->MakeCurrent();
|
mContext->gl->fDeleteProgram(mGLName);
|
||||||
gl->fDeleteProgram(mGLName);
|
|
||||||
|
|
||||||
mVertShader = nullptr;
|
|
||||||
mFragShader = nullptr;
|
|
||||||
|
|
||||||
mMostRecentLinkInfo = nullptr;
|
|
||||||
|
|
||||||
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
|
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
bool
|
||||||
// GL funcs
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::AttachShader(WebGLShader* shader)
|
WebGLProgram::AttachShader(WebGLShader* shader)
|
||||||
{
|
{
|
||||||
WebGLRefPtr<WebGLShader>* shaderSlot;
|
if (ContainsShader(shader))
|
||||||
switch (shader->mType) {
|
return false;
|
||||||
case LOCAL_GL_VERTEX_SHADER:
|
|
||||||
shaderSlot = &mVertShader;
|
|
||||||
break;
|
|
||||||
case LOCAL_GL_FRAGMENT_SHADER:
|
|
||||||
shaderSlot = &mFragShader;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*shaderSlot) {
|
mAttachedShaders.AppendElement(shader);
|
||||||
if (shader == *shaderSlot) {
|
|
||||||
mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
|
|
||||||
} else {
|
|
||||||
mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
|
|
||||||
" shader may be attached to a program.");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*shaderSlot = shader;
|
|
||||||
|
|
||||||
mContext->MakeContextCurrent();
|
mContext->MakeContextCurrent();
|
||||||
mContext->gl->fAttachShader(mGLName, shader->mGLName);
|
mContext->gl->fAttachShader(GLName(), shader->GLName());
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
|
|
||||||
{
|
|
||||||
if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (loc >= mContext->MaxVertexAttribs()) {
|
|
||||||
mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
|
|
||||||
" MAX_VERTEX_ATTRIBS.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
|
|
||||||
mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
|
|
||||||
" name that starts with 'gl_'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_LossyConvertUTF16toASCII asciiName(name);
|
|
||||||
|
|
||||||
auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
|
|
||||||
|
|
||||||
const bool wasInserted = res.second;
|
|
||||||
if (!wasInserted) {
|
|
||||||
auto itr = res.first;
|
|
||||||
itr->second = loc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::DetachShader(WebGLShader* shader)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(shader);
|
|
||||||
|
|
||||||
WebGLRefPtr<WebGLShader>* shaderSlot;
|
|
||||||
switch (shader->mType) {
|
|
||||||
case LOCAL_GL_VERTEX_SHADER:
|
|
||||||
shaderSlot = &mVertShader;
|
|
||||||
break;
|
|
||||||
case LOCAL_GL_FRAGMENT_SHADER:
|
|
||||||
shaderSlot = &mFragShader;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*shaderSlot != shader) {
|
|
||||||
mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*shaderSlot = nullptr;
|
|
||||||
|
|
||||||
mContext->MakeContextCurrent();
|
|
||||||
mContext->gl->fDetachShader(mGLName, shader->mGLName);
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<WebGLActiveInfo>
|
|
||||||
WebGLProgram::GetActiveAttrib(GLuint index) const
|
|
||||||
{
|
|
||||||
if (!mMostRecentLinkInfo) {
|
|
||||||
nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
|
|
||||||
return ret.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& activeList = mMostRecentLinkInfo->activeAttribs;
|
|
||||||
|
|
||||||
if (index >= activeList.size()) {
|
|
||||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
|
||||||
index, "ACTIVE_ATTRIBS", activeList.size());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<WebGLActiveInfo> ret = activeList[index];
|
|
||||||
return ret.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<WebGLActiveInfo>
|
|
||||||
WebGLProgram::GetActiveUniform(GLuint index) const
|
|
||||||
{
|
|
||||||
if (!mMostRecentLinkInfo) {
|
|
||||||
nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
|
|
||||||
return ret.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& activeList = mMostRecentLinkInfo->activeUniforms;
|
|
||||||
|
|
||||||
if (index >= activeList.size()) {
|
|
||||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
|
||||||
index, "ACTIVE_UNIFORMS", activeList.size());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<WebGLActiveInfo> ret = activeList[index];
|
|
||||||
return ret.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const
|
|
||||||
{
|
|
||||||
out->TruncateLength(0);
|
|
||||||
|
|
||||||
if (mVertShader)
|
|
||||||
out->AppendElement(mVertShader);
|
|
||||||
|
|
||||||
if (mFragShader)
|
|
||||||
out->AppendElement(mFragShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint
|
|
||||||
WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
|
|
||||||
{
|
|
||||||
if (!ValidateGLSLVariableName(userName_wide, mContext, "getAttribLocation"))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!IsLinked()) {
|
|
||||||
mContext->ErrorInvalidOperation("getAttribLocation: `program` must be linked.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
|
||||||
|
|
||||||
const WebGLActiveInfo* info;
|
|
||||||
if (!LinkInfo()->FindAttrib(userName, &info))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const nsCString& mappedName = info->mBaseMappedName;
|
|
||||||
|
|
||||||
gl::GLContext* gl = mContext->GL();
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::GetProgramInfoLog(nsAString* const out) const
|
|
||||||
{
|
|
||||||
CopyASCIItoUTF16(mLinkLog, *out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLint
|
|
||||||
GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname)
|
|
||||||
{
|
|
||||||
GLint ret = 0;
|
|
||||||
gl->fGetProgramiv(program, pname, &ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Value
|
|
||||||
WebGLProgram::GetProgramParameter(GLenum pname) const
|
|
||||||
{
|
|
||||||
gl::GLContext* gl = mContext->gl;
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
if (mContext->IsWebGL2()) {
|
|
||||||
switch (pname) {
|
|
||||||
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
|
|
||||||
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch (pname) {
|
|
||||||
case LOCAL_GL_ATTACHED_SHADERS:
|
|
||||||
case LOCAL_GL_ACTIVE_UNIFORMS:
|
|
||||||
case LOCAL_GL_ACTIVE_ATTRIBUTES:
|
|
||||||
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
|
|
||||||
|
|
||||||
case LOCAL_GL_DELETE_STATUS:
|
|
||||||
return JS::BooleanValue(IsDeleteRequested());
|
|
||||||
|
|
||||||
case LOCAL_GL_LINK_STATUS:
|
|
||||||
return JS::BooleanValue(IsLinked());
|
|
||||||
|
|
||||||
case LOCAL_GL_VALIDATE_STATUS:
|
|
||||||
#ifdef XP_MACOSX
|
|
||||||
// See comment in ValidateProgram.
|
|
||||||
if (gl->WorkAroundDriverBugs())
|
|
||||||
return JS::BooleanValue(true);
|
|
||||||
#endif
|
|
||||||
return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
|
|
||||||
|
|
||||||
default:
|
|
||||||
mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
|
|
||||||
pname);
|
|
||||||
return JS::NullValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<WebGLUniformLocation>
|
|
||||||
WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
|
||||||
{
|
|
||||||
if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!IsLinked()) {
|
|
||||||
mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
|
||||||
|
|
||||||
nsDependentCString baseUserName;
|
|
||||||
bool isArray;
|
|
||||||
size_t arrayIndex;
|
|
||||||
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const WebGLActiveInfo* activeInfo;
|
|
||||||
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
|
|
||||||
|
|
||||||
nsAutoCString mappedName(baseMappedName);
|
|
||||||
if (isArray) {
|
|
||||||
mappedName.AppendLiteral("[");
|
|
||||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
|
||||||
mappedName.AppendLiteral("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::GLContext* gl = mContext->GL();
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
|
|
||||||
if (loc == -1)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
nsRefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
|
|
||||||
loc, activeInfo);
|
|
||||||
return locObj.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLProgram::LinkProgram()
|
|
||||||
{
|
|
||||||
mContext->InvalidateBufferFetching(); // we do it early in this function
|
|
||||||
// as some of the validation below changes program state
|
|
||||||
|
|
||||||
mLinkLog.Truncate();
|
|
||||||
mMostRecentLinkInfo = nullptr;
|
|
||||||
|
|
||||||
if (!mVertShader || !mVertShader->IsCompiled()) {
|
|
||||||
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
|
|
||||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mFragShader || !mFragShader->IsCompiled()) {
|
|
||||||
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
|
|
||||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
|
|
||||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::GLContext* gl = mContext->gl;
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
// Bug 777028: Mesa can't handle more than 16 samplers per program,
|
|
||||||
// counting each array entry.
|
|
||||||
size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
|
|
||||||
mFragShader->CalcNumSamplerUniforms();
|
|
||||||
if (gl->WorkAroundDriverBugs() &&
|
|
||||||
mContext->mIsMesa &&
|
|
||||||
numSamplerUniforms_upperBound > 16)
|
|
||||||
{
|
|
||||||
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
|
|
||||||
" Mesa drivers to avoid crashing.");
|
|
||||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the attrib locations.
|
|
||||||
// This can't be done trivially, because we have to deal with mapped attrib names.
|
|
||||||
for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
|
|
||||||
const nsCString& name = itr->first;
|
|
||||||
GLuint index = itr->second;
|
|
||||||
|
|
||||||
mVertShader->BindAttribLocation(mGLName, name, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LinkAndUpdate())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Failed link.
|
|
||||||
if (mContext->ShouldGenerateWarnings()) {
|
|
||||||
// report shader/program infoLogs as warnings.
|
|
||||||
// note that shader compilation errors can be deferred to linkProgram,
|
|
||||||
// which is why we can't do anything in compileShader. In practice we could
|
|
||||||
// report in compileShader the translation errors generated by ANGLE,
|
|
||||||
// but it seems saner to keep a single way of obtaining shader infologs.
|
|
||||||
if (!mLinkLog.IsEmpty()) {
|
|
||||||
mContext->GenerateWarning("linkProgram: Failed to link, leaving the following"
|
|
||||||
" log:\n%s\n",
|
|
||||||
mLinkLog.BeginReading());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLProgram::UseProgram() const
|
|
||||||
{
|
|
||||||
if (!mMostRecentLinkInfo) {
|
|
||||||
mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
|
|
||||||
" linked.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mContext->MakeContextCurrent();
|
|
||||||
|
|
||||||
mContext->InvalidateBufferFetching();
|
|
||||||
|
|
||||||
mContext->gl->fUseProgram(mGLName);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
WebGLProgram::ValidateProgram() const
|
|
||||||
{
|
|
||||||
mContext->MakeContextCurrent();
|
|
||||||
gl::GLContext* gl = mContext->gl;
|
|
||||||
|
|
||||||
#ifdef XP_MACOSX
|
|
||||||
// See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
|
|
||||||
// with Mac OS 10.6.7.
|
|
||||||
if (gl->WorkAroundDriverBugs()) {
|
|
||||||
mContext->GenerateWarning("validateProgram: Implemented as a no-op on"
|
|
||||||
" Mac to work around crashes.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gl->fValidateProgram(mGLName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLProgram::LinkAndUpdate()
|
WebGLProgram::DetachShader(WebGLShader* shader)
|
||||||
{
|
{
|
||||||
mMostRecentLinkInfo = nullptr;
|
if (!mAttachedShaders.RemoveElement(shader))
|
||||||
|
|
||||||
gl::GLContext* gl = mContext->gl;
|
|
||||||
gl->fLinkProgram(mGLName);
|
|
||||||
|
|
||||||
// Grab the program log.
|
|
||||||
GLuint logLenWithNull = 0;
|
|
||||||
gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
|
|
||||||
if (logLenWithNull > 1) {
|
|
||||||
mLinkLog.SetLength(logLenWithNull - 1);
|
|
||||||
gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
|
|
||||||
} else {
|
|
||||||
mLinkLog.SetLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint ok = 0;
|
|
||||||
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
|
|
||||||
if (!ok)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mMostRecentLinkInfo = QueryProgramInfo(this, gl);
|
mContext->MakeContextCurrent();
|
||||||
|
mContext->gl->fDetachShader(GLName(), shader->GLName());
|
||||||
|
|
||||||
MOZ_ASSERT(mMostRecentLinkInfo);
|
return true;
|
||||||
if (!mMostRecentLinkInfo)
|
|
||||||
mLinkLog.AssignLiteral("Failed to gather program info.");
|
|
||||||
|
|
||||||
return mMostRecentLinkInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
|
WebGLProgram::HasAttachedShaderOfType(GLenum shaderType)
|
||||||
nsDependentCString* const out_userName) const
|
|
||||||
{
|
{
|
||||||
if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
|
for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
|
||||||
return true;
|
if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
|
WebGLProgram::HasBadShaderAttached()
|
||||||
nsCString* const out_userName,
|
|
||||||
bool* const out_isArray) const
|
|
||||||
{
|
{
|
||||||
if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
|
||||||
return true;
|
if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus())
|
||||||
|
return true;
|
||||||
if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
}
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
size_t
|
||||||
|
WebGLProgram::UpperBoundNumSamplerUniforms()
|
||||||
JSObject*
|
|
||||||
WebGLProgram::WrapObject(JSContext* js)
|
|
||||||
{
|
{
|
||||||
return dom::WebGLProgramBinding::Wrap(js, this);
|
size_t numSamplerUniforms = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
|
||||||
|
const WebGLShader* shader = mAttachedShaders[i];
|
||||||
|
if (!shader)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
|
||||||
|
WebGLUniformInfo u = shader->mUniformInfos[j];
|
||||||
|
if (u.type == LOCAL_GL_SAMPLER_2D ||
|
||||||
|
u.type == LOCAL_GL_SAMPLER_CUBE)
|
||||||
|
{
|
||||||
|
numSamplerUniforms += u.arraySize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numSamplerUniforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
|
void
|
||||||
|
WebGLProgram::MapIdentifier(const nsACString& name,
|
||||||
|
nsCString* const out_mappedName)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIdentifierMap);
|
||||||
|
|
||||||
|
nsCString mutableName(name);
|
||||||
|
nsCString bracketPart;
|
||||||
|
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||||
|
if (hadBracketPart)
|
||||||
|
mutableName.AppendLiteral("[0]");
|
||||||
|
|
||||||
|
if (mIdentifierMap->Get(mutableName, out_mappedName)) {
|
||||||
|
if (hadBracketPart) {
|
||||||
|
nsCString mappedBracketPart;
|
||||||
|
bool mappedHadBracketPart = SplitLastSquareBracket(*out_mappedName,
|
||||||
|
mappedBracketPart);
|
||||||
|
if (mappedHadBracketPart)
|
||||||
|
out_mappedName->Append(bracketPart);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found? We might be in the situation we have a uniform array name and
|
||||||
|
// the GL's glGetActiveUniform returned its name without [0], as is allowed
|
||||||
|
// by desktop GL but not in ES. Let's then try with [0].
|
||||||
|
mutableName.AppendLiteral("[0]");
|
||||||
|
if (mIdentifierMap->Get(mutableName, out_mappedName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Not found? Return name unchanged. This case happens e.g. on bad user
|
||||||
|
* input, or when we're not using identifier mapping, or if we didn't store
|
||||||
|
* an identifier in the map because e.g. its mapping is trivial. (as happens
|
||||||
|
* for short identifiers)
|
||||||
|
*/
|
||||||
|
out_mappedName->Assign(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WebGLProgram::ReverseMapIdentifier(const nsACString& name,
|
||||||
|
nsCString* const out_reverseMappedName)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIdentifierReverseMap);
|
||||||
|
|
||||||
|
nsCString mutableName(name);
|
||||||
|
nsCString bracketPart;
|
||||||
|
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||||
|
if (hadBracketPart)
|
||||||
|
mutableName.AppendLiteral("[0]");
|
||||||
|
|
||||||
|
if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName)) {
|
||||||
|
if (hadBracketPart) {
|
||||||
|
nsCString reverseMappedBracketPart;
|
||||||
|
bool reverseMappedHadBracketPart = SplitLastSquareBracket(*out_reverseMappedName,
|
||||||
|
reverseMappedBracketPart);
|
||||||
|
if (reverseMappedHadBracketPart)
|
||||||
|
out_reverseMappedName->Append(bracketPart);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found? We might be in the situation we have a uniform array name and
|
||||||
|
// the GL's glGetActiveUniform returned its name without [0], as is allowed
|
||||||
|
// by desktop GL but not in ES. Let's then try with [0].
|
||||||
|
mutableName.AppendLiteral("[0]");
|
||||||
|
if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Not found? Return name unchanged. This case happens e.g. on bad user
|
||||||
|
* input, or when we're not using identifier mapping, or if we didn't store
|
||||||
|
* an identifier in the map because e.g. its mapping is trivial. (as happens
|
||||||
|
* for short identifiers)
|
||||||
|
*/
|
||||||
|
out_reverseMappedName->Assign(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebGLUniformInfo
|
||||||
|
WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mUniformInfoMap);
|
||||||
|
|
||||||
|
nsCString mutableName(name);
|
||||||
|
nsCString bracketPart;
|
||||||
|
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||||
|
// If there is a bracket, we're either an array or an entry in an array.
|
||||||
|
if (hadBracketPart)
|
||||||
|
mutableName.AppendLiteral("[0]");
|
||||||
|
|
||||||
|
WebGLUniformInfo info;
|
||||||
|
mUniformInfoMap->Get(mutableName, &info);
|
||||||
|
// We don't check if that Get failed, as if it did, it left info with
|
||||||
|
// default values.
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WebGLProgram::UpdateInfo()
|
||||||
|
{
|
||||||
|
mAttribMaxNameLength = 0;
|
||||||
|
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
|
||||||
|
mAttribMaxNameLength = std::max(mAttribMaxNameLength,
|
||||||
|
mAttachedShaders[i]->mAttribMaxNameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint attribCount;
|
||||||
|
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
|
||||||
|
|
||||||
|
if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
|
||||||
|
mContext->ErrorOutOfMemory("updateInfo: Out of memory to allocate %d"
|
||||||
|
" attribs.", mContext->mGLMaxVertexAttribs);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mAttribsInUse.Length(); i++)
|
||||||
|
mAttribsInUse[i] = false;
|
||||||
|
|
||||||
|
nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
|
||||||
|
|
||||||
|
for (int i = 0; i < attribCount; ++i) {
|
||||||
|
GLint attrnamelen;
|
||||||
|
GLint attrsize;
|
||||||
|
GLenum attrtype;
|
||||||
|
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength,
|
||||||
|
&attrnamelen, &attrsize, &attrtype,
|
||||||
|
nameBuf);
|
||||||
|
if (attrnamelen > 0) {
|
||||||
|
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
|
||||||
|
MOZ_ASSERT(loc >= 0, "Major oops in managing the attributes of a"
|
||||||
|
" WebGL program.");
|
||||||
|
if (loc < mContext->mGLMaxVertexAttribs) {
|
||||||
|
mAttribsInUse[loc] = true;
|
||||||
|
} else {
|
||||||
|
mContext->GenerateWarning("Program exceeds MAX_VERTEX_ATTRIBS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsAutoPtr will delete old version first
|
||||||
|
mIdentifierMap = new CStringMap;
|
||||||
|
mIdentifierReverseMap = new CStringMap;
|
||||||
|
mUniformInfoMap = new CStringToUniformInfoMap;
|
||||||
|
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
|
||||||
|
// Loop through ATTRIBUTES
|
||||||
|
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
|
||||||
|
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
|
||||||
|
|
||||||
|
// FORWARD MAPPING
|
||||||
|
mIdentifierMap->Put(attrib.original, attrib.mapped);
|
||||||
|
// REVERSE MAPPING
|
||||||
|
mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through UNIFORMS
|
||||||
|
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
|
||||||
|
// Add the uniforms name mapping to mIdentifier[Reverse]Map
|
||||||
|
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
|
||||||
|
|
||||||
|
// FOWARD MAPPING
|
||||||
|
mIdentifierMap->Put(uniform.original, uniform.mapped);
|
||||||
|
// REVERSE MAPPING
|
||||||
|
mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
|
||||||
|
|
||||||
|
// Add uniform info to mUniformInfoMap
|
||||||
|
const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
|
||||||
|
mUniformInfoMap->Put(uniform.mapped, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mActiveAttribMap.clear();
|
||||||
|
|
||||||
|
GLint numActiveAttrs = 0;
|
||||||
|
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
|
||||||
|
|
||||||
|
// Spec says the maximum attrib name length is 256 chars, so this is
|
||||||
|
// sufficient to hold any attrib name.
|
||||||
|
char attrName[257];
|
||||||
|
|
||||||
|
GLint dummySize;
|
||||||
|
GLenum dummyType;
|
||||||
|
for (GLint i = 0; i < numActiveAttrs; i++) {
|
||||||
|
mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
|
||||||
|
&dummyType, attrName);
|
||||||
|
GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
|
||||||
|
MOZ_ASSERT(attrLoc >= 0);
|
||||||
|
mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ uint64_t
|
||||||
|
WebGLProgram::IdentifierHashFunction(const char* ident, size_t size)
|
||||||
|
{
|
||||||
|
uint64_t outhash[2];
|
||||||
|
// NB: we use the x86 function everywhere, even though it's suboptimal perf
|
||||||
|
// on x64. They return different results; not sure if that's a requirement.
|
||||||
|
MurmurHash3_x86_128(ident, size, 0, &outhash[0]);
|
||||||
|
return outhash[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ void
|
||||||
|
WebGLProgram::HashMapIdentifier(const nsACString& name,
|
||||||
|
nsCString* const out_hashedName)
|
||||||
|
{
|
||||||
|
uint64_t hash = IdentifierHashFunction(name.BeginReading(), name.Length());
|
||||||
|
out_hashedName->Truncate();
|
||||||
|
// This MUST MATCH HASHED_NAME_PREFIX from
|
||||||
|
// angle/src/compiler/translator/HashNames.h .
|
||||||
|
out_hashedName->AppendPrintf("webgl_%llx", hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
|
||||||
|
|||||||
@@ -9,74 +9,19 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "nsString.h"
|
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
#include "WebGLObjectModel.h"
|
#include "WebGLObjectModel.h"
|
||||||
#include "WebGLShader.h"
|
#include "WebGLShader.h"
|
||||||
|
#include "WebGLUniformInfo.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class WebGLActiveInfo;
|
|
||||||
class WebGLProgram;
|
|
||||||
class WebGLUniformLocation;
|
|
||||||
|
|
||||||
namespace webgl {
|
|
||||||
|
|
||||||
struct LinkedProgramInfo MOZ_FINAL
|
|
||||||
: public RefCounted<LinkedProgramInfo>
|
|
||||||
, public SupportsWeakPtr<LinkedProgramInfo>
|
|
||||||
{
|
|
||||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
|
|
||||||
|
|
||||||
WebGLProgram* const prog;
|
|
||||||
std::vector<nsRefPtr<WebGLActiveInfo>> activeAttribs;
|
|
||||||
std::vector<nsRefPtr<WebGLActiveInfo>> activeUniforms;
|
|
||||||
|
|
||||||
// Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
|
|
||||||
// user-facing `GLActiveInfo::name`s, without any final "[0]".
|
|
||||||
std::map<nsCString, const WebGLActiveInfo*> attribMap;
|
|
||||||
std::map<nsCString, const WebGLActiveInfo*> uniformMap;
|
|
||||||
|
|
||||||
// Needed for draw call validation.
|
|
||||||
std::set<GLuint> activeAttribLocs;
|
|
||||||
|
|
||||||
explicit LinkedProgramInfo(WebGLProgram* aProg);
|
|
||||||
|
|
||||||
bool FindAttrib(const nsCString& baseUserName,
|
|
||||||
const WebGLActiveInfo** const out_activeInfo) const
|
|
||||||
{
|
|
||||||
auto itr = attribMap.find(baseUserName);
|
|
||||||
if (itr == attribMap.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*out_activeInfo = itr->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindUniform(const nsCString& baseUserName,
|
|
||||||
const WebGLActiveInfo** const out_activeInfo) const
|
|
||||||
{
|
|
||||||
auto itr = uniformMap.find(baseUserName);
|
|
||||||
if (itr == uniformMap.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*out_activeInfo = itr->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasActiveAttrib(GLuint loc) const {
|
|
||||||
auto itr = activeAttribLocs.find(loc);
|
|
||||||
return itr != activeAttribLocs.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webgl
|
|
||||||
|
|
||||||
class WebGLShader;
|
class WebGLShader;
|
||||||
|
struct WebGLUniformInfo;
|
||||||
|
|
||||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
|
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
|
||||||
|
typedef nsDataHashtable<nsCStringHashKey,
|
||||||
|
WebGLUniformInfo> CStringToUniformInfoMap;
|
||||||
|
|
||||||
class WebGLProgram MOZ_FINAL
|
class WebGLProgram MOZ_FINAL
|
||||||
: public nsWrapperCache
|
: public nsWrapperCache
|
||||||
@@ -85,64 +30,107 @@ class WebGLProgram MOZ_FINAL
|
|||||||
, public WebGLContextBoundObject
|
, public WebGLContextBoundObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
|
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
|
|
||||||
|
|
||||||
explicit WebGLProgram(WebGLContext* webgl);
|
explicit WebGLProgram(WebGLContext* webgl);
|
||||||
|
|
||||||
void Delete();
|
void Delete();
|
||||||
|
|
||||||
// GL funcs
|
void DetachShaders() {
|
||||||
void AttachShader(WebGLShader* shader);
|
mAttachedShaders.Clear();
|
||||||
void BindAttribLocation(GLuint index, const nsAString& name);
|
|
||||||
void DetachShader(WebGLShader* shader);
|
|
||||||
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(GLuint index) const;
|
|
||||||
already_AddRefed<WebGLActiveInfo> GetActiveUniform(GLuint index) const;
|
|
||||||
void GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const;
|
|
||||||
GLint GetAttribLocation(const nsAString& name) const;
|
|
||||||
void GetProgramInfoLog(nsAString* const out) const;
|
|
||||||
JS::Value GetProgramParameter(GLenum pname) const;
|
|
||||||
already_AddRefed<WebGLUniformLocation> GetUniformLocation(const nsAString& name) const;
|
|
||||||
bool LinkProgram();
|
|
||||||
bool UseProgram() const;
|
|
||||||
void ValidateProgram() const;
|
|
||||||
|
|
||||||
////////////////
|
|
||||||
|
|
||||||
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
|
|
||||||
nsDependentCString* const out_userName) const;
|
|
||||||
bool FindUniformByMappedName(const nsACString& mappedName,
|
|
||||||
nsCString* const out_userName,
|
|
||||||
bool* const out_isArray) const;
|
|
||||||
|
|
||||||
bool IsLinked() const { return mMostRecentLinkInfo; }
|
|
||||||
|
|
||||||
const webgl::LinkedProgramInfo* LinkInfo() const {
|
|
||||||
return mMostRecentLinkInfo.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLuint GLName() { return mGLName; }
|
||||||
|
const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const {
|
||||||
|
return mAttachedShaders;
|
||||||
|
}
|
||||||
|
bool LinkStatus() { return mLinkStatus; }
|
||||||
|
uint32_t Generation() const { return mGeneration.value(); }
|
||||||
|
void SetLinkStatus(bool val) { mLinkStatus = val; }
|
||||||
|
|
||||||
|
bool ContainsShader(WebGLShader* shader) {
|
||||||
|
return mAttachedShaders.Contains(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if the shader wasn't already attached
|
||||||
|
bool AttachShader(WebGLShader* shader);
|
||||||
|
|
||||||
|
// return true if the shader was found and removed
|
||||||
|
bool DetachShader(WebGLShader* shader);
|
||||||
|
|
||||||
|
bool HasAttachedShaderOfType(GLenum shaderType);
|
||||||
|
|
||||||
|
bool HasBothShaderTypesAttached() {
|
||||||
|
return HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) &&
|
||||||
|
HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBadShaderAttached();
|
||||||
|
|
||||||
|
size_t UpperBoundNumSamplerUniforms();
|
||||||
|
|
||||||
|
bool NextGeneration() {
|
||||||
|
if (!(mGeneration + 1).isValid())
|
||||||
|
return false; // must exit without changing mGeneration
|
||||||
|
|
||||||
|
++mGeneration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called only after LinkProgram
|
||||||
|
bool UpdateInfo();
|
||||||
|
|
||||||
|
// Getters for cached program info
|
||||||
|
bool IsAttribInUse(uint32_t i) const { return mAttribsInUse[i]; }
|
||||||
|
|
||||||
|
// Maps identifier |name| to the mapped identifier |*mappedName|
|
||||||
|
// Both are ASCII strings.
|
||||||
|
void MapIdentifier(const nsACString& name, nsCString* out_mappedName);
|
||||||
|
|
||||||
|
// Un-maps mapped identifier |name| to the original identifier
|
||||||
|
// |*reverseMappedName|.
|
||||||
|
// Both are ASCII strings.
|
||||||
|
void ReverseMapIdentifier(const nsACString& name,
|
||||||
|
nsCString* out_reverseMappedName);
|
||||||
|
|
||||||
|
/* Returns the uniform array size (or 1 if the uniform is not an array) of
|
||||||
|
* the uniform with given mapped identifier.
|
||||||
|
*
|
||||||
|
* Note: The input string |name| is the mapped identifier, not the original
|
||||||
|
* identifier.
|
||||||
|
*/
|
||||||
|
WebGLUniformInfo GetUniformInfoForMappedIdentifier(const nsACString& name);
|
||||||
|
|
||||||
WebGLContext* GetParentObject() const {
|
WebGLContext* GetParentObject() const {
|
||||||
return Context();
|
return Context();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
|
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
|
||||||
|
|
||||||
private:
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
|
||||||
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
|
||||||
|
|
||||||
|
// public post-link data
|
||||||
|
std::map<GLint, nsCString> mActiveAttribMap;
|
||||||
|
|
||||||
|
static uint64_t IdentifierHashFunction(const char* ident, size_t size);
|
||||||
|
static void HashMapIdentifier(const nsACString& name,
|
||||||
|
nsCString* const out_hashedName);
|
||||||
|
|
||||||
|
protected:
|
||||||
~WebGLProgram() {
|
~WebGLProgram() {
|
||||||
DeleteOnce();
|
DeleteOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinkAndUpdate();
|
GLuint mGLName;
|
||||||
|
bool mLinkStatus;
|
||||||
|
// attached shaders of the program object
|
||||||
|
nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
|
||||||
|
CheckedUint32 mGeneration;
|
||||||
|
|
||||||
public:
|
// post-link data
|
||||||
const GLuint mGLName;
|
FallibleTArray<bool> mAttribsInUse;
|
||||||
|
nsAutoPtr<CStringMap> mIdentifierMap, mIdentifierReverseMap;
|
||||||
private:
|
nsAutoPtr<CStringToUniformInfoMap> mUniformInfoMap;
|
||||||
WebGLRefPtr<WebGLShader> mVertShader;
|
int mAttribMaxNameLength;
|
||||||
WebGLRefPtr<WebGLShader> mFragShader;
|
|
||||||
std::map<nsCString, GLuint> mBoundAttribLocs;
|
|
||||||
nsCString mLinkLog;
|
|
||||||
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -9,376 +9,53 @@
|
|||||||
#include "GLContext.h"
|
#include "GLContext.h"
|
||||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "nsPrintfCString.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "WebGLContext.h"
|
#include "WebGLContext.h"
|
||||||
#include "WebGLObjectModel.h"
|
#include "WebGLObjectModel.h"
|
||||||
#include "WebGLShaderValidator.h"
|
|
||||||
#include "WebGLValidateStrings.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
// On success, writes to out_validator and out_translatedSource.
|
JSObject*
|
||||||
// On failure, writes to out_translationLog.
|
WebGLShader::WrapObject(JSContext* cx) {
|
||||||
static bool
|
return dom::WebGLShaderBinding::Wrap(cx, this);
|
||||||
Translate(const nsACString& source, webgl::ShaderValidator* validator,
|
|
||||||
nsACString* const out_translationLog, nsACString* const out_translatedSource)
|
|
||||||
{
|
|
||||||
if (!validator->ValidateAndTranslate(source.BeginReading())) {
|
|
||||||
validator->GetInfoLog(out_translationLog);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
validator->GetOutput(out_translatedSource);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
static bool
|
|
||||||
SubstringStartsWith(const std::string& testStr, size_t offset, const char (& refStr)[N])
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < N-1; i++) {
|
|
||||||
if (testStr[offset + i] != refStr[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On success, writes to out_translatedSource.
|
|
||||||
* On failure, writes to out_translationLog.
|
|
||||||
*
|
|
||||||
* Requirements:
|
|
||||||
* #version is either omitted, `#version 100`, or `version 300 es`.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
TranslateWithoutValidation(const nsACString& sourceNS, bool isWebGL2,
|
|
||||||
nsACString* const out_translationLog,
|
|
||||||
nsACString* const out_translatedSource)
|
|
||||||
{
|
|
||||||
std::string source = sourceNS.BeginReading();
|
|
||||||
|
|
||||||
size_t versionStrStart = source.find("#version");
|
|
||||||
size_t versionStrLen;
|
|
||||||
uint32_t glesslVersion;
|
|
||||||
|
|
||||||
if (versionStrStart != std::string::npos) {
|
|
||||||
static const char versionStr100[] = "#version 100\n";
|
|
||||||
static const char versionStr300es[] = "#version 300 es\n";
|
|
||||||
|
|
||||||
if (isWebGL2 && SubstringStartsWith(source, versionStrStart, versionStr300es)) {
|
|
||||||
glesslVersion = 300;
|
|
||||||
versionStrLen = strlen(versionStr300es);
|
|
||||||
|
|
||||||
} else if (SubstringStartsWith(source, versionStrStart, versionStr100)) {
|
|
||||||
glesslVersion = 100;
|
|
||||||
versionStrLen = strlen(versionStr100);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
nsPrintfCString error("#version, if declared, must be %s.",
|
|
||||||
isWebGL2 ? "`100` or `300 es`"
|
|
||||||
: "`100`");
|
|
||||||
*out_translationLog = error;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
versionStrStart = 0;
|
|
||||||
versionStrLen = 0;
|
|
||||||
glesslVersion = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string reversionedSource = source;
|
|
||||||
reversionedSource.erase(versionStrStart, versionStrLen);
|
|
||||||
|
|
||||||
switch (glesslVersion) {
|
|
||||||
case 100:
|
|
||||||
break;
|
|
||||||
case 300:
|
|
||||||
reversionedSource.insert(versionStrStart, "#version 330\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Bad `glesslVersion`.");
|
|
||||||
}
|
|
||||||
|
|
||||||
out_translatedSource->Assign(reversionedSource.c_str(),
|
|
||||||
reversionedSource.length());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader, bool* const out_success,
|
|
||||||
nsACString* const out_log)
|
|
||||||
{
|
|
||||||
GLint compileStatus = LOCAL_GL_FALSE;
|
|
||||||
gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
|
|
||||||
|
|
||||||
// It's simpler if we always get the log.
|
|
||||||
GLint lenWithNull = 0;
|
|
||||||
gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
|
|
||||||
|
|
||||||
if (lenWithNull > 1) {
|
|
||||||
// SetLength takes the length without the null.
|
|
||||||
out_log->SetLength(lenWithNull - 1);
|
|
||||||
gl->fGetShaderInfoLog(shader, lenWithNull, nullptr, out_log->BeginWriting());
|
|
||||||
} else {
|
|
||||||
out_log->SetLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_success = (compileStatus == LOCAL_GL_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static GLuint
|
|
||||||
CreateShader(gl::GLContext* gl, GLenum type)
|
|
||||||
{
|
|
||||||
gl->MakeCurrent();
|
|
||||||
return gl->fCreateShader(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
|
WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
|
||||||
: WebGLContextBoundObject(webgl)
|
: WebGLContextBoundObject(webgl)
|
||||||
, mGLName(CreateShader(webgl->GL(), type))
|
|
||||||
, mType(type)
|
, mType(type)
|
||||||
|
, mNeedsTranslation(true)
|
||||||
|
, mAttribMaxNameLength(0)
|
||||||
|
, mCompileStatus(false)
|
||||||
{
|
{
|
||||||
|
mContext->MakeContextCurrent();
|
||||||
|
mGLName = mContext->gl->fCreateShader(mType);
|
||||||
mContext->mShaders.insertBack(this);
|
mContext->mShaders.insertBack(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGLShader::~WebGLShader()
|
|
||||||
{
|
|
||||||
DeleteOnce();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::ShaderSource(const nsAString& source)
|
|
||||||
{
|
|
||||||
StripComments stripComments(source);
|
|
||||||
const nsAString& cleanSource = Substring(stripComments.result().Elements(),
|
|
||||||
stripComments.length());
|
|
||||||
if (!ValidateGLSLString(cleanSource, mContext, "shaderSource"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// We checked that the source stripped of comments is in the
|
|
||||||
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
|
|
||||||
NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
|
|
||||||
|
|
||||||
if (mContext->gl->WorkAroundDriverBugs()) {
|
|
||||||
const size_t maxSourceLength = 0x3ffff;
|
|
||||||
if (sourceCString.Length() > maxSourceLength) {
|
|
||||||
mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
|
|
||||||
" characters. (Driver workaround)",
|
|
||||||
maxSourceLength);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK - dump shader source
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
printf_stderr("//-*- glsl -*-\n");
|
|
||||||
// Wow - Roll Your Own For Each Lines because printf_stderr has a hard-coded internal size, so long strings are truncated.
|
|
||||||
const nsString& src = shader->Source();
|
|
||||||
int32_t start = 0;
|
|
||||||
int32_t end = src.Find("\n", false, start, -1);
|
|
||||||
while (end > -1) {
|
|
||||||
printf_stderr("%s\n", NS_ConvertUTF16toUTF8(nsDependentSubstring(src, start, end - start)).get());
|
|
||||||
start = end + 1;
|
|
||||||
end = src.Find("\n", false, start, -1);
|
|
||||||
}
|
|
||||||
printf_stderr("//\n");
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
// HACK
|
|
||||||
|
|
||||||
mSource = source;
|
|
||||||
mCleanSource = sourceCString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::CompileShader()
|
|
||||||
{
|
|
||||||
mValidator = nullptr;
|
|
||||||
mTranslationSuccessful = false;
|
|
||||||
mCompilationSuccessful = false;
|
|
||||||
|
|
||||||
gl::GLContext* gl = mContext->gl;
|
|
||||||
|
|
||||||
mValidator.reset(mContext->CreateShaderValidator(mType));
|
|
||||||
|
|
||||||
bool success;
|
|
||||||
if (mValidator) {
|
|
||||||
success = Translate(mCleanSource, mValidator.get(), &mValidationLog,
|
|
||||||
&mTranslatedSource);
|
|
||||||
} else {
|
|
||||||
success = TranslateWithoutValidation(mCleanSource, mContext->IsWebGL2(),
|
|
||||||
&mValidationLog, &mTranslatedSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mTranslationSuccessful = true;
|
|
||||||
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
const char* const parts[] = {
|
|
||||||
mTranslatedSource.BeginReading()
|
|
||||||
};
|
|
||||||
gl->fShaderSource(mGLName, ArrayLength(parts), parts, nullptr);
|
|
||||||
|
|
||||||
gl->fCompileShader(mGLName);
|
|
||||||
|
|
||||||
GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful, &mCompilationLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::GetShaderInfoLog(nsAString* out) const
|
|
||||||
{
|
|
||||||
const nsCString& log = !mTranslationSuccessful ? mValidationLog
|
|
||||||
: mCompilationLog;
|
|
||||||
CopyASCIItoUTF16(log, *out);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Value
|
|
||||||
WebGLShader::GetShaderParameter(GLenum pname) const
|
|
||||||
{
|
|
||||||
switch (pname) {
|
|
||||||
case LOCAL_GL_SHADER_TYPE:
|
|
||||||
return JS::NumberValue(mType);
|
|
||||||
|
|
||||||
case LOCAL_GL_DELETE_STATUS:
|
|
||||||
return JS::BooleanValue(IsDeleteRequested());
|
|
||||||
|
|
||||||
case LOCAL_GL_COMPILE_STATUS:
|
|
||||||
return JS::BooleanValue(mCompilationSuccessful);
|
|
||||||
|
|
||||||
default:
|
|
||||||
mContext->ErrorInvalidEnumInfo("getShaderParameter: `pname`", pname);
|
|
||||||
return JS::NullValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::GetShaderSource(nsAString* out) const
|
|
||||||
{
|
|
||||||
out->SetIsVoid(false);
|
|
||||||
*out = mSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::GetShaderTranslatedSource(nsAString* out) const
|
|
||||||
{
|
|
||||||
if (!mCompilationSuccessful) {
|
|
||||||
mContext->ErrorInvalidOperation("getShaderTranslatedSource: Shader has"
|
|
||||||
" not been successfully compiled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out->SetIsVoid(false);
|
|
||||||
CopyASCIItoUTF16(mTranslatedSource, *out);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLShader::CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const
|
|
||||||
{
|
|
||||||
if (!mValidator)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return mValidator->CanLinkTo(prev->mValidator.get(), out_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
WebGLShader::CalcNumSamplerUniforms() const
|
|
||||||
{
|
|
||||||
if (mValidator)
|
|
||||||
return mValidator->CalcNumSamplerUniforms();
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
WebGLShader::BindAttribLocation(GLuint prog, const nsCString& userName,
|
|
||||||
GLuint index) const
|
|
||||||
{
|
|
||||||
std::string userNameStr(userName.BeginReading());
|
|
||||||
|
|
||||||
const std::string* mappedNameStr = &userNameStr;
|
|
||||||
if (mValidator)
|
|
||||||
mValidator->FindAttribMappedNameByUserName(userNameStr, &mappedNameStr);
|
|
||||||
|
|
||||||
mContext->gl->fBindAttribLocation(prog, index, mappedNameStr->c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLShader::FindAttribUserNameByMappedName(const nsACString& mappedName,
|
|
||||||
nsDependentCString* const out_userName) const
|
|
||||||
{
|
|
||||||
if (!mValidator)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const std::string mappedNameStr(mappedName.BeginReading());
|
|
||||||
const std::string* userNameStr;
|
|
||||||
if (!mValidator->FindAttribUserNameByMappedName(mappedNameStr, &userNameStr))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
out_userName->Rebind(userNameStr->c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLShader::FindUniformByMappedName(const nsACString& mappedName,
|
|
||||||
nsCString* const out_userName,
|
|
||||||
bool* const out_isArray) const
|
|
||||||
{
|
|
||||||
if (!mValidator)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const std::string mappedNameStr(mappedName.BeginReading(), mappedName.Length());
|
|
||||||
std::string userNameStr;
|
|
||||||
if (!mValidator->FindUniformByMappedName(mappedNameStr, &userNameStr, out_isArray))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*out_userName = userNameStr.c_str();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Boilerplate
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
WebGLShader::WrapObject(JSContext* js)
|
|
||||||
{
|
|
||||||
return dom::WebGLShaderBinding::Wrap(js, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
|
|
||||||
{
|
|
||||||
size_t validatorSize = mValidator ? mallocSizeOf(mValidator.get())
|
|
||||||
: 0;
|
|
||||||
return mallocSizeOf(this) +
|
|
||||||
mSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
|
|
||||||
mCleanSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
|
|
||||||
validatorSize +
|
|
||||||
mValidationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
|
|
||||||
mTranslatedSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
|
|
||||||
mCompilationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
WebGLShader::Delete()
|
WebGLShader::Delete()
|
||||||
{
|
{
|
||||||
gl::GLContext* gl = mContext->GL();
|
mSource.Truncate();
|
||||||
|
mTranslationLog.Truncate();
|
||||||
gl->MakeCurrent();
|
mContext->MakeContextCurrent();
|
||||||
gl->fDeleteShader(mGLName);
|
mContext->gl->fDeleteShader(mGLName);
|
||||||
|
|
||||||
LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders);
|
LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
|
||||||
|
{
|
||||||
|
return mallocSizeOf(this) +
|
||||||
|
mSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
|
||||||
|
mTranslationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WebGLShader::SetTranslationSuccess()
|
||||||
|
{
|
||||||
|
mTranslationLog.SetIsVoid(true);
|
||||||
|
mNeedsTranslation = false;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)
|
||||||
|
|||||||
@@ -6,17 +6,25 @@
|
|||||||
#ifndef WEBGL_SHADER_H_
|
#ifndef WEBGL_SHADER_H_
|
||||||
#define WEBGL_SHADER_H_
|
#define WEBGL_SHADER_H_
|
||||||
|
|
||||||
#include "GLDefs.h"
|
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "WebGLObjectModel.h"
|
#include "WebGLObjectModel.h"
|
||||||
|
#include "WebGLUniformInfo.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
namespace webgl {
|
struct WebGLMappedIdentifier
|
||||||
class ShaderValidator;
|
{
|
||||||
} // namespace webgl
|
// ASCII strings
|
||||||
|
nsCString original;
|
||||||
|
nsCString mapped;
|
||||||
|
|
||||||
|
WebGLMappedIdentifier(const nsACString& o, const nsACString& m)
|
||||||
|
: original(o)
|
||||||
|
, mapped(m)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
class WebGLShader MOZ_FINAL
|
class WebGLShader MOZ_FINAL
|
||||||
: public nsWrapperCache
|
: public nsWrapperCache
|
||||||
@@ -30,57 +38,67 @@ class WebGLShader MOZ_FINAL
|
|||||||
public:
|
public:
|
||||||
WebGLShader(WebGLContext* webgl, GLenum type);
|
WebGLShader(WebGLContext* webgl, GLenum type);
|
||||||
|
|
||||||
protected:
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||||
~WebGLShader();
|
|
||||||
|
|
||||||
public:
|
GLuint GLName() { return mGLName; }
|
||||||
// GL funcs
|
sh::GLenum ShaderType() { return mType; }
|
||||||
void CompileShader();
|
|
||||||
JS::Value GetShaderParameter(GLenum pname) const;
|
|
||||||
void GetShaderInfoLog(nsAString* out) const;
|
|
||||||
void GetShaderSource(nsAString* out) const;
|
|
||||||
void GetShaderTranslatedSource(nsAString* out) const;
|
|
||||||
void ShaderSource(const nsAString& source);
|
|
||||||
|
|
||||||
// Util funcs
|
void SetSource(const nsAString& src) {
|
||||||
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
|
// TODO: Do some quick gzip here maybe? Getting this will be very rare,
|
||||||
size_t CalcNumSamplerUniforms() const;
|
// and we have to keep it forever.
|
||||||
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
|
mSource.Assign(src);
|
||||||
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
|
}
|
||||||
nsDependentCString* const out_userName) const;
|
|
||||||
bool FindUniformByMappedName(const nsACString& mappedName,
|
const nsString& Source() const { return mSource; }
|
||||||
nsCString* const out_userName,
|
|
||||||
bool* const out_isArray) const;
|
void SetNeedsTranslation() { mNeedsTranslation = true; }
|
||||||
|
bool NeedsTranslation() const { return mNeedsTranslation; }
|
||||||
bool IsCompiled() const {
|
|
||||||
return mTranslationSuccessful && mCompilationSuccessful;
|
void SetCompileStatus (bool status) {
|
||||||
|
mCompileStatus = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other funcs
|
|
||||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
||||||
void Delete();
|
void Delete();
|
||||||
|
|
||||||
WebGLContext* GetParentObject() const { return Context(); }
|
bool CompileStatus() const {
|
||||||
|
return mCompileStatus;
|
||||||
|
}
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
|
void SetTranslationSuccess();
|
||||||
|
|
||||||
|
void SetTranslationFailure(const nsCString& msg) {
|
||||||
|
mTranslationLog.Assign(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsCString& TranslationLog() const { return mTranslationLog; }
|
||||||
|
|
||||||
|
const nsString& TranslatedSource() const { return mTranslatedSource; }
|
||||||
|
|
||||||
|
WebGLContext* GetParentObject() const {
|
||||||
|
return Context();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
|
||||||
|
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
|
||||||
|
|
||||||
public:
|
|
||||||
const GLuint mGLName;
|
|
||||||
const GLenum mType;
|
|
||||||
protected:
|
protected:
|
||||||
|
~WebGLShader() {
|
||||||
|
DeleteOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint mGLName;
|
||||||
|
GLenum mType;
|
||||||
nsString mSource;
|
nsString mSource;
|
||||||
nsCString mCleanSource;
|
nsString mTranslatedSource;
|
||||||
|
nsCString mTranslationLog; // The translation log should contain only ASCII characters
|
||||||
UniquePtr<webgl::ShaderValidator> mValidator;
|
bool mNeedsTranslation;
|
||||||
nsCString mValidationLog;
|
nsTArray<WebGLMappedIdentifier> mAttributes;
|
||||||
bool mTranslationSuccessful;
|
nsTArray<WebGLMappedIdentifier> mUniforms;
|
||||||
nsCString mTranslatedSource;
|
nsTArray<WebGLUniformInfo> mUniformInfos;
|
||||||
|
int mAttribMaxNameLength;
|
||||||
bool mCompilationSuccessful;
|
bool mCompileStatus;
|
||||||
nsCString mCompilationLog;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -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 "WebGLUniformLocation.h"
|
||||||
|
|
||||||
#include "GLContext.h"
|
|
||||||
#include "mozilla/dom/ToJSValue.h"
|
|
||||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||||
#include "WebGLActiveInfo.h"
|
|
||||||
#include "WebGLContext.h"
|
#include "WebGLContext.h"
|
||||||
#include "WebGLProgram.h"
|
#include "WebGLProgram.h"
|
||||||
|
#include "WebGLShader.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
|
|
||||||
const webgl::LinkedProgramInfo* linkInfo,
|
|
||||||
GLuint loc, const WebGLActiveInfo* activeInfo)
|
|
||||||
: WebGLContextBoundObject(webgl)
|
|
||||||
, mLinkInfo(linkInfo)
|
|
||||||
, mLoc(loc)
|
|
||||||
, mActiveInfo(activeInfo)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
WebGLUniformLocation::~WebGLUniformLocation()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
|
||||||
const char* funcName) const
|
|
||||||
{
|
|
||||||
// Check the weak-pointer.
|
|
||||||
if (!mLinkInfo) {
|
|
||||||
webgl->ErrorInvalidOperation("%s: This uniform location is obsolete because its"
|
|
||||||
" program has been successfully relinked.",
|
|
||||||
funcName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mLinkInfo->prog != prog) {
|
|
||||||
webgl->ErrorInvalidOperation("%s: This uniform location corresponds to a"
|
|
||||||
" different program.", funcName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
|
||||||
{
|
|
||||||
switch (uniformType) {
|
|
||||||
case LOCAL_GL_BOOL:
|
|
||||||
case LOCAL_GL_BOOL_VEC2:
|
|
||||||
case LOCAL_GL_BOOL_VEC3:
|
|
||||||
case LOCAL_GL_BOOL_VEC4:
|
|
||||||
return setterType == LOCAL_GL_INT ||
|
|
||||||
setterType == LOCAL_GL_FLOAT; // GLfloat(0.0) sets a bool to false.
|
|
||||||
|
|
||||||
case LOCAL_GL_INT:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_3D:
|
|
||||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
|
||||||
case LOCAL_GL_INT_VEC2:
|
|
||||||
case LOCAL_GL_INT_VEC3:
|
|
||||||
case LOCAL_GL_INT_VEC4:
|
|
||||||
case LOCAL_GL_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
|
||||||
case LOCAL_GL_SAMPLER_CUBE:
|
|
||||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
return setterType == LOCAL_GL_INT;
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT:
|
|
||||||
case LOCAL_GL_FLOAT_MAT2:
|
|
||||||
case LOCAL_GL_FLOAT_MAT2x3:
|
|
||||||
case LOCAL_GL_FLOAT_MAT2x4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT3:
|
|
||||||
case LOCAL_GL_FLOAT_MAT3x2:
|
|
||||||
case LOCAL_GL_FLOAT_MAT3x4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4x2:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4x3:
|
|
||||||
case LOCAL_GL_FLOAT_VEC2:
|
|
||||||
case LOCAL_GL_FLOAT_VEC3:
|
|
||||||
case LOCAL_GL_FLOAT_VEC4:
|
|
||||||
return setterType == LOCAL_GL_FLOAT;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Bad `uniformType`.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
|
||||||
WebGLContext* webgl, const char* funcName) const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mLinkInfo);
|
|
||||||
|
|
||||||
if (setterElemSize != mActiveInfo->mElemSize) {
|
|
||||||
webgl->ErrorInvalidOperation("%s: Bad uniform size: %i", funcName,
|
|
||||||
mActiveInfo->mElemSize);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsUniformSetterTypeValid(setterType, mActiveInfo->mElemType)) {
|
|
||||||
webgl->ErrorInvalidOperation("%s: Bad uniform type: %i", funcName,
|
|
||||||
mActiveInfo->mElemSize);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
|
||||||
WebGLContext* webgl, const char* funcName) const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mLinkInfo);
|
|
||||||
|
|
||||||
if (setterArraySize == 0 ||
|
|
||||||
setterArraySize % setterElemSize)
|
|
||||||
{
|
|
||||||
webgl->ErrorInvalidValue("%s: expected an array of length a multiple of"
|
|
||||||
" %d, got an array of length %d.",
|
|
||||||
funcName, setterElemSize, setterArraySize);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GLES 2.0.25, Section 2.10, p38
|
|
||||||
* When loading `N` elements starting at an arbitrary position `k` in a uniform
|
|
||||||
* declared as an array, elements `k` through `k + N - 1` in the array will be
|
|
||||||
* replaced with the new values. Values for any array element that exceeds the
|
|
||||||
* highest array element index used, as reported by `GetActiveUniform`, will be
|
|
||||||
* ignored by GL.
|
|
||||||
*/
|
|
||||||
if (!mActiveInfo->mIsArray &&
|
|
||||||
setterArraySize != setterElemSize)
|
|
||||||
{
|
|
||||||
webgl->ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
|
||||||
" (since this uniform is not an array"
|
|
||||||
" uniform), got an array of length %d.",
|
|
||||||
funcName, setterElemSize, setterArraySize);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
WebGLUniformLocation::ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
|
||||||
const char* funcName) const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mLinkInfo);
|
|
||||||
|
|
||||||
if (mActiveInfo->mElemType != LOCAL_GL_SAMPLER_2D &&
|
|
||||||
mActiveInfo->mElemType != LOCAL_GL_SAMPLER_CUBE)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value >= 0 && value < (GLint)webgl->GLMaxTextureUnits())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
|
|
||||||
" valid texture unit.",
|
|
||||||
funcName, value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::Value
|
|
||||||
WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mLinkInfo);
|
|
||||||
|
|
||||||
uint8_t elemSize = mActiveInfo->mElemSize;
|
|
||||||
static const uint8_t kMaxElemSize = 16;
|
|
||||||
MOZ_ASSERT(elemSize <= kMaxElemSize);
|
|
||||||
|
|
||||||
GLuint prog = mLinkInfo->prog->mGLName;
|
|
||||||
|
|
||||||
gl::GLContext* gl = webgl->GL();
|
|
||||||
gl->MakeCurrent();
|
|
||||||
|
|
||||||
switch (mActiveInfo->mElemType) {
|
|
||||||
case LOCAL_GL_INT:
|
|
||||||
case LOCAL_GL_INT_VEC2:
|
|
||||||
case LOCAL_GL_INT_VEC3:
|
|
||||||
case LOCAL_GL_INT_VEC4:
|
|
||||||
case LOCAL_GL_SAMPLER_2D:
|
|
||||||
case LOCAL_GL_SAMPLER_CUBE:
|
|
||||||
{
|
|
||||||
GLint buffer[kMaxElemSize] = {0};
|
|
||||||
gl->fGetUniformiv(prog, mLoc, buffer);
|
|
||||||
|
|
||||||
if (elemSize == 1)
|
|
||||||
return JS::Int32Value(buffer[0]);
|
|
||||||
|
|
||||||
JSObject* obj = dom::Int32Array::Create(js, webgl, elemSize, buffer);
|
|
||||||
if (!obj) {
|
|
||||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
|
||||||
return JS::NullValue();
|
|
||||||
}
|
|
||||||
return JS::ObjectOrNullValue(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LOCAL_GL_BOOL:
|
|
||||||
case LOCAL_GL_BOOL_VEC2:
|
|
||||||
case LOCAL_GL_BOOL_VEC3:
|
|
||||||
case LOCAL_GL_BOOL_VEC4:
|
|
||||||
{
|
|
||||||
GLint buffer[kMaxElemSize] = {0};
|
|
||||||
gl->fGetUniformiv(prog, mLoc, buffer);
|
|
||||||
|
|
||||||
if (elemSize == 1)
|
|
||||||
return JS::BooleanValue(buffer[0]);
|
|
||||||
|
|
||||||
bool boolBuffer[kMaxElemSize];
|
|
||||||
for (uint8_t i = 0; i < kMaxElemSize; i++)
|
|
||||||
boolBuffer[i] = buffer[i];
|
|
||||||
|
|
||||||
JS::RootedValue val(js);
|
|
||||||
// Be careful: we don't want to convert all of |uv|!
|
|
||||||
if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
|
|
||||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
|
||||||
return JS::NullValue();
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
case LOCAL_GL_FLOAT:
|
|
||||||
case LOCAL_GL_FLOAT_VEC2:
|
|
||||||
case LOCAL_GL_FLOAT_VEC3:
|
|
||||||
case LOCAL_GL_FLOAT_VEC4:
|
|
||||||
case LOCAL_GL_FLOAT_MAT2:
|
|
||||||
case LOCAL_GL_FLOAT_MAT3:
|
|
||||||
case LOCAL_GL_FLOAT_MAT4:
|
|
||||||
{
|
|
||||||
GLfloat buffer[16] = {0.0f};
|
|
||||||
gl->fGetUniformfv(prog, mLoc, buffer);
|
|
||||||
|
|
||||||
if (elemSize == 1)
|
|
||||||
return JS::DoubleValue(buffer[0]);
|
|
||||||
|
|
||||||
JSObject* obj = dom::Float32Array::Create(js, webgl, elemSize, buffer);
|
|
||||||
if (!obj) {
|
|
||||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
|
||||||
return JS::NullValue();
|
|
||||||
}
|
|
||||||
return JS::ObjectOrNullValue(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Invalid elemType.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
WebGLUniformLocation::WrapObject(JSContext* js)
|
WebGLUniformLocation::WrapObject(JSContext* cx)
|
||||||
{
|
{
|
||||||
return dom::WebGLUniformLocationBinding::Wrap(js, this);
|
return dom::WebGLUniformLocationBinding::Wrap(cx, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLUniformLocation)
|
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* context,
|
||||||
|
WebGLProgram* program,
|
||||||
|
GLint location,
|
||||||
|
const WebGLUniformInfo& info)
|
||||||
|
: WebGLContextBoundObject(context)
|
||||||
|
, mProgram(program)
|
||||||
|
, mProgramGeneration(program->Generation())
|
||||||
|
, mLocation(location)
|
||||||
|
, mInfo(info)
|
||||||
|
{
|
||||||
|
mElementSize = info.ElementSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION(WebGLUniformLocation, mProgram)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)
|
||||||
|
|||||||
@@ -6,56 +6,48 @@
|
|||||||
#ifndef WEBGL_UNIFORM_LOCATION_H_
|
#ifndef WEBGL_UNIFORM_LOCATION_H_
|
||||||
#define WEBGL_UNIFORM_LOCATION_H_
|
#define WEBGL_UNIFORM_LOCATION_H_
|
||||||
|
|
||||||
#include "GLDefs.h"
|
|
||||||
#include "mozilla/WeakPtr.h"
|
|
||||||
#include "nsWrapperCache.h"
|
|
||||||
#include "WebGLObjectModel.h"
|
#include "WebGLObjectModel.h"
|
||||||
|
#include "WebGLUniformInfo.h"
|
||||||
struct JSContext;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
class WebGLActiveInfo;
|
|
||||||
class WebGLContext;
|
|
||||||
class WebGLProgram;
|
class WebGLProgram;
|
||||||
|
|
||||||
namespace webgl {
|
|
||||||
struct LinkedProgramInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebGLUniformLocation MOZ_FINAL
|
class WebGLUniformLocation MOZ_FINAL
|
||||||
: public nsWrapperCache
|
: public WebGLContextBoundObject
|
||||||
, public WebGLContextBoundObject
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
|
WebGLUniformLocation(WebGLContext* context, WebGLProgram* program,
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLUniformLocation)
|
GLint location, const WebGLUniformInfo& info);
|
||||||
|
|
||||||
const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
|
// needed for certain helper functions like ValidateObject.
|
||||||
const GLuint mLoc;
|
// WebGLUniformLocation's can't be 'Deleted' in the WebGL sense.
|
||||||
const WebGLActiveInfo* const mActiveInfo;
|
|
||||||
|
|
||||||
WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
|
|
||||||
GLuint loc, const WebGLActiveInfo* activeInfo);
|
|
||||||
|
|
||||||
bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
|
||||||
const char* funcName) const;
|
|
||||||
bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
|
||||||
const char* funcName) const;
|
|
||||||
bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
|
||||||
WebGLContext* webgl, const char* funcName) const;
|
|
||||||
bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
|
||||||
WebGLContext* webgl, const char* funcName) const;
|
|
||||||
|
|
||||||
JS::Value GetUniform(JSContext* js, WebGLContext* webgl) const;
|
|
||||||
|
|
||||||
// Needed for certain helper functions like ValidateObject.
|
|
||||||
// `WebGLUniformLocation`s can't be 'Deleted' in the WebGL sense.
|
|
||||||
bool IsDeleted() const { return false; }
|
bool IsDeleted() const { return false; }
|
||||||
|
|
||||||
virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
|
const WebGLUniformInfo& Info() const { return mInfo; }
|
||||||
|
|
||||||
|
WebGLProgram* Program() const { return mProgram; }
|
||||||
|
GLint Location() const { return mLocation; }
|
||||||
|
uint32_t ProgramGeneration() const { return mProgramGeneration; }
|
||||||
|
int ElementSize() const { return mElementSize; }
|
||||||
|
|
||||||
|
JSObject* WrapObject(JSContext* cx);
|
||||||
|
|
||||||
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
|
||||||
|
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~WebGLUniformLocation();
|
~WebGLUniformLocation() { }
|
||||||
|
|
||||||
|
// nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
|
||||||
|
// we just want to avoid having a dangling pointer.
|
||||||
|
nsRefPtr<WebGLProgram> mProgram;
|
||||||
|
|
||||||
|
uint32_t mProgramGeneration;
|
||||||
|
GLint mLocation;
|
||||||
|
WebGLUniformInfo mInfo;
|
||||||
|
int mElementSize;
|
||||||
|
friend class WebGLProgram;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -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,130 +27,226 @@
|
|||||||
#ifndef WEBGL_VALIDATE_STRINGS_H_
|
#ifndef WEBGL_VALIDATE_STRINGS_H_
|
||||||
#define WEBGL_VALIDATE_STRINGS_H_
|
#define WEBGL_VALIDATE_STRINGS_H_
|
||||||
|
|
||||||
#include "nsString.h"
|
#include "WebGLContext.h"
|
||||||
#include "nsTArray.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class WebGLContext;
|
|
||||||
|
|
||||||
// The following code was taken from the WebKit WebGL implementation,
|
// The following code was taken from the WebKit WebGL implementation,
|
||||||
// which can be found here:
|
// which can be found here:
|
||||||
// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
|
// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
|
||||||
// Note that some modifications were done to adapt it to Mozilla.
|
// Note that some modifications were done to adapt it to Mozilla.
|
||||||
/****** BEGIN CODE TAKEN FROM WEBKIT ******/
|
/****** BEGIN CODE TAKEN FROM WEBKIT ******/
|
||||||
// Strips comments from shader text. This allows non-ASCII characters
|
bool WebGLContext::ValidateGLSLCharacter(char16_t c)
|
||||||
// to be used in comments without potentially breaking OpenGL
|
|
||||||
// implementations not expecting characters outside the GLSL ES set.
|
|
||||||
class StripComments {
|
|
||||||
public:
|
|
||||||
explicit StripComments(const nsAString& str)
|
|
||||||
: m_parseState(BeginningOfLine)
|
|
||||||
, m_end(str.EndReading())
|
|
||||||
, m_current(str.BeginReading())
|
|
||||||
, m_position(0)
|
|
||||||
{
|
{
|
||||||
m_result.SetLength(str.Length());
|
// Printing characters are valid except " $ ` @ \ ' DEL.
|
||||||
parse();
|
if (c >= 32 && c <= 126 &&
|
||||||
|
c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal tab, line feed, vertical tab, form feed, carriage return
|
||||||
|
// are also valid.
|
||||||
|
if (c >= 9 && c <= 13) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsTArray<char16_t>& result()
|
// Strips comments from shader text. This allows non-ASCII characters
|
||||||
{
|
// to be used in comments without potentially breaking OpenGL
|
||||||
return m_result;
|
// implementations not expecting characters outside the GLSL ES set.
|
||||||
}
|
class StripComments {
|
||||||
|
public:
|
||||||
|
explicit StripComments(const nsAString& str)
|
||||||
|
: m_parseState(BeginningOfLine)
|
||||||
|
, m_end(str.EndReading())
|
||||||
|
, m_current(str.BeginReading())
|
||||||
|
, m_position(0)
|
||||||
|
{
|
||||||
|
m_result.SetLength(str.Length());
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
|
||||||
size_t length()
|
const nsTArray<char16_t>& result()
|
||||||
{
|
{
|
||||||
return m_position;
|
return m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
size_t length()
|
||||||
bool hasMoreCharacters()
|
{
|
||||||
{
|
return m_position;
|
||||||
return (m_current < m_end);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void parse()
|
private:
|
||||||
|
bool hasMoreCharacters()
|
||||||
|
{
|
||||||
|
return (m_current < m_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse()
|
||||||
|
{
|
||||||
|
while (hasMoreCharacters()) {
|
||||||
|
process(current());
|
||||||
|
// process() might advance the position.
|
||||||
|
if (hasMoreCharacters())
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process(char16_t);
|
||||||
|
|
||||||
|
bool peek(char16_t& character)
|
||||||
|
{
|
||||||
|
if (m_current + 1 >= m_end)
|
||||||
|
return false;
|
||||||
|
character = *(m_current + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char16_t current()
|
||||||
|
{
|
||||||
|
//ASSERT(m_position < m_length);
|
||||||
|
return *m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance()
|
||||||
|
{
|
||||||
|
++m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNewline(char16_t character)
|
||||||
|
{
|
||||||
|
// Don't attempt to canonicalize newline related characters.
|
||||||
|
return (character == '\n' || character == '\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit(char16_t character)
|
||||||
|
{
|
||||||
|
m_result[m_position++] = character;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ParseState {
|
||||||
|
// Have not seen an ASCII non-whitespace character yet on
|
||||||
|
// this line. Possible that we might see a preprocessor
|
||||||
|
// directive.
|
||||||
|
BeginningOfLine,
|
||||||
|
|
||||||
|
// Have seen at least one ASCII non-whitespace character
|
||||||
|
// on this line.
|
||||||
|
MiddleOfLine,
|
||||||
|
|
||||||
|
// Handling a preprocessor directive. Passes through all
|
||||||
|
// characters up to the end of the line. Disables comment
|
||||||
|
// processing.
|
||||||
|
InPreprocessorDirective,
|
||||||
|
|
||||||
|
// Handling a single-line comment. The comment text is
|
||||||
|
// replaced with a single space.
|
||||||
|
InSingleLineComment,
|
||||||
|
|
||||||
|
// Handling a multi-line comment. Newlines are passed
|
||||||
|
// through to preserve line numbers.
|
||||||
|
InMultiLineComment
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseState m_parseState;
|
||||||
|
const char16_t* m_end;
|
||||||
|
const char16_t* m_current;
|
||||||
|
size_t m_position;
|
||||||
|
nsTArray<char16_t> m_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
void StripComments::process(char16_t c)
|
||||||
{
|
{
|
||||||
while (hasMoreCharacters()) {
|
if (isNewline(c)) {
|
||||||
process(current());
|
// No matter what state we are in, pass through newlines
|
||||||
// process() might advance the position.
|
// so we preserve line numbers.
|
||||||
if (hasMoreCharacters())
|
emit(c);
|
||||||
|
|
||||||
|
if (m_parseState != InMultiLineComment)
|
||||||
|
m_parseState = BeginningOfLine;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char16_t temp = 0;
|
||||||
|
switch (m_parseState) {
|
||||||
|
case BeginningOfLine:
|
||||||
|
// If it's an ASCII space.
|
||||||
|
if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
|
||||||
|
emit(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '#') {
|
||||||
|
m_parseState = InPreprocessorDirective;
|
||||||
|
emit(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition to normal state and re-handle character.
|
||||||
|
m_parseState = MiddleOfLine;
|
||||||
|
process(c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MiddleOfLine:
|
||||||
|
if (c == '/' && peek(temp)) {
|
||||||
|
if (temp == '/') {
|
||||||
|
m_parseState = InSingleLineComment;
|
||||||
|
emit(' ');
|
||||||
|
advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp == '*') {
|
||||||
|
m_parseState = InMultiLineComment;
|
||||||
|
// Emit the comment start in case the user has
|
||||||
|
// an unclosed comment and we want to later
|
||||||
|
// signal an error.
|
||||||
|
emit('/');
|
||||||
|
emit('*');
|
||||||
|
advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InPreprocessorDirective:
|
||||||
|
// No matter what the character is, just pass it
|
||||||
|
// through. Do not parse comments in this state. This
|
||||||
|
// might not be the right thing to do long term, but it
|
||||||
|
// should handle the #error preprocessor directive.
|
||||||
|
emit(c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InSingleLineComment:
|
||||||
|
// The newline code at the top of this function takes care
|
||||||
|
// of resetting our state when we get out of the
|
||||||
|
// single-line comment. Swallow all other characters.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InMultiLineComment:
|
||||||
|
if (c == '*' && peek(temp) && temp == '/') {
|
||||||
|
emit('*');
|
||||||
|
emit('/');
|
||||||
|
m_parseState = MiddleOfLine;
|
||||||
advance();
|
advance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swallow all other characters. Unclear whether we may
|
||||||
|
// want or need to just emit a space per character to try
|
||||||
|
// to preserve column numbers for debugging purposes.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void process(char16_t);
|
|
||||||
|
|
||||||
bool peek(char16_t& character)
|
|
||||||
{
|
|
||||||
if (m_current + 1 >= m_end)
|
|
||||||
return false;
|
|
||||||
character = *(m_current + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char16_t current()
|
|
||||||
{
|
|
||||||
//ASSERT(m_position < m_length);
|
|
||||||
return *m_current;
|
|
||||||
}
|
|
||||||
|
|
||||||
void advance()
|
|
||||||
{
|
|
||||||
++m_current;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNewline(char16_t character)
|
|
||||||
{
|
|
||||||
// Don't attempt to canonicalize newline related characters.
|
|
||||||
return (character == '\n' || character == '\r');
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit(char16_t character)
|
|
||||||
{
|
|
||||||
m_result[m_position++] = character;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ParseState {
|
|
||||||
// Have not seen an ASCII non-whitespace character yet on
|
|
||||||
// this line. Possible that we might see a preprocessor
|
|
||||||
// directive.
|
|
||||||
BeginningOfLine,
|
|
||||||
|
|
||||||
// Have seen at least one ASCII non-whitespace character
|
|
||||||
// on this line.
|
|
||||||
MiddleOfLine,
|
|
||||||
|
|
||||||
// Handling a preprocessor directive. Passes through all
|
|
||||||
// characters up to the end of the line. Disables comment
|
|
||||||
// processing.
|
|
||||||
InPreprocessorDirective,
|
|
||||||
|
|
||||||
// Handling a single-line comment. The comment text is
|
|
||||||
// replaced with a single space.
|
|
||||||
InSingleLineComment,
|
|
||||||
|
|
||||||
// Handling a multi-line comment. Newlines are passed
|
|
||||||
// through to preserve line numbers.
|
|
||||||
InMultiLineComment
|
|
||||||
};
|
|
||||||
|
|
||||||
ParseState m_parseState;
|
|
||||||
const char16_t* m_end;
|
|
||||||
const char16_t* m_current;
|
|
||||||
size_t m_position;
|
|
||||||
nsTArray<char16_t> m_result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****** END CODE TAKEN FROM WEBKIT ******/
|
/****** END CODE TAKEN FROM WEBKIT ******/
|
||||||
|
|
||||||
bool ValidateGLSLString(const nsAString& string, WebGLContext* webgl,
|
|
||||||
const char* funcName);
|
|
||||||
|
|
||||||
bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl,
|
|
||||||
const char* funcName);
|
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // WEBGL_VALIDATE_STRINGS_H_
|
#endif // WEBGL_VALIDATE_STRINGS_H_
|
||||||
|
|||||||
@@ -108,13 +108,11 @@ UNIFIED_SOURCES += [
|
|||||||
'WebGLSampler.cpp',
|
'WebGLSampler.cpp',
|
||||||
'WebGLShader.cpp',
|
'WebGLShader.cpp',
|
||||||
'WebGLShaderPrecisionFormat.cpp',
|
'WebGLShaderPrecisionFormat.cpp',
|
||||||
'WebGLShaderValidator.cpp',
|
|
||||||
'WebGLSync.cpp',
|
'WebGLSync.cpp',
|
||||||
'WebGLTexelConversions.cpp',
|
'WebGLTexelConversions.cpp',
|
||||||
'WebGLTexture.cpp',
|
'WebGLTexture.cpp',
|
||||||
'WebGLTransformFeedback.cpp',
|
'WebGLTransformFeedback.cpp',
|
||||||
'WebGLUniformLocation.cpp',
|
'WebGLUniformLocation.cpp',
|
||||||
'WebGLValidateStrings.cpp',
|
|
||||||
'WebGLVertexArray.cpp',
|
'WebGLVertexArray.cpp',
|
||||||
'WebGLVertexArrayFake.cpp',
|
'WebGLVertexArrayFake.cpp',
|
||||||
'WebGLVertexArrayGL.cpp',
|
'WebGLVertexArrayGL.cpp',
|
||||||
|
|||||||
@@ -68,13 +68,15 @@ function shouldBeEmptyString(command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < arguments.length; ++i) {
|
for (var i = 0; i < arguments.length; ++i) {
|
||||||
var func, func2;
|
var func, func2, func3;
|
||||||
if (arguments[i].throws) {
|
if (arguments[i].throws) {
|
||||||
func = shouldThrow;
|
func = shouldThrow;
|
||||||
func2 = shouldThrow;
|
func2 = shouldThrow;
|
||||||
|
func3 = shouldThrow;
|
||||||
} else {
|
} else {
|
||||||
func = shouldBeUndefined;
|
func = shouldBeUndefined;
|
||||||
func2 = shouldBeNull;
|
func2 = shouldBeNull;
|
||||||
|
func3 = shouldBeEmptyString;
|
||||||
}
|
}
|
||||||
argument = arguments[i].value;
|
argument = arguments[i].value;
|
||||||
func("context.compileShader(argument)");
|
func("context.compileShader(argument)");
|
||||||
@@ -96,14 +98,15 @@ for (var i = 0; i < arguments.length; ++i) {
|
|||||||
func("context.uniform2iv(argument, new Int32Array([0, 0]))");
|
func("context.uniform2iv(argument, new Int32Array([0, 0]))");
|
||||||
func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
|
func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
|
||||||
|
|
||||||
func2("context.getProgramInfoLog(argument)");
|
|
||||||
func2("context.getProgramParameter(argument, 0)");
|
func2("context.getProgramParameter(argument, 0)");
|
||||||
func2("context.getShaderInfoLog(argument)");
|
|
||||||
func2("context.getShaderParameter(argument, 0)");
|
func2("context.getShaderParameter(argument, 0)");
|
||||||
func2("context.getShaderSource(argument)");
|
|
||||||
func2("context.getUniform(argument, loc)");
|
func2("context.getUniform(argument, loc)");
|
||||||
func2("context.getUniform(program, argument)");
|
func2("context.getUniform(program, argument)");
|
||||||
func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
|
func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
|
||||||
|
|
||||||
|
func3("context.getProgramInfoLog(argument)");
|
||||||
|
func3("context.getShaderInfoLog(argument)");
|
||||||
|
func3("context.getShaderSource(argument)");
|
||||||
}
|
}
|
||||||
|
|
||||||
successfullyParsed = true;
|
successfullyParsed = true;
|
||||||
|
|||||||
@@ -2015,7 +2015,7 @@ public:
|
|||||||
AFTER_GL_CALL;
|
AFTER_GL_CALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths) {
|
void fShaderSource(GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths) {
|
||||||
BEFORE_GL_CALL;
|
BEFORE_GL_CALL;
|
||||||
mSymbols.fShaderSource(shader, count, strings, lengths);
|
mSymbols.fShaderSource(shader, count, strings, lengths);
|
||||||
AFTER_GL_CALL;
|
AFTER_GL_CALL;
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ struct GLContextSymbols
|
|||||||
PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat;
|
PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat;
|
||||||
typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source);
|
typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source);
|
||||||
PFNGLGETSHADERSOURCEPROC fGetShaderSource;
|
PFNGLGETSHADERSOURCEPROC fGetShaderSource;
|
||||||
typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths);
|
typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths);
|
||||||
PFNGLSHADERSOURCEPROC fShaderSource;
|
PFNGLSHADERSOURCEPROC fShaderSource;
|
||||||
|
|
||||||
typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);
|
typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);
|
||||||
|
|||||||
@@ -3841,6 +3841,7 @@ pref("gl.msaa-level", 2);
|
|||||||
#endif
|
#endif
|
||||||
pref("webgl.force-enabled", false);
|
pref("webgl.force-enabled", false);
|
||||||
pref("webgl.disabled", false);
|
pref("webgl.disabled", false);
|
||||||
|
pref("webgl.shader_validator", true);
|
||||||
pref("webgl.disable-angle", false);
|
pref("webgl.disable-angle", false);
|
||||||
pref("webgl.min_capability_mode", false);
|
pref("webgl.min_capability_mode", false);
|
||||||
pref("webgl.disable-extensions", false);
|
pref("webgl.disable-extensions", false);
|
||||||
@@ -3854,7 +3855,6 @@ pref("webgl.restore-context-when-visible", true);
|
|||||||
pref("webgl.max-warnings-per-context", 32);
|
pref("webgl.max-warnings-per-context", 32);
|
||||||
pref("webgl.enable-draft-extensions", false);
|
pref("webgl.enable-draft-extensions", false);
|
||||||
pref("webgl.enable-privileged-extensions", false);
|
pref("webgl.enable-privileged-extensions", false);
|
||||||
pref("webgl.bypass-shader-validation", false);
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
pref("webgl.angle.try-d3d11", true);
|
pref("webgl.angle.try-d3d11", true);
|
||||||
pref("webgl.angle.force-d3d11", false);
|
pref("webgl.angle.force-d3d11", false);
|
||||||
|
|||||||
Reference in New Issue
Block a user