/* * Copyright 2022 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/window/GraphiteDawnWindowContext.h" #include "include/core/SkSurface.h" #include "include/gpu/graphite/BackendTexture.h" #include "include/gpu/graphite/Context.h" #include "include/gpu/graphite/ContextOptions.h" #include "include/gpu/graphite/GraphiteTypes.h" #include "include/gpu/graphite/Recorder.h" #include "include/gpu/graphite/Recording.h" #include "include/gpu/graphite/Surface.h" #include "include/gpu/graphite/dawn/DawnBackendContext.h" #include "include/gpu/graphite/dawn/DawnTypes.h" #include "include/gpu/graphite/dawn/DawnUtils.h" #include "src/gpu/graphite/ContextOptionsPriv.h" #include "tools/ToolUtils.h" #include "tools/graphite/GraphiteToolUtils.h" #include "tools/graphite/TestOptions.h" #include "tools/window/GraphiteDisplayParams.h" #include "dawn/dawn_proc.h" namespace skwindow::internal { GraphiteDawnWindowContext::GraphiteDawnWindowContext(std::unique_ptr params, wgpu::TextureFormat surfaceFormat) : WindowContext(std::move(params)), fSurfaceFormat(surfaceFormat) { WGPUInstanceDescriptor desc{}; // need for WaitAny with timeout > 0 desc.features.timedWaitAnyEnable = true; fInstance = std::make_unique(&desc); } void GraphiteDawnWindowContext::initializeContext(int width, int height) { SkASSERT(!fContext); fWidth = width; fHeight = height; if (!this->onInitializeContext()) return; SkASSERT(fDevice); SkASSERT(fSurface); skgpu::graphite::DawnBackendContext backendContext; backendContext.fInstance = wgpu::Instance(fInstance->Get()); backendContext.fDevice = fDevice; backendContext.fQueue = fDevice.GetQueue(); SkASSERT(fDisplayParams->graphiteTestOptions()); skwindow::GraphiteTestOptions opts = *fDisplayParams->graphiteTestOptions(); // Needed to make synchronous readPixels work: opts.fPriv.fStoreContextRefInRecorder = true; fDisplayParams = GraphiteDisplayParamsBuilder(fDisplayParams.get()).graphiteTestOptions(opts).build(); fGraphiteContext = skgpu::graphite::ContextFactory::MakeDawn(backendContext, opts.fTestOptions.fContextOptions); if (!fGraphiteContext) { SkASSERT(false); return; } fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions()); SkASSERT(fGraphiteRecorder); } GraphiteDawnWindowContext::~GraphiteDawnWindowContext() = default; void GraphiteDawnWindowContext::destroyContext() { if (!fDevice.Get()) { return; } this->onDestroyContext(); fGraphiteRecorder = nullptr; fGraphiteContext = nullptr; fSurface = nullptr; fDevice = nullptr; } sk_sp GraphiteDawnWindowContext::getBackbufferSurface() { wgpu::SurfaceTexture surfaceTexture; fSurface.GetCurrentTexture(&surfaceTexture); SkASSERT(surfaceTexture.texture); auto texture = surfaceTexture.texture; skgpu::graphite::DawnTextureInfo info(/*sampleCount=*/1, skgpu::Mipmapped::kNo, fSurfaceFormat, texture.GetUsage(), wgpu::TextureAspect::All); auto backendTex = skgpu::graphite::BackendTextures::MakeDawn(texture.Get()); SkASSERT(this->graphiteRecorder()); auto surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(), backendTex, kBGRA_8888_SkColorType, fDisplayParams->colorSpace(), &fDisplayParams->surfaceProps()); SkASSERT(surface); return surface; } void GraphiteDawnWindowContext::onSwapBuffers() { this->submitToGpu(); fSurface.Present(); } void GraphiteDawnWindowContext::setDisplayParams(std::unique_ptr params) { this->destroyContext(); fDisplayParams = std::move(params); this->initializeContext(fWidth, fHeight); } wgpu::Device GraphiteDawnWindowContext::createDevice(wgpu::BackendType type) { DawnProcTable backendProcs = dawn::native::GetProcs(); dawnProcSetProcs(&backendProcs); static constexpr const char* kToggles[] = { "allow_unsafe_apis", // Needed for dual-source blending, BufferMapExtendedUsages. "use_user_defined_labels_in_backend", // Robustness impacts performance and is always disabled when running Graphite in Chrome, // so this keeps Skia's tests operating closer to real-use behavior. "disable_robustness", // Must be last to correctly respond to `fUseTintIR` option. "use_tint_ir", }; wgpu::DawnTogglesDescriptor togglesDesc; togglesDesc.enabledToggleCount = std::size(kToggles) - (fDisplayParams->graphiteTestOptions()->fTestOptions.fUseTintIR ? 0 : 1); togglesDesc.enabledToggles = kToggles; wgpu::RequestAdapterOptions adapterOptions; adapterOptions.backendType = type; adapterOptions.compatibilityMode = type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES; adapterOptions.nextInChain = &togglesDesc; std::vector adapters = fInstance->EnumerateAdapters(&adapterOptions); if (adapters.empty()) { return nullptr; } wgpu::Adapter adapter = adapters[0].Get(); std::vector features; if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) { features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled); } if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) { features.push_back(wgpu::FeatureName::TransientAttachments); } if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) { features.push_back(wgpu::FeatureName::Unorm16TextureFormats); } if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) { features.push_back(wgpu::FeatureName::DualSourceBlending); } if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) { features.push_back(wgpu::FeatureName::FramebufferFetch); } if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) { features.push_back(wgpu::FeatureName::BufferMapExtendedUsages); } if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) { features.push_back(wgpu::FeatureName::TextureCompressionETC2); } if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) { features.push_back(wgpu::FeatureName::TextureCompressionBC); } if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) { features.push_back(wgpu::FeatureName::R8UnormStorage); } if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) { features.push_back(wgpu::FeatureName::DawnLoadResolveTexture); } if (adapter.HasFeature(wgpu::FeatureName::DawnPartialLoadResolveTexture)) { features.push_back(wgpu::FeatureName::DawnPartialLoadResolveTexture); } if (adapter.HasFeature(wgpu::FeatureName::TimestampQuery)) { features.push_back(wgpu::FeatureName::TimestampQuery); } if (adapter.HasFeature(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment)) { features.push_back(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment); } wgpu::DeviceDescriptor deviceDescriptor; deviceDescriptor.requiredFeatures = features.data(); deviceDescriptor.requiredFeatureCount = features.size(); deviceDescriptor.nextInChain = &togglesDesc; deviceDescriptor.SetDeviceLostCallback( wgpu::CallbackMode::AllowSpontaneous, [](const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) { if (reason != wgpu::DeviceLostReason::Destroyed && reason != wgpu::DeviceLostReason::InstanceDropped) { SK_ABORT("Device lost: %s\n", message); } }); deviceDescriptor.SetUncapturedErrorCallback( [](const wgpu::Device&, wgpu::ErrorType, const char* message) { SkDebugf("Device error: %s\n", message); SkASSERT(false); }); wgpu::DawnTogglesDescriptor deviceTogglesDesc; if (fDisplayParams->graphiteTestOptions()->fTestOptions.fDisableTintSymbolRenaming) { static constexpr const char* kOptionalDeviceToggles[] = { "disable_symbol_renaming", }; deviceTogglesDesc.enabledToggleCount = std::size(kOptionalDeviceToggles); deviceTogglesDesc.enabledToggles = kOptionalDeviceToggles; // Insert the toggles descriptor ahead of any existing entries in the chain that might have // been added above. deviceTogglesDesc.nextInChain = deviceDescriptor.nextInChain; deviceDescriptor.nextInChain = &deviceTogglesDesc; } auto device = adapter.CreateDevice(&deviceDescriptor); if (!device) { return nullptr; } return device; } void GraphiteDawnWindowContext::configureSurface() { SkASSERT(fDevice); SkASSERT(fSurface); wgpu::SurfaceConfiguration surfaceConfig; surfaceConfig.device = fDevice; surfaceConfig.format = fSurfaceFormat; surfaceConfig.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; surfaceConfig.width = fWidth; surfaceConfig.height = fHeight; surfaceConfig.presentMode = fDisplayParams->disableVsync() ? wgpu::PresentMode::Immediate : wgpu::PresentMode::Fifo; fSurface.Configure(&surfaceConfig); } } //namespace skwindow::internal