• 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/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