Bug 1048747 - Cleanup how uniform interface blocks are handled. r=jgilbert

This commit is contained in:
Dan Glastonbury 2015-03-18 13:30:52 +10:00
parent 8c317a09dd
commit 5893d8a315
6 changed files with 306 additions and 74 deletions

View File

@ -11,8 +11,7 @@
#include "WebGLVertexAttribData.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
using namespace mozilla;
using namespace mozilla::dom;
namespace mozilla {
typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
@ -538,39 +537,7 @@ WebGL2Context::GetUniformBlockIndex(WebGLProgram* program,
if (!ValidateObject("getUniformBlockIndex: program", program))
return 0;
// Leave this unchecked for now.
const NS_LossyConvertUTF16toASCII cname(uniformBlockName);
GLuint progname = program->mGLName;
MakeContextCurrent();
return gl->fGetUniformBlockIndex(progname, cname.BeginReading());
}
static bool
GetUniformBlockActiveUniforms(gl::GLContext* gl, JSContext* cx,
WebGL2Context* owner, GLuint progname,
GLuint uniformBlockIndex,
JS::MutableHandleObject out_array)
{
GLint length = 0;
gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &length);
JS::RootedObject obj(cx, Uint32Array::Create(cx, owner, length, nullptr));
if (!obj)
return false;
Uint32Array result;
DebugOnly<bool> inited = result.Init(obj);
MOZ_ASSERT(inited);
result.ComputeLengthAndData();
gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
(GLint*) result.Data());
out_array.set(obj);
return true;
return program->GetUniformBlockIndex(uniformBlockName);
}
void
@ -586,46 +553,25 @@ WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* progr
if (!ValidateObject("getActiveUniformBlockParameter: program", program))
return;
GLuint progname = program->mGLName;
GLint param = 0;
MakeContextCurrent();
switch(pname) {
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsBoolean() = (param != 0);
return;
case LOCAL_GL_UNIFORM_BLOCK_BINDING:
case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
case LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH:
case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsUnsignedLong() = param;
program->GetActiveUniformBlockParam(uniformBlockIndex, pname, retval);
return;
case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
JS::RootedObject array(cx);
if (!GetUniformBlockActiveUniforms(gl, cx, this, progname, uniformBlockIndex,
&array))
{
rv = NS_ERROR_OUT_OF_MEMORY;
return;
}
DebugOnly<bool> inited = retval.SetValue().SetAsUint32Array().Init(array);
MOZ_ASSERT(inited);
program->GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex, retval, rv);
return;
}
ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname);
}
#define WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH 256
void
WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex,
nsAString& retval)
@ -636,19 +582,9 @@ WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBl
if (!ValidateObject("getActiveUniformBlockName: program", program))
return;
GLuint progname = program->mGLName;
GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
GLsizei length = 0;
MakeContextCurrent();
gl->fGetActiveUniformBlockName(progname, uniformBlockIndex,
WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH, &length,
nameBuffer);
retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(nameBuffer)));
program->GetActiveUniformBlockName(uniformBlockIndex, retval);
}
#undef WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH
void
WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex,
GLuint uniformBlockBinding)
@ -659,8 +595,7 @@ WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockInd
if (!ValidateObject("uniformBlockBinding: program", program))
return;
GLuint progname = program->mGLName;
MakeContextCurrent();
gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
program->UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
}
} // namespace mozilla

View File

@ -29,9 +29,9 @@ ElemSizeFromType(GLenum elemType)
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_2D_ARRAY:
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_BOOL_VEC2:

View File

