• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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 "src/gpu/graphite/dawn/DawnCaps.h"
9 
10 #include <algorithm>
11 
12 #include "include/gpu/graphite/TextureInfo.h"
13 #include "src/gpu/graphite/AttachmentTypes.h"
14 #include "src/gpu/graphite/ComputePipelineDesc.h"
15 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
16 #include "src/gpu/graphite/GraphiteResourceKey.h"
17 #include "src/gpu/graphite/UniformManager.h"
18 #include "src/gpu/graphite/dawn/DawnUtilsPriv.h"
19 #include "src/sksl/SkSLUtil.h"
20 
21 namespace {
22 
23 // These are all the valid wgpu::TextureFormat that we currently support in Skia.
24 // They are roughly ordered from most frequently used to least to improve look
25 // up times in arrays.
26 static constexpr wgpu::TextureFormat kFormats[] = {
27     wgpu::TextureFormat::RGBA8Unorm,
28     wgpu::TextureFormat::R8Unorm,
29     wgpu::TextureFormat::BGRA8Unorm,
30     wgpu::TextureFormat::RGBA16Float,
31 
32     wgpu::TextureFormat::Stencil8,
33     wgpu::TextureFormat::Depth32Float,
34     wgpu::TextureFormat::Depth32FloatStencil8,
35 
36     wgpu::TextureFormat::Undefined,
37 };
38 
39 }
40 
41 namespace skgpu::graphite {
42 
DawnCaps(const wgpu::Device & device,const ContextOptions & options)43 DawnCaps::DawnCaps(const wgpu::Device& device, const ContextOptions& options)
44     : Caps() {
45     this->initCaps(device);
46     this->initShaderCaps();
47     this->initFormatTable(device);
48     this->finishInitialization(options);
49 }
50 
51 DawnCaps::~DawnCaps() = default;
52 
onIsTexturable(const TextureInfo & info) const53 bool DawnCaps::onIsTexturable(const TextureInfo& info) const {
54     if (!(info.dawnTextureSpec().fUsage & wgpu::TextureUsage::TextureBinding)) {
55         return false;
56     }
57     return this->isTexturable(info.dawnTextureSpec().fFormat);
58 }
59 
isTexturable(wgpu::TextureFormat format) const60 bool DawnCaps::isTexturable(wgpu::TextureFormat format) const {
61     const FormatInfo& formatInfo = this->getFormatInfo(format);
62     return SkToBool(FormatInfo::kTexturable_Flag & formatInfo.fFlags);
63 }
64 
isRenderable(const TextureInfo & info) const65 bool DawnCaps::isRenderable(const TextureInfo& info) const {
66     return info.dawnTextureSpec().fUsage & wgpu::TextureUsage::RenderAttachment &&
67     this->isRenderable(info.dawnTextureSpec().fFormat, info.numSamples());
68 }
69 
maxRenderTargetSampleCount(wgpu::TextureFormat format) const70 uint32_t DawnCaps::maxRenderTargetSampleCount(wgpu::TextureFormat format) const {
71     const FormatInfo& formatInfo = this->getFormatInfo(format);
72     if (!SkToBool(formatInfo.fFlags & FormatInfo::kRenderable_Flag)) {
73         return 0;
74     }
75     if (SkToBool(formatInfo.fFlags & FormatInfo::kMSAA_Flag)) {
76         return 8;
77     } else {
78         return 1;
79     }
80 }
81 
isRenderable(wgpu::TextureFormat format,uint32_t sampleCount) const82 bool DawnCaps::isRenderable(wgpu::TextureFormat format, uint32_t sampleCount) const {
83     return sampleCount <= this->maxRenderTargetSampleCount(format);
84 }
85 
getDefaultSampledTextureInfo(SkColorType colorType,Mipmapped mipmapped,Protected,Renderable renderable) const86 TextureInfo DawnCaps::getDefaultSampledTextureInfo(SkColorType colorType,
87                                                    Mipmapped mipmapped,
88                                                    Protected,
89                                                    Renderable renderable) const {
90     wgpu::TextureUsage usage = wgpu::TextureUsage::TextureBinding |
91                                wgpu::TextureUsage::CopyDst |
92                                wgpu::TextureUsage::CopySrc;
93     if (renderable == Renderable::kYes) {
94         usage |= wgpu::TextureUsage::RenderAttachment;
95     }
96 
97     wgpu::TextureFormat format = this->getFormatFromColorType(colorType);
98     if (format == wgpu::TextureFormat::Undefined) {
99         SkDebugf("colorType=%d is not supported\n", static_cast<int>(colorType));
100         return {};
101     }
102 
103     DawnTextureInfo info;
104     info.fSampleCount = 1;
105     info.fMipmapped = mipmapped;
106     info.fFormat = format;
107     info.fUsage = usage;
108 
109     return info;
110 }
111 
getDefaultMSAATextureInfo(const TextureInfo & singleSampledInfo,Discardable discardable) const112 TextureInfo DawnCaps::getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
113                                                 Discardable discardable) const {
114     const DawnTextureSpec& singleSpec = singleSampledInfo.dawnTextureSpec();
115 
116     DawnTextureInfo info;
117     info.fSampleCount = this->defaultMSAASamples();
118     info.fMipmapped   = Mipmapped::kNo;
119     info.fFormat      = singleSpec.fFormat;
120     info.fUsage       = wgpu::TextureUsage::RenderAttachment;
121     return info;
122 }
123 
getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> depthStencilType,uint32_t sampleCount,Protected) const124 TextureInfo DawnCaps::getDefaultDepthStencilTextureInfo(
125     SkEnumBitMask<DepthStencilFlags> depthStencilType,
126     uint32_t sampleCount,
127     Protected) const {
128     DawnTextureInfo info;
129     info.fSampleCount = sampleCount;
130     info.fMipmapped   = Mipmapped::kNo;
131     info.fFormat      = DawnDepthStencilFlagsToFormat(depthStencilType);
132     info.fUsage       = wgpu::TextureUsage::RenderAttachment;
133     return info;
134 }
135 
getColorTypeInfo(SkColorType colorType,const TextureInfo & textureInfo) const136 const Caps::ColorTypeInfo* DawnCaps::getColorTypeInfo(SkColorType colorType,
137                                                       const TextureInfo& textureInfo) const {
138     auto dawnFormat = textureInfo.dawnTextureSpec().fFormat;
139     if (dawnFormat == wgpu::TextureFormat::Undefined) {
140         SkASSERT(false);
141         return nullptr;
142     }
143 
144     const FormatInfo& info = this->getFormatInfo(dawnFormat);
145     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
146         const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
147         if (ctInfo.fColorType == colorType) {
148             return &ctInfo;
149         }
150     }
151 
152     SkASSERT(false);
153     return nullptr;
154 }
155 
supportsWritePixels(const TextureInfo & textureInfo) const156 bool DawnCaps::supportsWritePixels(const TextureInfo& textureInfo) const {
157     const auto& spec = textureInfo.dawnTextureSpec();
158     return spec.fUsage & wgpu::TextureUsage::CopyDst;
159 }
160 
supportsReadPixels(const TextureInfo & textureInfo) const161 bool DawnCaps::supportsReadPixels(const TextureInfo& textureInfo) const {
162     const auto& spec = textureInfo.dawnTextureSpec();
163     return spec.fUsage & wgpu::TextureUsage::CopySrc;
164 }
165 
supportedWritePixelsColorType(SkColorType dstColorType,const TextureInfo & dstTextureInfo,SkColorType srcColorType) const166 SkColorType DawnCaps::supportedWritePixelsColorType(SkColorType dstColorType,
167                                                     const TextureInfo& dstTextureInfo,
168                                                     SkColorType srcColorType) const {
169     SkASSERT(false);
170     return kUnknown_SkColorType;
171 }
172 
supportedReadPixelsColorType(SkColorType srcColorType,const TextureInfo & srcTextureInfo,SkColorType dstColorType) const173 SkColorType DawnCaps::supportedReadPixelsColorType(SkColorType srcColorType,
174                                                    const TextureInfo& srcTextureInfo,
175                                                    SkColorType dstColorType) const {
176     auto dawnFormat = getFormatFromColorType(srcColorType);
177     const FormatInfo& info = this->getFormatInfo(dawnFormat);
178     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
179         const auto& ctInfo = info.fColorTypeInfos[i];
180         if (ctInfo.fColorType == srcColorType) {
181             return srcColorType;
182         }
183     }
184     return kUnknown_SkColorType;
185 }
186 
initCaps(const wgpu::Device & device)187 void DawnCaps::initCaps(const wgpu::Device& device) {
188     wgpu::SupportedLimits limits;
189     if (!device.GetLimits(&limits)) {
190         SkASSERT(false);
191     }
192     fMaxTextureSize = limits.limits.maxTextureDimension2D;
193 
194     fRequiredTransferBufferAlignment = 4;
195     fRequiredUniformBufferAlignment = 256;
196     fRequiredStorageBufferAlignment = fRequiredUniformBufferAlignment;
197 
198     // Dawn requires 256 bytes per row alignment for buffer texture copies.
199     fTextureDataRowBytesAlignment = 256;
200 
201     fResourceBindingReqs.fUniformBufferLayout = Layout::kStd140;
202     fResourceBindingReqs.fStorageBufferLayout = Layout::kStd430;
203     fResourceBindingReqs.fSeparateTextureAndSamplerBinding = true;
204 
205     // TODO: support storage buffer
206     fStorageBufferSupport = false;
207     fStorageBufferPreferred = false;
208 
209     fDrawBufferCanBeMapped = false;
210 
211     // TODO: support clamp to border.
212     fClampToBorderSupport = false;
213 }
214 
initShaderCaps()215 void DawnCaps::initShaderCaps() {
216     SkSL::ShaderCaps* shaderCaps = fShaderCaps.get();
217 
218     // WGSL does not support infinities regardless of hardware support. There are discussions around
219     // enabling it using an extension in the future.
220     shaderCaps->fInfinitySupport = false;
221 }
222 
initFormatTable(const wgpu::Device & device)223 void DawnCaps::initFormatTable(const wgpu::Device& device) {
224     FormatInfo* info;
225     // Format: RGBA8Unorm
226     {
227         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::RGBA8Unorm)];
228         info->fFlags = FormatInfo::kAllFlags;
229         info->fColorTypeInfoCount = 2;
230         info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
231         int ctIdx = 0;
232         // Format: RGBA8Unorm, Surface: kRGBA_8888
233         {
234             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
235             ctInfo.fColorType = kRGBA_8888_SkColorType;
236             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
237         }
238         // Format: RGBA8Unorm, Surface: kRGB_888x
239         {
240             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
241             ctInfo.fColorType = kRGB_888x_SkColorType;
242             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
243             ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
244         }
245     }
246 
247 
248     // Format: R8Unorm
249     {
250         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::R8Unorm)];
251         info->fFlags = FormatInfo::kAllFlags;
252         info->fColorTypeInfoCount = 3;
253         info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
254         int ctIdx = 0;
255         // Format: R8Unorm, Surface: kR8_unorm
256         {
257             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
258             ctInfo.fColorType = kR8_unorm_SkColorType;
259             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
260         }
261         // Format: R8Unorm, Surface: kAlpha_8
262         {
263             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
264             ctInfo.fColorType = kAlpha_8_SkColorType;
265             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
266             ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
267             ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
268         }
269         // Format: R8Unorm, Surface: kGray_8
270         {
271             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
272             ctInfo.fColorType = kGray_8_SkColorType;
273             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
274             ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
275         }
276     }
277 
278     // Format: BGRA8Unorm
279     {
280         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::BGRA8Unorm)];
281         info->fFlags = FormatInfo::kAllFlags;
282         info->fColorTypeInfoCount = 1;
283         info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
284         int ctIdx = 0;
285         // Format: BGRA8Unorm, Surface: kBGRA_8888
286         {
287             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
288             ctInfo.fColorType = kBGRA_8888_SkColorType;
289             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
290         }
291     }
292 
293     // Format: RGBA16Float
294     {
295         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::RGBA16Float)];
296         info->fFlags = FormatInfo::kAllFlags;
297         info->fColorTypeInfoCount = 1;
298         info->fColorTypeInfos.reset(new ColorTypeInfo[info->fColorTypeInfoCount]());
299         int ctIdx = 0;
300         // Format: RGBA16Float, Surface: RGBA_F16
301         {
302             auto& ctInfo = info->fColorTypeInfos[ctIdx++];
303             ctInfo.fColorType = kRGBA_F16_SkColorType;
304             ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
305         }
306     }
307 
308     /*
309      * Non-color formats
310      */
311 
312     // Format: Stencil8
313     {
314         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::Stencil8)];
315         info->fFlags = FormatInfo::kMSAA_Flag;
316         info->fColorTypeInfoCount = 0;
317     }
318 
319     // Format: Depth32Float
320     {
321         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::Depth32Float)];
322         info->fFlags = FormatInfo::kMSAA_Flag;
323         info->fColorTypeInfoCount = 0;
324     }
325 
326     // Format: Depth32Float_Stencil8
327     {
328         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::Depth32FloatStencil8)];
329         info->fFlags = FormatInfo::kMSAA_Flag;
330         info->fColorTypeInfoCount = 0;
331     }
332 
333     // Format: Undefined
334     {
335         info = &fFormatTable[GetFormatIndex(wgpu::TextureFormat::Undefined)];
336         info->fFlags = 0;
337         info->fColorTypeInfoCount = 0;
338     }
339 
340     ////////////////////////////////////////////////////////////////////////////
341     // Map SkColorTypes (used for creating SkSurfaces) to wgpu::TextureFormat.
342     // The order in which the formats are passed into the setColorType function
343     // indicates the priority in selecting which format we use for a given
344     // SkColorType.
345 
346     std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, wgpu::TextureFormat::Undefined);
347 
348     this->setColorType(kAlpha_8_SkColorType,          { wgpu::TextureFormat::R8Unorm });
349     this->setColorType(kRGBA_8888_SkColorType,        { wgpu::TextureFormat::RGBA8Unorm });
350     this->setColorType(kRGB_888x_SkColorType,         { wgpu::TextureFormat::RGBA8Unorm });
351     this->setColorType(kBGRA_8888_SkColorType,        { wgpu::TextureFormat::BGRA8Unorm });
352     this->setColorType(kGray_8_SkColorType,           { wgpu::TextureFormat::R8Unorm });
353     this->setColorType(kR8_unorm_SkColorType,         { wgpu::TextureFormat::R8Unorm });
354     this->setColorType(kRGBA_F16_SkColorType,         { wgpu::TextureFormat::RGBA16Float });
355 }
356 
357 // static
GetFormatIndex(wgpu::TextureFormat format)358 size_t DawnCaps::GetFormatIndex(wgpu::TextureFormat format) {
359     for (size_t i = 0; i < std::size(kFormats); ++i) {
360         if (format == kFormats[i]) {
361             return i;
362         }
363         if (kFormats[i] == wgpu::TextureFormat::Undefined) {
364             SkDEBUGFAILF("Not supported wgpu::TextureFormat: %d\n", format);
365             return i;
366         }
367     }
368     SkUNREACHABLE;
369     return 0;
370 }
371 
setColorType(SkColorType colorType,std::initializer_list<wgpu::TextureFormat> formats)372 void DawnCaps::setColorType(SkColorType colorType,
373                             std::initializer_list<wgpu::TextureFormat> formats) {
374     static_assert(std::tuple_size<decltype(fFormatTable)>::value == std::size(kFormats),
375                   "Size is not same for DawnCaps::fFormatTable and kFormats");
376 #ifdef SK_DEBUG
377     for (size_t i = 0; i < std::size(fFormatTable); ++i) {
378         const auto& formatInfo = fFormatTable[i];
379         for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
380             const auto& ctInfo = formatInfo.fColorTypeInfos[j];
381             if (ctInfo.fColorType == colorType) {
382                 bool found = false;
383                 for (auto it = formats.begin(); it != formats.end(); ++it) {
384                     if (kFormats[i] == *it) {
385                         found = true;
386                     }
387                 }
388                 SkASSERT(found);
389             }
390         }
391     }
392 #endif
393     int idx = static_cast<int>(colorType);
394     for (auto it = formats.begin(); it != formats.end(); ++it) {
395         const auto& info = this->getFormatInfo(*it);
396         for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
397             if (info.fColorTypeInfos[i].fColorType == colorType) {
398                 fColorTypeToFormatTable[idx] = *it;
399                 return;
400             }
401         }
402     }
403 }
404 
getRenderPassDescKey(const RenderPassDesc & renderPassDesc) const405 uint64_t DawnCaps::getRenderPassDescKey(const RenderPassDesc& renderPassDesc) const {
406     DawnTextureInfo colorInfo, depthStencilInfo;
407     renderPassDesc.fColorAttachment.fTextureInfo.getDawnTextureInfo(&colorInfo);
408     renderPassDesc.fDepthStencilAttachment.fTextureInfo.getDawnTextureInfo(&depthStencilInfo);
409     SkASSERT(static_cast<uint32_t>(colorInfo.fFormat) <= 0xffff &&
410              static_cast<uint32_t>(depthStencilInfo.fFormat) <= 0xffff);
411     uint32_t colorAttachmentKey =
412             static_cast<uint32_t>(colorInfo.fFormat) << 16 | colorInfo.fSampleCount;
413     uint32_t dsAttachmentKey =
414             static_cast<uint32_t>(depthStencilInfo.fFormat) << 16 | depthStencilInfo.fSampleCount;
415     return (((uint64_t) colorAttachmentKey) << 32) | dsAttachmentKey;
416 }
417 
makeGraphicsPipelineKey(const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc) const418 UniqueKey DawnCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc,
419                                             const RenderPassDesc& renderPassDesc) const {
420     UniqueKey pipelineKey;
421     {
422         static const skgpu::UniqueKey::Domain kGraphicsPipelineDomain = UniqueKey::GenerateDomain();
423         // 4 uint32_t's (render step id, paint id, uint64 RenderPass desc)
424         UniqueKey::Builder builder(&pipelineKey, kGraphicsPipelineDomain, 4, "GraphicsPipeline");
425         // add GraphicsPipelineDesc key
426         builder[0] = pipelineDesc.renderStepID();
427         builder[1] = pipelineDesc.paintParamsID().asUInt();
428 
429         // add RenderPassDesc key
430         uint64_t renderPassKey = this->getRenderPassDescKey(renderPassDesc);
431         builder[2] = renderPassKey & 0xFFFFFFFF;
432         builder[3] = (renderPassKey >> 32) & 0xFFFFFFFF;
433         builder.finish();
434     }
435 
436     return pipelineKey;
437 }
438 
makeComputePipelineKey(const ComputePipelineDesc & pipelineDesc) const439 UniqueKey DawnCaps::makeComputePipelineKey(const ComputePipelineDesc& pipelineDesc) const {
440     SkASSERT(false);
441     return {};
442 }
443 
buildKeyForTexture(SkISize dimensions,const TextureInfo & info,ResourceType type,Shareable shareable,GraphiteResourceKey * key) const444 void DawnCaps::buildKeyForTexture(SkISize dimensions,
445                                   const TextureInfo& info,
446                                   ResourceType type,
447                                   Shareable shareable,
448                                   GraphiteResourceKey* key) const {
449     const DawnTextureSpec& dawnSpec = info.dawnTextureSpec();
450 
451     SkASSERT(!dimensions.isEmpty());
452 
453     SkASSERT(dawnSpec.fFormat != wgpu::TextureFormat::Undefined);
454     uint32_t formatKey = static_cast<uint32_t>(dawnSpec.fFormat);
455 
456     uint32_t samplesKey = SamplesToKey(info.numSamples());
457     // We don't have to key the number of mip levels because it is inherit in the combination of
458     // isMipped and dimensions.
459     bool isMipped = info.mipmapped() == Mipmapped::kYes;
460 
461     // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
462     // amounts in the asserts must be less than or equal to 32.
463     SkASSERT(samplesKey                             < (1u << 3));
464     SkASSERT(static_cast<uint32_t>(isMipped)        < (1u << 1));
465     SkASSERT(static_cast<uint32_t>(dawnSpec.fUsage) < (1u << 5));
466 
467     // We need two uint32_ts for dimensions, 1 for format, and 1 for the rest of the key;
468     static int kNum32DataCnt = 2 + 1 + 1;
469 
470     GraphiteResourceKey::Builder builder(key, type, kNum32DataCnt, shareable);
471 
472     builder[0] = dimensions.width();
473     builder[1] = dimensions.height();
474     builder[2] = formatKey;
475     builder[3] = (samplesKey                                   << 0) |
476                  (static_cast<uint32_t>(isMipped)              << 3) |
477                  (static_cast<uint32_t>(dawnSpec.fUsage)       << 4);
478 }
479 
480 } // namespace skgpu::graphite
481