1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 /// \file bindingMap.cpp
25 
26 #include "pxr/imaging/garch/glApi.h"
27 
28 #include "pxr/imaging/glf/bindingMap.h"
29 #include "pxr/base/tf/diagnostic.h"
30 #include "pxr/base/tf/stl.h"
31 #include "pxr/base/tf/type.h"
32 
33 PXR_NAMESPACE_OPEN_SCOPE
34 
35 
36 int
GetSamplerUnit(std::string const & name)37 GlfBindingMap::GetSamplerUnit(std::string const & name)
38 {
39     return GetSamplerUnit(TfToken(name));
40 }
41 
42 int
GetSamplerUnit(TfToken const & name)43 GlfBindingMap::GetSamplerUnit(TfToken const & name)
44 {
45     int samplerUnit = -1;
46     if (!TfMapLookup(_samplerBindings, name, &samplerUnit)) {
47         // XXX error check < MAX_TEXTURE_IMAGE_UNITS
48         samplerUnit = _samplerBindingBaseIndex + (int)_samplerBindings.size();
49         _samplerBindings[name] = samplerUnit;
50     }
51     TF_VERIFY(samplerUnit >= 0);
52     return samplerUnit;
53 }
54 
55 int
GetAttributeIndex(std::string const & name)56 GlfBindingMap::GetAttributeIndex(std::string const & name)
57 {
58     return GetAttributeIndex(TfToken(name));
59 }
60 
61 int
GetAttributeIndex(TfToken const & name)62 GlfBindingMap::GetAttributeIndex(TfToken const & name)
63 {
64     int attribIndex = -1;
65     if (!TfMapLookup(_attribBindings, name, &attribIndex)) {
66         return -1;
67     }
68     return attribIndex;
69 }
70 
71 void
AssignSamplerUnitsToProgram(GLuint program)72 GlfBindingMap::AssignSamplerUnitsToProgram(GLuint program)
73 {
74     for (BindingMap::value_type const& p : _samplerBindings) {
75         GLint loc = glGetUniformLocation(program, p.first.GetText());
76         if (loc != -1) {
77             glProgramUniform1i(program, loc, p.second);
78         }
79     }
80 }
81 
82 int
GetUniformBinding(std::string const & name)83 GlfBindingMap::GetUniformBinding(std::string const & name)
84 {
85     return GetUniformBinding(TfToken(name));
86 }
87 
88 int
GetUniformBinding(TfToken const & name)89 GlfBindingMap::GetUniformBinding(TfToken const & name)
90 {
91     int binding = -1;
92     if (!TfMapLookup(_uniformBindings, name, &binding)) {
93         binding = _uniformBindingBaseIndex + (int)_uniformBindings.size();
94         _uniformBindings[name] = binding;
95     }
96     TF_VERIFY(binding >= 0);
97     return binding;
98 }
99 
100 bool
HasUniformBinding(std::string const & name) const101 GlfBindingMap::HasUniformBinding(std::string const & name) const
102 {
103     return HasUniformBinding(TfToken(name));
104 }
105 
106 bool
HasUniformBinding(TfToken const & name) const107 GlfBindingMap::HasUniformBinding(TfToken const & name) const
108 {
109     return (_uniformBindings.find(name) != _uniformBindings.end());
110 }
111 
112 void
AssignUniformBindingsToProgram(GLuint program)113 GlfBindingMap::AssignUniformBindingsToProgram(GLuint program)
114 {
115     for (BindingMap::value_type const& p : _uniformBindings) {
116         GLuint uboIndex = glGetUniformBlockIndex(program, p.first.GetText());
117         if (uboIndex != GL_INVALID_INDEX) {
118             glUniformBlockBinding(program, uboIndex, p.second);
119         }
120     }
121 }
122 
123 void
AddCustomBindings(GLuint program)124 GlfBindingMap::AddCustomBindings(GLuint program)
125 {
126     _AddActiveAttributeBindings(program);
127     _AddActiveUniformBindings(program);
128     _AddActiveUniformBlockBindings(program);
129 
130     // assign uniform bindings / texture samplers
131     AssignUniformBindingsToProgram(program);
132     AssignSamplerUnitsToProgram(program);
133 }
134 
135 void
_AddActiveAttributeBindings(GLuint program)136 GlfBindingMap::_AddActiveAttributeBindings(GLuint program)
137 {
138     GLint numAttributes = 0;
139     glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttributes);
140     if (numAttributes == 0) return;
141 
142     GLint maxNameLength = 0;
143     glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
144     maxNameLength = std::max(maxNameLength, 100);
145     GLint size;
146     GLenum type;
147     char * name = new char[maxNameLength];
148 
149     for (int i = 0; i < numAttributes; ++i) {
150         glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name);
151         GLint location = glGetAttribLocation(program, name);
152         TfToken token(name);
153 
154         BindingMap::iterator it = _attribBindings.find(token);
155         if (it == _attribBindings.end()) {
156             _attribBindings[token] = location;
157         } else if (it->second != location) {
158             TF_RUNTIME_ERROR("Inconsistent attribute binding detected.");
159         }
160     }
161 
162     delete[] name;
163 }
164 
165 void
_AddActiveUniformBindings(GLuint program)166 GlfBindingMap::_AddActiveUniformBindings(GLuint program)
167 {
168     GLint numUniforms = 0;
169     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms);
170     if (numUniforms == 0) return;
171 
172     GLint maxNameLength = 0;
173     glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
174     GLint size;
175     GLenum type;
176     char * name = new char[maxNameLength];
177 
178     for (int i = 0; i < numUniforms; ++i) {
179         glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name);
180         switch(type) {
181         case GL_SAMPLER_1D:
182         case GL_SAMPLER_2D:
183         case GL_SAMPLER_3D:
184         case GL_SAMPLER_CUBE:
185         case GL_SAMPLER_1D_SHADOW:
186         case GL_SAMPLER_2D_SHADOW:
187         case GL_SAMPLER_1D_ARRAY:
188         case GL_SAMPLER_2D_ARRAY:
189         case GL_SAMPLER_1D_ARRAY_SHADOW:
190         case GL_SAMPLER_2D_ARRAY_SHADOW:
191         case GL_SAMPLER_2D_MULTISAMPLE:
192         case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
193         case GL_SAMPLER_CUBE_SHADOW:
194         case GL_SAMPLER_BUFFER:
195         case GL_SAMPLER_2D_RECT:
196         case GL_SAMPLER_2D_RECT_SHADOW:
197         case GL_INT_SAMPLER_1D:
198         case GL_INT_SAMPLER_2D:
199         case GL_INT_SAMPLER_3D:
200         case GL_INT_SAMPLER_CUBE:
201         case GL_INT_SAMPLER_1D_ARRAY:
202         case GL_INT_SAMPLER_2D_ARRAY:
203         case GL_INT_SAMPLER_2D_MULTISAMPLE:
204         case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
205         case GL_INT_SAMPLER_BUFFER:
206         case GL_INT_SAMPLER_2D_RECT:
207         case GL_UNSIGNED_INT_SAMPLER_1D:
208         case GL_UNSIGNED_INT_SAMPLER_2D:
209         case GL_UNSIGNED_INT_SAMPLER_3D:
210         case GL_UNSIGNED_INT_SAMPLER_CUBE:
211         case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
212         case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
213         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
214         case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
215         case GL_UNSIGNED_INT_SAMPLER_BUFFER:
216         case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
217             GetSamplerUnit(name);
218             break;
219         }
220     }
221     delete[] name;
222 }
223 
224 void
_AddActiveUniformBlockBindings(GLuint program)225 GlfBindingMap::_AddActiveUniformBlockBindings(GLuint program)
226 {
227     GLint numUniformBlocks = 0;
228     glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
229     if (numUniformBlocks == 0) return;
230 
231     GLint maxNameLength = 0;
232     glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxNameLength);
233     char *name = new char[maxNameLength];
234 
235     for (int i = 0; i < numUniformBlocks; ++i) {
236         glGetActiveUniformBlockName(program, i, maxNameLength, NULL, name);
237         GetUniformBinding(name);
238     }
239     delete[] name;
240 }
241 
242 void
Debug() const243 GlfBindingMap::Debug() const
244 {
245     printf("GlfBindingMap\n");
246 
247     // sort for comparing baseline in testGlfBindingMap
248     std::map<TfToken, int> attribBindings, samplerBindings, uniformBindings;
249     for (BindingMap::value_type const& p : _attribBindings ) {
250         attribBindings.insert(p);
251     }
252     for (BindingMap::value_type const& p : _samplerBindings ) {
253         samplerBindings.insert(p);
254     }
255     for (BindingMap::value_type const& p : _uniformBindings ) {
256         uniformBindings.insert(p);
257     }
258 
259     printf(" Attribute bindings\n");
260     for (BindingMap::value_type const& p : attribBindings ) {
261         printf("  %s : %d\n", p.first.GetText(), p.second);
262     }
263     printf(" Sampler bindings\n");
264     for (BindingMap::value_type const& p : samplerBindings) {
265         printf("  %s : %d\n", p.first.GetText(), p.second);
266     }
267     printf(" Uniform bindings\n");
268     for (BindingMap::value_type const& p : uniformBindings) {
269         printf("  %s : %d\n", p.first.GetText(), p.second);
270     }
271 }
272 
273 
274 PXR_NAMESPACE_CLOSE_SCOPE
275 
276