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.featureLevel =
146 type == wgpu::BackendType::OpenGL || type == wgpu::BackendType::OpenGLES
147 ? wgpu::FeatureLevel::Compatibility
148 : wgpu::FeatureLevel::Core;
149 adapterOptions.nextInChain = &togglesDesc;
150
151 std::vector<dawn::native::Adapter> adapters = fInstance->EnumerateAdapters(&adapterOptions);
152 if (adapters.empty()) {
153 return nullptr;
154 }
155
156 wgpu::Adapter adapter = adapters[0].Get();
157
158 std::vector<wgpu::FeatureName> features;
159 if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) {
160 features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled);
161 }
162 if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {
163 features.push_back(wgpu::FeatureName::TransientAttachments);
164 }
165 if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) {
166 features.push_back(wgpu::FeatureName::Unorm16TextureFormats);
167 }
168 if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) {
169 features.push_back(wgpu::FeatureName::DualSourceBlending);
170 }
171 if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) {
172 features.push_back(wgpu::FeatureName::FramebufferFetch);
173 }
174 if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) {
175 features.push_back(wgpu::FeatureName::BufferMapExtendedUsages);
176 }
177 if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) {
178 features.push_back(wgpu::FeatureName::TextureCompressionETC2);
179 }
180 if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
181 features.push_back(wgpu::FeatureName::TextureCompressionBC);
182 }
183 if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
184 features.push_back(wgpu::FeatureName::R8UnormStorage);
185 }
186 if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
187 features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
188 }
189 if (adapter.HasFeature(wgpu::FeatureName::DawnPartialLoadResolveTexture)) {
190 features.push_back(wgpu::FeatureName::DawnPartialLoadResolveTexture);
191 }
192 if (adapter.HasFeature(wgpu::FeatureName::TimestampQuery)) {
193 features.push_back(wgpu::FeatureName::TimestampQuery);
194 }
195 if (adapter.HasFeature(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment)) {
196 features.push_back(wgpu::FeatureName::DawnTexelCopyBufferRowAlignment);
197 }
198
199 wgpu::DeviceDescriptor deviceDescriptor;
200 deviceDescriptor.requiredFeatures = features.data();
201 deviceDescriptor.requiredFeatureCount = features.size();
202 deviceDescriptor.nextInChain = &togglesDesc;
203 deviceDescriptor.SetDeviceLostCallback(
204 wgpu::CallbackMode::AllowSpontaneous,
205 [](const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) {
206 if (reason != wgpu::DeviceLostReason::Destroyed &&
207 reason != wgpu::DeviceLostReason::InstanceDropped) {
208 SK_ABORT("Device lost: %s\n", message);
209 }
210 });
211 deviceDescriptor.SetUncapturedErrorCallback(
212 [](const wgpu::Device&, wgpu::ErrorType, const char* message) {
213 SkDebugf("Device error: %s\n", message);
214 SkASSERT(false);
215 });
216
217 wgpu::DawnTogglesDescriptor deviceTogglesDesc;
218
219 if (fDisplayParams->graphiteTestOptions()->fTestOptions.fDisableTintSymbolRenaming) {
220 static constexpr const char* kOptionalDeviceToggles[] = {
221 "disable_symbol_renaming",
222 };
223 deviceTogglesDesc.enabledToggleCount = std::size(kOptionalDeviceToggles);
224 deviceTogglesDesc.enabledToggles = kOptionalDeviceToggles;
225
226 // Insert the toggles descriptor ahead of any existing entries in the chain that might have
227 // been added above.
228 deviceTogglesDesc.nextInChain = deviceDescriptor.nextInChain;
229 deviceDescriptor.nextInChain = &deviceTogglesDesc;
230 }
231
232 auto device = adapter.CreateDevice(&deviceDescriptor);
233 if (!device) {
234 return nullptr;
235 }
236
237 return device;
238 }
239
configureSurface()240 void GraphiteDawnWindowContext::configureSurface() {
241 SkASSERT(fDevice);
242 SkASSERT(fSurface);
243
244 wgpu::SurfaceConfiguration surfaceConfig;
245 surfaceConfig.device = fDevice;
246 surfaceConfig.format = fSurfaceFormat;
247 surfaceConfig.usage = wgpu::TextureUsage::RenderAttachment |
248 wgpu::TextureUsage::TextureBinding |
249 wgpu::TextureUsage::CopySrc |
250 wgpu::TextureUsage::CopyDst;
251 surfaceConfig.width = fWidth;
252 surfaceConfig.height = fHeight;
253 surfaceConfig.presentMode =
254 fDisplayParams->disableVsync() ? wgpu::PresentMode::Immediate : wgpu::PresentMode::Fifo;
255 fSurface.Configure(&surfaceConfig);
256 }
257
258 } //namespace skwindow::internal
259