| // 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/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/dcheck_is_on.h" |
| #include "base/debug/crash_logging.h" |
| #include "base/debug/dump_without_crashing.h" |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/synchronization/lock.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/thread_annotations.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/trace_event/memory_dump_manager.h" |
| #include "base/trace_event/memory_dump_provider.h" |
| #include "base/trace_event/process_memory_dump.h" |
| #include "base/trace_event/trace_arguments.h" |
| #include "base/trace_event/trace_event.h" |
| #include "build/build_config.h" |
| #include "components/crash/core/common/crash_key.h" |
| #include "gpu/command_buffer/service/dawn_instance.h" |
| #include "gpu/command_buffer/service/dawn_platform.h" |
| #include "gpu/command_buffer/service/skia_utils.h" |
| #include "gpu/config/gpu_driver_bug_workaround_type.h" |
| #include "gpu/config/gpu_finch_features.h" |
| #include "gpu/config/gpu_preferences.h" |
| #include "gpu/config/gpu_switches.h" |
| #include "gpu/config/gpu_util.h" |
| #include "third_party/dawn/include/dawn/webgpu_cpp_print.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" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_switches.h" |
| |
| #if BUILDFLAG(IS_WIN) |
| #include <d3d11_4.h> |
| |
| #include "third_party/dawn/include/dawn/native/D3D11Backend.h" |
| #include "ui/gl/direct_composition_support.h" |
| #include "ui/gl/gl_angle_util_win.h" |
| #endif |
| |
| |
| namespace gpu { |
| namespace { |
| |
| // Used as a flag to test dawn initialization failure. |
| BASE_FEATURE(kForceDawnInitializeFailure, base::FEATURE_DISABLED_BY_DEFAULT); |
| |
| // Sets crash key in thread safe manner. This should be used for any crash keys |
| // set from dawn error or device lost callbacks that may run on multiple |
| // threads. |
| template <uint32_t KeySize> |
| void SetCrashKeyThreadSafe(crash_reporter::CrashKeyString<KeySize>& crash_key, |
| std::string_view message) { |
| static base::NoDestructor<base::Lock> lock; |
| base::AutoLock auto_lock(*lock.get()); |
| crash_key.Set(message); |
| } |
| |
| void SetDawnErrorCrashKey(std::string_view message) { |
| static crash_reporter::CrashKeyString<1024> error_key("dawn-error"); |
| SetCrashKeyThreadSafe(error_key, message); |
| } |
| |
| // Different versions of DumpWithoutCrashing for different reasons. |
| // Deliberately prevent inlining so that the crash report's call stack can |
| // distinguish between them. |
| #if BUILDFLAG(IS_WIN) |
| NOINLINE NOOPT void DumpWithoutCrashingOnDXGIError(wgpu::ErrorType error_type, |
| std::string_view message) { |
| LOG(ERROR) << "DXGI Error: " << message; |
| |
| if (features::kSkiaGraphiteDawnDumpWCOnD3DError.Get()) { |
| base::debug::DumpWithoutCrashing(); |
| } |
| } |
| |
| NOINLINE NOOPT void DumpWithoutCrashingOnD3D11DebugLayerError( |
| wgpu::ErrorType error_type, |
| std::string_view message) { |
| LOG(ERROR) << message; |
| if (features::kSkiaGraphiteDawnDumpWCOnD3DError.Get()) { |
| base::debug::DumpWithoutCrashing(); |
| } |
| } |
| #endif |
| |
| NOINLINE NOOPT void DumpWithoutCrashingOnGenericError( |
| wgpu::ErrorType error_type, |
| std::string_view message) { |
| LOG(ERROR) << message; |
| base::debug::DumpWithoutCrashing(); |
| } |
| |
| void DumpWithoutCrashingOnError(wgpu::ErrorType error_type, |
| std::string_view message) { |
| SetDawnErrorCrashKey(message); |
| #if BUILDFLAG(IS_WIN) |
| if (message.find("DXGI_ERROR") != std::string_view::npos) { |
| DumpWithoutCrashingOnDXGIError(error_type, message); |
| } else if (message.find("The D3D11 debug layer") != std::string_view::npos) { |
| DumpWithoutCrashingOnD3D11DebugLayerError(error_type, message); |
| } else |
| #endif |
| { |
| DumpWithoutCrashingOnGenericError(error_type, message); |
| } |
| } |
| |
| // NOTE: Update the toggles in GpuInfoCollector whenever a toggle is disabled |
| // here. |
| std::vector<const char*> GetDisabledToggles( |
| const GpuPreferences& gpu_preferences) { |
| std::vector<const char*> disabled_toggles; |
| for (const auto& toggle : gpu_preferences.disabled_dawn_features_list) { |
| disabled_toggles.push_back(toggle.c_str()); |
| } |
| return disabled_toggles; |
| } |
| |
| // NOTE: Update the toggles in GpuInfoCollector whenever a toggle is enabled |
| // here. |
| std::vector<const char*> GetEnabledToggles( |
| wgpu::BackendType backend_type, |
| bool force_fallback_adapter, |
| const GpuPreferences& gpu_preferences) { |
| // If a new toggle is added here, ForceDawnTogglesForSkia() which collects |
| // info for about:gpu should be updated as well. |
| std::vector<const char*> enabled_toggles; |
| for (const auto& toggle : gpu_preferences.enabled_dawn_features_list) { |
| enabled_toggles.push_back(toggle.c_str()); |
| } |
| |
| // The following toggles are all device-scoped toggles so it's not necessary |
| // to pass them when creating the Instance above. |
| if (features::kSkiaGraphiteDawnBackendDebugLabels.Get()) { |
| enabled_toggles.push_back("use_user_defined_labels_in_backend"); |
| } |
| |
| if (features::kSkiaGraphiteDawnSkipValidation.Get()) { |
| enabled_toggles.push_back("skip_validation"); |
| } |
| |
| enabled_toggles.push_back("disable_robustness"); |
| enabled_toggles.push_back("disable_lazy_clear_for_mapped_at_creation_buffer"); |
| |
| #if BUILDFLAG(IS_WIN) |
| if (backend_type == wgpu::BackendType::D3D11) { |
| // Use packed D24_UNORM_S8_UINT DXGI format for Depth24PlusStencil8 |
| // format. |
| enabled_toggles.push_back("use_packed_depth24_unorm_stencil8_format"); |
| |
| if (features::kSkiaGraphiteDawnD3D11DelayFlush.Get()) { |
| // Tell Dawn to defer sending commands to GPU until swapchain's Present. |
| // This will batch the commands better. |
| enabled_toggles.push_back("d3d11_delay_flush_to_gpu"); |
| } |
| } |
| |
| if (backend_type == wgpu::BackendType::D3D11 || |
| backend_type == wgpu::BackendType::D3D12) { |
| if (features::kSkiaGraphiteDawnDisableD3DShaderOptimizations.Get()) { |
| enabled_toggles.push_back("d3d_skip_shader_optimizations"); |
| } |
| } |
| #endif |
| |
| if (backend_type == wgpu::BackendType::Vulkan) { |
| #if BUILDFLAG(IS_ANDROID) |
| // Enable this toggle for all Android devices suspecting vulkan image size |
| // mismatch causing SharedTextureMemory creation failures, leading to |
| // promise image creation failures. See https://crbug.com/377935752 for |
| // details. |
| enabled_toggles.push_back( |
| "ignore_imported_ahardwarebuffer_vulkan_image_size"); |
| #endif |
| |
| // Use a single VkPipelineCache inside dawn. |
| enabled_toggles.push_back("vulkan_monolithic_pipeline_cache"); |
| } |
| |
| // Skip expensive swiftshader vkCmdDraw* for tests. |
| // TODO(penghuang): rename kDisableGLDrawingForTests to |
| // kDisableGpuDrawingForTests |
| // TODO(crbug.com/407497928): Enable this toggle over GpuInfoCollector. |
| auto* command_line = base::CommandLine::ForCurrentProcess(); |
| if (backend_type == wgpu::BackendType::Vulkan && force_fallback_adapter && |
| command_line->HasSwitch(switches::kDisableGLDrawingForTests)) { |
| enabled_toggles.push_back("vulkan_skip_draw"); |
| } |
| |
| return enabled_toggles; |
| } |
| |
| std::vector<wgpu::FeatureName> GetRequiredFeatures( |
| wgpu::BackendType backend_type, |
| wgpu::Adapter adapter) { |
| std::vector<wgpu::FeatureName> features = { |
| wgpu::FeatureName::DawnInternalUsages, |
| wgpu::FeatureName::ImplicitDeviceSynchronization, |
| #if BUILDFLAG(IS_ANDROID) |
| wgpu::FeatureName::TextureCompressionETC2, |
| #endif |
| }; |
| |
| if (backend_type == wgpu::BackendType::Vulkan) { |
| #if BUILDFLAG(IS_ANDROID) |
| features.push_back(wgpu::FeatureName::StaticSamplers); |
| features.push_back(wgpu::FeatureName::YCbCrVulkanSamplers); |
| #endif |
| features.push_back(wgpu::FeatureName::DawnDeviceAllocatorControl); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| if (backend_type == wgpu::BackendType::D3D11) { |
| features.push_back(wgpu::FeatureName::D3D11MultithreadProtected); |
| } |
| #endif |
| |
| constexpr wgpu::FeatureName kOptionalFeatures[] = { |
| wgpu::FeatureName::BGRA8UnormStorage, |
| wgpu::FeatureName::BufferMapExtendedUsages, |
| wgpu::FeatureName::DawnMultiPlanarFormats, |
| wgpu::FeatureName::DualSourceBlending, |
| wgpu::FeatureName::FramebufferFetch, |
| wgpu::FeatureName::MultiPlanarFormatExtendedUsages, |
| wgpu::FeatureName::MultiPlanarFormatNv16, |
| wgpu::FeatureName::MultiPlanarFormatNv24, |
| wgpu::FeatureName::MultiPlanarFormatP010, |
| wgpu::FeatureName::MultiPlanarFormatP210, |
| wgpu::FeatureName::MultiPlanarFormatP410, |
| wgpu::FeatureName::MultiPlanarFormatNv12a, |
| wgpu::FeatureName::MultiPlanarRenderTargets, |
| wgpu::FeatureName::Unorm16TextureFormats, |
| |
| // The following features are always supported by the the Metal backend on |
| // the Mac versions on which Chrome runs. |
| wgpu::FeatureName::SharedTextureMemoryIOSurface, |
| wgpu::FeatureName::SharedFenceMTLSharedEvent, |
| |
| // The following features are always supported when running on the Vulkan |
| // backend on Android. |
| wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer, |
| wgpu::FeatureName::SharedFenceSyncFD, |
| |
| // The following features are always supported by the the D3D backends. |
| wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D, |
| wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle, |
| wgpu::FeatureName::SharedFenceDXGISharedHandle, |
| |
| // The following feature is always supported by the the D3D12 backend. |
| wgpu::FeatureName::SharedBufferMemoryD3D12Resource, |
| |
| wgpu::FeatureName::TransientAttachments, |
| |
| wgpu::FeatureName::DawnLoadResolveTexture, |
| wgpu::FeatureName::DawnPartialLoadResolveTexture, |
| wgpu::FeatureName::DawnTexelCopyBufferRowAlignment, |
| wgpu::FeatureName::FlexibleTextureViews, |
| }; |
| |
| for (auto feature : kOptionalFeatures) { |
| if (!adapter.HasFeature(feature)) { |
| continue; |
| } |
| features.push_back(feature); |
| |
| // Enabling MSAARenderToSingleSampled causes performance regression without |
| // TransientAttachments support. |
| if (feature == wgpu::FeatureName::TransientAttachments && |
| adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) { |
| features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled); |
| } |
| } |
| |
| return features; |
| } |
| |
| 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; |
| } |
| |
| bool IsD3D11DebugLayerEnabled( |
| const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device) { |
| Microsoft::WRL::ComPtr<ID3D11Debug> d3d11_debug; |
| return SUCCEEDED(d3d11_device.As(&d3d11_debug)); |
| } |
| |
| const char* HRESULTToString(HRESULT result) { |
| switch (result) { |
| #define ERROR_CASE(E) \ |
| case E: \ |
| return #E; |
| ERROR_CASE(DXGI_ERROR_DEVICE_HUNG) |
| ERROR_CASE(DXGI_ERROR_DEVICE_REMOVED) |
| ERROR_CASE(DXGI_ERROR_DEVICE_RESET) |
| ERROR_CASE(DXGI_ERROR_DRIVER_INTERNAL_ERROR) |
| ERROR_CASE(DXGI_ERROR_INVALID_CALL) |
| ERROR_CASE(S_OK) |
| #undef ERROR_CASE |
| default: |
| return nullptr; |
| } |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| const char* BackendTypeToString(wgpu::BackendType backend_type) { |
| switch (backend_type) { |
| case wgpu::BackendType::D3D11: |
| return "D3D11"; |
| case wgpu::BackendType::D3D12: |
| return "D3D12"; |
| case wgpu::BackendType::Metal: |
| return "Metal"; |
| case wgpu::BackendType::Vulkan: |
| return "Vulkan"; |
| case wgpu::BackendType::OpenGL: |
| return "OpenGL"; |
| case wgpu::BackendType::OpenGLES: |
| return "OpenGLES"; |
| default: |
| CHECK(false); |
| } |
| } |
| |
| } // namespace |
| |
| // static |
| wgpu::BackendType DawnContextProvider::GetDefaultBackendType() { |
| const auto switch_value = |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kSkiaGraphiteBackend); |
| if (switch_value == switches::kSkiaGraphiteBackendDawnD3D11) { |
| return wgpu::BackendType::D3D11; |
| } else if (switch_value == switches::kSkiaGraphiteBackendDawnD3D12) { |
| return wgpu::BackendType::D3D12; |
| } else if (switch_value == switches::kSkiaGraphiteBackendDawnMetal) { |
| return wgpu::BackendType::Metal; |
| } else if (switch_value == switches::kSkiaGraphiteBackendDawnSwiftshader || |
| switch_value == switches::kSkiaGraphiteBackendDawnVulkan) { |
| return wgpu::BackendType::Vulkan; |
| } |
| |
| if (gl::GetANGLEImplementation() == gl::ANGLEImplementation::kSwiftShader) { |
| return wgpu::BackendType::Vulkan; |
| } |
| #if BUILDFLAG(IS_WIN) |
| return base::FeatureList::IsEnabled(features::kSkiaGraphiteDawnUseD3D12) |
| ? wgpu::BackendType::D3D12 |
| : wgpu::BackendType::D3D11; |
| #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
| return wgpu::BackendType::Vulkan; |
| #elif BUILDFLAG(IS_APPLE) |
| return wgpu::BackendType::Metal; |
| #else |
| NOTREACHED(); |
| #endif |
| } |
| |
| // static |
| bool DawnContextProvider::DefaultForceFallbackAdapter() { |
| return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kSkiaGraphiteBackend) == |
| switches::kSkiaGraphiteBackendDawnSwiftshader || |
| gl::GetANGLEImplementation() == gl::ANGLEImplementation::kSwiftShader; |
| } |
| |
| // static |
| bool DawnContextProvider::DefaultValidateAdapterFn(wgpu::BackendType, |
| wgpu::Adapter) { |
| return true; |
| } |
| |
| // Owns the dawn instance/adapter/device so that it's lifetime is not linked to |
| // a specific DawnContextProvider. |
| class DawnSharedContext : public base::RefCountedThreadSafe<DawnSharedContext>, |
| public base::trace_event::MemoryDumpProvider { |
| public: |
| DawnSharedContext(gl::ProgressReporter* progress_reporter, |
| bool thread_safe_graphite_context); |
| |
| bool Initialize(wgpu::BackendType backend_type, |
| bool force_fallback_adapter, |
| const GpuPreferences& gpu_preferences, |
| const GpuDriverBugWorkarounds& workarounds, |
| DawnContextProvider::ValidateAdapterFn validate_adapter_fn); |
| void SetCachingInterface( |
| std::unique_ptr<webgpu::DawnCachingInterface> caching_interface); |
| |
| wgpu::Device GetDevice() const { return device_; } |
| wgpu::BackendType backend_type() const { return backend_type_; } |
| bool is_vulkan_swiftshader_adapter() const { |
| return is_vulkan_swiftshader_adapter_; |
| } |
| wgpu::Adapter GetAdapter() const { return adapter_; } |
| wgpu::Instance GetInstance() const { return instance_->Get(); } |
| |
| webgpu::DawnPlatform* GetDawnPlatform() { return &platform_; } |
| |
| webgpu::DawnCachingInterface* GetCachingInterface() { |
| return caching_interface_.get(); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const { |
| if (backend_type() == wgpu::BackendType::D3D11) { |
| return dawn::native::d3d11::GetD3D11Device(device_.Get()); |
| } |
| return nullptr; |
| } |
| |
| void FlushD3D11CommandsIfDelayed() const { |
| if (backend_type() != wgpu::BackendType::D3D11) { |
| return; |
| } |
| |
| // This function is meant for delayed flush option. |
| if (!features::kSkiaGraphiteDawnD3D11DelayFlush.Get()) { |
| return; |
| } |
| |
| TRACE_EVENT0("gpu", "DawnSharedContext::FlushD3D11Commands"); |
| |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = |
| dawn::native::d3d11::GetD3D11Device(device_.Get()); |
| if (!d3d11_device) { |
| return; |
| } |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext> context; |
| d3d11_device->GetImmediateContext(&context); |
| context->Flush(); |
| } |
| #endif |
| |
| std::optional<error::ContextLostReason> GetResetStatus() const; |
| |
| std::unique_ptr<GraphiteSharedContext> CreateGraphiteSharedContext( |
| const skgpu::graphite::ContextOptions& options, |
| GpuProcessShmCount* use_shader_cache_shm_count, |
| bool is_thread_safe) { |
| if (!device_) { |
| return nullptr; |
| } |
| |
| skgpu::graphite::DawnBackendContext backend_context; |
| backend_context.fInstance = GetInstance(); |
| backend_context.fDevice = device_; |
| backend_context.fQueue = device_.GetQueue(); |
| |
| std::unique_ptr<skgpu::graphite::Context> graphite_context = |
| skgpu::graphite::ContextFactory::MakeDawn(backend_context, options); |
| if (!graphite_context) { |
| return nullptr; |
| } |
| |
| return std::make_unique<GraphiteSharedContext>( |
| std::move(graphite_context), use_shader_cache_shm_count, is_thread_safe, |
| features::kSkiaGraphiteMaxPendingRecordings.Get(), |
| GetBackendFlushCallback()); |
| } |
| |
| bool use_thread_safe_graphite_context() const { |
| return use_thread_safe_graphite_context_; |
| } |
| |
| GraphiteSharedContext* GetThreadSafeGraphiteSharedContext() const { |
| CHECK(use_thread_safe_graphite_context()); |
| return thread_safe_graphite_shared_context_.get(); |
| } |
| |
| bool InitializeThreadSafeGraphiteContext( |
| const skgpu::graphite::ContextOptions& options, |
| GpuProcessShmCount* use_shader_cache_shm_count) { |
| DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_); |
| CHECK(use_thread_safe_graphite_context()); |
| CHECK(!thread_safe_graphite_shared_context_); |
| thread_safe_graphite_shared_context_ = CreateGraphiteSharedContext( |
| options, use_shader_cache_shm_count, /*is_thread_safe=*/true); |
| return !!thread_safe_graphite_shared_context_; |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<DawnSharedContext>; |
| |
| // Provided to wgpu::Device as caching callback. |
| static size_t LoadCachedData(const void* key, |
| size_t key_size, |
| void* value, |
| size_t value_size, |
| void* userdata) { |
| if (auto& caching_interface = |
| static_cast<DawnSharedContext*>(userdata)->caching_interface_) { |
| return caching_interface->LoadData(key, key_size, value, value_size); |
| } |
| return 0; |
| } |
| |
| // Provided to wgpu::Device as caching callback. |
| static void StoreCachedData(const void* key, |
| size_t key_size, |
| const void* value, |
| size_t value_size, |
| void* userdata) { |
| if (auto& caching_interface = |
| static_cast<DawnSharedContext*>(userdata)->caching_interface_) { |
| caching_interface->StoreData(key, key_size, value, value_size); |
| } |
| } |
| |
| // Provided to wgpu::Device as logging callback. |
| static void DeviceLogInfo(wgpu::LoggingType type, |
| wgpu::StringView message, |
| DawnSharedContext* shared_context) { |
| CHECK(shared_context); |
| |
| std::string_view view = {message.data, message.length}; |
| |
| switch (static_cast<wgpu::LoggingType>(type)) { |
| case wgpu::LoggingType::Warning: |
| LOG(WARNING) << view; |
| break; |
| case wgpu::LoggingType::Error: |
| // Trigger context loss. |
| shared_context->OnError(wgpu::ErrorType::Internal, view); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // Provided to wgpu::Instance as logging callback. |
| static void InstanceLogInfo(wgpu::LoggingType type, |
| wgpu::StringView message, |
| DawnSharedContext* shared_context) { |
| CHECK(shared_context); |
| |
| std::string_view view = {message.data, message.length}; |
| |
| if (!shared_context->device_) { |
| // If device hasn't been created yet. Saving the message so that if there |
| // is any init failure afterward, we can include the messages in the |
| // LogInitFailure()'s report. |
| shared_context->StoreInitLoggingMessage(view); |
| } |
| |
| switch (static_cast<wgpu::LoggingType>(type)) { |
| case wgpu::LoggingType::Warning: |
| LOG(WARNING) << view; |
| break; |
| case wgpu::LoggingType::Error: |
| LOG(ERROR) << view; |
| if (shared_context->device_) { |
| // Only DwC if the device is already created. |
| // We don't need to DwC for any error before the device is initialized |
| // because LogInitFailure() would handle them instead. |
| // Note: We don't trigger context loss here for now since most of the |
| // errors reported via instance callback is related to Surface |
| // creation. In that case, instead of triggering context loss, we |
| // should let the call sites handle them gracefully. |
| SetDawnErrorCrashKey(view); |
| base::debug::DumpWithoutCrashing(); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| ~DawnSharedContext() override; |
| |
| GraphiteSharedContext::FlushCallback GetBackendFlushCallback() { |
| #if BUILDFLAG(IS_WIN) |
| return base::BindRepeating(&DawnSharedContext::FlushD3D11CommandsIfDelayed, |
| base::RetainedRef(this)); |
| #else |
| return {}; |
| #endif |
| } |
| |
| void OnError(wgpu::ErrorType error_type, wgpu::StringView message); |
| |
| void StoreInitLoggingMessage(std::string_view message) { |
| init_logging_msgs_.append(message); |
| init_logging_msgs_.append("\n"); |
| } |
| |
| void LogInitFailure(std::string_view reason, |
| bool generate_crash_report, |
| wgpu::BackendType backend_type, |
| bool force_fallback_adapter) { |
| LOG(ERROR) << reason; |
| |
| if (!generate_crash_report) { |
| return; |
| } |
| |
| SCOPED_CRASH_KEY_STRING256("dawn-shared-context", "init-failure", reason); |
| SCOPED_CRASH_KEY_STRING32("dawn-shared-context", "backend-type", |
| BackendTypeToString(backend_type)); |
| SCOPED_CRASH_KEY_BOOL("dawn-shared-context", "fallback-adapter", |
| force_fallback_adapter); |
| // Also include any logging messages collected during the initialization. |
| SCOPED_CRASH_KEY_STRING1024("dawn-shared-context", "init-logging-msgs", |
| init_logging_msgs_); |
| init_logging_msgs_.clear(); |
| base::debug::DumpWithoutCrashing(); |
| } |
| |
| // base::trace_event::MemoryDumpProvider implementation: |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) override; |
| |
| std::unique_ptr<webgpu::DawnCachingInterface> caching_interface_; |
| |
| Platform platform_; |
| std::unique_ptr<webgpu::DawnInstance> instance_; |
| wgpu::Adapter adapter_; |
| wgpu::Device device_; |
| wgpu::BackendType backend_type_; |
| // Store logging messages collected during device initialization. |
| std::string init_logging_msgs_; |
| bool is_vulkan_swiftshader_adapter_ = false; |
| bool registered_memory_dump_provider_ = false; |
| |
| // If true, both GpuMain and CompositorGpuThread share the same |
| // GraphiteSharedContext which is created lazily. If false, |
| // DawnContextProvider owns GraphiteSharedContext and each DawnContextProvider |
| // (i.e. each thread) has its own GraphiteSharedContext. |
| const bool use_thread_safe_graphite_context_; |
| std::unique_ptr<GraphiteSharedContext> thread_safe_graphite_shared_context_; |
| |
| mutable base::Lock context_lost_lock_; |
| std::optional<error::ContextLostReason> context_lost_reason_ |
| GUARDED_BY(context_lost_lock_); |
| |
| THREAD_CHECKER(main_thread_checker_); |
| }; |
| |
| DawnSharedContext::DawnSharedContext(gl::ProgressReporter* progress_reporter, |
| bool use_thread_safe_graphite_context) |
| : platform_(/*dawn_caching_interface=*/nullptr, |
| progress_reporter, |
| /*uma_prefix=*/"GPU.GraphiteDawn.", |
| /*record_cache_count_uma=*/true), |
| use_thread_safe_graphite_context_(use_thread_safe_graphite_context) { |
| DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_); |
| } |
| |
| DawnSharedContext::~DawnSharedContext() { |
| DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_); |
| if (device_) { |
| if (registered_memory_dump_provider_) { |
| base::trace_event::MemoryDumpManager::GetInstance() |
| ->UnregisterDumpProvider(this); |
| } |
| device_.SetLoggingCallback([](wgpu::LoggingType, wgpu::StringView) {}); |
| |
| // Destroy GraphiteSharedContext and skgpu::graphite::Context before |
| // device_, on which skgpu::graphite::Context is created. |
| thread_safe_graphite_shared_context_ = nullptr; |
| |
| // Destroy the device now so that the lost callback, which references this |
| // class, is fired now before we clean up the rest of this class. |
| device_.Destroy(); |
| } |
| if (instance_) { |
| instance_->DisconnectDawnPlatform(); |
| } |
| } |
| |
| namespace { |
| // Dawn Graphite adapter feature level for metrics. |
| // |
| // See also: webgpu.h:WGPUFeatureLevel |
| // |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| // |
| // LINT.IfChange(DawnAdapterFeatureLevel) |
| enum class DawnAdapterFeatureLevel { |
| kUnknown = 0, |
| kCompatibility = 1, |
| kCore = 2, |
| kMaxValue = kCore, |
| }; |
| // LINT.ThenChange(//tools/metrics/histograms/metadata/gpu/enums.xml:DawnAdapterFeatureLevel) |
| |
| DawnAdapterFeatureLevel DawnAdapterFeatureLevelFromWGPU( |
| wgpu::FeatureLevel level) { |
| switch (level) { |
| case wgpu::FeatureLevel::Compatibility: |
| return DawnAdapterFeatureLevel::kCompatibility; |
| case wgpu::FeatureLevel::Core: |
| return DawnAdapterFeatureLevel::kCore; |
| default: |
| return DawnAdapterFeatureLevel::kUnknown; |
| } |
| } |
| } // namespace |
| |
| bool DawnSharedContext::Initialize( |
| wgpu::BackendType backend_type, |
| bool force_fallback_adapter, |
| const GpuPreferences& gpu_preferences, |
| const GpuDriverBugWorkarounds& workarounds, |
| DawnContextProvider::ValidateAdapterFn validate_adapter_fn) { |
| // Make Dawn experimental API and WGSL features available since access to this |
| // instance doesn't exit the GPU process. |
| // LogInfo will be used to receive instance level errors. For example failures |
| // of loading libraries, initializing backend, etc |
| dawn::native::DawnInstanceDescriptor dawn_instance_desc; |
| dawn_instance_desc.SetLoggingCallback(&DawnSharedContext::InstanceLogInfo, |
| this); |
| instance_ = webgpu::DawnInstance::Create(&platform_, gpu_preferences, |
| webgpu::SafetyLevel::kUnsafe, |
| &dawn_instance_desc); |
| |
| std::vector<const char*> enabled_toggles = |
| GetEnabledToggles(backend_type, force_fallback_adapter, gpu_preferences); |
| std::vector<const char*> disabled_toggles = |
| GetDisabledToggles(gpu_preferences); |
| |
| wgpu::DawnTogglesDescriptor toggles_desc; |
| toggles_desc.enabledToggles = enabled_toggles.data(); |
| toggles_desc.disabledToggles = disabled_toggles.data(); |
| toggles_desc.enabledToggleCount = enabled_toggles.size(); |
| toggles_desc.disabledToggleCount = disabled_toggles.size(); |
| |
| wgpu::RequestAdapterOptions adapter_options; |
| adapter_options.backendType = backend_type; |
| adapter_options.forceFallbackAdapter = force_fallback_adapter; |
| if (workarounds.force_high_performance_gpu) { |
| adapter_options.powerPreference = wgpu::PowerPreference::HighPerformance; |
| } else { |
| adapter_options.powerPreference = wgpu::PowerPreference::LowPower; |
| } |
| adapter_options.nextInChain = &toggles_desc; |
| |
| #if BUILDFLAG(IS_WIN) |
| dawn::native::d3d::RequestAdapterOptionsLUID adapter_options_luid; |
| if ((adapter_options.backendType == wgpu::BackendType::D3D11 || |
| adapter_options.backendType == wgpu::BackendType::D3D12) && |
| GetANGLED3D11DeviceLUID(&adapter_options_luid.adapterLUID)) { |
| // Request the GPU that ANGLE is using if possible. |
| adapter_options_luid.nextInChain = adapter_options.nextInChain; |
| adapter_options.nextInChain = &adapter_options_luid; |
| } |
| |
| // Share D3D11 device with ANGLE to reduce synchronization overhead. |
| dawn::native::d3d11::RequestAdapterOptionsD3D11Device |
| adapter_options_d3d11_device; |
| if (adapter_options.backendType == wgpu::BackendType::D3D11) { |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = |
| gl::QueryD3D11DeviceObjectFromANGLE(); |
| CHECK(d3d11_device) << "Query d3d11 device from ANGLE failed."; |
| |
| static crash_reporter::CrashKeyString<16> feature_level_key( |
| "d3d11-feature-level"); |
| std::string feature_level = |
| D3DFeatureLevelToString(d3d11_device->GetFeatureLevel()); |
| feature_level_key.Set(feature_level.c_str()); |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context; |
| d3d11_device->GetImmediateContext(&d3d11_device_context); |
| |
| Microsoft::WRL::ComPtr<ID3D11Multithread> d3d11_multithread; |
| HRESULT hr = d3d11_device_context.As(&d3d11_multithread); |
| CHECK(SUCCEEDED(hr)) << "Query ID3D11Multithread interface failed: 0x" |
| << std::hex << hr; |
| |
| // Dawn requires enable multithread protection for d3d11 device. |
| d3d11_multithread->SetMultithreadProtected(TRUE); |
| adapter_options_d3d11_device.device = std::move(d3d11_device); |
| adapter_options_d3d11_device.nextInChain = adapter_options.nextInChain; |
| adapter_options.nextInChain = &adapter_options_d3d11_device; |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| adapter_options.featureLevel = wgpu::FeatureLevel::Core; |
| std::vector<dawn::native::Adapter> adapters = |
| instance_->EnumerateAdapters(&adapter_options); |
| |
| if (adapters.empty()) { |
| LOG(ERROR) << "No adapters found for non compatibility mode."; |
| adapter_options.featureLevel = wgpu::FeatureLevel::Compatibility; |
| adapters = instance_->EnumerateAdapters(&adapter_options); |
| } |
| |
| if (adapters.empty()) { |
| // On Android, it's expected that some devices might not support Dawn atm. |
| // So don't generate report for it. |
| LogInitFailure("No adapters found.", |
| /*generate_crash_report=*/!BUILDFLAG(IS_ANDROID), |
| backend_type, force_fallback_adapter); |
| return false; |
| } |
| adapter_ = wgpu::Adapter(adapters[0].Get()); |
| |
| if (!validate_adapter_fn(backend_type, adapter_)) { |
| LogInitFailure("Validate adapter failed.", |
| /*generate_crash_report=*/!BUILDFLAG(IS_ANDROID), |
| backend_type, force_fallback_adapter); |
| return false; |
| } |
| |
| // Start initializing dawn device here. |
| wgpu::DawnCacheDeviceDescriptor cache_desc; |
| cache_desc.loadDataFunction = &DawnSharedContext::LoadCachedData; |
| cache_desc.storeDataFunction = &DawnSharedContext::StoreCachedData; |
| // The dawn device is owned by this so a pointer back here is safe. |
| cache_desc.functionUserdata = this; |
| cache_desc.nextInChain = &toggles_desc; |
| |
| wgpu::DawnDeviceAllocatorControl allocator_desc; |
| wgpu::DeviceDescriptor descriptor; |
| if (backend_type == wgpu::BackendType::Vulkan) { |
| // Use a 256kb heap block size in the Vulkan backend to minimize |
| // fragmentation. |
| allocator_desc.allocatorHeapBlockSize = 256 * 1024; |
| allocator_desc.nextInChain = &cache_desc; |
| descriptor.nextInChain = &allocator_desc; |
| } else { |
| descriptor.nextInChain = &cache_desc; |
| } |
| |
| descriptor.SetUncapturedErrorCallback( |
| [](const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView message, |
| DawnSharedContext* state) { |
| if (type != wgpu::ErrorType::NoError) { |
| state->OnError(type, message); |
| } |
| }, |
| this); |
| descriptor.SetDeviceLostCallback( |
| wgpu::CallbackMode::AllowSpontaneous, |
| [](const wgpu::Device&, wgpu::DeviceLostReason reason, |
| wgpu::StringView message, DawnSharedContext* state) { |
| if (reason != wgpu::DeviceLostReason::Destroyed) { |
| state->OnError(wgpu::ErrorType::Unknown, message); |
| } |
| }, |
| this); |
| |
| std::vector<wgpu::FeatureName> features = |
| GetRequiredFeatures(backend_type, adapter_); |
| descriptor.requiredFeatures = features.data(); |
| descriptor.requiredFeatureCount = std::size(features); |
| |
| // Use best limits for the device. |
| wgpu::Limits supportedLimits = {}; |
| if (adapter_.GetLimits(&supportedLimits) != wgpu::Status::Success) { |
| LogInitFailure("Failed to call adapter.GetLimits().", |
| /*generate_crash_report=*/true, backend_type, |
| force_fallback_adapter); |
| return false; |
| } |
| descriptor.requiredLimits = &supportedLimits; |
| |
| // ANGLE always tries creating D3D11 device with debug layer when dcheck is |
| // on, so tries creating dawn device with backend validation as well. |
| constexpr bool enable_backend_validation = |
| DCHECK_IS_ON() && BUILDFLAG(IS_WIN); |
| |
| std::vector<dawn::native::BackendValidationLevel> backend_validation_levels = |
| {dawn::native::BackendValidationLevel::Disabled}; |
| if (features::kSkiaGraphiteDawnBackendValidation.Get() || |
| enable_backend_validation) { |
| backend_validation_levels.push_back( |
| dawn::native::BackendValidationLevel::Partial); |
| backend_validation_levels.push_back( |
| dawn::native::BackendValidationLevel::Full); |
| } |
| |
| if (base::FeatureList::IsEnabled(kForceDawnInitializeFailure)) { |
| LOG(ERROR) << "DawnSharedContext creation failed for testing"; |
| return false; |
| } |
| |
| // Try create device with backend validation level. |
| for (auto it = backend_validation_levels.rbegin(); |
| it != backend_validation_levels.rend(); ++it) { |
| auto level = *it; |
| instance_->SetBackendValidationLevel(level); |
| device_ = adapter_.CreateDevice(&descriptor); |
| if (device_) { |
| break; |
| } |
| } |
| |
| if (!device_) { |
| LogInitFailure("Failed to create device.", /*generate_crash_report=*/true, |
| backend_type, force_fallback_adapter); |
| return false; |
| } |
| |
| device_.SetLoggingCallback(&DawnSharedContext::DeviceLogInfo, this); |
| |
| backend_type_ = backend_type; |
| is_vulkan_swiftshader_adapter_ = |
| backend_type == wgpu::BackendType::Vulkan && force_fallback_adapter; |
| |
| #if BUILDFLAG(IS_WIN) |
| if (auto d3d11_device = GetD3D11Device()) { |
| static auto* crash_key = base::debug::AllocateCrashKeyString( |
| "d3d11-debug-layer", base::debug::CrashKeySize::Size32); |
| const bool enabled = IsD3D11DebugLayerEnabled(d3d11_device); |
| base::debug::SetCrashKeyString(crash_key, enabled ? "enabled" : "disabled"); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| if (base::SingleThreadTaskRunner::HasCurrentDefault()) { |
| base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| this, "DawnSharedContext", |
| base::SingleThreadTaskRunner::GetCurrentDefault()); |
| registered_memory_dump_provider_ = true; |
| } |
| |
| base::UmaHistogramEnumeration( |
| "GPU.Dawn.AdapterFeatureLevel", |
| DawnAdapterFeatureLevelFromWGPU(adapter_options.featureLevel)); |
| return true; |
| } |
| |
| void DawnSharedContext::SetCachingInterface( |
| std::unique_ptr<webgpu::DawnCachingInterface> caching_interface) { |
| CHECK(!caching_interface_); |
| caching_interface_ = std::move(caching_interface); |
| } |
| |
| std::optional<error::ContextLostReason> DawnSharedContext::GetResetStatus() |
| const { |
| base::AutoLock auto_lock(context_lost_lock_); |
| return context_lost_reason_; |
| } |
| |
| void DawnSharedContext::OnError(wgpu::ErrorType error_type, |
| wgpu::StringView message) { |
| #if BUILDFLAG(IS_WIN) |
| if (auto d3d11_device = GetD3D11Device()) { |
| static crash_reporter::CrashKeyString<64> reason_message_key( |
| "d3d11-device-removed-reason"); |
| HRESULT result = d3d11_device->GetDeviceRemovedReason(); |
| |
| if (const char* result_string = HRESULTToString(result)) { |
| LOG(ERROR) << "Device removed reason: " << result_string; |
| SetCrashKeyThreadSafe(reason_message_key, result_string); |
| } else { |
| auto unknown_error = base::StringPrintf("Unknown error(0x%08lX)", result); |
| LOG(ERROR) << "Device removed reason: " << unknown_error; |
| SetCrashKeyThreadSafe(reason_message_key, unknown_error.c_str()); |
| } |
| } |
| #endif |
| |
| DumpWithoutCrashingOnError(error_type, |
| static_cast<std::string_view>(message)); |
| |
| #if !DCHECK_IS_ON() |
| // Do not provoke context loss on validation failures for non-DCHECK builds. |
| // We want to capture the above dump on validation errors, but not necessarily |
| // restart the GPU process unless we also have a device loss. |
| if (error_type == wgpu::ErrorType::Validation) { |
| return; |
| } |
| #endif |
| |
| base::AutoLock auto_lock(context_lost_lock_); |
| if (context_lost_reason_.has_value()) { |
| return; |
| } |
| |
| switch (error_type) { |
| case wgpu::ErrorType::OutOfMemory: |
| context_lost_reason_ = error::kOutOfMemory; |
| break; |
| case wgpu::ErrorType::Validation: |
| context_lost_reason_ = error::kGuilty; |
| break; |
| default: |
| context_lost_reason_ = error::kUnknown; |
| break; |
| } |
| } |
| |
| namespace { |
| static constexpr char kDawnMemoryDumpPrefix[] = "gpu/dawn"; |
| |
| static constexpr char kAllocatorMemoryDumpPrefix[] = |
| "gpu/vulkan/graphite_allocator"; |
| |
| class DawnMemoryDump : public dawn::native::MemoryDump { |
| public: |
| explicit DawnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) |
| : pmd_(pmd) { |
| CHECK(pmd_); |
| } |
| |
| ~DawnMemoryDump() override = default; |
| |
| void AddScalar(const char* name, |
| const char* key, |
| const char* units, |
| uint64_t value) override { |
| pmd_->GetOrCreateAllocatorDump( |
| base::JoinString({kDawnMemoryDumpPrefix, name}, "/")) |
| ->AddScalar(key, units, value); |
| } |
| |
| void AddString(const char* name, |
| const char* key, |
| const std::string& value) override { |
| pmd_->GetOrCreateAllocatorDump( |
| base::JoinString({kDawnMemoryDumpPrefix, name}, "/")) |
| ->AddString(key, "", value); |
| } |
| |
| private: |
| const raw_ptr<base::trace_event::ProcessMemoryDump> pmd_; |
| }; |
| } // namespace |
| |
| bool DawnSharedContext::OnMemoryDump( |
| const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) { |
| using base::trace_event::MemoryAllocatorDump; |
| if (args.level_of_detail == |
| base::trace_event::MemoryDumpLevelOfDetail::kBackground) { |
| const dawn::native::MemoryUsageInfo mem_usage = |
| dawn::native::ComputeEstimatedMemoryUsageInfo(device_.Get()); |
| |
| pmd->GetOrCreateAllocatorDump(kDawnMemoryDumpPrefix) |
| ->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, mem_usage.totalUsage); |
| pmd->GetOrCreateAllocatorDump( |
| base::JoinString({kDawnMemoryDumpPrefix, "textures"}, "/")) |
| ->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, mem_usage.texturesUsage); |
| pmd |
| ->GetOrCreateAllocatorDump(base::JoinString( |
| {kDawnMemoryDumpPrefix, "textures/depth_stencil"}, "/")) |
| ->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, |
| mem_usage.depthStencilTexturesUsage); |
| auto* msaa_dump = pmd->GetOrCreateAllocatorDump( |
| base::JoinString({kDawnMemoryDumpPrefix, "textures/msaa"}, "/")); |
| msaa_dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, |
| mem_usage.msaaTexturesUsage); |
| msaa_dump->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
| MemoryAllocatorDump::kUnitsObjects, |
| mem_usage.msaaTexturesCount); |
| msaa_dump->AddScalar("biggest_size", MemoryAllocatorDump::kUnitsBytes, |
| mem_usage.largestMsaaTextureUsage); |
| pmd->GetOrCreateAllocatorDump( |
| base::JoinString({kDawnMemoryDumpPrefix, "buffers"}, "/")) |
| ->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, mem_usage.buffersUsage); |
| } else { |
| DawnMemoryDump dawnMemoryDump(pmd); |
| dawn::native::DumpMemoryStatistics(device_.Get(), &dawnMemoryDump); |
| } |
| |
| if (backend_type() == wgpu::BackendType::Vulkan) { |
| // For Graphite-Vulkan backend, report vulkan allocator dumps and |
| // statistics. |
| auto* dump = pmd->GetOrCreateAllocatorDump(kAllocatorMemoryDumpPrefix); |
| const dawn::native::AllocatorMemoryInfo allocator_usage = |
| dawn::native::GetAllocatorMemoryInfo(device_.Get()); |
| // `allocated_size` is memory allocated from the device, used is what is |
| // actually used. |
| dump->AddScalar("allocated_size", MemoryAllocatorDump::kUnitsBytes, |
| allocator_usage.totalAllocatedMemory - |
| allocator_usage.totalLazyAllocatedMemory); |
| dump->AddScalar( |
| "used_size", MemoryAllocatorDump::kUnitsBytes, |
| allocator_usage.totalUsedMemory - allocator_usage.totalLazyUsedMemory); |
| dump->AddScalar( |
| "fragmentation_size", MemoryAllocatorDump::kUnitsBytes, |
| allocator_usage.totalAllocatedMemory - allocator_usage.totalUsedMemory); |
| dump->AddScalar("lazy_allocated_size", MemoryAllocatorDump::kUnitsBytes, |
| allocator_usage.totalLazyAllocatedMemory); |
| dump->AddScalar("lazy_used_size", MemoryAllocatorDump::kUnitsBytes, |
| allocator_usage.totalLazyUsedMemory); |
| } |
| |
| return true; |
| } |
| |
| std::unique_ptr<DawnContextProvider> DawnContextProvider::Create( |
| const GpuPreferences& gpu_preferences, |
| const GpuFeatureInfo& gpu_feature_info, |
| gl::ProgressReporter* progress_reporter, |
| ValidateAdapterFn validate_adapter_fn) { |
| return DawnContextProvider::CreateWithBackend( |
| GetDefaultBackendType(), DefaultForceFallbackAdapter(), gpu_preferences, |
| gpu_feature_info, progress_reporter, validate_adapter_fn); |
| } |
| |
| std::unique_ptr<DawnContextProvider> DawnContextProvider::CreateWithBackend( |
| wgpu::BackendType backend_type, |
| bool force_fallback_adapter, |
| const GpuPreferences& gpu_preferences, |
| const GpuFeatureInfo& gpu_feature_info, |
| gl::ProgressReporter* progress_reporter, |
| ValidateAdapterFn validate_adapter_fn) { |
| bool use_thread_safe_graphite_context = |
| features::IsDrDcEnabled(gpu_feature_info) && |
| features::IsGraphiteContextThreadSafe(); |
| auto dawn_shared_context = base::MakeRefCounted<DawnSharedContext>( |
| progress_reporter, use_thread_safe_graphite_context); |
| GpuDriverBugWorkarounds workarounds( |
| gpu_feature_info.enabled_gpu_driver_bug_workarounds); |
| if (!dawn_shared_context->Initialize(backend_type, force_fallback_adapter, |
| gpu_preferences, workarounds, |
| validate_adapter_fn)) { |
| return nullptr; |
| } |
| return base::WrapUnique( |
| new DawnContextProvider(std::move(dawn_shared_context))); |
| } |
| |
| std::unique_ptr<DawnContextProvider> |
| DawnContextProvider::CreateWithSharedDevice( |
| const DawnContextProvider* existing) { |
| CHECK(existing); |
| CHECK(existing->dawn_shared_context_); |
| return base::WrapUnique( |
| new DawnContextProvider(existing->dawn_shared_context_)); |
| } |
| |
| DawnContextProvider::DawnContextProvider( |
| scoped_refptr<DawnSharedContext> dawn_shared_context) |
| : dawn_shared_context_(std::move(dawn_shared_context)) { |
| CHECK(dawn_shared_context_); |
| } |
| |
| DawnContextProvider::~DawnContextProvider() = default; |
| |
| wgpu::Device DawnContextProvider::GetDevice() const { |
| return dawn_shared_context_->GetDevice(); |
| } |
| |
| wgpu::BackendType DawnContextProvider::backend_type() const { |
| return dawn_shared_context_->backend_type(); |
| } |
| |
| bool DawnContextProvider::is_vulkan_swiftshader_adapter() const { |
| return dawn_shared_context_->is_vulkan_swiftshader_adapter(); |
| } |
| |
| wgpu::Adapter DawnContextProvider::GetAdapter() const { |
| return dawn_shared_context_->GetAdapter(); |
| } |
| |
| wgpu::Instance DawnContextProvider::GetInstance() const { |
| return dawn_shared_context_->GetInstance(); |
| } |
| |
| bool DawnContextProvider::use_thread_safe_shared_context() const { |
| return dawn_shared_context_->use_thread_safe_graphite_context(); |
| } |
| |
| void DawnContextProvider::InitializeThreadSafeGraphiteContext( |
| const skgpu::graphite::ContextOptions& options, |
| GpuProcessShmCount* use_shader_cache_shm_count) { |
| dawn_shared_context_->InitializeThreadSafeGraphiteContext( |
| options, use_shader_cache_shm_count); |
| } |
| |
| bool DawnContextProvider::InitializeGraphiteContext( |
| const skgpu::graphite::ContextOptions& options, |
| GpuProcessShmCount* use_shader_cache_shm_count) { |
| if (dawn_shared_context_->use_thread_safe_graphite_context()) { |
| return !!dawn_shared_context_->GetThreadSafeGraphiteSharedContext(); |
| } |
| graphite_shared_context_ = dawn_shared_context_->CreateGraphiteSharedContext( |
| options, use_shader_cache_shm_count, /*is_thread_safe=*/false); |
| return !!graphite_shared_context_; |
| } |
| |
| void DawnContextProvider::SetCachingInterface( |
| std::unique_ptr<webgpu::DawnCachingInterface> caching_interface) { |
| CHECK(dawn_shared_context_->HasOneRef()); |
| CHECK(!graphite_shared_context_); |
| dawn_shared_context_->SetCachingInterface(std::move(caching_interface)); |
| } |
| |
| webgpu::DawnCachingInterface* DawnContextProvider::GetCachingInterface() const { |
| return dawn_shared_context_->GetCachingInterface(); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| Microsoft::WRL::ComPtr<ID3D11Device> DawnContextProvider::GetD3D11Device() |
| const { |
| return dawn_shared_context_->GetD3D11Device(); |
| } |
| #endif |
| |
| bool DawnContextProvider::SupportsFeature(wgpu::FeatureName feature) { |
| return dawn_shared_context_->GetDevice().HasFeature(feature); |
| } |
| |
| std::optional<error::ContextLostReason> DawnContextProvider::GetResetStatus() |
| const { |
| return dawn_shared_context_->GetResetStatus(); |
| } |
| |
| GraphiteSharedContext* DawnContextProvider::GetGraphiteSharedContext() const { |
| if (dawn_shared_context_->use_thread_safe_graphite_context()) { |
| // Both threads shares the same GraphiteSharedContext. DawnSharedContext |
| // owns GraphiteSharedContext |
| return dawn_shared_context_->GetThreadSafeGraphiteSharedContext(); |
| } else { |
| // Each DawnContextProvider owns its own GraphiteSharedContext and |
| // skgpu::graphite::Context |
| return graphite_shared_context_.get(); |
| } |
| } |
| |
| webgpu::DawnPlatform* DawnContextProvider::GetDawnPlatform() { |
| return dawn_shared_context_->GetDawnPlatform(); |
| } |
| |
| } // namespace gpu |