• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/window/GraphiteDawnWindowContext.h"
9 
10 #include "include/core/SkSurface.h"
11 #include "include/gpu/graphite/BackendTexture.h"
12 #include "include/gpu/graphite/Context.h"
13 #include "include/gpu/graphite/ContextOptions.h"
14 #include "include/gpu/graphite/GraphiteTypes.h"
15 #include "include/gpu/graphite/Recorder.h"
16 #include "include/gpu/graphite/Recording.h"
17 #include "include/gpu/graphite/Surface.h"
18 #include "include/gpu/graphite/dawn/DawnBackendContext.h"
19 #include "include/gpu/graphite/dawn/DawnUtils.h"
20 #include "include/private/gpu/graphite/ContextOptionsPriv.h"
21 #include "tools/ToolUtils.h"
22 #include "tools/GpuToolUtils.h"
23 
24 #include "dawn/dawn_proc.h"
25 
26 namespace skwindow::internal {
27 
GraphiteDawnWindowContext(const DisplayParams & params,wgpu::TextureFormat swapChainFormat)28 GraphiteDawnWindowContext::GraphiteDawnWindowContext(const DisplayParams& params,
29                                                      wgpu::TextureFormat swapChainFormat)
30     : WindowContext(params)
31     , fSwapChainFormat(swapChainFormat) {
32     WGPUInstanceDescriptor desc{};
33     // need for WaitAny with timeout > 0
34     desc.features.timedWaitAnyEnable = true;
35     fInstance = std::make_unique<dawn::native::Instance>(&desc);
36 }
37 
initializeContext(int width,int height)38 void GraphiteDawnWindowContext::initializeContext(int width, int height) {
39     SkASSERT(!fContext);
40 
41     fWidth = width;
42     fHeight = height;
43 
44     if (!onInitializeContext())
45         return;
46 
47     SkASSERT(fDevice);
48     SkASSERT(fSurface);
49     SkASSERT(fSwapChain);
50 
51     skgpu::graphite::DawnBackendContext backendContext;
52     backendContext.fInstance = wgpu::Instance(fInstance->Get());
53     backendContext.fDevice = fDevice;
54     backendContext.fQueue = fDevice.GetQueue();
55     // Needed to make synchronous readPixels work:
56     fDisplayParams.fGraphiteContextOptions.fPriv.fStoreContextRefInRecorder = true;
57     fGraphiteContext = skgpu::graphite::ContextFactory::MakeDawn(
58             backendContext, fDisplayParams.fGraphiteContextOptions.fOptions);
59     if (!fGraphiteContext) {
60         SkASSERT(false);
61         return;
62     }
63 
64     fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
65     SkASSERT(fGraphiteRecorder);
66 }
67 
68 GraphiteDawnWindowContext::~GraphiteDawnWindowContext() = default;
69 
destroyContext()70 void GraphiteDawnWindowContext::destroyContext() {
71     if (!fDevice.Get()) {
72         return;
73     }
74 
75     this->onDestroyContext();
76 
77     fGraphiteRecorder = nullptr;
78     fGraphiteContext = nullptr;
79     fSwapChain = nullptr;
80     fSurface = nullptr;
81     fDevice = nullptr;
82 }
83 
getBackbufferSurface()84 sk_sp<SkSurface> GraphiteDawnWindowContext::getBackbufferSurface() {
85     auto texture = fSwapChain.GetCurrentTexture();
86     skgpu::graphite::DawnTextureInfo info(/*sampleCount=*/1,
87                                           skgpu::Mipmapped::kNo,
88                                           fSwapChainFormat,
89                                           texture.GetUsage(),
90                                           wgpu::TextureAspect::All);
91     skgpu::graphite::BackendTexture backendTex(texture.Get());
92     SkASSERT(this->graphiteRecorder());
93     auto surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(),
94                                                   backendTex,
95                                                   kBGRA_8888_SkColorType,
96                                                   fDisplayParams.fColorSpace,
97                                                   &fDisplayParams.fSurfaceProps);
98     SkASSERT(surface);
99     return surface;
100 }
101 
onSwapBuffers()102 void GraphiteDawnWindowContext::onSwapBuffers() {
103     this->snapRecordingAndSubmit();
104     fSwapChain.Present();
105 }
106 
setDisplayParams(const DisplayParams & params)107 void GraphiteDawnWindowContext::setDisplayParams(const DisplayParams& params) {
108     this->destroyContext();
109     fDisplayParams = params;
110     this->initializeContext(fWidth, fHeight);
111 }
112 
createDevice(wgpu::BackendType type)113 wgpu::Device GraphiteDawnWindowContext::createDevice(wgpu::BackendType type) {
114     DawnProcTable backendProcs = dawn::native::GetProcs();
115     dawnProcSetProcs(&backendProcs);
116 
117     static constexpr const char* kAdapterToggles[] = {
118         "allow_unsafe_apis",  // Needed for dual-source blending, BufferMapExtendedUsages.
119         "use_user_defined_labels_in_backend",
120     };
121     wgpu::DawnTogglesDescriptor adapterTogglesDesc;
122     adapterTogglesDesc.enabledToggleCount  = std::size(kAdapterToggles);
123     adapterTogglesDesc.enabledToggles      = kAdapterToggles;
124 
125     wgpu::RequestAdapterOptions adapterOptions;
126     adapterOptions.backendType = type;
127     adapterOptions.nextInChain = &adapterTogglesDesc;
128 
129     std::vector<dawn::native::Adapter> adapters = fInstance->EnumerateAdapters(&adapterOptions);
130     if (adapters.empty()) {
131         return nullptr;
132     }
133 
134     wgpu::Adapter adapter = adapters[0].Get();
135 
136     std::vector<wgpu::FeatureName> features;
137     features.push_back(wgpu::FeatureName::SurfaceCapabilities);
138     if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) {
139         features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled);
140     }
141     if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {
142         features.push_back(wgpu::FeatureName::TransientAttachments);
143     }
144     if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) {
145         features.push_back(wgpu::FeatureName::Unorm16TextureFormats);
146     }
147     if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) {
148         features.push_back(wgpu::FeatureName::DualSourceBlending);
149     }
150     if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) {
151         features.push_back(wgpu::FeatureName::FramebufferFetch);
152     }
153     if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) {
154         features.push_back(wgpu::FeatureName::BufferMapExtendedUsages);
155     }
156     if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) {
157         features.push_back(wgpu::FeatureName::TextureCompressionETC2);
158     }
159     if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
160         features.push_back(wgpu::FeatureName::TextureCompressionBC);
161     }
162     if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
163         features.push_back(wgpu::FeatureName::R8UnormStorage);
164     }
165     if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
166         features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
167     }
168 
169     wgpu::DeviceDescriptor deviceDescriptor;
170     deviceDescriptor.requiredFeatures = features.data();
171     deviceDescriptor.requiredFeatureCount = features.size();
172     deviceDescriptor.deviceLostCallbackInfo.callback =
173         [](WGPUDeviceImpl *const *, WGPUDeviceLostReason reason, const char* message, void*) {
174             if (reason != WGPUDeviceLostReason_Destroyed &&
175                 reason != WGPUDeviceLostReason_InstanceDropped) {
176                 SK_ABORT("Device lost: %s\n", message);
177             }
178         };
179 
180     wgpu::DawnTogglesDescriptor deviceTogglesDesc;
181 
182     if (fDisplayParams.fDisableTintSymbolRenaming) {
183         static constexpr const char* kOptionalDeviceToggles[] = {
184             "disable_symbol_renaming",
185         };
186         deviceTogglesDesc.enabledToggleCount = std::size(kOptionalDeviceToggles);
187         deviceTogglesDesc.enabledToggles     = kOptionalDeviceToggles;
188 
189         // Insert the toggles descriptor ahead of any existing entries in the chain that might have
190         // been added above.
191         deviceTogglesDesc.nextInChain = deviceDescriptor.nextInChain;
192         deviceDescriptor.nextInChain  = &deviceTogglesDesc;
193     }
194 
195     auto device = adapter.CreateDevice(&deviceDescriptor);
196     if (!device) {
197         return nullptr;
198     }
199 
200     device.SetUncapturedErrorCallback(
201             [](WGPUErrorType type, const char* message, void*) {
202                 SkDebugf("Device error: %s\n", message);
203                 SkASSERT(false);
204             },
205             nullptr);
206     return device;
207 }
208 
createSwapChain()209 wgpu::SwapChain GraphiteDawnWindowContext::createSwapChain() {
210     wgpu::SwapChainDescriptor swapChainDesc;
211     swapChainDesc.usage = wgpu::TextureUsage::RenderAttachment |
212                           wgpu::TextureUsage::TextureBinding |
213                           wgpu::TextureUsage::CopySrc |
214                           wgpu::TextureUsage::CopyDst;
215     swapChainDesc.format = fSwapChainFormat;
216     swapChainDesc.width = fWidth;
217     swapChainDesc.height = fHeight;
218     swapChainDesc.presentMode =
219             fDisplayParams.fDisableVsync ? wgpu::PresentMode::Immediate : wgpu::PresentMode::Fifo;
220     auto swapChain = fDevice.CreateSwapChain(fSurface, &swapChainDesc);
221     SkASSERT(swapChain);
222     return swapChain;
223 }
224 
225 }   //namespace skwindow::internal
226