Austin Eng 9978b2f742 Add Adapter::SupportsExternalImages
This commit adds a getter so that Chromium can check whether an
Adapter would support external images. External images are
necessary to implement the WebGPU swapchain and interop with the
rest of the web platform. We should not expose adapters that
cannot interop with the canvas and other web platform primitives
until WebGPU gains options to request more "limited" adapters.

Bug: dawn:1056
Change-Id: Iff83ac26b0e92dccdd4e29c0d854d9276a4a37bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/61580
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Brian Ho <hob@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
2021-08-11 14:27:55 +00:00

301 lines
13 KiB
C++

// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/opengl/BackendGL.h"
#include "common/GPUInfo.h"
#include "common/Log.h"
#include "dawn_native/Instance.h"
#include "dawn_native/OpenGLBackend.h"
#include "dawn_native/opengl/DeviceGL.h"
#include <cstring>
namespace dawn_native { namespace opengl {
namespace {
struct Vendor {
const char* vendorName;
uint32_t vendorId;
};
const Vendor kVendors[] = {{"ATI", gpu_info::kVendorID_AMD},
{"ARM", gpu_info::kVendorID_ARM},
{"Imagination", gpu_info::kVendorID_ImgTec},
{"Intel", gpu_info::kVendorID_Intel},
{"NVIDIA", gpu_info::kVendorID_Nvidia},
{"Qualcomm", gpu_info::kVendorID_Qualcomm}};
uint32_t GetVendorIdFromVendors(const char* vendor) {
uint32_t vendorId = 0;
for (const auto& it : kVendors) {
// Matching vendor name with vendor string
if (strstr(vendor, it.vendorName) != nullptr) {
vendorId = it.vendorId;
break;
}
}
return vendorId;
}
void KHRONOS_APIENTRY OnGLDebugMessage(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
const char* sourceText;
switch (source) {
case GL_DEBUG_SOURCE_API:
sourceText = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
sourceText = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER:
sourceText = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY:
sourceText = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION:
sourceText = "Application";
break;
case GL_DEBUG_SOURCE_OTHER:
sourceText = "Other";
break;
default:
sourceText = "UNKNOWN";
break;
}
const char* severityText;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
severityText = "High";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
severityText = "Medium";
break;
case GL_DEBUG_SEVERITY_LOW:
severityText = "Low";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severityText = "Notification";
break;
default:
severityText = "UNKNOWN";
break;
}
if (type == GL_DEBUG_TYPE_ERROR) {
dawn::WarningLog() << "OpenGL error:"
<< "\n Source: " << sourceText //
<< "\n ID: " << id //
<< "\n Severity: " << severityText //
<< "\n Message: " << message;
// Abort on an error when in Debug mode.
UNREACHABLE();
}
}
} // anonymous namespace
// The OpenGL backend's Adapter.
class Adapter : public AdapterBase {
public:
Adapter(InstanceBase* instance, wgpu::BackendType backendType)
: AdapterBase(instance, backendType) {
}
MaybeError Initialize(const AdapterDiscoveryOptions* options) {
// Use getProc to populate the dispatch table
DAWN_TRY(mFunctions.Initialize(options->getProc));
if (mFunctions.GetVersion().IsES()) {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES);
} else {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGL);
}
// Use the debug output functionality to get notified about GL errors
// TODO(cwallez@chromium.org): add support for the KHR_debug and ARB_debug_output
// extensions
bool hasDebugOutput = mFunctions.IsAtLeastGL(4, 3) || mFunctions.IsAtLeastGLES(3, 2);
if (GetInstance()->IsBackendValidationEnabled() && hasDebugOutput) {
mFunctions.Enable(GL_DEBUG_OUTPUT);
mFunctions.Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
// Any GL error; dangerous undefined behavior; any shader compiler and linker errors
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH,
0, nullptr, GL_TRUE);
// Severe performance warnings; GLSL or other shader compiler and linker warnings;
// use of currently deprecated behavior
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM,
0, nullptr, GL_TRUE);
// Performance warnings from redundant state changes; trivial undefined behavior
// This is disabled because we do an incredible amount of redundant state changes.
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
nullptr, GL_FALSE);
// Any message which is not an error or performance concern
mFunctions.DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr,
GL_FALSE);
mFunctions.DebugMessageCallback(&OnGLDebugMessage, nullptr);
}
// Set state that never changes between devices.
mFunctions.Enable(GL_DEPTH_TEST);
mFunctions.Enable(GL_SCISSOR_TEST);
mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
if (mFunctions.GetVersion().IsDesktop()) {
// These are not necessary on GLES. The functionality is enabled by default, and
// works by specifying sample counts and SRGB textures, respectively.
mFunctions.Enable(GL_MULTISAMPLE);
mFunctions.Enable(GL_FRAMEBUFFER_SRGB);
}
mFunctions.Enable(GL_SAMPLE_MASK);
mPCIInfo.name = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
// Workaroud to find vendor id from vendor name
const char* vendor = reinterpret_cast<const char*>(mFunctions.GetString(GL_VENDOR));
mPCIInfo.vendorId = GetVendorIdFromVendors(vendor);
mDriverDescription = std::string("OpenGL version ") +
reinterpret_cast<const char*>(mFunctions.GetString(GL_VERSION));
if (mPCIInfo.name.find("SwiftShader") != std::string::npos) {
mAdapterType = wgpu::AdapterType::CPU;
}
InitializeSupportedExtensions();
return {};
}
~Adapter() override = default;
// AdapterBase Implementation
bool SupportsExternalImages() const override {
// Via dawn_native::opengl::WrapExternalEGLImage
return GetBackendType() == wgpu::BackendType::OpenGLES;
}
private:
OpenGLFunctions mFunctions;
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
// There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context.
return Device::Create(this, descriptor, mFunctions);
}
void InitializeSupportedExtensions() {
// TextureCompressionBC
{
// BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features.
bool supportsS3TC =
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc") ||
(mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_dxt1") &&
mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt3") &&
mFunctions.IsGLExtensionSupported("GL_ANGLE_texture_compression_dxt5"));
// COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT and
// COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT requires both GL_EXT_texture_sRGB and
// GL_EXT_texture_compression_s3tc on desktop OpenGL drivers.
// (https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB.txt)
bool supportsTextureSRGB = mFunctions.IsGLExtensionSupported("GL_EXT_texture_sRGB");
// GL_EXT_texture_compression_s3tc_srgb is an extension in OpenGL ES.
// NVidia GLES drivers don't support this extension, but they do support
// GL_NV_sRGB_formats. (Note that GL_EXT_texture_sRGB does not exist on ES.
// GL_EXT_sRGB does (core in ES 3.0), but it does not automatically provide S3TC
// SRGB support even if S3TC is supported; see
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_sRGB.txt.)
bool supportsS3TCSRGB =
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_s3tc_srgb") ||
mFunctions.IsGLExtensionSupported("GL_NV_sRGB_formats");
// BC4 and BC5
bool supportsRGTC =
mFunctions.IsAtLeastGL(3, 0) ||
mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_rgtc") ||
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_rgtc");
// BC6 and BC7
bool supportsBPTC =
mFunctions.IsAtLeastGL(4, 2) ||
mFunctions.IsGLExtensionSupported("GL_ARB_texture_compression_bptc") ||
mFunctions.IsGLExtensionSupported("GL_EXT_texture_compression_bptc");
if (supportsS3TC && (supportsTextureSRGB || supportsS3TCSRGB) && supportsRGTC &&
supportsBPTC) {
mSupportedExtensions.EnableExtension(
dawn_native::Extension::TextureCompressionBC);
}
}
}
};
// Implementation of the OpenGL backend's BackendConnection
Backend::Backend(InstanceBase* instance, wgpu::BackendType backendType)
: BackendConnection(instance, backendType) {
}
std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
// The OpenGL backend needs at least "getProcAddress" to discover an adapter.
return {};
}
ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
const AdapterDiscoveryOptionsBase* optionsBase) {
// TODO(cwallez@chromium.org): For now only create a single OpenGL adapter because don't
// know how to handle MakeCurrent.
if (mCreatedAdapter) {
return DAWN_VALIDATION_ERROR("The OpenGL backend can only create a single adapter");
}
ASSERT(static_cast<wgpu::BackendType>(optionsBase->backendType) == GetType());
const AdapterDiscoveryOptions* options =
static_cast<const AdapterDiscoveryOptions*>(optionsBase);
if (options->getProc == nullptr) {
return DAWN_VALIDATION_ERROR("AdapterDiscoveryOptions::getProc must be set");
}
std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType));
DAWN_TRY(adapter->Initialize(options));
mCreatedAdapter = true;
std::vector<std::unique_ptr<AdapterBase>> adapters;
adapters.push_back(std::unique_ptr<AdapterBase>(adapter.release()));
return std::move(adapters);
}
BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType) {
return new Backend(instance, backendType);
}
}} // namespace dawn_native::opengl