static already_AddRefed<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; 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; } 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; } #ifdef DUMP_SHADERVAR_MAPPINGS printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull); printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull); printf_stderr("maxUniformBlockLenWithNull: %d\n", maxUniformBlockLenWithNull); #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(prog->mContext, elemCount, elemType, isArray, userName, mappedName, &info->activeAttribs, &info->attribMap); // Collect active locations: GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading()); if (loc == -1) { if (mappedName != "gl_InstanceID") MOZ_CRASH("Active attrib has no location."); } else { info->activeAttribLocs.insert(loc); } } // Uniforms const bool needsCheckForArrays = gl->WorkAroundDriverBugs(); 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 mappedNameStr = baseMappedName.BeginReading(); mappedNameStr += "[0]"; GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedNameStr.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(prog->mContext, elemCount, elemType, isArray, baseUserName, 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 < numActiveUniformBlocks; 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 mappedNameStr = baseMappedName.BeginReading(); mappedNameStr += "[0]"; GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName, mappedNameStr.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); } } // 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; GLsizei size; GLenum type; gl->fGetTransformFeedbackVarying(prog->mGLName, i, maxTransformFeedbackVaryingLenWithNull, &lengthWithoutNull, &size, &type, 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->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; } } AddActiveInfo(prog->mContext, size, type, isArray, baseUserName, mappedName, &info->transformFeedbackVaryings, &info->transformFeedbackVaryingsMap); } } return info.forget(); }
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(prog->Context(), 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(prog->Context(), elemCount, elemType, isArray, baseUserName, baseMappedName, &info->activeUniforms, &info->uniformMap); } return info.forget(); }