• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/opengl/BackendGL.h"
16 
17 #include "common/GPUInfo.h"
18 #include "common/Log.h"
19 #include "dawn_native/Instance.h"
20 #include "dawn_native/OpenGLBackend.h"
21 #include "dawn_native/opengl/DeviceGL.h"
22 
23 #include <cstring>
24 
25 namespace dawn_native { namespace opengl {
26 
27     namespace {
28 
29         struct Vendor {
30             const char* vendorName;
31             uint32_t vendorId;
32         };
33 
34         const Vendor kVendors[] = {{"ATI", gpu_info::kVendorID_AMD},
35                                    {"ARM", gpu_info::kVendorID_ARM},
36                                    {"Imagination", gpu_info::kVendorID_ImgTec},
37                                    {"Intel", gpu_info::kVendorID_Intel},
38                                    {"NVIDIA", gpu_info::kVendorID_Nvidia},
39                                    {"Qualcomm", gpu_info::kVendorID_Qualcomm}};
40 
GetVendorIdFromVendors(const char * vendor)41         uint32_t GetVendorIdFromVendors(const char* vendor) {
42             uint32_t vendorId = 0;
43             for (const auto& it : kVendors) {
44                 // Matching vendor name with vendor string
45                 if (strstr(vendor, it.vendorName) != nullptr) {
46                     vendorId = it.vendorId;
47                     break;
48                 }
49             }
50             return vendorId;
51         }
52 
OnGLDebugMessage(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)53         void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
54                                                GLenum type,
55                                                GLuint id,
56                                                GLenum severity,
57                                                GLsizei length,
58                                                const GLchar* message,
59                                                const void* userParam) {
60             const char* sourceText;
61             switch (source) {
62                 case GL_DEBUG_SOURCE_API:
63                     sourceText = "OpenGL";
64                     break;
65                 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
66                     sourceText = "Window System";
67                     break;
68                 case GL_DEBUG_SOURCE_SHADER_COMPILER:
69                     sourceText = "Shader Compiler";
70                     break;
71                 case GL_DEBUG_SOURCE_THIRD_PARTY:
72                     sourceText = "Third Party";
73                     break;
74                 case GL_DEBUG_SOURCE_APPLICATION:
75                     sourceText = "Application";
76                     break;
77                 case GL_DEBUG_SOURCE_OTHER:
78                     sourceText = "Other";
79                     break;
80                 default:
81                     sourceText = "UNKNOWN";
82                     break;
83             }
84 
85             const char* severityText;
86             switch (severity) {
87                 case GL_DEBUG_SEVERITY_HIGH:
88                     severityText = "High";
89                     break;
90                 case GL_DEBUG_SEVERITY_MEDIUM:
91                     severityText = "Medium";
92                     break;
93                 case GL_DEBUG_SEVERITY_LOW:
94                     severityText = "Low";
95                     break;
96                 case GL_DEBUG_SEVERITY_NOTIFICATION:
97                     severityText = "Notification";
98                     break;
99                 default:
100                     severityText = "UNKNOWN";
101                     break;
102             }
103 
104             if (type == GL_DEBUG_TYPE_ERROR) {
105                 dawn::WarningLog() << "OpenGL error:"
106                                    << "\n    Source: " << sourceText      //
107                                    << "\n    ID: " << id                  //
108                                    << "\n    Severity: " << severityText  //
109                                    << "\n    Message: " << message;
110 
111                 // Abort on an error when in Debug mode.
112                 UNREACHABLE();
113             }
114         }
115 
116     }  // anonymous namespace
117 
118     // The OpenGL backend's Adapter.
119 
120     class Adapter : public AdapterBase {
121       public:
Adapter(InstanceBase * instance,wgpu::BackendType backendType)122         Adapter(InstanceBase* instance, wgpu::BackendType backendType)
123             : AdapterBase(instance, backendType) {
124         }
125 
InitializeGLFunctions(void * (* getProc)(const char *))126         MaybeError InitializeGLFunctions(void* (*getProc)(const char*)) {
127             // Use getProc to populate the dispatch table
128             return mFunctions.Initialize(getProc);
129         }
130 
131         ~Adapter() override = default;
132 
133         // AdapterBase Implementation
SupportsExternalImages() const134         bool SupportsExternalImages() const override {
135             // Via dawn_native::opengl::WrapExternalEGLImage
136             return GetBackendType() == wgpu::BackendType::OpenGLES;
137         }
138 
139       private:
InitializeImpl()140         MaybeError InitializeImpl() override {
141             if (mFunctions.GetVersion().IsES()) {
142                 ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES);
143             } else {
144                 ASSERT(GetBackendType() == wgpu::BackendType::OpenGL);
145             }
146 
147             // Use the debug output functionality to get notified about GL errors
148             // TODO(cwallez@chromium.org): add support for the KHR_debug and ARB_debug_output
149             // extensions
150             bool hasDebugOutput = mFunctions.IsAtLeastGL(4, 3) || mFunctions.IsAtLeastGLES(3, 2);
151 
152             if (GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
153                 mFunctions.Enable(GL_DEBUG_OUTPUT);
154                 mFunctions.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
155 
156                 // Any GL error; dangerous undefined behavior; any shader compiler and linker errors
157                 mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH,
158                                                0, nullptr, GL_TRUE);
159 
160                 // Severe performance warnings; GLSL or other shader compiler and linker warnings;
161                 // use of currently deprecated behavior
162                 mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM,
163                                                0, nullptr, GL_TRUE);
164 
165                 // Performance warnings from redundant state changes; trivial undefined behavior
166                 // This is disabled because we do an incredible amount of redundant state changes.
167                 mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
168                                                nullptr, GL_FALSE);
169 
170                 // Any message which is not an error or performance concern
171                 mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
172                                                GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr,
173                                                GL_FALSE);
174                 mFunctions.DebugMessageCallback(&OnGLDebugMessage, nullptr);
175             }
176 
177             // Set state that never changes between devices.
178             mFunctions.Enable(GL_DEPTH_TEST);
179             mFunctions.Enable(GL_SCISSOR_TEST);
180             mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
181             if (mFunctions.GetVersion().IsDesktop()) {
182                 // These are not necessary on GLES. The functionality is enabled by default, and
183                 // works by specifying sample counts and SRGB textures, respectively.
184                 mFunctions.Enable(GL_MULTISAMPLE);
185                 mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
186             }
187             mFunctions.Enable(GL_SAMPLE_MASK);
188 
189             mPCIInfo.name = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
190 
191             // Workaroud to find vendor id from vendor name
192             const char* vendor = reinterpret_cast<const char*>(mFunctions.GetString(GL_VENDOR));
193             mPCIInfo.vendorId = GetVendorIdFromVendors(vendor);
194 
195             mDriverDescription = std::string("OpenGL version ") +
196                                  reinterpret_cast<const char*>(mFunctions.GetString(GL_VERSION));
197 
198             if (mPCIInfo.name.find("SwiftShader") != std::string::npos) {
199                 mAdapterType = wgpu::AdapterType::CPU;
200             }
201 
202             return {};
203         }
204 
InitializeSupportedFeaturesImpl()205         MaybeError InitializeSupportedFeaturesImpl() override {
206             // TextureCompressionBC
207             {
208                 // BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features.
209                 bool supportsS3TC =
210                     mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc") ||
211                     (mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_dxt1") &&
212                      mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt3") &&
213                      mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt5"));
214 
215                 // COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT and
216                 // COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT requires both GL_EXT_texture_sRGB and
217                 // GL_EXT_texture_compression_s3tc on desktop OpenGL drivers.
218                 // (https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB.txt)
219                 bool supportsTextureSRGB = mFunctions.IsGLExtensionSupported("GL_EXT_texture_sRGB");
220 
221                 // GL_EXT_texture_compression_s3tc_srgb is an extension in OpenGL ES.
222                 // NVidia GLES drivers don't support this extension, but they do support
223                 // GL_NV_sRGB_formats. (Note that GL_EXT_texture_sRGB does not exist on ES.
224                 // GL_EXT_sRGB does (core in ES 3.0), but it does not automatically provide S3TC
225                 // SRGB support even if S3TC is supported; see
226                 // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_sRGB.txt.)
227                 bool supportsS3TCSRGB =
228                     mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc_srgb") ||
229                     mFunctions.IsGLExtensionSupported("GL_NV_sRGB_formats");
230 
231                 // BC4 and BC5
232                 bool supportsRGTC =
233                     mFunctions.IsAtLeastGL(3, 0) ||
234                     mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_rgtc") ||
235                     mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_rgtc");
236 
237                 // BC6 and BC7
238                 bool supportsBPTC =
239                     mFunctions.IsAtLeastGL(4, 2) ||
240                     mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_bptc") ||
241                     mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_bptc");
242 
243                 if (supportsS3TC && (supportsTextureSRGB || supportsS3TCSRGB) && supportsRGTC &&
244                     supportsBPTC) {
245                     mSupportedFeatures.EnableFeature(dawn_native::Feature::TextureCompressionBC);
246                 }
247             }
248 
249             return {};
250         }
251 
InitializeSupportedLimitsImpl(CombinedLimits * limits)252         MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override {
253             GetDefaultLimits(&limits->v1);
254             return {};
255         }
256 
CreateDeviceImpl(const DawnDeviceDescriptor * descriptor)257         ResultOrError<DeviceBase*> CreateDeviceImpl(
258             const DawnDeviceDescriptor* descriptor) override {
259             // There is no limit on the number of devices created from this adapter because they can
260             // all share the same backing OpenGL context.
261             return Device::Create(this, descriptor, mFunctions);
262         }
263 
264         OpenGLFunctions mFunctions;
265     };
266 
267     // Implementation of the OpenGL backend's BackendConnection
268 
Backend(InstanceBase * instance,wgpu::BackendType backendType)269     Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
270         : BackendConnection(instance, backendType) {
271     }
272 
DiscoverDefaultAdapters()273     std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
274         // The OpenGL backend needs at least "getProcAddress" to discover an adapter.
275         return {};
276     }
277 
DiscoverAdapters(const AdapterDiscoveryOptionsBase * optionsBase)278     ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
279         const AdapterDiscoveryOptionsBase* optionsBase) {
280         // TODO(cwallez@chromium.org): For now only create a single OpenGL adapter because don't
281         // know how to handle MakeCurrent.
282         DAWN_INVALID_IF(mCreatedAdapter, "The OpenGL backend can only create a single adapter.");
283 
284         ASSERT(static_cast<wgpu::BackendType>(optionsBase->backendType) == GetType());
285         const AdapterDiscoveryOptions* options =
286             static_cast<const AdapterDiscoveryOptions*>(optionsBase);
287 
288         DAWN_INVALID_IF(options->getProc == nullptr,
289                         "AdapterDiscoveryOptions::getProc must be set");
290 
291         std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
292             GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType));
293         DAWN_TRY(adapter->InitializeGLFunctions(options->getProc));
294         DAWN_TRY(adapter->Initialize());
295 
296         mCreatedAdapter = true;
297         std::vector<std::unique_ptr<AdapterBase>> adapters;
298         adapters.push_back(std::unique_ptr<AdapterBase>(adapter.release()));
299         return std::move(adapters);
300     }
301 
Connect(InstanceBase * instance,wgpu::BackendType backendType)302     BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType) {
303         return new Backend(instance, backendType);
304     }
305 
306 }}  // namespace dawn_native::opengl
307