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