1 //
2 // Copyright 2018 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
25 #include "pxr/imaging/garch/glApi.h"
26
27 #include "pxr/imaging/glf/contextCaps.h"
28
29 #include "pxr/imaging/glf/glContext.h"
30 #include "pxr/imaging/glf/debugCodes.h"
31
32 #include "pxr/base/tf/diagnostic.h"
33 #include "pxr/base/tf/envSetting.h"
34 #include "pxr/base/tf/instantiateSingleton.h"
35
36 #include <iostream>
37 #include <mutex>
38
39 PXR_NAMESPACE_OPEN_SCOPE
40
41
42 TF_INSTANTIATE_SINGLETON(GlfContextCaps);
43
44 TF_DEFINE_ENV_SETTING(GLF_ENABLE_SHADER_STORAGE_BUFFER, true,
45 "Use GL shader storage buffer (OpenGL 4.3)");
46 TF_DEFINE_ENV_SETTING(GLF_ENABLE_BINDLESS_BUFFER, false,
47 "Use GL bindless buffer extention");
48 TF_DEFINE_ENV_SETTING(GLF_ENABLE_BINDLESS_TEXTURE, false,
49 "Use GL bindless texture extention");
50 TF_DEFINE_ENV_SETTING(GLF_ENABLE_MULTI_DRAW_INDIRECT, true,
51 "Use GL multi draw indirect extention");
52 TF_DEFINE_ENV_SETTING(GLF_ENABLE_DIRECT_STATE_ACCESS, true,
53 "Use GL direct state access extention");
54 TF_DEFINE_ENV_SETTING(GLF_ENABLE_COPY_BUFFER, true,
55 "Use GL copy buffer data");
56 TF_DEFINE_ENV_SETTING(GLF_ENABLE_SHADER_DRAW_PARAMETERS, true,
57 "Use GL shader draw params if available (OpenGL 4.5+)");
58
59 TF_DEFINE_ENV_SETTING(GLF_GLSL_VERSION, 0,
60 "GLSL version");
61
62
63 // Set defaults based on GL spec minimums
64 static const int _DefaultMaxArrayTextureLayers = 256;
65 static const int _DefaultMaxUniformBlockSize = 16*1024;
66 static const int _DefaultMaxShaderStorageBlockSize = 16*1024*1024;
67 static const int _DefaultMaxTextureBufferSize = 64*1024;
68 static const int _DefaultGLSLVersion = 400;
69
70 // Initialize members to ensure a sane starting state.
GlfContextCaps()71 GlfContextCaps::GlfContextCaps()
72 : glVersion(0)
73 , coreProfile(false)
74
75 , maxArrayTextureLayers(_DefaultMaxArrayTextureLayers)
76 , maxUniformBlockSize(_DefaultMaxUniformBlockSize)
77 , maxShaderStorageBlockSize(_DefaultMaxShaderStorageBlockSize)
78 , maxTextureBufferSize(_DefaultMaxTextureBufferSize)
79 , uniformBufferOffsetAlignment(0)
80
81 , arrayTexturesEnabled(false)
82 , shaderStorageBufferEnabled(false)
83 , bufferStorageEnabled(false)
84 , directStateAccessEnabled(false)
85 , multiDrawIndirectEnabled(false)
86 , bindlessTextureEnabled(false)
87 , bindlessBufferEnabled(false)
88
89 , glslVersion(_DefaultGLSLVersion)
90 , explicitUniformLocation(false)
91 , shadingLanguage420pack(false)
92 , shaderDrawParametersEnabled(false)
93
94 , copyBufferEnabled(true)
95 , floatingPointBuffersEnabled(false)
96 {
97 }
98
99 /*static*/
100 void
InitInstance()101 GlfContextCaps::InitInstance()
102 {
103 // Initialize the render context caps.
104 // This needs to be called on a thread that has the gl context
105 // bound before we go wide on the cpus.
106
107 // XXX: This should be called on
108 // an render context change event api. (bug #124971)
109
110 GlfContextCaps& caps = TfSingleton<GlfContextCaps>::GetInstance();
111
112 GarchGLApiLoad();
113
114 caps._LoadCaps();
115 }
116
117 /*static*/
118 const GlfContextCaps&
GetInstance()119 GlfContextCaps::GetInstance()
120 {
121 GlfContextCaps& caps = TfSingleton<GlfContextCaps>::GetInstance();
122
123 if (caps.glVersion == 0) {
124 TF_CODING_ERROR("GlfContextCaps has not been initialized");
125 // Return the default set
126 }
127
128 return caps;
129 }
130
131 void
_LoadCaps()132 GlfContextCaps::_LoadCaps()
133 {
134 // Reset Values to reasonable defaults based of OpenGL minimums.
135 // So that if we early out, systems can still depend on the
136 // caps values being valid.
137 //
138 // _LoadCaps can also be called multiple times, so not want
139 // to mix and match values in the event of an early out.
140 glVersion = 0;
141 coreProfile = false;
142 maxArrayTextureLayers = _DefaultMaxArrayTextureLayers;
143 maxUniformBlockSize = _DefaultMaxUniformBlockSize;
144 maxShaderStorageBlockSize = _DefaultMaxShaderStorageBlockSize;
145 maxTextureBufferSize = _DefaultMaxTextureBufferSize;
146 uniformBufferOffsetAlignment = 0;
147 arrayTexturesEnabled = false;
148 shaderStorageBufferEnabled = false;
149 bufferStorageEnabled = false;
150 directStateAccessEnabled = false;
151 multiDrawIndirectEnabled = false;
152 bindlessTextureEnabled = false;
153 bindlessBufferEnabled = false;
154 glslVersion = _DefaultGLSLVersion;
155 explicitUniformLocation = false;
156 shadingLanguage420pack = false;
157 shaderDrawParametersEnabled = false;
158 copyBufferEnabled = true;
159 floatingPointBuffersEnabled = false;
160
161
162 if (!TF_VERIFY(GlfGLContext::GetCurrentGLContext()->IsValid())) {
163 return;
164 }
165
166 const char *glVendorStr = (const char*)glGetString(GL_VENDOR);
167 const char *glRendererStr = (const char*)glGetString(GL_RENDERER);
168 const char *glVersionStr = (const char*)glGetString(GL_VERSION);
169
170 // GL hasn't been initialized yet.
171 if (glVersionStr == NULL) return;
172
173 const char *dot = strchr(glVersionStr, '.');
174 if (TF_VERIFY((dot && dot != glVersionStr),
175 "Can't parse GL_VERSION %s", glVersionStr)) {
176 // GL_VERSION = "4.5.0 <vendor> <version>"
177 // "4.1 <vendor-os-ver> <version>"
178 // "4.1 <vendor-os-ver>"
179 int major = std::max(0, std::min(9, *(dot-1) - '0'));
180 int minor = std::max(0, std::min(9, *(dot+1) - '0'));
181 glVersion = major * 100 + minor * 10;
182 }
183
184 if (glVersion >= 200) {
185 const char *glslVersionStr =
186 (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
187 dot = strchr(glslVersionStr, '.');
188 if (TF_VERIFY((dot && dot != glslVersionStr),
189 "Can't parse GL_SHADING_LANGUAGE_VERSION %s",
190 glslVersionStr)) {
191 // GL_SHADING_LANGUAGE_VERSION = "4.10"
192 // "4.50 <vendor>"
193 int major = std::max(0, std::min(9, *(dot-1) - '0'));
194 int minor = std::max(0, std::min(9, *(dot+1) - '0'));
195 glslVersion = major * 100 + minor * 10;
196 }
197 } else {
198 glslVersion = 0;
199 }
200
201 if (glVersion >= 300) {
202 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArrayTextureLayers);
203 arrayTexturesEnabled = true;
204 }
205
206 // initialize by Core versions
207 if (glVersion >= 310) {
208 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
209 &maxUniformBlockSize);
210 glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE,
211 &maxTextureBufferSize);
212 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
213 &uniformBufferOffsetAlignment);
214 }
215 if (glVersion >= 320) {
216 GLint profileMask = 0;
217 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
218 coreProfile = (profileMask & GL_CONTEXT_CORE_PROFILE_BIT);
219 }
220 if (glVersion >= 400) {
221 // Older versions of GL maybe support R16F and D32F, but for now we set
222 // the minimum GL at 4.
223 floatingPointBuffersEnabled = true;
224 }
225 if (glVersion >= 420) {
226 shadingLanguage420pack = true;
227 }
228 if (glVersion >= 430) {
229 shaderStorageBufferEnabled = true;
230 explicitUniformLocation = true;
231 glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE,
232 &maxShaderStorageBlockSize);
233 }
234 if (glVersion >= 440) {
235 bufferStorageEnabled = true;
236 }
237 if (glVersion >= 450) {
238 multiDrawIndirectEnabled = true;
239 }
240 if (glVersion >= 460) {
241 shaderDrawParametersEnabled = true;
242 }
243
244 // initialize by individual extension.
245 if (GARCH_GLAPI_HAS(ARB_bindless_texture)) {
246 bindlessTextureEnabled = true;
247 }
248 if (GARCH_GLAPI_HAS(NV_shader_buffer_load)) {
249 bindlessBufferEnabled = true;
250 }
251 if (GARCH_GLAPI_HAS(ARB_explicit_uniform_location)) {
252 explicitUniformLocation = true;
253 }
254 if (GARCH_GLAPI_HAS(ARB_shading_language_420pack)) {
255 shadingLanguage420pack = true;
256 }
257 if (GARCH_GLAPI_HAS(ARB_multi_draw_indirect)) {
258 multiDrawIndirectEnabled = true;
259 }
260 #if defined(GL_VERSION_4_5)
261 if (GARCH_GLAPI_HAS(VERSION_4_5) ||
262 GARCH_GLAPI_HAS(ARB_direct_state_access)) {
263 directStateAccessEnabled = true;
264 }
265 if (GARCH_GLAPI_HAS(ARB_shader_draw_parameters)) {
266 shaderDrawParametersEnabled = true;
267 }
268 #endif
269
270 // Environment variable overrides (only downgrading is possible)
271 if (!TfGetEnvSetting(GLF_ENABLE_SHADER_STORAGE_BUFFER)) {
272 shaderStorageBufferEnabled = false;
273 }
274 if (!TfGetEnvSetting(GLF_ENABLE_BINDLESS_TEXTURE)) {
275 bindlessTextureEnabled = false;
276 }
277 if (!TfGetEnvSetting(GLF_ENABLE_BINDLESS_BUFFER)) {
278 bindlessBufferEnabled = false;
279 }
280 if (!TfGetEnvSetting(GLF_ENABLE_MULTI_DRAW_INDIRECT)) {
281 multiDrawIndirectEnabled = false;
282 }
283 if (!TfGetEnvSetting(GLF_ENABLE_DIRECT_STATE_ACCESS)) {
284 directStateAccessEnabled = false;
285 }
286 if (!TfGetEnvSetting(GLF_ENABLE_SHADER_DRAW_PARAMETERS)) {
287 shaderDrawParametersEnabled = false;
288 }
289
290 // For debugging and unit testing
291 if (TfGetEnvSetting(GLF_GLSL_VERSION) > 0) {
292 // GLSL version override
293 glslVersion = std::min(glslVersion, TfGetEnvSetting(GLF_GLSL_VERSION));
294
295 // downgrade to the overridden GLSL version
296 floatingPointBuffersEnabled &= (glslVersion >= 400);
297 shadingLanguage420pack &= (glslVersion >= 420);
298 explicitUniformLocation &= (glslVersion >= 430);
299 bindlessTextureEnabled &= (glslVersion >= 430);
300 bindlessBufferEnabled &= (glslVersion >= 430);
301 shaderStorageBufferEnabled &= (glslVersion >= 430);
302 shaderDrawParametersEnabled &= (glslVersion >= 450);
303 }
304
305 // For driver issues workaround
306 if (!TfGetEnvSetting(GLF_ENABLE_COPY_BUFFER)) {
307 copyBufferEnabled = false;
308 }
309
310 if (TfDebug::IsEnabled(GLF_DEBUG_CONTEXT_CAPS)) {
311 std::cout
312 << "GlfContextCaps: \n"
313 << " GL_VENDOR = "
314 << glVendorStr << "\n"
315 << " GL_RENDERER = "
316 << glRendererStr << "\n"
317 << " GL_VERSION = "
318 << glVersionStr << "\n"
319 << " GL version = "
320 << glVersion << "\n"
321 << " GLSL version = "
322 << glslVersion << "\n"
323
324 << " GL_MAX_UNIFORM_BLOCK_SIZE = "
325 << maxUniformBlockSize << "\n"
326 << " GL_MAX_SHADER_STORAGE_BLOCK_SIZE = "
327 << maxShaderStorageBlockSize << "\n"
328 << " GL_MAX_TEXTURE_BUFFER_SIZE = "
329 << maxTextureBufferSize << "\n"
330 << " GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = "
331 << uniformBufferOffsetAlignment << "\n"
332 // order alphabetically
333 << " ARB_bindless_texture = "
334 << bindlessTextureEnabled << "\n"
335 << " ARB_direct_state_access = "
336 << directStateAccessEnabled << "\n"
337 << " ARB_explicit_uniform_location = "
338 << explicitUniformLocation << "\n"
339 << " ARB_multi_draw_indirect = "
340 << multiDrawIndirectEnabled << "\n"
341 << " ARB_shader_draw_parameters = "
342 << shaderDrawParametersEnabled << "\n"
343 << " ARB_shader_storage_buffer_object = "
344 << shaderStorageBufferEnabled << "\n"
345 << " ARB_shading_language_420pack = "
346 << shadingLanguage420pack << "\n"
347 << " NV_shader_buffer_load = "
348 << bindlessBufferEnabled << "\n"
349
350 ;
351
352 if (!copyBufferEnabled) {
353 std::cout << " CopyBuffer : disabled\n";
354 }
355 }
356 }
357
358
359 PXR_NAMESPACE_CLOSE_SCOPE
360
361