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