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 #include "pxr/imaging/garch/glApi.h"
25
26 #include "pxr/imaging/hdSt/glConversions.h"
27 #include "pxr/base/tf/staticTokens.h"
28 #include "pxr/base/tf/stringUtils.h"
29
30 #include <cctype>
31
32 PXR_NAMESPACE_OPEN_SCOPE
33
34
35 GLenum
GetGlDepthFunc(HdCompareFunction func)36 HdStGLConversions::GetGlDepthFunc(HdCompareFunction func)
37 {
38 static GLenum HD_2_GL_DEPTH_FUNC[] =
39 {
40 GL_NEVER, // HdCmpFuncNever
41 GL_LESS, // HdCmpFuncLess
42 GL_EQUAL, // HdCmpFuncEqual
43 GL_LEQUAL, // HdCmpFuncLEqual
44 GL_GREATER, // HdCmpFuncGreater
45 GL_NOTEQUAL, // HdCmpFuncNotEqual
46 GL_GEQUAL, // HdCmpFuncGEqual
47 GL_ALWAYS, // HdCmpFuncAlways
48 };
49 static_assert(
50 (sizeof(HD_2_GL_DEPTH_FUNC) / sizeof(HD_2_GL_DEPTH_FUNC[0])) ==
51 HdCmpFuncLast, "Mismatch enum sizes in convert function");
52
53 return HD_2_GL_DEPTH_FUNC[func];
54 }
55
56 GLenum
GetGlStencilFunc(HdCompareFunction func)57 HdStGLConversions::GetGlStencilFunc(HdCompareFunction func)
58 {
59 static GLenum HD_2_GL_STENCIL_FUNC[] =
60 {
61 GL_NEVER, // HdCmpFuncNever
62 GL_LESS, // HdCmpFuncLess
63 GL_EQUAL, // HdCmpFuncEqual
64 GL_LEQUAL, // HdCmpFuncLEqual
65 GL_GREATER, // HdCmpFuncGreater
66 GL_NOTEQUAL, // HdCmpFuncNotEqual
67 GL_GEQUAL, // HdCmpFuncGEqual
68 GL_ALWAYS, // HdCmpFuncAlways
69 };
70 static_assert(
71 (sizeof(HD_2_GL_STENCIL_FUNC) / sizeof(HD_2_GL_STENCIL_FUNC[0])) ==
72 HdCmpFuncLast, "Mismatch enum sizes in convert function");
73
74 return HD_2_GL_STENCIL_FUNC[func];
75 }
76
77 GLenum
GetGlStencilOp(HdStencilOp op)78 HdStGLConversions::GetGlStencilOp(HdStencilOp op)
79 {
80 static GLenum HD_2_GL_STENCIL_OP[] =
81 {
82 GL_KEEP, // HdStencilOpKeep
83 GL_ZERO, // HdStencilOpZero
84 GL_REPLACE, // HdStencilOpReplace
85 GL_INCR, // HdStencilOpIncrement
86 GL_INCR_WRAP, // HdStencilOpIncrementWrap
87 GL_DECR, // HdStencilOpDecrement
88 GL_DECR_WRAP, // HdStencilOpDecrementWrap
89 GL_INVERT, // HdStencilOpInvert
90 };
91 static_assert(
92 (sizeof(HD_2_GL_STENCIL_OP) / sizeof(HD_2_GL_STENCIL_OP[0])) ==
93 HdStencilOpLast, "Mismatch enum sizes in convert function");
94
95 return HD_2_GL_STENCIL_OP[op];
96 }
97
98 GLenum
GetGlBlendOp(HdBlendOp op)99 HdStGLConversions::GetGlBlendOp(HdBlendOp op)
100 {
101 static GLenum HD_2_GL_BLEND_OP[] =
102 {
103 GL_FUNC_ADD, // HdBlendOpAdd
104 GL_FUNC_SUBTRACT, // HdBlendOpSubtract
105 GL_FUNC_REVERSE_SUBTRACT, // HdBlendOpReverseSubtract
106 GL_MIN, // HdBlendOpMin
107 GL_MAX, // HdBlendOpMax
108 };
109 static_assert(
110 (sizeof(HD_2_GL_BLEND_OP) / sizeof(HD_2_GL_BLEND_OP[0])) ==
111 HdBlendOpLast, "Mismatch enum sizes in convert function");
112
113 return HD_2_GL_BLEND_OP[op];
114 }
115
116 GLenum
GetGlBlendFactor(HdBlendFactor factor)117 HdStGLConversions::GetGlBlendFactor(HdBlendFactor factor)
118 {
119 static GLenum HD_2_GL_BLEND_FACTOR[] =
120 {
121 GL_ZERO, // HdBlendFactorZero,
122 GL_ONE, // HdBlendFactorOne,
123 GL_SRC_COLOR, // HdBlendFactorSrcColor,
124 GL_ONE_MINUS_SRC_COLOR, // HdBlendFactorOneMinusSrcColor,
125 GL_DST_COLOR, // HdBlendFactorDstColor,
126 GL_ONE_MINUS_DST_COLOR, // HdBlendFactorOneMinusDstColor,
127 GL_SRC_ALPHA, // HdBlendFactorSrcAlpha,
128 GL_ONE_MINUS_SRC_ALPHA, // HdBlendFactorOneMinusSrcAlpha,
129 GL_DST_ALPHA, // HdBlendFactorDstAlpha,
130 GL_ONE_MINUS_DST_ALPHA, // HdBlendFactorOneMinusDstAlpha,
131 GL_CONSTANT_COLOR, // HdBlendFactorConstantColor,
132 GL_ONE_MINUS_CONSTANT_COLOR, // HdBlendFactorOneMinusConstantColor,
133 GL_CONSTANT_ALPHA, // HdBlendFactorConstantAlpha,
134 GL_ONE_MINUS_CONSTANT_ALPHA, // HdBlendFactorOneMinusConstantAlpha,
135 GL_SRC_ALPHA_SATURATE, // HdBlendFactorSrcAlphaSaturate,
136 GL_SRC1_COLOR, // HdBlendFactorSrc1Color,
137 GL_ONE_MINUS_SRC1_COLOR, // HdBlendFactorOneMinusSrc1Color,
138 GL_SRC1_ALPHA, // HdBlendFactorSrc1Alpha,
139 GL_ONE_MINUS_SRC1_COLOR, // HdBlendFactorOneMinusSrc1Alpha,
140 };
141 static_assert(
142 (sizeof(HD_2_GL_BLEND_FACTOR) / sizeof(HD_2_GL_BLEND_FACTOR[0])) ==
143 HdBlendFactorLast, "Mismatch enum sizes in convert function");
144
145 return HD_2_GL_BLEND_FACTOR[factor];
146 }
147
148 int
GetGLAttribType(HdType type)149 HdStGLConversions::GetGLAttribType(HdType type)
150 {
151 switch (type) {
152 case HdTypeHalfFloatVec2:
153 case HdTypeHalfFloatVec4:
154 return GL_HALF_FLOAT;
155 case HdTypeInt32:
156 case HdTypeInt32Vec2:
157 case HdTypeInt32Vec3:
158 case HdTypeInt32Vec4:
159 return GL_INT;
160 case HdTypeUInt32:
161 case HdTypeUInt32Vec2:
162 case HdTypeUInt32Vec3:
163 case HdTypeUInt32Vec4:
164 return GL_UNSIGNED_INT;
165 case HdTypeFloat:
166 case HdTypeFloatVec2:
167 case HdTypeFloatVec3:
168 case HdTypeFloatVec4:
169 case HdTypeFloatMat3:
170 case HdTypeFloatMat4:
171 return GL_FLOAT;
172 case HdTypeDouble:
173 case HdTypeDoubleVec2:
174 case HdTypeDoubleVec3:
175 case HdTypeDoubleVec4:
176 case HdTypeDoubleMat3:
177 case HdTypeDoubleMat4:
178 return GL_DOUBLE;
179 case HdTypeInt32_2_10_10_10_REV:
180 return GL_INT_2_10_10_10_REV;
181 default:
182 break;
183 };
184 return -1;
185 }
186
187 TF_DEFINE_PRIVATE_TOKENS(
188 _glTypeNames,
189 ((_bool, "bool"))
190
191 ((_float, "float"))
192 (vec2)
193 (vec3)
194 (vec4)
195 (mat3)
196 (mat4)
197
198 ((_double, "double"))
199 (dvec2)
200 (dvec3)
201 (dvec4)
202 (dmat3)
203 (dmat4)
204
205 ((_int, "int"))
206 (ivec2)
207 (ivec3)
208 (ivec4)
209
210 ((_uint, "uint"))
211 (uvec2)
212 (uvec3)
213 (uvec4)
214
215 (packed_2_10_10_10)
216 (packed_half2)
217 (packed_half4)
218 );
219
220 TfToken
GetGLSLTypename(HdType type)221 HdStGLConversions::GetGLSLTypename(HdType type)
222 {
223 switch (type) {
224 case HdTypeInvalid:
225 default:
226 return TfToken();
227
228 // Packed types (require special handling in codegen)...
229 case HdTypeInt32_2_10_10_10_REV:
230 return _glTypeNames->packed_2_10_10_10;
231 // XXX: Note that we don't support half or half3, since we can't
232 // index-address them...
233 case HdTypeHalfFloatVec2:
234 return _glTypeNames->packed_half2;
235 case HdTypeHalfFloatVec4:
236 return _glTypeNames->packed_half4;
237
238 case HdTypeBool:
239 return _glTypeNames->_bool;
240
241 case HdTypeInt32:
242 return _glTypeNames->_int;
243 case HdTypeInt32Vec2:
244 return _glTypeNames->ivec2;
245 case HdTypeInt32Vec3:
246 return _glTypeNames->ivec3;
247 case HdTypeInt32Vec4:
248 return _glTypeNames->ivec4;
249
250 case HdTypeUInt32:
251 return _glTypeNames->_uint;
252 case HdTypeUInt32Vec2:
253 return _glTypeNames->uvec2;
254 case HdTypeUInt32Vec3:
255 return _glTypeNames->uvec3;
256 case HdTypeUInt32Vec4:
257 return _glTypeNames->uvec4;
258
259 case HdTypeFloat:
260 return _glTypeNames->_float;
261 case HdTypeFloatVec2:
262 return _glTypeNames->vec2;
263 case HdTypeFloatVec3:
264 return _glTypeNames->vec3;
265 case HdTypeFloatVec4:
266 return _glTypeNames->vec4;
267 case HdTypeFloatMat3:
268 return _glTypeNames->mat3;
269 case HdTypeFloatMat4:
270 return _glTypeNames->mat4;
271
272 case HdTypeDouble:
273 return _glTypeNames->_double;
274 case HdTypeDoubleVec2:
275 return _glTypeNames->dvec2;
276 case HdTypeDoubleVec3:
277 return _glTypeNames->dvec3;
278 case HdTypeDoubleVec4:
279 return _glTypeNames->dvec4;
280 case HdTypeDoubleMat3:
281 return _glTypeNames->dmat3;
282 case HdTypeDoubleMat4:
283 return _glTypeNames->dmat4;
284 };
285 }
286
287 // This isn't an exhaustive checker. It doesn't check for built-in/internal
288 // variable names in GLSL, reserved keywords and such.
289 static bool
_IsIdentiferGLSLCompatible(std::string const & in)290 _IsIdentiferGLSLCompatible(std::string const& in)
291 {
292 char const *p = in.c_str();
293
294 // Leading non-alpha characters are not allowed.
295 if (*p && !isalpha(*p)) {
296 return false;
297 }
298 // Characters must be in [_a-zA-Z0-9]
299 while (*p) {
300 if (isalnum(*p)) {
301 p++;
302 } else {
303 // _ is allowed, but __ isn't
304 if (*p == '_' && *(p-1) != '_') {
305 // checking the last character is safe here, because of the
306 // earlier check for leading non-alpha characters.
307 p++;
308 } else {
309 return false;
310 }
311 }
312 }
313
314 return true;
315 }
316
317 TfToken
GetGLSLIdentifier(TfToken const & identifier)318 HdStGLConversions::GetGLSLIdentifier(TfToken const& identifier)
319 {
320 std::string const& in = identifier.GetString();
321 // Avoid allocating a string and constructing a token for the general case,
322 // wherein identifers conform to the naming rules.
323 if (_IsIdentiferGLSLCompatible(in)) {
324 return identifier;
325 }
326
327 // Name-mangling rules:
328 // https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
329 // We choose to specifically disallow:
330 // 1) Leading non-alpha characters: GLSL allows leading underscores, but we
331 // choose to reserve them for internal use.
332 // 2) Consecutive underscores: To avoid unintended GLSL behaviors.
333 std::string result;
334 result.reserve(in.size());
335 char const *p = in.c_str();
336
337 // Skip leading non-alpha characters.
338 while (*p && !isalpha(*p)) {
339 ++p;
340 }
341 for (; *p; ++p) {
342 bool isValidChar = isalnum(*p) || (*p == '_');
343 if (!isValidChar) {
344 // Replace characters not in [_a-zA-Z0-9] with _, unless the last
345 // character added was also _.
346 // Calling back() is safe here because the first character is either
347 // alpha-numeric or null, as guaranteed by the while loop above.
348 if (result.back() != '_') {
349 result.push_back('_');
350 }
351 } else if (*p == '_' && result.back() == '_') {
352 // no-op to skip consecutive _
353 } else {
354 result.push_back(*p);
355 }
356 }
357
358 if (result.empty()) {
359 TF_CODING_ERROR("Invalid identifier '%s' could not be name-mangled",
360 identifier.GetText());
361 return identifier;
362 }
363
364 return TfToken(result);
365 }
366
367 PXR_NAMESPACE_CLOSE_SCOPE
368
369