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