1 /*
2  * Copyright 2019 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 "src/gpu/ganesh/dawn/GrDawnCaps.h"
9 
10 #include "src/gpu/KeyBuilder.h"
11 #include "src/gpu/ganesh/GrProgramDesc.h"
12 #include "src/gpu/ganesh/GrProgramInfo.h"
13 #include "src/gpu/ganesh/GrRenderTarget.h"
14 #include "src/gpu/ganesh/GrStencilSettings.h"
15 #include "src/gpu/ganesh/TestFormatColorTypeCombination.h"
16 
GrDawnCaps(const GrContextOptions & contextOptions)17 GrDawnCaps::GrDawnCaps(const GrContextOptions& contextOptions) : INHERITED(contextOptions) {
18     fMipmapSupport = true;
19     fAnisoSupport = true;
20     fBufferMapThreshold = SK_MaxS32;  // FIXME: get this from Dawn?
21     fShaderCaps = std::make_unique<GrShaderCaps>();
22     fMaxTextureSize = fMaxRenderTargetSize = 8192; // FIXME
23     fMaxVertexAttributes = 16; // FIXME
24     fClampToBorderSupport = false;
25     fPerformPartialClearsAsDraws = true;
26     fDynamicStateArrayGeometryProcessorTextureSupport = true;
27     fTwoSidedStencilRefsAndMasksMustMatch = true;
28 
29     // WebGPU zero-initializes resources. https://www.w3.org/TR/webgpu/#security-uninitialized
30     fBuffersAreInitiallyZero = true;
31 
32     fShaderCaps->fFlatInterpolationSupport = true;
33     fShaderCaps->fIntegerSupport = true;
34     // FIXME: each fragment sampler takes two binding slots in Dawn (sampler + texture). Limit to
35     // 6 * 2 = 12, since kMaxBindingsPerGroup is 16 in Dawn, and we need to keep a few for
36     // non-texture bindings. Eventually, we may be able to increase kMaxBindingsPerGroup in Dawn.
37     fShaderCaps->fMaxFragmentSamplers = 6;
38     fShaderCaps->fShaderDerivativeSupport = true;
39     fShaderCaps->fExplicitTextureLodSupport = true;
40 
41     // We haven't yet implemented GrGpu::transferFromBufferToBuffer for Dawn but GrDawnBuffer uses
42     // transfers to implement buffer mapping and updates and transfers must be 4 byte aligned.
43     fTransferFromBufferToBufferAlignment = 4;
44     // Buffer updates are sometimes implemented through transfers in GrDawnBuffer.
45     fBufferUpdateDataPreserveAlignment = 4;
46 
47     this->finishInitialization(contextOptions);
48 }
49 
isFormatSRGB(const GrBackendFormat & format) const50 bool GrDawnCaps::isFormatSRGB(const GrBackendFormat& format) const {
51     return false;
52 }
53 
isFormatTexturable(const GrBackendFormat & format,GrTextureType) const54 bool GrDawnCaps::isFormatTexturable(const GrBackendFormat& format, GrTextureType) const {
55     // Currently, all the formats in GrDawnFormatToPixelConfig are texturable.
56     wgpu::TextureFormat dawnFormat;
57     return format.asDawnFormat(&dawnFormat);
58 }
59 
get_swizzle(const GrBackendFormat & format,GrColorType colorType,bool forOutput)60 static skgpu::Swizzle get_swizzle(const GrBackendFormat& format, GrColorType colorType,
61                                   bool forOutput) {
62     switch (colorType) {
63         case GrColorType::kAlpha_8: // fall through
64         case GrColorType::kAlpha_F16:
65             if (forOutput) {
66                 return skgpu::Swizzle("a000");
67             } else {
68                 return skgpu::Swizzle("000r");
69             }
70         case GrColorType::kGray_8:
71             if (!forOutput) {
72                 return skgpu::Swizzle::RRRA();
73             }
74             break;
75         case GrColorType::kRGB_888x:
76             if (!forOutput) {
77                 return skgpu::Swizzle::RGB1();
78             }
79             break;
80         default:
81             return skgpu::Swizzle::RGBA();
82     }
83     return skgpu::Swizzle::RGBA();
84 }
85 
isFormatRenderable(const GrBackendFormat & format,int sampleCount) const86 bool GrDawnCaps::isFormatRenderable(const GrBackendFormat& format,
87                                     int sampleCount) const {
88     wgpu::TextureFormat dawnFormat;
89     if (!format.isValid() || sampleCount > 1 || !format.asDawnFormat(&dawnFormat)) {
90         return false;
91     }
92 
93     return GrDawnFormatIsRenderable(dawnFormat);
94 }
95 
isFormatAsColorTypeRenderable(GrColorType ct,const GrBackendFormat & format,int sampleCount) const96 bool GrDawnCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format,
97                                                int sampleCount) const {
98     return isFormatRenderable(format, sampleCount);
99 }
100 
surfaceSupportsReadPixels(const GrSurface * surface) const101 GrCaps::SurfaceReadPixelsSupport GrDawnCaps::surfaceSupportsReadPixels(
102       const GrSurface* surface) const {
103     // We currently support readbacks only from Textures and TextureRenderTargets.
104     return surface->asTexture() ? SurfaceReadPixelsSupport::kSupported
105                                 : SurfaceReadPixelsSupport::kUnsupported;
106 }
107 
onSurfaceSupportsWritePixels(const GrSurface * surface) const108 bool GrDawnCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
109     // We currently support writePixels only to Textures and TextureRenderTargets.
110     return surface->asTexture() != nullptr;
111 }
112 
getRenderTargetSampleCount(int requestedCount,const GrBackendFormat & backendFormat) const113 int GrDawnCaps::getRenderTargetSampleCount(int requestedCount,
114                                            const GrBackendFormat& backendFormat) const {
115     wgpu::TextureFormat dawnFormat;
116     if (!backendFormat.asDawnFormat(&dawnFormat)) {
117         return 0;
118     }
119     return GrDawnFormatIsRenderable(dawnFormat) ? 1 : 0;
120 }
121 
maxRenderTargetSampleCount(const GrBackendFormat & format) const122 int GrDawnCaps::maxRenderTargetSampleCount(const GrBackendFormat& format) const {
123     return format.isValid() ? 1 : 0;
124 }
125 
onGetDefaultBackendFormat(GrColorType ct) const126 GrBackendFormat GrDawnCaps::onGetDefaultBackendFormat(GrColorType ct) const {
127     wgpu::TextureFormat format;
128     if (!GrColorTypeToDawnFormat(ct, &format)) {
129         return {};
130     }
131     return GrBackendFormat::MakeDawn(format);
132 }
133 
getBackendFormatFromCompressionType(SkImage::CompressionType type) const134 GrBackendFormat GrDawnCaps::getBackendFormatFromCompressionType(SkImage::CompressionType type) const
135 {
136     return GrBackendFormat();
137 }
138 
onGetReadSwizzle(const GrBackendFormat & format,GrColorType colorType) const139 skgpu::Swizzle GrDawnCaps::onGetReadSwizzle(const GrBackendFormat& format,
140                                             GrColorType colorType) const {
141     return get_swizzle(format, colorType, false);
142 }
143 
getWriteSwizzle(const GrBackendFormat & format,GrColorType colorType) const144 skgpu::Swizzle GrDawnCaps::getWriteSwizzle(const GrBackendFormat& format,
145                                            GrColorType colorType) const {
146     return get_swizzle(format, colorType, true);
147 }
148 
computeFormatKey(const GrBackendFormat & format) const149 uint64_t GrDawnCaps::computeFormatKey(const GrBackendFormat& format) const {
150     wgpu::TextureFormat dawnFormat;
151     SkAssertResult(format.asDawnFormat(&dawnFormat));
152 
153     // Dawn max enum value should always fit in 32 bits.
154 
155     // disabled: no member named 'WGPUTextureFormat_Force32' in namespace 'wgpu'
156     //SkASSERT(dawnFormat <= wgpu::WGPUTextureFormat_Force32);
157     return (uint64_t)dawnFormat;
158 }
159 
onAreColorTypeAndFormatCompatible(GrColorType ct,const GrBackendFormat & format) const160 bool GrDawnCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
161                                                    const GrBackendFormat& format) const {
162     return true;
163 }
164 
165 // FIXME: taken from GrVkPipelineState; refactor.
get_blend_info_key(const GrPipeline & pipeline)166 static uint32_t get_blend_info_key(const GrPipeline& pipeline) {
167     skgpu::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
168 
169     static const uint32_t kBlendWriteShift = 1;
170     static const uint32_t kBlendCoeffShift = 5;
171     static_assert((int)skgpu::BlendCoeff::kLast < (1 << kBlendCoeffShift));
172     static_assert((int)skgpu::BlendEquation::kFirstAdvanced - 1 < 4);
173 
174     uint32_t key = blendInfo.fWritesColor;
175     key |= ((int)blendInfo.fSrcBlend << kBlendWriteShift);
176     key |= ((int)blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
177     key |= ((int)blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
178 
179     return key;
180 }
181 
makeDesc(GrRenderTarget * rt,const GrProgramInfo & programInfo,ProgramDescOverrideFlags overrideFlags) const182 GrProgramDesc GrDawnCaps::makeDesc(GrRenderTarget* rt,
183                                    const GrProgramInfo& programInfo,
184                                    ProgramDescOverrideFlags overrideFlags) const {
185     SkASSERT(overrideFlags == ProgramDescOverrideFlags::kNone);
186     GrProgramDesc desc;
187     GrProgramDesc::Build(&desc, programInfo, *this);
188 
189     wgpu::TextureFormat format;
190     if (!programInfo.backendFormat().asDawnFormat(&format)) {
191         desc.reset();
192         SkASSERT(!desc.isValid());
193         return desc;
194     }
195 
196     skgpu::KeyBuilder b(desc.key());
197     GrStencilSettings stencil = programInfo.nonGLStencilSettings();
198     stencil.genKey(&b, true);
199 
200     // TODO: remove this reliance on the renderTarget
201     bool hasDepthStencil = rt->getStencilAttachment() != nullptr;
202 
203     b.add32(static_cast<uint32_t>(format));
204     b.add32(static_cast<int32_t>(hasDepthStencil));
205     b.add32(get_blend_info_key(programInfo.pipeline()));
206     b.add32(programInfo.primitiveTypeKey());
207 
208     b.flush();
209     return desc;
210 }
211 
212 #if GR_TEST_UTILS
getTestingCombinations() const213 std::vector<GrTest::TestFormatColorTypeCombination> GrDawnCaps::getTestingCombinations() const {
214     std::vector<GrTest::TestFormatColorTypeCombination> combos = {
215         { GrColorType::kAlpha_8,   GrBackendFormat::MakeDawn(wgpu::TextureFormat::R8Unorm)    },
216         { GrColorType::kRGBA_8888, GrBackendFormat::MakeDawn(wgpu::TextureFormat::RGBA8Unorm) },
217         { GrColorType::kRGBA_8888, GrBackendFormat::MakeDawn(wgpu::TextureFormat::BGRA8Unorm) },
218         { GrColorType::kRGB_888x,  GrBackendFormat::MakeDawn(wgpu::TextureFormat::RGBA8Unorm) },
219         { GrColorType::kRGB_888x,  GrBackendFormat::MakeDawn(wgpu::TextureFormat::BGRA8Unorm) },
220         { GrColorType::kBGRA_8888, GrBackendFormat::MakeDawn(wgpu::TextureFormat::BGRA8Unorm) },
221         { GrColorType::kBGRA_8888, GrBackendFormat::MakeDawn(wgpu::TextureFormat::RGBA8Unorm) },
222     };
223 
224 #ifdef SK_DEBUG
225     for (const GrTest::TestFormatColorTypeCombination& combo : combos) {
226         SkASSERT(this->onAreColorTypeAndFormatCompatible(combo.fColorType, combo.fFormat));
227     }
228 #endif
229     return combos;
230 }
231 #endif
232