Commit d860552f by Geoff Lang Committed by Commit Bot

Implement support for CHROMIUM_bind_uniform_location.

BUG=angleproject:1353 Change-Id: Ia219ff973de0de2f8e112c276b3ab6319f7d3884 Reviewed-on: https://chromium-review.googlesource.com/334252Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent 5ed23982
Name
CHROMIUM_bind_uniform_location
Name Strings
GL_CHROMIUM_bind_uniform_location
Version
Last Modifed Date: September 8, 2015
Dependencies
OpenGL ES 2.0 is required.
Overview
This extension is simlar to glBindAttribLocation but instead
lets you choose a location for a uniform. This allows you
to not have to query the locations of uniforms.
This allows the client program to know the locations of uniforms
without having to wait for shaders to compile or GLSL programs to
link to query the locations and therefore have no blocking calls
when initializing programs.
Issues
If a uniform is an array you can only call glBindUniformLocation
for the location of the first element. Other elements' locations
must be queried if you need them. Often this is not an issue
because you can set all the elements with a single gl call from
the first location.
Good Example:
--shader--
uniform float u_someArray[4];
--C--
GLint location = 123;
glBindUniformLocation(program, location, "u_someArray");
glLinkProgram(program);
glUseProgram(program);
// set all 4 floats in u_someArray
float values[] = { 0.1f, 0.2f, 0.3f, 0.4f, };
glUniform1fv(location, 4, values);
Bad example 1:
GLint location = 123;
glBindUniformLocation(program, location, "u_someArray");
glLinkProgram(program);
glUseProgram(program);
// set floats in u_someArray one at a time
glUniform1f(location, 0.1f);
glUniform1f(location + 1, 0.2f); // ERROR! math not allowed on locations
Bad example 2:
GLint location0 = 123;
GLint location1 = 124;
glBindUniformLocation(program, location0, "u_someArray[0]");
glBindUniformLocation(program, location1, "u_someArray[1]"); // ERROR!
// not allowed to assign locations to array elements
If you need to set individual elements of a uniform array you must query the
location of the each element you wish to set.
New Tokens
None
New Procedures and Functions
void BindUniformLocationCHROMIUM (GLuint program, GLint location,
const GLhchar* name);
specifes that the uniform variable named <name> in program <program>
should be bound to uniform location <location> when the program is next
linked. If <name> was bound previously, its assigned binding is replaced
with <location>. <name> must be a null terminated string. The error
INVALID_VALUE is generated if <location> is equal or greater than
(MAX_VERTEX_UNIFORM_VECTORS + MAX_FRAGMENT_UNIFORM_VECTORS) * 4
or less than 0. BindUniformLocation has no effect until the program is
linked. In particular, it doesn't modify the bindings of active uniforms
variables in a program that has already been linked.
The error INVALID_OPERATION is generated if name starts with the reserved
"gl_" prefix. The error INVALID_VALUE is generated if name ends with
an array element expression other than "[0]".
When a program is linked, any active uniforms without a binding specified
through BindUniformLocation will be automatically be bound to locations by
the GL. Such bindings can be queried using the command
GetUniformLocation.
BindUniformLocation may be issued before any shader objects are attached
to a program object. Hence it is allowed to bind any name (except a name
starting with "gl_") to an index, including a name that is never used as a
uniform in any shader object. Assigned bindings for uniform variables
that do not exist or are not active are ignored. Using such bindings
behaves as if passed location was -1.
It is possible for an application to bind more than one uniform name to
the same location. This is referred to as aliasing. This will only work
if only one of the aliased uniforms is active in the executable program,
or if no path through the shader consumes more than one uniform of a set
of uniforms aliased to the same location. If two statically used uniforms
in a program are bound to the name location, link must fail.
Errors
None.
New State
None.
Revision History
7/20/2012 Documented the extension
9/8/2015 Require program link to fail if two statically used uniforms
are bound to the same location.
11/6/2015 Require inactive and non-existing, bound uniform locations
to behave like location -1.
...@@ -158,6 +158,7 @@ Extensions::Extensions() ...@@ -158,6 +158,7 @@ Extensions::Extensions()
maxLabelLength(0), maxLabelLength(0),
noError(false), noError(false),
lossyETCDecode(false), lossyETCDecode(false),
bindUniformLocation(false),
colorBufferFloat(false) colorBufferFloat(false)
{ {
} }
...@@ -230,6 +231,7 @@ std::vector<std::string> Extensions::getStrings() const ...@@ -230,6 +231,7 @@ std::vector<std::string> Extensions::getStrings() const
//InsertExtensionString("GL_KHR_no_error", noError, &extensionStrings); //InsertExtensionString("GL_KHR_no_error", noError, &extensionStrings);
InsertExtensionString("GL_ANGLE_lossy_etc_decode", lossyETCDecode, &extensionStrings); InsertExtensionString("GL_ANGLE_lossy_etc_decode", lossyETCDecode, &extensionStrings);
InsertExtensionString("GL_CHROMIUM_bind_uniform_location", bindUniformLocation, &extensionStrings);
// clang-format on // clang-format on
return extensionStrings; return extensionStrings;
......
...@@ -281,6 +281,9 @@ struct Extensions ...@@ -281,6 +281,9 @@ struct Extensions
// GL_ANGLE_lossy_etc_decode // GL_ANGLE_lossy_etc_decode
bool lossyETCDecode; bool lossyETCDecode;
// GL_CHROMIUM_bind_uniform_location
bool bindUniformLocation;
// ES3 Extension support // ES3 Extension support
// GL_EXT_color_buffer_float // GL_EXT_color_buffer_float
......
...@@ -1634,6 +1634,14 @@ void Context::popGroupMarker() ...@@ -1634,6 +1634,14 @@ void Context::popGroupMarker()
mRenderer->popGroupMarker(); mRenderer->popGroupMarker();
} }
void Context::bindUniformLocation(GLuint program, GLint location, const GLchar *name)
{
Program *programObject = getProgram(program);
ASSERT(programObject);
programObject->bindUniformLocation(location, name);
}
void Context::recordError(const Error &error) void Context::recordError(const Error &error)
{ {
if (error.isError()) if (error.isError())
......
...@@ -386,6 +386,8 @@ class Context final : public ValidationContext ...@@ -386,6 +386,8 @@ class Context final : public ValidationContext
void pushGroupMarker(GLsizei length, const char *marker); void pushGroupMarker(GLsizei length, const char *marker);
void popGroupMarker(); void popGroupMarker();
void bindUniformLocation(GLuint program, GLint location, const GLchar *name);
void recordError(const Error &error) override; void recordError(const Error &error) override;
GLenum getError(); GLenum getError();
......
...@@ -42,7 +42,6 @@ struct Data; ...@@ -42,7 +42,6 @@ struct Data;
class ResourceManager; class ResourceManager;
class Shader; class Shader;
class InfoLog; class InfoLog;
class AttributeBindings;
class Buffer; class Buffer;
class Framebuffer; class Framebuffer;
struct UniformBlock; struct UniformBlock;
...@@ -50,19 +49,6 @@ struct LinkedUniform; ...@@ -50,19 +49,6 @@ struct LinkedUniform;
extern const char * const g_fakepath; extern const char * const g_fakepath;
class AttributeBindings
{
public:
AttributeBindings();
~AttributeBindings();
void bindAttributeLocation(GLuint index, const char *name);
int getAttributeBinding(const std::string &name) const;
private:
std::set<std::string> mAttributeBinding[MAX_VERTEX_ATTRIBS];
};
class InfoLog : angle::NonCopyable class InfoLog : angle::NonCopyable
{ {
public: public:
...@@ -142,6 +128,13 @@ struct VariableLocation ...@@ -142,6 +128,13 @@ struct VariableLocation
std::string name; std::string name;
unsigned int element; unsigned int element;
unsigned int index; unsigned int index;
// If this is a valid uniform location
bool used;
// If this location was bound to an unreferenced uniform. Setting data on this uniform is a
// no-op.
bool ignored;
}; };
class Program final : angle::NonCopyable, public LabeledObject class Program final : angle::NonCopyable, public LabeledObject
...@@ -240,6 +233,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -240,6 +233,7 @@ class Program final : angle::NonCopyable, public LabeledObject
int getAttachedShadersCount() const; int getAttachedShadersCount() const;
void bindAttributeLocation(GLuint index, const char *name); void bindAttributeLocation(GLuint index, const char *name);
void bindUniformLocation(GLuint index, const char *name);
Error link(const gl::Data &data); Error link(const gl::Data &data);
bool isLinked() const; bool isLinked() const;
...@@ -274,6 +268,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -274,6 +268,7 @@ class Program final : angle::NonCopyable, public LabeledObject
GLint getActiveUniformMaxLength() const; GLint getActiveUniformMaxLength() const;
GLint getActiveUniformi(GLuint index, GLenum pname) const; GLint getActiveUniformi(GLuint index, GLenum pname) const;
bool isValidUniformLocation(GLint location) const; bool isValidUniformLocation(GLint location) const;
bool isIgnoredUniformLocation(GLint location) const;
const LinkedUniform &getUniformByLocation(GLint location) const; const LinkedUniform &getUniformByLocation(GLint location) const;
GLint getUniformLocation(const std::string &name) const; GLint getUniformLocation(const std::string &name) const;
...@@ -341,19 +336,33 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -341,19 +336,33 @@ class Program final : angle::NonCopyable, public LabeledObject
} }
private: private:
class Bindings final : angle::NonCopyable
{
public:
void bindLocation(GLuint index, const std::string &name);
int getBinding(const std::string &name) const;
typedef std::unordered_map<std::string, GLuint>::const_iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string, GLuint> mBindings;
};
void unlink(bool destroy = false); void unlink(bool destroy = false);
void resetUniformBlockBindings(); void resetUniformBlockBindings();
bool linkAttributes(const gl::Data &data, bool linkAttributes(const gl::Data &data,
InfoLog &infoLog, InfoLog &infoLog,
const AttributeBindings &attributeBindings, const Bindings &attributeBindings,
const Shader *vertexShader); const Shader *vertexShader);
bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps); bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps);
static bool linkVaryings(InfoLog &infoLog, static bool linkVaryings(InfoLog &infoLog,
const Shader *vertexShader, const Shader *vertexShader,
const Shader *fragmentShader); const Shader *fragmentShader);
bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps, const Bindings &uniformBindings);
void indexUniforms(); bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps, const Bindings &uniformBindings);
bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
const sh::InterfaceBlock &fragmentInterfaceBlock); const sh::InterfaceBlock &fragmentInterfaceBlock);
...@@ -420,7 +429,8 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -420,7 +429,8 @@ class Program final : angle::NonCopyable, public LabeledObject
bool mValidated; bool mValidated;
AttributeBindings mAttributeBindings; Bindings mAttributeBindings;
Bindings mUniformBindings;
bool mLinked; bool mLinked;
bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use
......
...@@ -1234,6 +1234,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons ...@@ -1234,6 +1234,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
extensions->vertexArrayObject = true; extensions->vertexArrayObject = true;
extensions->noError = true; extensions->noError = true;
extensions->lossyETCDecode = true; extensions->lossyETCDecode = true;
extensions->bindUniformLocation = true;
// D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing. // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
// D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing. // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.
......
...@@ -579,6 +579,7 @@ void GenerateCaps(IDirect3D9 *d3d9, ...@@ -579,6 +579,7 @@ void GenerateCaps(IDirect3D9 *d3d9,
extensions->packSubimage = true; extensions->packSubimage = true;
extensions->vertexArrayObject = true; extensions->vertexArrayObject = true;
extensions->noError = true; extensions->noError = true;
extensions->bindUniformLocation = true;
// D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
// state. // state.
......
...@@ -157,9 +157,17 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog) ...@@ -157,9 +157,17 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
// Query the uniform information // Query the uniform information
ASSERT(mUniformRealLocationMap.empty()); ASSERT(mUniformRealLocationMap.empty());
const auto &uniformLocations = mData.getUniformLocations();
const auto &uniforms = mData.getUniforms(); const auto &uniforms = mData.getUniforms();
for (const gl::VariableLocation &entry : mData.getUniformLocations()) mUniformRealLocationMap.resize(uniformLocations.size(), GL_INVALID_INDEX);
for (size_t uniformLocation = 0; uniformLocation < uniformLocations.size(); uniformLocation++)
{ {
const auto &entry = uniformLocations[uniformLocation];
if (!entry.used)
{
continue;
}
// From the spec: // From the spec:
// "Locations for sequential array indices are not required to be sequential." // "Locations for sequential array indices are not required to be sequential."
const gl::LinkedUniform &uniform = uniforms[entry.index]; const gl::LinkedUniform &uniform = uniforms[entry.index];
...@@ -172,7 +180,7 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog) ...@@ -172,7 +180,7 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
const std::string &fullName = fullNameStr.str(); const std::string &fullName = fullNameStr.str();
GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str()); GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
mUniformRealLocationMap.push_back(realLocation); mUniformRealLocationMap[uniformLocation] = realLocation;
} }
mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX); mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX);
......
...@@ -642,6 +642,8 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM ...@@ -642,6 +642,8 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
extensions->vertexArrayObject = true; extensions->vertexArrayObject = true;
extensions->noError = true; extensions->noError = true;
extensions->bindUniformLocation = true;
} }
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds) void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds)
......
...@@ -1391,7 +1391,7 @@ static bool ValidateUniformCommonBase(gl::Context *context, ...@@ -1391,7 +1391,7 @@ static bool ValidateUniformCommonBase(gl::Context *context,
return false; return false;
} }
if (location == -1) if (program->isIgnoredUniformLocation(location))
{ {
// Silently ignore the uniform command // Silently ignore the uniform command
return false; return false;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "libANGLE/Renderbuffer.h" #include "libANGLE/Renderbuffer.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Uniform.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -2011,4 +2012,48 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture) ...@@ -2011,4 +2012,48 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture)
return true; return true;
} }
bool ValidateBindUniformLocationCHROMIUM(Context *context,
GLuint program,
GLint location,
const GLchar *name)
{
if (!context->getExtensions().bindUniformLocation)
{
context->recordError(
Error(GL_INVALID_OPERATION, "GL_CHROMIUM_bind_uniform_location is not available."));
return false;
}
Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
return false;
}
if (location < 0)
{
context->recordError(Error(GL_INVALID_VALUE, "Location cannot be less than 0."));
return false;
}
const Caps &caps = context->getCaps();
if (static_cast<size_t>(location) >=
(caps.maxVertexUniformVectors + caps.maxFragmentUniformVectors) * 4)
{
context->recordError(Error(GL_INVALID_VALUE,
"Location must be less than (MAX_VERTEX_UNIFORM_VECTORS + "
"MAX_FRAGMENT_UNIFORM_VECTORS) * 4"));
return false;
}
if (strncmp(name, "gl_", 3) == 0)
{
context->recordError(
Error(GL_INVALID_OPERATION, "Name cannot start with the reserved \"gl_\" prefix."));
return false;
}
return true;
}
} // namespace gl } // namespace gl
...@@ -183,6 +183,11 @@ bool ValidateFlushMappedBufferRangeEXT(Context *context, ...@@ -183,6 +183,11 @@ bool ValidateFlushMappedBufferRangeEXT(Context *context,
GLintptr offset, GLintptr offset,
GLsizeiptr length); GLsizeiptr length);
bool ValidateBindUniformLocationCHROMIUM(Context *context,
GLuint program,
GLint location,
const GLchar *name);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES2_H_ #endif // LIBANGLE_VALIDATION_ES2_H_
...@@ -1460,6 +1460,9 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char * ...@@ -1460,6 +1460,9 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *
INSERT_PROC_ADDRESS(gl, GetObjectPtrLabelKHR); INSERT_PROC_ADDRESS(gl, GetObjectPtrLabelKHR);
INSERT_PROC_ADDRESS(gl, GetPointervKHR); INSERT_PROC_ADDRESS(gl, GetPointervKHR);
// GL_CHROMIUM_bind_uniform_location
INSERT_PROC_ADDRESS(gl, BindUniformLocationCHROMIUM);
// GLES3 core // GLES3 core
INSERT_PROC_ADDRESS(gl, ReadBuffer); INSERT_PROC_ADDRESS(gl, ReadBuffer);
INSERT_PROC_ADDRESS(gl, DrawRangeElements); INSERT_PROC_ADDRESS(gl, DrawRangeElements);
......
...@@ -1369,4 +1369,23 @@ void GL_APIENTRY GetPointervKHR(GLenum pname, void **params) ...@@ -1369,4 +1369,23 @@ void GL_APIENTRY GetPointervKHR(GLenum pname, void **params)
context->getPointerv(pname, params); context->getPointerv(pname, params);
} }
} }
ANGLE_EXPORT void GL_APIENTRY BindUniformLocationCHROMIUM(GLuint program,
GLint location,
const GLchar *name)
{
EVENT("(GLuint program = %u, GLint location = %d, const GLchar *name = 0x%0.8p)", program,
location, name);
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateBindUniformLocationCHROMIUM(context, program, location, name))
{
return;
}
context->bindUniformLocation(program, location, name);
}
}
} }
...@@ -140,6 +140,11 @@ ANGLE_EXPORT void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr, ...@@ -140,6 +140,11 @@ ANGLE_EXPORT void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr,
GLsizei *length, GLsizei *length,
GLchar *label); GLchar *label);
ANGLE_EXPORT void GL_APIENTRY GetPointervKHR(GLenum pname, void **params); ANGLE_EXPORT void GL_APIENTRY GetPointervKHR(GLenum pname, void **params);
// GL_CHROMIUM_bind_uniform_location
ANGLE_EXPORT void GL_APIENTRY BindUniformLocationCHROMIUM(GLuint program,
GLint location,
const GLchar *name);
} }
#endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_ #endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_
...@@ -1562,4 +1562,9 @@ void GL_APIENTRY glGetPointervKHR(GLenum pname, void **params) ...@@ -1562,4 +1562,9 @@ void GL_APIENTRY glGetPointervKHR(GLenum pname, void **params)
{ {
return gl::GetPointervKHR(pname, params); return gl::GetPointervKHR(pname, params);
} }
void GL_APIENTRY glBindUniformLocationCHROMIUM(GLuint program, GLint location, const GLchar *name)
{
return gl::BindUniformLocationCHROMIUM(program, location, name);
}
} }
...@@ -202,6 +202,7 @@ EXPORTS ...@@ -202,6 +202,7 @@ EXPORTS
glGetQueryObjectivEXT @315 glGetQueryObjectivEXT @315
glGetQueryObjecti64vEXT @316 glGetQueryObjecti64vEXT @316
glGetQueryObjectui64vEXT @317 glGetQueryObjectui64vEXT @317
glBindUniformLocationCHROMIUM @318
; GLES 3.0 Functions ; GLES 3.0 Functions
glReadBuffer @180 glReadBuffer @180
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
{ {
'angle_end2end_tests_sources': 'angle_end2end_tests_sources':
[ [
'<(angle_path)/src/tests/gl_tests/BindUniformLocationTest.cpp',
'<(angle_path)/src/tests/gl_tests/BlendMinMaxTest.cpp', '<(angle_path)/src/tests/gl_tests/BlendMinMaxTest.cpp',
'<(angle_path)/src/tests/gl_tests/BlitFramebufferANGLETest.cpp', '<(angle_path)/src/tests/gl_tests/BlitFramebufferANGLETest.cpp',
'<(angle_path)/src/tests/gl_tests/BufferDataTest.cpp', '<(angle_path)/src/tests/gl_tests/BufferDataTest.cpp',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment