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/DawnUtils.h"
20 #include "include/private/gpu/graphite/ContextOptionsPriv.h"
21 #include "tools/ToolUtils.h"
22 #include "tools/GpuToolUtils.h"
23
24 #include "dawn/dawn_proc.h"
25
26 namespace skwindow::internal {
27
GraphiteDawnWindowContext(const DisplayParams & params,wgpu::TextureFormat swapChainFormat)28 GraphiteDawnWindowContext::GraphiteDawnWindowContext(const DisplayParams& params,
29 wgpu::TextureFormat swapChainFormat)
30 : WindowContext(params)
31 , fSwapChainFormat(swapChainFormat) {
32 WGPUInstanceDescriptor desc{};
33 // need for WaitAny with timeout > 0
34 desc.features.timedWaitAnyEnable = true;
35 fInstance = std::make_unique<dawn::native::Instance>(&desc);
36 }
37
initializeContext(int width,int height)38 void GraphiteDawnWindowContext::initializeContext(int width, int height) {
39 SkASSERT(!fContext);
40
41 fWidth = width;
42 fHeight = height;
43
44 if (!onInitializeContext())
45 return;
46
47 SkASSERT(fDevice);
48 SkASSERT(fSurface);
49 SkASSERT(fSwapChain);
50
51 skgpu::graphite::DawnBackendContext backendContext;
52 backendContext.fInstance = wgpu::Instance(fInstance->Get());
53 backendContext.fDevice = fDevice;
54 backendContext.fQueue = fDevice.GetQueue();
55 // Needed to make synchronous readPixels work:
56 fDisplayParams.fGraphiteContextOptions.fPriv.fStoreContextRefInRecorder = true;
57 fGraphiteContext = skgpu::graphite::ContextFactory::MakeDawn(
58 backendContext, fDisplayParams.fGraphiteContextOptions.fOptions);
59 if (!fGraphiteContext) {
60 SkASSERT(false);
61 return;
62 }
63
64 fGraphiteRecorder = fGraphiteContext->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
65 SkASSERT(fGraphiteRecorder);
66 }
67
68 GraphiteDawnWindowContext::~GraphiteDawnWindowContext() = default;
69
destroyContext()70 void GraphiteDawnWindowContext::destroyContext() {
71 if (!fDevice.Get()) {
72 return;
73 }
74
75 this->onDestroyContext();
76
77 fGraphiteRecorder = nullptr;
78 fGraphiteContext = nullptr;
79 fSwapChain = nullptr;
80 fSurface = nullptr;
81 fDevice = nullptr;
82 }
83
getBackbufferSurface()84 sk_sp<SkSurface> GraphiteDawnWindowContext::getBackbufferSurface() {
85 auto texture = fSwapChain.GetCurrentTexture();
86 skgpu::graphite::DawnTextureInfo info(/*sampleCount=*/1,
87 skgpu::Mipmapped::kNo,
88 fSwapChainFormat,
89 texture.GetUsage(),
90 wgpu::TextureAspect::All);
91 skgpu::graphite::BackendTexture backendTex(texture.Get());
92 SkASSERT(this->graphiteRecorder());
93 auto surface = SkSurfaces::WrapBackendTexture(this->graphiteRecorder(),
94 backendTex,
95 kBGRA_8888_SkColorType,
96 fDisplayParams.fColorSpace,
97 &fDisplayParams.fSurfaceProps);
98 SkASSERT(surface);
99 return surface;
100 }
101
onSwapBuffers()102 void GraphiteDawnWindowContext::onSwapBuffers() {
103 this->snapRecordingAndSubmit();
104 fSwapChain.Present();
105 }
106
setDisplayParams(const DisplayParams & params)107 void GraphiteDawnWindowContext::setDisplayParams(const DisplayParams& params) {
108 this->destroyContext();
109 fDisplayParams = params;
110 this->initializeContext(fWidth, fHeight);
111 }
112
createDevice(wgpu::BackendType type)113 wgpu::Device GraphiteDawnWindowContext::createDevice(wgpu::BackendType type) {
114 DawnProcTable backendProcs = dawn::native::GetProcs();
115 dawnProcSetProcs(&backendProcs);
116
117 static constexpr const char* kAdapterToggles[] = {
118 "allow_unsafe_apis", // Needed for dual-source blending, BufferMapExtendedUsages.
119 "use_user_defined_labels_in_backend",
120 };
121 wgpu::DawnTogglesDescriptor adapterTogglesDesc;
122 adapterTogglesDesc.enabledToggleCount = std::size(kAdapterToggles);
123 adapterTogglesDesc.enabledToggles = kAdapterToggles;
124
125 wgpu::RequestAdapterOptions adapterOptions;
126 adapterOptions.backendType = type;
127 adapterOptions.nextInChain = &adapterTogglesDesc;
128
129 std::vector<dawn::native::Adapter> adapters = fInstance->EnumerateAdapters(&adapterOptions);
130 if (adapters.empty()) {
131 return nullptr;
132 }
133
134 wgpu::Adapter adapter = adapters[0].Get();
135
136 std::vector<wgpu::FeatureName> features;
137 features.push_back(wgpu::FeatureName::SurfaceCapabilities);
138 if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) {
139 features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled);
140 }
141 if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {
142 features.push_back(wgpu::FeatureName::TransientAttachments);
143 }
144 if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) {
145 features.push_back(wgpu::FeatureName::Unorm16TextureFormats);
146 }
147 if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) {
148 features.push_back(wgpu::FeatureName::DualSourceBlending);
149 }
150 if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) {
151 features.push_back(wgpu::FeatureName::FramebufferFetch);
152 }
153 if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) {
154 features.push_back(wgpu::FeatureName::BufferMapExtendedUsages);
155 }
156 if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) {
157 features.push_back(wgpu::FeatureName::TextureCompressionETC2);
158 }
159 if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
160 features.push_back(wgpu::FeatureName::TextureCompressionBC);
161 }
162 if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {
163 features.push_back(wgpu::FeatureName::R8UnormStorage);
164 }
165 if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {
166 features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);
167 }
168
169 wgpu::DeviceDescriptor deviceDescriptor;
170 deviceDescriptor.requiredFeatures = features.data();
171 deviceDescriptor.requiredFeatureCount = features.size();
172 deviceDescriptor.deviceLostCallbackInfo.callback =
173 [](WGPUDeviceImpl *const *, WGPUDeviceLostReason reason, const char* message, void*) {
174 if (reason != WGPUDeviceLostReason_Destroyed &&
175 reason != WGPUDeviceLostReason_InstanceDropped) {
176 SK_ABORT("Device lost: %s\n", message);
177 }
178 };
179
180 wgpu::DawnTogglesDescriptor deviceTogglesDesc;
181
182 if (fDisplayParams.fDisableTintSymbolRenaming) {
183 static constexpr const char* kOptionalDeviceToggles[] = {
184 "disable_symbol_renaming",
185 };
186 deviceTogglesDesc.enabledToggleCount = std::size(kOptionalDeviceToggles);
187 deviceTogglesDesc.enabledToggles = kOptionalDeviceToggles;
188
189 // Insert the toggles descriptor ahead of any existing entries in the chain that might have
190 // been added above.
191 deviceTogglesDesc.nextInChain = deviceDescriptor.nextInChain;
192 deviceDescriptor.nextInChain = &deviceTogglesDesc;
193 }
194
195 auto device = adapter.CreateDevice(&deviceDescriptor);
196 if (!device) {
197 return nullptr;
198 }
199
200 device.SetUncapturedErrorCallback(
201 [](WGPUErrorType type, const char* message, void*) {
202 SkDebugf("Device error: %s\n", message);
203 SkASSERT(false);
204 },
205 nullptr);
206 return device;
207 }
208
createSwapChain()209 wgpu::SwapChain GraphiteDawnWindowContext::createSwapChain() {
210 wgpu::SwapChainDescriptor swapChainDesc;
211 swapChainDesc.usage = wgpu::TextureUsage::RenderAttachment |
212 wgpu::TextureUsage::TextureBinding |
213 wgpu::TextureUsage::CopySrc |
214 wgpu::TextureUsage::CopyDst;
215 swapChainDesc.format = fSwapChainFormat;
216 swapChainDesc.width = fWidth;
217 swapChainDesc.height = fHeight;
218 swapChainDesc.presentMode =
219 fDisplayParams.fDisableVsync ? wgpu::PresentMode::Immediate : wgpu::PresentMode::Fifo;
220 auto swapChain = fDevice.CreateSwapChain(fSurface, &swapChainDesc);
221 SkASSERT(swapChain);
222 return swapChain;
223 }
224
225 } //namespace skwindow::internal
226