2012-10-05 00:35:54 +04:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2012-12-09 00:41:02 +04:00
|
|
|
#include "WebGLProgram.h"
|
2012-10-05 00:35:54 +04:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
#include "GLContext.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
#include "mozilla/CheckedInt.h"
|
|
|
|
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2016-05-05 02:39:02 +03:00
|
|
|
#include "nsPrintfCString.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
#include "WebGLActiveInfo.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
#include "WebGLContext.h"
|
|
|
|
#include "WebGLShader.h"
|
2016-09-10 07:02:54 +03:00
|
|
|
#include "WebGLTransformFeedback.h"
|
2015-01-16 02:40:39 +03:00
|
|
|
#include "WebGLUniformLocation.h"
|
|
|
|
#include "WebGLValidateStrings.h"
|
2014-05-14 04:15:19 +04:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
namespace mozilla {
|
2012-10-05 00:35:54 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
/* If `name`: "foo[3]"
|
|
|
|
* Then returns true, with
|
|
|
|
* `out_baseName`: "foo"
|
|
|
|
* `out_isArray`: true
|
|
|
|
* `out_index`: 3
|
|
|
|
*
|
|
|
|
* If `name`: "foo"
|
|
|
|
* Then returns true, with
|
|
|
|
* `out_baseName`: "foo"
|
|
|
|
* `out_isArray`: false
|
|
|
|
* `out_index`: <not written>
|
|
|
|
*/
|
2014-11-14 07:03:50 +03:00
|
|
|
static bool
|
2015-01-16 02:40:39 +03:00
|
|
|
ParseName(const nsCString& name, nsCString* const out_baseName,
|
|
|
|
bool* const out_isArray, size_t* const out_arrayIndex)
|
2012-12-09 00:41:02 +04:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
int32_t indexEnd = name.RFind("]");
|
|
|
|
if (indexEnd == -1 ||
|
|
|
|
(uint32_t)indexEnd != name.Length() - 1)
|
|
|
|
{
|
|
|
|
*out_baseName = name;
|
|
|
|
*out_isArray = false;
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
int32_t indexOpenBracket = name.RFind("[");
|
|
|
|
if (indexOpenBracket == -1)
|
2015-01-10 05:40:56 +03:00
|
|
|
return false;
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
uint32_t indexStart = indexOpenBracket + 1;
|
|
|
|
uint32_t indexLen = indexEnd - indexStart;
|
|
|
|
if (indexLen == 0)
|
2015-01-13 06:51:20 +03:00
|
|
|
return false;
|
2015-01-10 08:03:54 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
|
|
|
|
|
|
|
|
nsresult errorcode;
|
|
|
|
int32_t indexNum = indexStr.ToInteger(&errorcode);
|
|
|
|
if (NS_FAILED(errorcode))
|
|
|
|
return false;
|
2015-01-13 11:07:26 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (indexNum < 0)
|
2012-12-09 00:41:02 +04:00
|
|
|
return false;
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
*out_baseName = StringHead(name, indexOpenBracket);
|
|
|
|
*out_isArray = true;
|
|
|
|
*out_arrayIndex = indexNum;
|
2012-12-09 00:41:02 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
//////////
|
|
|
|
|
|
|
|
/*static*/ const webgl::UniformInfo::TexListT*
|
|
|
|
webgl::UniformInfo::GetTexList(WebGLActiveInfo* activeInfo)
|
2015-01-16 02:40:39 +03:00
|
|
|
{
|
2016-07-14 22:04:31 +03:00
|
|
|
const auto& webgl = activeInfo->mWebGL;
|
|
|
|
|
|
|
|
switch (activeInfo->mElemType) {
|
|
|
|
case LOCAL_GL_SAMPLER_2D:
|
|
|
|
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
|
|
|
case LOCAL_GL_INT_SAMPLER_2D:
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
|
|
|
return &webgl->mBound2DTextures;
|
|
|
|
|
|
|
|
case LOCAL_GL_SAMPLER_CUBE:
|
|
|
|
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
|
|
|
case LOCAL_GL_INT_SAMPLER_CUBE:
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
|
|
return &webgl->mBoundCubeMapTextures;
|
|
|
|
|
|
|
|
case LOCAL_GL_SAMPLER_3D:
|
|
|
|
case LOCAL_GL_INT_SAMPLER_3D:
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
|
|
|
return &webgl->mBound3DTextures;
|
|
|
|
|
|
|
|
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
|
|
|
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
|
|
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
|
|
return &webgl->mBound2DArrayTextures;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
webgl::UniformInfo::UniformInfo(WebGLActiveInfo* activeInfo)
|
|
|
|
: mActiveInfo(activeInfo)
|
|
|
|
, mSamplerTexList(GetTexList(activeInfo))
|
2015-03-18 06:30:52 +03:00
|
|
|
{
|
2016-07-14 22:04:31 +03:00
|
|
|
if (mSamplerTexList) {
|
|
|
|
mSamplerValues.assign(mActiveInfo->mElemCount, 0);
|
|
|
|
}
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
//////////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
//#define DUMP_SHADERVAR_MAPPINGS
|
|
|
|
|
2015-06-17 17:00:52 +03:00
|
|
|
static already_AddRefed<const webgl::LinkedProgramInfo>
|
2015-01-16 02:40:39 +03:00
|
|
|
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|
|
|
{
|
2016-07-14 22:04:31 +03:00
|
|
|
WebGLContext* const webgl = prog->mContext;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
GLuint maxTransformFeedbackVaryingLenWithNull = 0;
|
|
|
|
if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
|
|
|
|
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
|
|
|
|
(GLint*)&maxTransformFeedbackVaryingLenWithNull);
|
|
|
|
if (maxTransformFeedbackVaryingLenWithNull < 1)
|
|
|
|
maxTransformFeedbackVaryingLenWithNull = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
#ifdef DUMP_SHADERVAR_MAPPINGS
|
|
|
|
printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
|
|
|
|
printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
|
2015-03-18 06:30:52 +03:00
|
|
|
printf_stderr("maxUniformBlockLenWithNull: %d\n", maxUniformBlockLenWithNull);
|
2015-01-16 02:40:39 +03:00
|
|
|
#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());
|
2016-09-13 20:13:00 +03:00
|
|
|
GLenum error = gl->fGetError();
|
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
|
|
|
gfxCriticalNote << "Failed to do glGetActiveAttrib: " << error;
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
mappedName.SetLength(lengthWithoutNull);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
|
|
|
|
|
|
|
const GLint loc = gl->fGetAttribLocation(prog->mGLName,
|
|
|
|
mappedName.BeginReading());
|
|
|
|
if (loc == -1) {
|
|
|
|
MOZ_ASSERT(mappedName == "gl_InstanceID",
|
|
|
|
"Active attrib should have a location.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
#ifdef DUMP_SHADERVAR_MAPPINGS
|
2016-07-14 22:04:31 +03:00
|
|
|
printf_stderr("[attrib %i: %i] %s/%s\n", i, loc, mappedName.BeginReading(),
|
2015-01-16 02:40:39 +03:00
|
|
|
userName.BeginReading());
|
|
|
|
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
|
|
|
#endif
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
const bool isArray = false;
|
|
|
|
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
|
|
|
elemType, isArray,
|
|
|
|
userName,
|
|
|
|
mappedName);
|
|
|
|
const webgl::AttribInfo attrib = {activeInfo, uint32_t(loc)};
|
|
|
|
info->attribs.push_back(attrib);
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Uniforms
|
|
|
|
|
2015-08-08 05:29:53 +03:00
|
|
|
const bool needsCheckForArrays = gl->WorkAroundDriverBugs();
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
nsAutoCString baseMappedName;
|
|
|
|
bool isArray;
|
|
|
|
size_t arrayIndex;
|
|
|
|
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
|
2016-06-06 18:17:23 +03:00
|
|
|
MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
// Note that for good drivers, `isArray` should already be correct.
|
|
|
|
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
nsAutoCString baseUserName;
|
|
|
|
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
|
2016-07-14 22:04:31 +03:00
|
|
|
// Validator likely missing.
|
2015-01-16 02:40:39 +03:00
|
|
|
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.
|
2015-07-15 03:37:28 +03:00
|
|
|
std::string mappedNameStr = baseMappedName.BeginReading();
|
|
|
|
mappedNameStr += "[0]";
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedNameStr.c_str());
|
2015-01-16 02:40:39 +03:00
|
|
|
if (loc != -1)
|
|
|
|
isArray = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
#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
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
///////
|
|
|
|
|
|
|
|
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
|
|
|
elemType, isArray,
|
|
|
|
baseUserName,
|
|
|
|
baseMappedName);
|
|
|
|
|
|
|
|
auto* uniform = new webgl::UniformInfo(activeInfo);
|
|
|
|
info->uniforms.push_back(uniform);
|
|
|
|
|
|
|
|
if (uniform->mSamplerTexList) {
|
|
|
|
info->uniformSamplers.push_back(uniform);
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
// Uniform Blocks
|
2016-07-14 22:04:31 +03:00
|
|
|
// (no sampler types allowed!)
|
2015-03-18 06:30:52 +03:00
|
|
|
|
|
|
|
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
|
|
|
|
GLuint numActiveUniformBlocks = 0;
|
|
|
|
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
|
|
|
|
(GLint*)&numActiveUniformBlocks);
|
|
|
|
|
2015-04-21 04:02:34 +03:00
|
|
|
for (GLuint i = 0; i < numActiveUniformBlocks; i++) {
|
2015-03-18 06:30:52 +03:00
|
|
|
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))
|
2016-06-06 18:17:23 +03:00
|
|
|
MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
|
2015-03-18 06:30:52 +03:00
|
|
|
|
|
|
|
nsAutoCString baseUserName;
|
2015-07-15 03:37:28 +03:00
|
|
|
if (!prog->FindUniformBlockByMappedName(baseMappedName, &baseUserName,
|
|
|
|
&isArray))
|
|
|
|
{
|
2015-03-18 06:30:52 +03:00
|
|
|
baseUserName = baseMappedName;
|
|
|
|
|
|
|
|
if (needsCheckForArrays && !isArray) {
|
2015-07-15 03:37:28 +03:00
|
|
|
std::string mappedNameStr = baseMappedName.BeginReading();
|
|
|
|
mappedNameStr += "[0]";
|
2015-03-18 06:30:52 +03:00
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
|
|
|
|
mappedNameStr.c_str());
|
2015-03-18 06:30:52 +03:00
|
|
|
if (loc != LOCAL_GL_INVALID_INDEX)
|
|
|
|
isArray = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
|
|
|
|
|
|
|
GLuint dataSize = 0;
|
|
|
|
gl->fGetActiveUniformBlockiv(prog->mGLName, i,
|
|
|
|
LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
|
|
|
|
(GLint*)&dataSize);
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
#ifdef DUMP_SHADERVAR_MAPPINGS
|
2016-07-14 22:04:31 +03:00
|
|
|
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
|
|
|
|
mappedName.BeginReading(), (int)isArray,
|
|
|
|
baseMappedName.BeginReading(), baseUserName.BeginReading());
|
2015-03-18 06:30:52 +03:00
|
|
|
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
|
|
|
printf_stderr(" isArray: %d\n", (int)isArray);
|
|
|
|
#endif
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
auto* block = new webgl::UniformBlockInfo(webgl, baseUserName, baseMappedName,
|
|
|
|
dataSize);
|
2016-07-14 22:04:31 +03:00
|
|
|
info->uniformBlocks.push_back(block);
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
// Transform feedback varyings
|
|
|
|
|
|
|
|
if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
|
|
|
|
GLuint numTransformFeedbackVaryings = 0;
|
|
|
|
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS,
|
|
|
|
(GLint*)&numTransformFeedbackVaryings);
|
|
|
|
|
|
|
|
for (GLuint i = 0; i < numTransformFeedbackVaryings; i++) {
|
|
|
|
nsAutoCString mappedName;
|
|
|
|
mappedName.SetLength(maxTransformFeedbackVaryingLenWithNull - 1);
|
|
|
|
|
|
|
|
GLint lengthWithoutNull;
|
2016-07-14 22:04:31 +03:00
|
|
|
GLsizei elemCount;
|
|
|
|
GLenum elemType;
|
|
|
|
gl->fGetTransformFeedbackVarying(prog->mGLName, i,
|
|
|
|
maxTransformFeedbackVaryingLenWithNull,
|
|
|
|
&lengthWithoutNull, &elemCount, &elemType,
|
2015-11-14 06:27:17 +03:00
|
|
|
mappedName.BeginWriting());
|
|
|
|
mappedName.SetLength(lengthWithoutNull);
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
////
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
nsAutoCString baseMappedName;
|
|
|
|
bool isArray;
|
|
|
|
size_t arrayIndex;
|
|
|
|
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
|
2016-06-06 18:17:23 +03:00
|
|
|
MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
|
2015-11-14 06:27:17 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
nsAutoCString baseUserName;
|
|
|
|
if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
|
|
|
|
baseUserName = baseMappedName;
|
|
|
|
|
|
|
|
if (needsCheckForArrays && !isArray) {
|
|
|
|
std::string mappedNameStr = baseMappedName.BeginReading();
|
|
|
|
mappedNameStr += "[0]";
|
|
|
|
|
|
|
|
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
|
|
|
|
mappedNameStr.c_str());
|
|
|
|
if (loc != LOCAL_GL_INVALID_INDEX)
|
|
|
|
isArray = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
////
|
|
|
|
|
|
|
|
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl,
|
|
|
|
elemCount,
|
|
|
|
elemType,
|
|
|
|
isArray,
|
|
|
|
baseUserName,
|
|
|
|
mappedName);
|
|
|
|
info->transformFeedbackVaryings.push_back(activeInfo);
|
2015-11-14 06:27:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 15:19:04 +03:00
|
|
|
// Frag outputs
|
|
|
|
|
|
|
|
prog->EnumerateFragOutputs(info->fragDataMap);
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
return info.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
|
|
|
|
: prog(prog)
|
2015-01-16 02:40:39 +03:00
|
|
|
{ }
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
webgl::LinkedProgramInfo::~LinkedProgramInfo()
|
|
|
|
{
|
|
|
|
for (auto& cur : uniforms) {
|
|
|
|
delete cur;
|
|
|
|
}
|
|
|
|
for (auto& cur : uniformBlocks) {
|
|
|
|
delete cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// WebGLProgram
|
|
|
|
|
|
|
|
static GLuint
|
|
|
|
CreateProgram(gl::GLContext* gl)
|
|
|
|
{
|
|
|
|
gl->MakeCurrent();
|
|
|
|
return gl->fCreateProgram();
|
2012-10-05 00:35:54 +04:00
|
|
|
}
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLProgram::WebGLProgram(WebGLContext* webgl)
|
|
|
|
: WebGLContextBoundObject(webgl)
|
2015-01-16 02:40:39 +03:00
|
|
|
, mGLName(CreateProgram(webgl->GL()))
|
2016-09-10 07:02:54 +03:00
|
|
|
, mNumActiveTFOs(0)
|
|
|
|
, mNextLink_TransformFeedbackBufferMode(LOCAL_GL_SEPARATE_ATTRIBS)
|
2012-12-09 00:41:02 +04:00
|
|
|
{
|
|
|
|
mContext->mPrograms.insertBack(this);
|
|
|
|
}
|
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
WebGLProgram::~WebGLProgram()
|
|
|
|
{
|
|
|
|
DeleteOnce();
|
|
|
|
}
|
|
|
|
|
2012-12-09 00:41:02 +04:00
|
|
|
void
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLProgram::Delete()
|
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
gl::GLContext* gl = mContext->GL();
|
|
|
|
|
|
|
|
gl->MakeCurrent();
|
|
|
|
gl->fDeleteProgram(mGLName);
|
|
|
|
|
|
|
|
mVertShader = nullptr;
|
|
|
|
mFragShader = nullptr;
|
|
|
|
|
|
|
|
mMostRecentLinkInfo = nullptr;
|
|
|
|
|
2012-12-09 00:41:02 +04:00
|
|
|
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// GL funcs
|
|
|
|
|
|
|
|
void
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLProgram::AttachShader(WebGLShader* shader)
|
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
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;
|
|
|
|
}
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (*shaderSlot) {
|
|
|
|
if (shader == *shaderSlot) {
|
|
|
|
mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
|
|
|
|
} else {
|
|
|
|
mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
|
|
|
|
" shader may be attached to a program.");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-01-10 05:40:56 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
*shaderSlot = shader;
|
2015-01-13 06:51:20 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->MakeContextCurrent();
|
|
|
|
mContext->gl->fAttachShader(mGLName, shader->mGLName);
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
void
|
|
|
|
WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
|
2014-11-14 07:03:50 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
|
|
|
|
return;
|
2015-01-13 06:51:20 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (loc >= mContext->MaxVertexAttribs()) {
|
|
|
|
mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
|
|
|
|
" MAX_VERTEX_ATTRIBS.");
|
|
|
|
return;
|
|
|
|
}
|
2015-01-13 11:07:26 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
|
2016-09-28 23:54:07 +03:00
|
|
|
mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
|
2015-01-16 02:40:39 +03:00
|
|
|
" name that starts with 'gl_'.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_LossyConvertUTF16toASCII asciiName(name);
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
const bool wasInserted = res.second;
|
|
|
|
if (!wasInserted) {
|
|
|
|
auto itr = res.first;
|
|
|
|
itr->second = loc;
|
|
|
|
}
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
void
|
|
|
|
WebGLProgram::DetachShader(WebGLShader* shader)
|
2014-11-14 07:03:50 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
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;
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (*shaderSlot != shader) {
|
|
|
|
mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*shaderSlot = nullptr;
|
|
|
|
|
|
|
|
mContext->MakeContextCurrent();
|
|
|
|
mContext->gl->fDetachShader(mGLName, shader->mGLName);
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
already_AddRefed<WebGLActiveInfo>
|
|
|
|
WebGLProgram::GetActiveAttrib(GLuint index) const
|
2014-11-14 07:03:50 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!mMostRecentLinkInfo) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
|
2015-01-16 02:40:39 +03:00
|
|
|
return ret.forget();
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
const auto& attribs = mMostRecentLinkInfo->attribs;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
if (index >= attribs.size()) {
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
2016-07-14 22:04:31 +03:00
|
|
|
index, "ACTIVE_ATTRIBS", attribs.size());
|
2015-01-16 02:40:39 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
RefPtr<WebGLActiveInfo> ret = attribs[index].mActiveInfo;
|
2015-01-16 02:40:39 +03:00
|
|
|
return ret.forget();
|
2015-01-10 05:40:56 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
already_AddRefed<WebGLActiveInfo>
|
|
|
|
WebGLProgram::GetActiveUniform(GLuint index) const
|
2015-01-10 05:40:56 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!mMostRecentLinkInfo) {
|
2015-04-21 04:02:34 +03:00
|
|
|
// According to the spec, this can return null.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
|
2015-01-16 02:40:39 +03:00
|
|
|
return ret.forget();
|
2015-01-13 11:07:26 +03:00
|
|
|
}
|
2015-01-13 06:51:20 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
const auto& uniforms = mMostRecentLinkInfo->uniforms;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
if (index >= uniforms.size()) {
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
2016-07-14 22:04:31 +03:00
|
|
|
index, "ACTIVE_UNIFORMS", uniforms.size());
|
2015-01-16 02:40:39 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
RefPtr<WebGLActiveInfo> ret = uniforms[index]->mActiveInfo;
|
2015-01-16 02:40:39 +03:00
|
|
|
return ret.forget();
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
|
|
|
|
2015-01-13 11:07:26 +03:00
|
|
|
void
|
2015-10-18 08:24:48 +03:00
|
|
|
WebGLProgram::GetAttachedShaders(nsTArray<RefPtr<WebGLShader>>* const out) const
|
2015-01-13 06:51:20 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
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;
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
const webgl::AttribInfo* info;
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!LinkInfo()->FindAttrib(userName, &info))
|
|
|
|
return -1;
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
return GLint(info->mLoc);
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-01-27 04:10:25 +03:00
|
|
|
GLint
|
|
|
|
WebGLProgram::GetFragDataLocation(const nsAString& userName_wide) const
|
|
|
|
{
|
|
|
|
if (!ValidateGLSLVariableName(userName_wide, mContext, "getFragDataLocation"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!IsLinked()) {
|
|
|
|
mContext->ErrorInvalidOperation("getFragDataLocation: `program` must be linked.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
|
|
|
nsCString mappedName;
|
2016-07-18 15:19:04 +03:00
|
|
|
|
|
|
|
if (!LinkInfo()->FindFragData(userName, &mappedName)) {
|
2016-03-14 09:48:00 +03:00
|
|
|
mappedName = userName;
|
|
|
|
}
|
2015-01-27 04:10:25 +03:00
|
|
|
|
|
|
|
gl::GLContext* gl = mContext->GL();
|
|
|
|
gl->MakeCurrent();
|
|
|
|
|
|
|
|
return gl->fGetFragDataLocation(mGLName, mappedName.BeginReading());
|
|
|
|
}
|
|
|
|
|
2012-12-09 00:41:02 +04:00
|
|
|
void
|
2015-01-16 02:40:39 +03:00
|
|
|
WebGLProgram::GetProgramInfoLog(nsAString* const out) const
|
2014-11-14 07:03:50 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
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));
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2015-04-21 04:02:34 +03:00
|
|
|
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
|
2016-09-10 07:02:54 +03:00
|
|
|
return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
|
|
|
|
|
|
|
|
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
|
|
|
|
return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
|
|
|
}
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
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();
|
|
|
|
}
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
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;
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
const webgl::UniformBlockInfo* info;
|
2015-03-18 06:30:52 +03:00
|
|
|
if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
|
|
|
|
return LOCAL_GL_INVALID_INDEX;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
nsAutoCString mappedName(info->mBaseMappedName);
|
2015-03-18 06:30:52 +03:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2016-10-15 01:59:27 +03:00
|
|
|
JS::Value
|
|
|
|
WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname) const
|
2015-03-18 06:30:52 +03:00
|
|
|
{
|
|
|
|
if (!IsLinked()) {
|
|
|
|
mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
|
2016-10-15 01:59:27 +03:00
|
|
|
return JS::NullValue();
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
|
|
|
|
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
|
|
|
|
if (uniformBlockIndex >= uniformBlockCount) {
|
|
|
|
mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
|
2016-10-15 01:59:27 +03:00
|
|
|
return JS::NullValue();
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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, ¶m);
|
2016-10-15 01:59:27 +03:00
|
|
|
return JS::BooleanValue(bool(param));
|
2015-03-18 06:30:52 +03:00
|
|
|
|
|
|
|
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, ¶m);
|
2016-10-15 01:59:27 +03:00
|
|
|
return JS::NumberValue(param);
|
|
|
|
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("bad `pname`.");
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 01:59:27 +03:00
|
|
|
JS::Value
|
2015-03-18 06:30:52 +03:00
|
|
|
WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
|
2016-10-15 01:59:27 +03:00
|
|
|
ErrorResult* const out_error) const
|
2015-03-18 06:30:52 +03:00
|
|
|
{
|
2016-10-15 01:59:27 +03:00
|
|
|
const char funcName[] = "getActiveUniformBlockParameter";
|
2015-03-18 06:30:52 +03:00
|
|
|
if (!IsLinked()) {
|
2016-10-15 01:59:27 +03:00
|
|
|
mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
|
|
|
|
return JS::NullValue();
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
|
|
|
|
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
|
|
|
|
if (uniformBlockIndex >= uniformBlockCount) {
|
2016-10-15 01:59:27 +03:00
|
|
|
mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
|
|
|
|
return JS::NullValue();
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2016-10-15 01:59:27 +03:00
|
|
|
*out_error = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return JS::NullValue();
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
2016-10-15 01:59:27 +03:00
|
|
|
return JS::ObjectValue(*obj);
|
2015-03-18 06:30:52 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
already_AddRefed<WebGLUniformLocation>
|
|
|
|
WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
2014-11-14 07:03:50 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
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;
|
2016-05-25 17:27:41 +03:00
|
|
|
bool isArray = false;
|
|
|
|
// GLES 2.0.25, Section 2.10, p35
|
|
|
|
// If the the uniform location is an array, then the location of the first
|
|
|
|
// element of that array can be retrieved by either using the name of the
|
|
|
|
// uniform array, or the name of the uniform array appended with "[0]".
|
|
|
|
// The ParseName() can't recognize this rule. So always initialize
|
|
|
|
// arrayIndex with 0.
|
|
|
|
size_t arrayIndex = 0;
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
|
|
|
return nullptr;
|
2014-08-12 01:36:30 +04:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
webgl::UniformInfo* info;
|
|
|
|
if (!LinkInfo()->FindUniform(baseUserName, &info))
|
2015-01-16 02:40:39 +03:00
|
|
|
return nullptr;
|
2012-12-09 00:41:02 +04:00
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
2015-01-16 02:40:39 +03:00
|
|
|
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;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
|
2016-07-14 22:04:31 +03:00
|
|
|
info, loc, arrayIndex);
|
2015-01-16 02:40:39 +03:00
|
|
|
return locObj.forget();
|
2012-12-09 00:41:02 +04:00
|
|
|
}
|
|
|
|
|
2015-11-03 19:02:30 +03:00
|
|
|
void
|
|
|
|
WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
|
|
|
|
dom::Nullable< nsTArray<GLuint> >& retval) const
|
|
|
|
{
|
2016-11-07 06:53:25 +03:00
|
|
|
const char funcName[] = "getUniformIndices";
|
|
|
|
if (!IsLinked()) {
|
|
|
|
mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-03 19:02:30 +03:00
|
|
|
size_t count = uniformNames.Length();
|
|
|
|
nsTArray<GLuint>& arr = retval.SetValue();
|
|
|
|
|
|
|
|
gl::GLContext* gl = mContext->GL();
|
|
|
|
gl->MakeCurrent();
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
const NS_LossyConvertUTF16toASCII userName(uniformNames[i]);
|
|
|
|
|
|
|
|
nsDependentCString baseUserName;
|
|
|
|
bool isArray;
|
|
|
|
size_t arrayIndex;
|
|
|
|
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex)) {
|
|
|
|
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
webgl::UniformInfo* info;
|
|
|
|
if (!LinkInfo()->FindUniform(baseUserName, &info)) {
|
2015-11-03 19:02:30 +03:00
|
|
|
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
2015-11-03 19:02:30 +03:00
|
|
|
if (isArray) {
|
|
|
|
mappedName.AppendLiteral("[");
|
|
|
|
mappedName.AppendInt(uint32_t(arrayIndex));
|
|
|
|
mappedName.AppendLiteral("]");
|
|
|
|
}
|
|
|
|
|
|
|
|
const GLchar* mappedNameBytes = mappedName.BeginReading();
|
|
|
|
|
|
|
|
GLuint index = 0;
|
|
|
|
gl->fGetUniformIndices(mGLName, 1, &mappedNameBytes, &index);
|
|
|
|
arr.AppendElement(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
void
|
2016-09-10 07:02:54 +03:00
|
|
|
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
|
|
|
|
GLuint uniformBlockBinding) const
|
2015-03-18 06:30:52 +03:00
|
|
|
{
|
2016-09-10 07:02:54 +03:00
|
|
|
const char funcName[] = "getActiveUniformBlockName";
|
2015-03-18 06:30:52 +03:00
|
|
|
if (!IsLinked()) {
|
2016-09-10 07:02:54 +03:00
|
|
|
mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
|
2015-03-18 06:30:52 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& uniformBlocks = LinkInfo()->uniformBlocks;
|
|
|
|
if (uniformBlockIndex >= uniformBlocks.size()) {
|
|
|
|
mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
|
2015-03-18 06:30:52 +03:00
|
|
|
return;
|
|
|
|
}
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& uniformBlock = uniformBlocks[uniformBlockIndex];
|
2015-03-18 06:30:52 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
|
|
|
|
if (uniformBlockBinding >= indexedBindings.size()) {
|
|
|
|
mContext->ErrorInvalidValue("%s: Binding %u invalid.", funcName,
|
|
|
|
uniformBlockBinding);
|
2015-03-18 06:30:52 +03:00
|
|
|
return;
|
|
|
|
}
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& indexedBinding = indexedBindings[uniformBlockBinding];
|
|
|
|
|
|
|
|
////
|
2015-03-18 06:30:52 +03:00
|
|
|
|
|
|
|
gl::GLContext* gl = mContext->GL();
|
|
|
|
gl->MakeCurrent();
|
|
|
|
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
uniformBlock->mBinding = &indexedBinding;
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::ValidateForLink()
|
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!mVertShader || !mVertShader->IsCompiled()) {
|
|
|
|
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
|
2016-09-10 07:02:54 +03:00
|
|
|
return false;
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
2014-10-04 01:36:57 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!mFragShader || !mFragShader->IsCompiled()) {
|
|
|
|
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
|
2016-09-10 07:02:54 +03:00
|
|
|
return false;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
2015-01-10 05:40:56 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog))
|
|
|
|
return false;
|
2015-01-13 06:51:20 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& gl = mContext->gl;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
if (gl->WorkAroundDriverBugs() &&
|
2015-10-24 07:35:16 +03:00
|
|
|
mContext->mIsMesa)
|
2015-01-16 02:40:39 +03:00
|
|
|
{
|
2015-10-24 07:35:16 +03:00
|
|
|
// 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 (numSamplerUniforms_upperBound > 16) {
|
|
|
|
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
|
|
|
|
" Mesa drivers to avoid crashing.");
|
2016-09-10 07:02:54 +03:00
|
|
|
return false;
|
2015-10-24 07:35:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
|
|
|
|
if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
|
2016-09-10 07:02:54 +03:00
|
|
|
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max"
|
|
|
|
" attribute count.");
|
|
|
|
return false;
|
2015-10-24 07:35:16 +03:00
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
WebGLProgram::LinkProgram()
|
|
|
|
{
|
|
|
|
const char funcName[] = "linkProgram";
|
|
|
|
|
|
|
|
if (mNumActiveTFOs) {
|
|
|
|
mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active"
|
|
|
|
" transform feedback objects.",
|
|
|
|
funcName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mContext->MakeContextCurrent();
|
|
|
|
mContext->InvalidateBufferFetching(); // we do it early in this function
|
|
|
|
// as some of the validation changes program state
|
|
|
|
|
|
|
|
mLinkLog.Truncate();
|
|
|
|
mMostRecentLinkInfo = nullptr;
|
|
|
|
|
|
|
|
if (!ValidateForLink()) {
|
|
|
|
mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
// Bind the attrib locations.
|
|
|
|
// This can't be done trivially, because we have to deal with mapped attrib names.
|
2016-09-10 07:02:54 +03:00
|
|
|
for (const auto& pair : mNextLink_BoundAttribLocs) {
|
|
|
|
const auto& name = pair.first;
|
|
|
|
const auto& index = pair.second;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
mVertShader->BindAttribLocation(mGLName, name, index);
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
// Storage for transform feedback varyings before link.
|
|
|
|
// (Work around for bug seen on nVidia drivers.)
|
|
|
|
std::vector<std::string> scopedMappedTFVaryings;
|
|
|
|
|
|
|
|
if (mContext->IsWebGL2()) {
|
|
|
|
mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings,
|
|
|
|
&scopedMappedTFVaryings);
|
|
|
|
|
|
|
|
std::vector<const char*> driverVaryings;
|
|
|
|
driverVaryings.reserve(scopedMappedTFVaryings.size());
|
|
|
|
for (const auto& cur : scopedMappedTFVaryings) {
|
|
|
|
driverVaryings.push_back(cur.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(),
|
|
|
|
driverVaryings.data(),
|
|
|
|
mNextLink_TransformFeedbackBufferMode);
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
|
|
|
|
2016-04-20 22:02:07 +03:00
|
|
|
LinkAndUpdate();
|
2016-04-28 13:10:00 +03:00
|
|
|
|
2016-07-07 19:12:10 +03:00
|
|
|
if (mMostRecentLinkInfo) {
|
|
|
|
nsCString postLinkLog;
|
|
|
|
if (ValidateAfterTentativeLink(&postLinkLog))
|
|
|
|
return;
|
|
|
|
|
|
|
|
mMostRecentLinkInfo = nullptr;
|
|
|
|
mLinkLog = postLinkLog;
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
// 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());
|
2015-01-13 11:07:26 +03:00
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 10:35:56 +03:00
|
|
|
static uint8_t
|
|
|
|
NumUsedLocationsByElemType(GLenum elemType)
|
|
|
|
{
|
|
|
|
// GLES 3.0.4 p55
|
|
|
|
|
|
|
|
switch (elemType) {
|
|
|
|
case LOCAL_GL_FLOAT_MAT2:
|
|
|
|
case LOCAL_GL_FLOAT_MAT2x3:
|
|
|
|
case LOCAL_GL_FLOAT_MAT2x4:
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case LOCAL_GL_FLOAT_MAT3x2:
|
|
|
|
case LOCAL_GL_FLOAT_MAT3:
|
|
|
|
case LOCAL_GL_FLOAT_MAT3x4:
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
case LOCAL_GL_FLOAT_MAT4x2:
|
|
|
|
case LOCAL_GL_FLOAT_MAT4x3:
|
|
|
|
case LOCAL_GL_FLOAT_MAT4:
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
static uint8_t
|
|
|
|
NumComponents(GLenum elemType)
|
|
|
|
{
|
|
|
|
switch (elemType) {
|
|
|
|
case LOCAL_GL_FLOAT:
|
|
|
|
case LOCAL_GL_INT:
|
|
|
|
case LOCAL_GL_UNSIGNED_INT:
|
|
|
|
case LOCAL_GL_BOOL:
|
|
|
|
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_CRASH("`elemType`");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-07 19:12:10 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
|
|
|
|
{
|
|
|
|
const auto& linkInfo = mMostRecentLinkInfo;
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& gl = mContext->gl;
|
2016-07-07 19:12:10 +03:00
|
|
|
|
|
|
|
// Check if the attrib name conflicting to uniform name
|
2016-07-14 22:08:06 +03:00
|
|
|
for (const auto& attrib : linkInfo->attribs) {
|
|
|
|
const auto& attribName = attrib.mActiveInfo->mBaseUserName;
|
|
|
|
|
|
|
|
for (const auto& uniform : linkInfo->uniforms) {
|
|
|
|
const auto& uniformName = uniform->mActiveInfo->mBaseUserName;
|
|
|
|
if (attribName == uniformName) {
|
|
|
|
*out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:"
|
|
|
|
" %s",
|
|
|
|
attribName.BeginReading());
|
|
|
|
return false;
|
|
|
|
}
|
2016-07-07 19:12:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:08:06 +03:00
|
|
|
std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc;
|
|
|
|
for (const auto& attrib : linkInfo->attribs) {
|
2016-07-14 10:35:56 +03:00
|
|
|
const auto& elemType = attrib.mActiveInfo->mElemType;
|
|
|
|
const auto numUsedLocs = NumUsedLocationsByElemType(elemType);
|
|
|
|
for (uint32_t i = 0; i < numUsedLocs; i++) {
|
2016-07-14 22:08:06 +03:00
|
|
|
const uint32_t usedLoc = attrib.mLoc + i;
|
|
|
|
|
|
|
|
const auto res = attribsByLoc.insert({usedLoc, &attrib});
|
|
|
|
const bool& didInsert = res.second;
|
|
|
|
if (!didInsert) {
|
|
|
|
const auto& aliasingName = attrib.mActiveInfo->mBaseUserName;
|
|
|
|
const auto& itrExisting = res.first;
|
|
|
|
const auto& existingInfo = itrExisting->second;
|
|
|
|
const auto& existingName = existingInfo->mActiveInfo->mBaseUserName;
|
|
|
|
*out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by"
|
|
|
|
" attrib \"%s\".",
|
|
|
|
aliasingName.BeginReading(),
|
|
|
|
existingName.BeginReading());
|
2016-07-07 19:12:10 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
// Forbid:
|
|
|
|
// * Unrecognized varying name
|
|
|
|
// * Duplicate varying name
|
|
|
|
// * Too many components for specified buffer mode
|
|
|
|
if (mNextLink_TransformFeedbackVaryings.size()) {
|
|
|
|
GLuint maxComponentsPerIndex = 0;
|
|
|
|
switch (mNextLink_TransformFeedbackBufferMode) {
|
|
|
|
case LOCAL_GL_INTERLEAVED_ATTRIBS:
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
|
|
|
|
&maxComponentsPerIndex);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LOCAL_GL_SEPARATE_ATTRIBS:
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
|
|
|
|
&maxComponentsPerIndex);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("`bufferMode`");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<size_t> componentsPerVert;
|
|
|
|
std::set<const WebGLActiveInfo*> alreadyUsed;
|
|
|
|
for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) {
|
|
|
|
if (!componentsPerVert.size() ||
|
|
|
|
mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS)
|
|
|
|
{
|
|
|
|
componentsPerVert.push_back(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
////
|
|
|
|
|
|
|
|
const WebGLActiveInfo* curInfo = nullptr;
|
|
|
|
for (const auto& info : linkInfo->transformFeedbackVaryings) {
|
|
|
|
const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName);
|
|
|
|
if (info_wideUserName == wideUserName) {
|
|
|
|
curInfo = info.get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!curInfo) {
|
|
|
|
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
|
|
|
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not"
|
|
|
|
" found.",
|
|
|
|
asciiUserName.BeginReading());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto insertResPair = alreadyUsed.insert(curInfo);
|
|
|
|
const auto& didInsert = insertResPair.second;
|
|
|
|
if (!didInsert) {
|
|
|
|
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
|
|
|
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
|
|
|
|
" specified twice.",
|
|
|
|
asciiUserName.BeginReading());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
////
|
|
|
|
|
|
|
|
size_t varyingComponents = NumComponents(curInfo->mElemType);
|
|
|
|
varyingComponents *= curInfo->mElemCount;
|
|
|
|
|
|
|
|
auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
|
|
|
|
totalComponentsForIndex += varyingComponents;
|
|
|
|
|
|
|
|
if (totalComponentsForIndex > maxComponentsPerIndex) {
|
|
|
|
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
|
|
|
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
|
|
|
|
" pushed `componentsForIndex` over the"
|
|
|
|
" limit of %u.",
|
|
|
|
asciiUserName.BeginReading(),
|
|
|
|
maxComponentsPerIndex);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
linkInfo->componentsPerTFVert.swap(componentsPerVert);
|
|
|
|
}
|
|
|
|
|
2016-07-07 19:12:10 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::UseProgram() const
|
|
|
|
{
|
2016-09-10 07:02:54 +03:00
|
|
|
const char funcName[] = "useProgram";
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!mMostRecentLinkInfo) {
|
2016-09-10 07:02:54 +03:00
|
|
|
mContext->ErrorInvalidOperation("%s: Program has not been successfully linked.",
|
|
|
|
funcName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mContext->mBoundTransformFeedback &&
|
|
|
|
mContext->mBoundTransformFeedback->mIsActive &&
|
|
|
|
!mContext->mBoundTransformFeedback->mIsPaused)
|
|
|
|
{
|
|
|
|
mContext->ErrorInvalidOperation("%s: Transform feedback active and not paused.",
|
|
|
|
funcName);
|
2015-01-16 02:40:39 +03:00
|
|
|
return false;
|
|
|
|
}
|
2014-10-04 01:36:57 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->MakeContextCurrent();
|
2015-01-10 05:40:56 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->InvalidateBufferFetching();
|
2015-01-13 06:51:20 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
mContext->gl->fUseProgram(mGLName);
|
|
|
|
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;
|
2014-10-04 01:36:57 +04:00
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
#endif
|
2014-10-04 01:36:57 +04:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
gl->fValidateProgram(mGLName);
|
|
|
|
}
|
2014-10-04 01:36:57 +04:00
|
|
|
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2014-10-04 01:36:57 +04:00
|
|
|
|
2016-04-20 22:02:07 +03:00
|
|
|
void
|
2015-01-16 02:40:39 +03:00
|
|
|
WebGLProgram::LinkAndUpdate()
|
|
|
|
{
|
|
|
|
mMostRecentLinkInfo = nullptr;
|
|
|
|
|
|
|
|
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);
|
2014-10-04 01:36:57 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
GLint ok = 0;
|
|
|
|
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
|
|
|
|
if (!ok)
|
2016-04-20 22:02:07 +03:00
|
|
|
return;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
mMostRecentLinkInfo = QueryProgramInfo(this, gl);
|
2016-07-07 19:12:10 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mMostRecentLinkInfo, "GFX: most recent link info not set.");
|
2015-01-13 06:51:20 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
|
|
|
|
nsDependentCString* const out_userName) const
|
2015-01-13 06:51:20 +03:00
|
|
|
{
|
2015-01-16 02:40:39 +03:00
|
|
|
if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::FindVaryingByMappedName(const nsACString& mappedName,
|
|
|
|
nsCString* const out_userName,
|
|
|
|
bool* const out_isArray) const
|
|
|
|
{
|
|
|
|
if (mVertShader->FindVaryingByMappedName(mappedName, out_userName, out_isArray))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
bool
|
|
|
|
WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
|
|
|
|
nsCString* const out_userName,
|
|
|
|
bool* const out_isArray) const
|
|
|
|
{
|
|
|
|
if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2014-05-14 04:15:19 +04:00
|
|
|
}
|
|
|
|
|
2015-04-21 04:02:34 +03:00
|
|
|
void
|
|
|
|
WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
|
|
|
|
GLenum bufferMode)
|
|
|
|
{
|
2016-09-10 07:02:54 +03:00
|
|
|
const char funcName[] = "transformFeedbackVaryings";
|
2015-04-21 04:02:34 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& gl = mContext->gl;
|
|
|
|
gl->MakeCurrent();
|
2015-04-21 04:02:34 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
switch (bufferMode) {
|
|
|
|
case LOCAL_GL_INTERLEAVED_ATTRIBS:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LOCAL_GL_SEPARATE_ATTRIBS:
|
|
|
|
{
|
|
|
|
GLuint maxAttribs = 0;
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
|
|
|
&maxAttribs);
|
|
|
|
if (varyings.Length() >= maxAttribs) {
|
|
|
|
mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
|
|
|
|
funcName,
|
|
|
|
"TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-04-21 04:02:34 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
default:
|
|
|
|
mContext->ErrorInvalidEnum("%s: Bad `bufferMode`: 0x%04x.", funcName, bufferMode);
|
|
|
|
return;
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
|
|
|
|
|
|
|
mNextLink_TransformFeedbackVaryings.assign(varyings.Elements(),
|
|
|
|
varyings.Elements() + varyings.Length());
|
|
|
|
mNextLink_TransformFeedbackBufferMode = bufferMode;
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<WebGLActiveInfo>
|
2016-09-10 07:02:54 +03:00
|
|
|
WebGLProgram::GetTransformFeedbackVarying(GLuint index) const
|
2015-04-21 04:02:34 +03:00
|
|
|
{
|
|
|
|
// No docs in the WebGL 2 spec for this function. Taking the language for
|
|
|
|
// getActiveAttrib, which states that the function returns null on any error.
|
|
|
|
if (!IsLinked()) {
|
|
|
|
mContext->ErrorInvalidOperation("getTransformFeedbackVarying: `program` must be "
|
|
|
|
"linked.");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
if (index >= LinkInfo()->transformFeedbackVaryings.size()) {
|
2015-04-21 04:02:34 +03:00
|
|
|
mContext->ErrorInvalidValue("getTransformFeedbackVarying: `index` is greater or "
|
|
|
|
"equal to TRANSFORM_FEEDBACK_VARYINGS.");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:27:17 +03:00
|
|
|
RefPtr<WebGLActiveInfo> ret = LinkInfo()->transformFeedbackVaryings[index];
|
2015-04-21 04:02:34 +03:00
|
|
|
return ret.forget();
|
|
|
|
}
|
|
|
|
|
2015-03-18 06:30:52 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-18 15:19:04 +03:00
|
|
|
void
|
|
|
|
WebGLProgram::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mFragShader);
|
|
|
|
|
|
|
|
mFragShader->EnumerateFragOutputs(out_FragOutputs);
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-14 22:04:31 +03:00
|
|
|
bool
|
|
|
|
webgl::LinkedProgramInfo::FindAttrib(const nsCString& baseUserName,
|
|
|
|
const webgl::AttribInfo** const out) const
|
|
|
|
{
|
|
|
|
for (const auto& attrib : attribs) {
|
|
|
|
if (attrib.mActiveInfo->mBaseUserName == baseUserName) {
|
|
|
|
*out = &attrib;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
webgl::LinkedProgramInfo::FindUniform(const nsCString& baseUserName,
|
|
|
|
webgl::UniformInfo** const out) const
|
|
|
|
{
|
|
|
|
for (const auto& uniform : uniforms) {
|
|
|
|
if (uniform->mActiveInfo->mBaseUserName == baseUserName) {
|
|
|
|
*out = uniform;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
webgl::LinkedProgramInfo::FindUniformBlock(const nsCString& baseUserName,
|
|
|
|
const webgl::UniformBlockInfo** const out) const
|
|
|
|
{
|
|
|
|
for (const auto& block : uniformBlocks) {
|
|
|
|
if (block->mBaseUserName == baseUserName) {
|
|
|
|
*out = block;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
JSObject*
|
2015-07-15 03:37:28 +03:00
|
|
|
WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
|
2014-05-14 04:15:19 +04:00
|
|
|
{
|
2015-07-15 03:37:28 +03:00
|
|
|
return dom::WebGLProgramBinding::Wrap(js, this, givenProto);
|
2014-05-14 04:15:19 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
|
2012-10-05 00:35:54 +04:00
|
|
|
|
2013-08-29 19:39:17 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
|
2014-11-14 07:03:50 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|