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