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