@ -78,6 +78,16 @@ AddActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArra
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
}
static void
AddActiveBlockInfo(const nsACString& baseUserName,
const nsACString& baseMappedName,
std::vector<RefPtr<webgl::UniformBlockInfo>>* activeInfoList)
{
RefPtr<webgl::UniformBlockInfo> info = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
activeInfoList->push_back(info);
}
//#define DUMP_SHADERVAR_MAPPINGS
static TemporaryRef<const webgl::LinkedProgramInfo>
@ -97,9 +107,18 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
if (maxUniformLenWithNull < 1)
maxUniformLenWithNull = 1;
GLuint maxUniformBlockLenWithNull = 0;
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
(GLint*)&maxUniformBlockLenWithNull);
if (maxUniformBlockLenWithNull < 1)
maxUniformBlockLenWithNull = 1;
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
printf_stderr("maxUniformBlockLenWithNull: %d\n", maxUniformBlockLenWithNull);
#endif
// Attribs
@ -204,6 +223,54 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
baseMappedName, &info->activeUniforms, &info->uniformMap);
}
// Uniform Blocks
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
GLuint numActiveUniformBlocks = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
(GLint*)&numActiveUniformBlocks);
for (GLuint i = 0; i < numActiveAttribs; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxUniformBlockLenWithNull - 1);
GLint lengthWithoutNull;
gl->fGetActiveUniformBlockiv(prog->mGLName, i, LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH, &lengthWithoutNull);
gl->fGetActiveUniformBlockName(prog->mGLName, i, maxUniformBlockLenWithNull, &lengthWithoutNull, 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.");
nsAutoCString baseUserName;
if (!prog->FindUniformBlockByMappedName(baseMappedName, &baseUserName, &isArray)) {
baseUserName = baseMappedName;
if (needsCheckForArrays && !isArray) {
std::string mappedName = baseMappedName.BeginReading();
mappedName += "[0]";
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName, mappedName.c_str());
if (loc != LOCAL_GL_INVALID_INDEX)
isArray = true;
}
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform block %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
AddActiveBlockInfo(baseUserName, baseMappedName, &info->uniformBlocks);
}
}
return info.forget();
}
@ -496,6 +563,141 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
}
}
GLuint
WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformBlockIndex"))
return LOCAL_GL_INVALID_INDEX;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getUniformBlockIndex: `program` must be linked.");
return LOCAL_GL_INVALID_INDEX;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
nsDependentCString baseUserName;
bool isArray;
size_t arrayIndex;
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
return LOCAL_GL_INVALID_INDEX;
RefPtr<const webgl::UniformBlockInfo> info;
if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
return LOCAL_GL_INVALID_INDEX;
}
const nsCString& baseMappedName = info->mBaseMappedName;
nsAutoCString mappedName(baseMappedName);
if (isArray) {
mappedName.AppendLiteral("[");
mappedName.AppendInt(uint32_t(arrayIndex));
mappedName.AppendLiteral("]");
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
return gl->fGetUniformBlockIndex(mGLName, mappedName.BeginReading());
}
void
WebGLProgram::GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& retval) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint) linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
return;
}
const webgl::UniformBlockInfo* blockInfo = linkInfo->uniformBlocks[uniformBlockIndex];
retval.Assign(NS_ConvertASCIItoUTF16(blockInfo->mBaseUserName));
}
void
WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname,
Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const
{
retval.SetNull();
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
return;
}
gl::GLContext* gl = mContext->GL();
GLint param = 0;
switch (pname) {
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsBoolean() = (param != 0);
return;
case LOCAL_GL_UNIFORM_BLOCK_BINDING:
case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsUnsignedLong() = param;
return;
}
}
void
WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
ErrorResult& rv) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
return;
}
gl::GLContext* gl = mContext->GL();
GLint activeUniformCount = 0;
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
&activeUniformCount);
JS::RootedObject obj(cx, dom::Uint32Array::Create(cx, mContext, activeUniformCount,
nullptr));
if (!obj) {
rv = NS_ERROR_OUT_OF_MEMORY;
return;
}
dom::Uint32Array result;
DebugOnly<bool> inited = result.Init(obj);
MOZ_ASSERT(inited);
result.ComputeLengthAndData();
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
(GLint*)result.Data());
inited = retval.SetValue().SetAsUint32Array().Init(obj);
MOZ_ASSERT(inited);
}
already_AddRefed<WebGLUniformLocation>
WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
{
@ -540,6 +742,31 @@ WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
return locObj.forget();
}
void
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
return;
}
if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
return;
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
}
bool
WebGLProgram::LinkProgram()
{
@ -707,6 +934,20 @@ WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
return false;
}
bool
WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
if (mVertShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
return true;
if (mFragShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
JSObject*

View File

@ -9,6 +9,7 @@
#include <map>
#include "mozilla/CheckedInt.h"
#include "mozilla/LinkedList.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "nsString.h"
#include "nsWrapperCache.h"
#include <set>
@ -24,6 +25,21 @@ class WebGLUniformLocation;
namespace webgl {
struct UniformBlockInfo final
: public RefCounted<UniformBlockInfo>
{
MOZ_DECLARE_REFCOUNTED_TYPENAME(UniformBlockInfo);
const nsCString mBaseUserName;
const nsCString mBaseMappedName;
UniformBlockInfo(const nsACString& baseUserName,
const nsACString& baseMappedName)
: mBaseUserName(baseUserName)
, mBaseMappedName(baseMappedName)
{}
};
struct LinkedProgramInfo final
: public RefCounted<LinkedProgramInfo>
, public SupportsWeakPtr<LinkedProgramInfo>
@ -40,6 +56,8 @@ struct LinkedProgramInfo final
std::map<nsCString, const WebGLActiveInfo*> uniformMap;
std::map<nsCString, const nsCString>* fragDataMap;
std::vector<RefPtr<UniformBlockInfo>> uniformBlocks;
// Needed for draw call validation.
std::set<GLuint> activeAttribLocs;
@ -67,6 +85,20 @@ struct LinkedProgramInfo final
return true;
}
bool FindUniformBlock(const nsCString& baseUserName,
RefPtr<const UniformBlockInfo>* const out_info) const
{
const size_t count = uniformBlocks.size();
for (size_t i = 0; i < count; i++) {
if (baseUserName == uniformBlocks[i]->mBaseUserName) {
*out_info = uniformBlocks[i].get();
return true;
}
}
return false;
}
bool FindFragData(const nsCString& baseUserName,
nsCString* const out_baseMappedName) const
{
@ -115,7 +147,16 @@ public:
GLint GetFragDataLocation(const nsAString& name) const;
void GetProgramInfoLog(nsAString* const out) const;
JS::Value GetProgramParameter(GLenum pname) const;
GLuint GetUniformBlockIndex(const nsAString& name) const;
void GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& name) const;
void GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname,
Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const;
void GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
ErrorResult& rv) const;
already_AddRefed<WebGLUniformLocation> GetUniformLocation(const nsAString& name) const;
void UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const;
bool LinkProgram();
bool UseProgram() const;
void ValidateProgram() const;
@ -127,6 +168,9 @@ public:
bool FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool IsLinked() const { return mMostRecentLinkInfo; }

View File

@ -345,6 +345,15 @@ WebGLShader::FindUniformByMappedName(const nsACString& mappedName,
return true;
}
bool
WebGLShader::FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
// TODO: Extract block information from shader validator.
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Boilerplate

View File

@ -51,6 +51,9 @@ public:
bool FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool IsCompiled() const {
return mTranslationSuccessful && mCompilationSuccessful;