blob: bd30d03c3984f77e0ba6e1df6159dec221302684 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/dawn_context_provider.h"
#include <memory>
#include <vector>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/threading/platform_thread.h"
#include "base/trace_event/trace_arguments.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "gpu/command_buffer/service/dawn_instance.h"
#include "gpu/command_buffer/service/dawn_platform.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"
#include "third_party/skia/include/gpu/graphite/Context.h"
#include "third_party/skia/include/gpu/graphite/dawn/DawnBackendContext.h"
#include "third_party/skia/include/gpu/graphite/dawn/DawnUtils.h"
#if BUILDFLAG(IS_WIN)
#include "third_party/dawn/include/dawn/native/D3D11Backend.h"
#include "ui/gl/gl_angle_util_win.h"
#endif
namespace gpu {
namespace {
void LogInfo(WGPULoggingType type, char const* message, void* userdata) {
VLOG(1) << message;
}
void LogError(WGPUErrorType type, char const* message, void* userdata) {
LOG(ERROR) << message;
}
void LogDeviceLost(WGPUDeviceLostReason reason,
char const* message,
void* userdata) {
if (reason == WGPUDeviceLostReason::WGPUDeviceLostReason_Destroyed)
return;
LOG(FATAL) << message;
}
wgpu::BackendType GetDefaultBackendType() {
#if BUILDFLAG(IS_WIN)
return base::FeatureList::IsEnabled(features::kSkiaGraphiteDawnUseD3D12)
? wgpu::BackendType::D3D12
: wgpu::BackendType::D3D11;
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return wgpu::BackendType::Vulkan;
#elif BUILDFLAG(IS_APPLE)
return wgpu::BackendType::Metal;
#else
NOTREACHED();
return wgpu::BackendType::Null;
#endif
}
class Platform : public webgpu::DawnPlatform {
public:
using webgpu::DawnPlatform::DawnPlatform;
~Platform() override = default;
const unsigned char* GetTraceCategoryEnabledFlag(
dawn::platform::TraceCategory category) override {
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("gpu.graphite.dawn"));
}
};
#if BUILDFLAG(IS_WIN)
bool GetANGLED3D11DeviceLUID(LUID* luid) {
// On Windows, query the LUID of ANGLE's adapter.
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
gl::QueryD3D11DeviceObjectFromANGLE();
if (!d3d11_device) {
LOG(ERROR) << "Failed to query ID3D11Device from ANGLE.";
return false;
}
Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
if (!SUCCEEDED(d3d11_device.As(&dxgi_device))) {
LOG(ERROR) << "Failed to get IDXGIDevice from ANGLE.";
return false;
}
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
if (!SUCCEEDED(dxgi_device->GetAdapter(&dxgi_adapter))) {
LOG(ERROR) << "Failed to get IDXGIAdapter from ANGLE.";
return false;
}
DXGI_ADAPTER_DESC adapter_desc;
if (!SUCCEEDED(dxgi_adapter->GetDesc(&adapter_desc))) {
LOG(ERROR) << "Failed to get DXGI_ADAPTER_DESC from ANGLE.";
return false;
}
*luid = adapter_desc.AdapterLuid;
return true;
}
#endif // BUILDFLAG(IS_WIN)
} // namespace
std::unique_ptr<DawnContextProvider> DawnContextProvider::Create(
webgpu::DawnCachingInterfaceFactory* caching_interface_factory,
CacheBlobCallback callback) {
auto context_provider =
base::WrapUnique(new DawnContextProvider(caching_interface_factory));
// TODO(rivr): This may return a GPU that is not the active one. Currently
// the only known way to avoid this is platform-specific; e.g. on Mac, create
// a Dawn device, get the actual Metal device from it, and compare against
// MTLCreateSystemDefaultDevice().
if (!context_provider->Initialize(std::move(callback))) {
context_provider.reset();
}
return context_provider;
}
DawnContextProvider::DawnContextProvider(
webgpu::DawnCachingInterfaceFactory* caching_interface_factory)
: caching_interface_factory_(caching_interface_factory) {}
DawnContextProvider::~DawnContextProvider() = default;
bool DawnContextProvider::Initialize(CacheBlobCallback callback) {
std::unique_ptr<webgpu::DawnCachingInterface> caching_interface;
if (caching_interface_factory_) {
caching_interface = caching_interface_factory_->CreateInstance(
kGraphiteDawnGpuDiskCacheHandle, std::move(callback));
}
platform_ = std::make_unique<Platform>(std::move(caching_interface));
GpuPreferences preferences;
#if DCHECK_IS_ON()
preferences.enable_dawn_backend_validation =
DawnBackendValidationLevel::kFull;
#else
preferences.enable_dawn_backend_validation =
DawnBackendValidationLevel::kDisabled;
#endif
instance_ = webgpu::DawnInstance::Create(platform_.get(), preferences);
// If a new toggle is added here, ForceDawnTogglesForSkia() which collects
// info for about:gpu should be updated as well.
wgpu::DawnTogglesDescriptor toggles_desc;
std::vector<const char*> enabled_toggles;
#if DCHECK_IS_ON()
enabled_toggles.push_back("use_user_defined_labels_in_backend");
#else
// Disable validation in non-DCHECK builds.
// TODO(crbug.com/1456492): check if below toggles are necessary.
enabled_toggles.push_back("disable_robustness");
enabled_toggles.push_back("skip_validation");
#endif
toggles_desc.enabledToggles = enabled_toggles.data();
toggles_desc.enabledTogglesCount = enabled_toggles.size();
wgpu::DeviceDescriptor descriptor;
descriptor.nextInChain = &toggles_desc;
// TODO(crbug.com/1456492): verify the required features.
std::vector<wgpu::FeatureName> features = {
wgpu::FeatureName::DawnInternalUsages,
wgpu::FeatureName::DawnMultiPlanarFormats,
wgpu::FeatureName::ImplicitDeviceSynchronization,
wgpu::FeatureName::SurfaceCapabilities,
};
wgpu::RequestAdapterOptions adapter_options;
adapter_options.backendType = GetDefaultBackendType();
adapter_options.powerPreference = wgpu::PowerPreference::LowPower;
#if BUILDFLAG(IS_WIN)
if (adapter_options.backendType == wgpu::BackendType::D3D11) {
features.push_back(wgpu::FeatureName::D3D11MultithreadProtected);
}
// Request the GPU that ANGLE is using if possible.
dawn::native::d3d::RequestAdapterOptionsLUID adapter_options_luid;
if (GetANGLED3D11DeviceLUID(&adapter_options_luid.adapterLUID)) {
adapter_options.nextInChain = &adapter_options_luid;
}
#endif // BUILDFLAG(IS_WIN)
std::vector<dawn::native::Adapter> adapters =
instance_->EnumerateAdapters(&adapter_options);
if (adapters.empty()) {
LOG(ERROR) << "No adapters found.";
return false;
}
wgpu::Adapter adapter(adapters[0].Get());
if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {
features.push_back(wgpu::FeatureName::TransientAttachments);
}
descriptor.requiredFeatures = features.data();
descriptor.requiredFeaturesCount = std::size(features);
wgpu::Device device = adapter.CreateDevice(&descriptor);
if (!device) {
LOG(ERROR) << "Failed to create device.";
return false;
}
device.SetUncapturedErrorCallback(&LogError, nullptr);
device.SetDeviceLostCallback(&LogDeviceLost, nullptr);
device.SetLoggingCallback(&LogInfo, nullptr);
device_ = std::move(device);
return true;
}
bool DawnContextProvider::InitializeGraphiteContext(
const skgpu::graphite::ContextOptions& options) {
CHECK(!graphite_context_);
if (device_) {
skgpu::graphite::DawnBackendContext backend_context;
backend_context.fDevice = device_;
backend_context.fQueue = device_.GetQueue();
graphite_context_ =
skgpu::graphite::ContextFactory::MakeDawn(backend_context, options);
}
return !!graphite_context_;
}
wgpu::Instance DawnContextProvider::GetInstance() const {
return instance_->Get();
}
#if BUILDFLAG(IS_WIN)
Microsoft::WRL::ComPtr<ID3D11Device> DawnContextProvider::GetD3D11Device()
const {
if (GetDefaultBackendType() == wgpu::BackendType::D3D11) {
return dawn::native::d3d11::GetD3D11Device(device_.Get());
}
return nullptr;
}
#endif
} // namespace gpu