// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // /// \file bindingMap.cpp #include "pxr/imaging/glf/glew.h" #include "pxr/imaging/glf/bindingMap.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/stl.h" #include "pxr/base/tf/type.h" PXR_NAMESPACE_OPEN_SCOPE int GlfBindingMap::GetSamplerUnit(std::string const & name) { return GetSamplerUnit(TfToken(name)); } int GlfBindingMap::GetSamplerUnit(TfToken const & name) { int samplerUnit = -1; if (!TfMapLookup(_samplerBindings, name, &samplerUnit)) { // XXX error check < MAX_TEXTURE_IMAGE_UNITS samplerUnit = _samplerBindings.size(); _samplerBindings[name] = samplerUnit; } TF_VERIFY(samplerUnit >= 0); return samplerUnit; } int GlfBindingMap::GetAttributeIndex(std::string const & name) { return GetAttributeIndex(TfToken(name)); } int GlfBindingMap::GetAttributeIndex(TfToken const & name) { int attribIndex = -1; if (!TfMapLookup(_attribBindings, name, &attribIndex)) { return -1; } return attribIndex; } void GlfBindingMap::AssignSamplerUnitsToProgram(GLuint program) { for (BindingMap::value_type const& p : _samplerBindings) { GLint loc = glGetUniformLocation(program, p.first.GetText()); if (loc != -1) { glProgramUniform1i(program, loc, p.second); } } } int GlfBindingMap::GetUniformBinding(std::string const & name) { return GetUniformBinding(TfToken(name)); } int GlfBindingMap::GetUniformBinding(TfToken const & name) { int binding = -1; if (!TfMapLookup(_uniformBindings, name, &binding)) { binding = (int)_uniformBindings.size(); _uniformBindings[name] = binding; } TF_VERIFY(binding >= 0); return binding; } bool GlfBindingMap::HasUniformBinding(std::string const & name) const { return HasUniformBinding(TfToken(name)); } bool GlfBindingMap::HasUniformBinding(TfToken const & name) const { return (_uniformBindings.find(name) != _uniformBindings.end()); } void GlfBindingMap::AssignUniformBindingsToProgram(GLuint program) { for (BindingMap::value_type const& p : _uniformBindings) { GLuint uboIndex = glGetUniformBlockIndex(program, p.first.GetText()); if (uboIndex != GL_INVALID_INDEX) { glUniformBlockBinding(program, uboIndex, p.second); } } } void GlfBindingMap::AddCustomBindings(GLuint program) { _AddActiveAttributeBindings(program); _AddActiveUniformBindings(program); _AddActiveUniformBlockBindings(program); // assign uniform bindings / texture samplers AssignUniformBindingsToProgram(program); AssignSamplerUnitsToProgram(program); } void GlfBindingMap::_AddActiveAttributeBindings(GLuint program) { GLint numAttributes = 0; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttributes); if (numAttributes == 0) return; GLint maxNameLength = 0; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength); maxNameLength = std::max(maxNameLength, 100); GLint size; GLenum type; char * name = new char[maxNameLength]; for (int i = 0; i < numAttributes; ++i) { glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name); GLint location = glGetAttribLocation(program, name); TfToken token(name); BindingMap::iterator it = _attribBindings.find(token); if (it == _attribBindings.end()) { _attribBindings[token] = location; } else if (it->second != location) { TF_RUNTIME_ERROR("Inconsistent attribute binding detected."); } } delete[] name; } void GlfBindingMap::_AddActiveUniformBindings(GLuint program) { GLint numUniforms = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms); if (numUniforms == 0) return; GLint maxNameLength = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); GLint size; GLenum type; char * name = new char[maxNameLength]; for (int i = 0; i < numUniforms; ++i) { glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name); switch(type) { case GL_SAMPLER_1D: case GL_SAMPLER_2D: case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_1D_ARRAY: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_1D_ARRAY_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_BUFFER: case GL_SAMPLER_2D_RECT: case GL_SAMPLER_2D_RECT_SHADOW: case GL_INT_SAMPLER_1D: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_1D_ARRAY: case GL_INT_SAMPLER_2D_ARRAY: case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_BUFFER: case GL_INT_SAMPLER_2D_RECT: case GL_UNSIGNED_INT_SAMPLER_1D: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_UNSIGNED_INT_SAMPLER_2D_RECT: GetSamplerUnit(name); break; } } delete[] name; } void GlfBindingMap::_AddActiveUniformBlockBindings(GLuint program) { GLint numUniformBlocks = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks); if (numUniformBlocks == 0) return; GLint maxNameLength = 0; glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxNameLength); char *name = new char[maxNameLength]; for (int i = 0; i < numUniformBlocks; ++i) { glGetActiveUniformBlockName(program, i, maxNameLength, NULL, name); GetUniformBinding(name); } delete[] name; } void GlfBindingMap::Debug() const { printf("GlfBindingMap\n"); // sort for comparing baseline in testGlfBindingMap std::map attribBindings, samplerBindings, uniformBindings; for (BindingMap::value_type const& p : _attribBindings ) { attribBindings.insert(p); } for (BindingMap::value_type const& p : _samplerBindings ) { samplerBindings.insert(p); } for (BindingMap::value_type const& p : _uniformBindings ) { uniformBindings.insert(p); } printf(" Attribute bindings\n"); for (BindingMap::value_type const& p : attribBindings ) { printf(" %s : %d\n", p.first.GetText(), p.second); } printf(" Sampler bindings\n"); for (BindingMap::value_type const& p : samplerBindings) { printf(" %s : %d\n", p.first.GetText(), p.second); } printf(" Uniform bindings\n"); for (BindingMap::value_type const& p : uniformBindings) { printf(" %s : %d\n", p.first.GetText(), p.second); } } PXR_NAMESPACE_CLOSE_SCOPE