xref: /aosp_15_r20/external/skia/tools/window/GraphiteDawnWindowContext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/DawnTypes.h"
20 #include "include/gpu/graphite/dawn/DawnUtils.h"
21 #include "src/gpu/graphite/ContextOptionsPriv.h"
22 #include "tools/ToolUtils.h"
23 #include "tools/graphite/GraphiteToolUtils.h"
24 #include "tools/graphite/TestOptions.h"
25 #include "tools/window/GraphiteDisplayParams.h"
26 
27 #include "dawn/dawn_proc.h"
28 
29 namespace skwindow::internal {
30 
GraphiteDawnWindowContext(std::unique_ptr<const DisplayParams> params,wgpu::TextureFormat surfaceFormat)31 GraphiteDawnWindowContext::GraphiteDawnWindowContext(std::unique_ptr<const DisplayParams> params,
32                                                      wgpu::TextureFormat surfaceFormat)
33         : WindowContext(std::move(params)), fSurfaceFormat(surfaceFormat) {
34     WGPUInstanceDescriptor desc{};
35     // need for WaitAny with timeout > 0
36     desc.features.timedWaitAnyEnable = true;
37     fInstance = std::make_unique<dawn::native::Instance>(&desc);
38 }
39 
initializeContext(int width,int height)40 void GraphiteDawnWindowContext::initializeContext(int width, int height) {
41     SkASSERT(!fContext);
42 
43     fWidth = width;
44     fHeight = height;
45 
46     if (!this->onInitializeContext())
47         return;
48 
49     SkASSERT(fDevice);
50     SkASSERT(fSurface);
51 
52     skgpu::graphite::DawnBackendContext backendContext;
53     backendContext.fInstance = wgpu::Instance(fInstance->Get());
54     backendContext.fDevice = fDevice;
55     backendContext.fQueue = fDevice.GetQueue();
56 
57     SkASSERT(fDisplayParams->graphiteTestOptions());
58     skwindow::GraphiteTestOptions opts = *fDisplayParams->graphiteTestOptions();
59 
60     // Needed to make synchronous readPixels work:
61     opts.fPriv.fStoreContextRefInRecorder = true;
62     fDisplayParams =
63             GraphiteDisplayParamsBuilder(fDisplayParams.get()).graphiteTestOptions(opts).build();
64 
65     fGraphiteContext = skgpu::graphite::ContextFactory::MakeDawn(backendContext,
66                                                                  opts.fTestOptions.fContextOptions);
67     if (!fGraphiteContext) {
68         SkASSERT(false);
69         return;
70     }
71 
72     fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
73     SkASSERT(fGraphiteRecorder);
74 }
75 
76 GraphiteDawnWindowContext::~GraphiteDawnWindowContext() = default;
77 
destroyContext()78 void GraphiteDawnWindowContext::destroyContext() {
79     if (!fDevice.Get()) {
80         return;
81     }
82 
83     this->onDestroyContext();
84 
85     fGraphiteRecorder = nullptr;
86     fGraphiteContext = nullptr;
87     fSurface = nullptr;
88     fDevice = nullptr;
89 }
90 
getBackbufferSurface()91 sk_sp<SkSurface> GraphiteDawnWindowContext::getBackbufferSurface() {
92     wgpu::SurfaceTexture surfaceTexture;
93     fSurface.GetCurrentTexture(&surfaceTexture);
94     SkASSERT(surfaceTexture.texture);
95     auto texture = surfaceTexture.texture;
96 
97     skgpu::graphite::DawnTextureInfo info(/*sampleCount=*/1,
98                                           skgpu::Mipmapped::kNo,
99                                           fSurfaceFormat,
100                                           texture.GetUsage(),
101                                           wgpu::TextureAspect::All);
102     auto backendTex = skgpu::graphite::BackendTextures::MakeDawn(texture.Get());
103     SkASSERT(this->graphiteRecorder());
104     auto surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(),
105                                                   backendTex,
106                                                   kBGRA_8888_SkColorType,
107                                                   fDisplayParams->colorSpace(),
108                                                   &fDisplayParams->surfaceProps());
109     SkASSERT(surface);
110     return surface;
111 }
112 
onSwapBuffers()113 void GraphiteDawnWindowContext::onSwapBuffers() {
114     this->submitToGpu();
115     fSurface.Present();
116 }
117 
setDisplayParams(std::unique_ptr<const DisplayParams> params)118 void GraphiteDawnWindowContext::setDisplayParams(std::unique_ptr<const DisplayParams> params) {
119     this->destroyContext();
120     fDisplayParams = std::move(params);
121     this->initializeContext(fWidth, fHeight);
122 }
123 
createDevice(wgpu::BackendType type)124 wgpu::Device GraphiteDawnWindowContext::createDevice(wgpu::BackendType type) {
125     DawnProcTable backendProcs = dawn::native::GetProcs();
126     dawnProcSetProcs(&backendProcs);
127 
128     static constexpr const char* kToggles[] = {
129         "allow_unsafe_apis",  // Needed for dual-source blending, BufferMapExtendedUsages.
130         "use_user_defined_labels_in_backend",
131         // Robustness impacts performance and is always disabled when running Graphite in Chrome,
132         // so this keeps Skia's tests operating closer to real-use behavior.
133         "disable_robustness",
134         // Must be last to correctly respond to `fUseTintIR` option.
135         "use_tint_ir",
136     };
137     wgpu::DawnTogglesDescriptor togglesDesc;
138     togglesDesc.enabledToggleCount =
139             std::size(kToggles) -
140             (fDisplayParams->graphiteTestOptions()->fTestOptions.fUseTintIR ? 0 : 1);
141     togglesDesc.enabledToggles      = kToggles;
142 
143     wgpu::RequestAdapterOptions adapterOptions;
144     adapterOptions.backendType = type;
145     adapterOptions.compatibilityMode =
146             type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES;
147     adapterOptions.nextInChain = &togglesDesc;
148 
149     std::vector<dawn::native::Adapter> adapters = fInstance->EnumerateAdapters(&adapterOptions);
150     if (adapters.empty()) {
151         return nullptr;
152     }
153 
154     wgpu::Adapter adapter = adapters[0].Get();
155 
156     std::vector<wgpu::FeatureName> features;
157     if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) {
158         features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled);
159     }
160     if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {
161         features.push_back(wgpu::FeatureName::TransientAttachments);
162     }
163     if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) {
164         features.push_back(wgpu::FeatureName::Unorm16TextureFormats);
165     }
166     if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) {
167         features.push_back(wgpu::FeatureName::DualSourceBlending);
168     }
169     if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) {
170         features.push_back(wgpu::FeatureName::FramebufferFetch);
171     }
172     if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) {
173         features.push_back(wgpu::FeatureName::BufferMapExtendedUsages);
174     }
175     if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) {
176         features.push_back(wgpu::FeatureName::TextureCompressionETC2);
177     }
178     if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
179         features.push_back(wgpu::FeatureName::TextureCompressionBC);
180     }
181     if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
182         features.push_back(wgpu::FeatureName::R8UnormStorage);
183     }
184     if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
185         features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
186     }
187     if (adapter.HasFeature(wgpu::FeatureName::DawnPartialLoadResolveTexture)) {
188         features.push_back(wgpu::FeatureName::DawnPartialLoadResolveTexture);
189     }
190     if (adapter.HasFeature(wgpu::FeatureName::TimestampQuery)) {
191         features.push_back(wgpu::FeatureName::TimestampQuery);
192     }
193     if (adapter.HasFeature(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment)) {
194         features.push_back(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment);
195     }
196 
197     wgpu::DeviceDescriptor deviceDescriptor;
198     deviceDescriptor.requiredFeatures = features.data();
199     deviceDescriptor.requiredFeatureCount = features.size();
200     deviceDescriptor.nextInChain = &togglesDesc;
201     deviceDescriptor.SetDeviceLostCallback(
202             wgpu::CallbackMode::AllowSpontaneous,
203             [](const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) {
204                 if (reason != wgpu::DeviceLostReason::Destroyed &&
205                     reason != wgpu::DeviceLostReason::InstanceDropped) {
206                     SK_ABORT("Device lost: %s\n", message);
207                 }
208             });
209     deviceDescriptor.SetUncapturedErrorCallback(
210             [](const wgpu::Device&, wgpu::ErrorType, const char* message) {
211                 SkDebugf("Device error: %s\n", message);
212                 SkASSERT(false);
213             });
214 
215     wgpu::DawnTogglesDescriptor deviceTogglesDesc;
216 
217     if (fDisplayParams->graphiteTestOptions()->fTestOptions.fDisableTintSymbolRenaming) {
218         static constexpr const char* kOptionalDeviceToggles[] = {
219             "disable_symbol_renaming",
220         };
221         deviceTogglesDesc.enabledToggleCount = std::size(kOptionalDeviceToggles);
222         deviceTogglesDesc.enabledToggles     = kOptionalDeviceToggles;
223 
224         // Insert the toggles descriptor ahead of any existing entries in the chain that might have
225         // been added above.
226         deviceTogglesDesc.nextInChain = deviceDescriptor.nextInChain;
227         deviceDescriptor.nextInChain  = &deviceTogglesDesc;
228     }
229 
230     auto device = adapter.CreateDevice(&deviceDescriptor);
231     if (!device) {
232         return nullptr;
233     }
234 
235     return device;
236 }
237 
configureSurface()238 void GraphiteDawnWindowContext::configureSurface() {
239     SkASSERT(fDevice);
240     SkASSERT(fSurface);
241 
242     wgpu::SurfaceConfiguration surfaceConfig;
243     surfaceConfig.device = fDevice;
244     surfaceConfig.format = fSurfaceFormat;
245     surfaceConfig.usage = wgpu::TextureUsage::RenderAttachment |
246                           wgpu::TextureUsage::TextureBinding |
247                           wgpu::TextureUsage::CopySrc |
248                           wgpu::TextureUsage::CopyDst;
249     surfaceConfig.width = fWidth;
250     surfaceConfig.height = fHeight;
251     surfaceConfig.presentMode =
252             fDisplayParams->disableVsync() ? wgpu::PresentMode::Immediate : wgpu::PresentMode::Fifo;
253     fSurface.Configure(&surfaceConfig);
254 }
255 
256 }   //namespace skwindow::internal
257