xref: /third_party/skia/src/gpu/d3d/GrD3DCaps.cpp (revision cb93a386)
1/*
2 * Copyright 2020 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 "include/gpu/GrBackendSurface.h"
9#include "include/gpu/GrContextOptions.h"
10#include "include/gpu/d3d/GrD3DBackendContext.h"
11#include "include/gpu/d3d/GrD3DTypes.h"
12
13#include "src/core/SkCompressedDataUtils.h"
14#include "src/gpu/GrBackendUtils.h"
15#include "src/gpu/GrProgramDesc.h"
16#include "src/gpu/GrProgramInfo.h"
17#include "src/gpu/GrShaderCaps.h"
18#include "src/gpu/GrStencilSettings.h"
19#include "src/gpu/d3d/GrD3DCaps.h"
20#include "src/gpu/d3d/GrD3DGpu.h"
21#include "src/gpu/d3d/GrD3DRenderTarget.h"
22#include "src/gpu/d3d/GrD3DTexture.h"
23#include "src/gpu/d3d/GrD3DUtil.h"
24
25GrD3DCaps::GrD3DCaps(const GrContextOptions& contextOptions, IDXGIAdapter1* adapter,
26                     ID3D12Device* device)
27        : INHERITED(contextOptions) {
28    /**************************************************************************
29     * GrCaps fields
30     **************************************************************************/
31    fMipmapSupport = true;   // always available in Direct3D
32    fNPOTTextureTileSupport = true;  // available in feature level 10_0 and up
33    fReuseScratchTextures = true; //TODO: figure this out
34    fGpuTracingSupport = false; //TODO: figure this out
35    fOversizedStencilSupport = false; //TODO: figure this out
36    fDrawInstancedSupport = true;
37    fNativeDrawIndirectSupport = true;
38
39    fSemaphoreSupport = true;
40    fFenceSyncSupport = true;
41    // TODO: implement these
42    fCrossContextTextureSupport = false;
43    fHalfFloatVertexAttributeSupport = false;
44
45    // We always copy in/out of a transfer buffer so it's trivial to support row bytes.
46    fReadPixelsRowBytesSupport = true;
47    fWritePixelsRowBytesSupport = true;
48    fTransferPixelsToRowBytesSupport = true;
49
50    fTransferFromBufferToTextureSupport = true;
51    fTransferFromSurfaceToBufferSupport = true;
52
53    fMaxRenderTargetSize = 16384;  // minimum required by feature level 11_0
54    fMaxTextureSize = 16384;       // minimum required by feature level 11_0
55
56    fTransferBufferAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
57
58    // TODO: implement
59    fDynamicStateArrayGeometryProcessorTextureSupport = false;
60
61    fShaderCaps = std::make_unique<GrShaderCaps>();
62
63    this->init(contextOptions, adapter, device);
64}
65
66bool GrD3DCaps::canCopyTexture(DXGI_FORMAT dstFormat, int dstSampleCnt,
67                               DXGI_FORMAT srcFormat, int srcSampleCnt) const {
68    if ((dstSampleCnt > 1 || srcSampleCnt > 1) && dstSampleCnt != srcSampleCnt) {
69        return false;
70    }
71
72    // D3D allows us to copy within the same format family but doesn't do conversions
73    // so we require strict identity.
74    return srcFormat == dstFormat;
75}
76
77bool GrD3DCaps::canCopyAsResolve(DXGI_FORMAT dstFormat, int dstSampleCnt,
78                                 DXGI_FORMAT srcFormat, int srcSampleCnt) const {
79    // The src surface must be multisampled.
80    if (srcSampleCnt <= 1) {
81        return false;
82    }
83
84    // The dst must not be multisampled.
85    if (dstSampleCnt > 1) {
86        return false;
87    }
88
89    // Surfaces must have the same format.
90    // D3D12 can resolve between typeless and non-typeless formats, but we are not using
91    // typeless formats. It's not possible to resolve within the same format family otherwise.
92    if (srcFormat != dstFormat) {
93        return false;
94    }
95
96    return true;
97}
98
99bool GrD3DCaps::onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
100                                 const SkIRect& srcRect, const SkIPoint& dstPoint) const {
101    if (src->isProtected() == GrProtected::kYes && dst->isProtected() != GrProtected::kYes) {
102        return false;
103    }
104
105    int dstSampleCnt = 0;
106    int srcSampleCnt = 0;
107    if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) {
108        dstSampleCnt = rtProxy->numSamples();
109    }
110    if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) {
111        srcSampleCnt = rtProxy->numSamples();
112    }
113    SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy()));
114    SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy()));
115
116    DXGI_FORMAT dstFormat, srcFormat;
117    SkAssertResult(dst->backendFormat().asDxgiFormat(&dstFormat));
118    SkAssertResult(src->backendFormat().asDxgiFormat(&srcFormat));
119
120    return this->canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt) ||
121           this->canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt);
122}
123
124void GrD3DCaps::init(const GrContextOptions& contextOptions, IDXGIAdapter1* adapter,
125                     ID3D12Device* device) {
126    D3D_FEATURE_LEVEL featureLevels[] = {
127        D3D_FEATURE_LEVEL_11_0,
128        D3D_FEATURE_LEVEL_11_1,
129        D3D_FEATURE_LEVEL_12_0,
130        D3D_FEATURE_LEVEL_12_1,
131    };
132    D3D12_FEATURE_DATA_FEATURE_LEVELS flDesc = {};
133    flDesc.NumFeatureLevels = _countof(featureLevels);
134    flDesc.pFeatureLevelsRequested = featureLevels;
135    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &flDesc,
136                                                     sizeof(flDesc)));
137    // This had better be true
138    SkASSERT(flDesc.MaxSupportedFeatureLevel >= D3D_FEATURE_LEVEL_11_0);
139
140    DXGI_ADAPTER_DESC adapterDesc;
141    GR_D3D_CALL_ERRCHECK(adapter->GetDesc(&adapterDesc));
142
143    D3D12_FEATURE_DATA_D3D12_OPTIONS optionsDesc;
144    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &optionsDesc,
145                                                     sizeof(optionsDesc)));
146
147
148    // See https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
149    if (D3D12_RESOURCE_BINDING_TIER_1 == optionsDesc.ResourceBindingTier) {
150        fMaxPerStageShaderResourceViews = 128;
151        if (D3D_FEATURE_LEVEL_11_0 == flDesc.MaxSupportedFeatureLevel) {
152            fMaxPerStageUnorderedAccessViews = 8;
153        } else {
154            fMaxPerStageUnorderedAccessViews = 64;
155        }
156    } else {
157        // The doc above says "full heap", but practically it seems like it should be
158        // limited by the maximum number of samplers in a heap
159        fMaxPerStageUnorderedAccessViews = 2032;
160        fMaxPerStageShaderResourceViews = 2032;
161    }
162
163    fStandardSwizzleLayoutSupport = (optionsDesc.StandardSwizzle64KBSupported);
164
165    D3D12_FEATURE_DATA_D3D12_OPTIONS2 optionsDesc2;
166    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &optionsDesc2,
167                                                     sizeof(optionsDesc2)));
168    fResolveSubresourceRegionSupport = (optionsDesc2.ProgrammableSamplePositionsTier !=
169                                        D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED);
170
171    this->initGrCaps(optionsDesc, device);
172    this->initShaderCaps(adapterDesc.VendorId, optionsDesc);
173
174    this->initFormatTable(adapterDesc, device);
175    this->initStencilFormat(device);
176
177    if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
178        this->applyDriverCorrectnessWorkarounds(adapterDesc.VendorId);
179    }
180
181    this->finishInitialization(contextOptions);
182}
183
184void GrD3DCaps::initGrCaps(const D3D12_FEATURE_DATA_D3D12_OPTIONS& optionsDesc,
185                           ID3D12Device* device) {
186    // We assume a minimum of Shader Model 5.1, which allows at most 32 vertex inputs.
187    fMaxVertexAttributes = 32;
188
189    // Can use standard sample locations
190    fSampleLocationsSupport = true;
191
192    if (D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED !=
193            optionsDesc.ConservativeRasterizationTier) {
194        fConservativeRasterSupport = true;
195    }
196
197    fWireframeSupport = true;
198
199    // Feature level 11_0 and up support up to 16K in texture dimension
200    fMaxTextureSize = 16384;
201    // There's no specific cap for RT size, so use texture size
202    fMaxRenderTargetSize = fMaxTextureSize;
203    if (fDriverBugWorkarounds.max_texture_size_limit_4096) {
204        fMaxTextureSize = std::min(fMaxTextureSize, 4096);
205    }
206    // Our render targets are always created with textures as the color
207    // attachment, hence this min:
208    fMaxRenderTargetSize = fMaxTextureSize;
209
210    fMaxPreferredRenderTargetSize = fMaxRenderTargetSize;
211
212    // Assuming since we will always map in the end to upload the data we might as well just map
213    // from the get go. There is no hard data to suggest this is faster or slower.
214    fBufferMapThreshold = 0;
215
216    fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag | kAsyncRead_MapFlag;
217
218    fOversizedStencilSupport = true;
219
220    fTwoSidedStencilRefsAndMasksMustMatch = true;
221
222    // Advanced blend modes don't appear to be supported.
223}
224
225void GrD3DCaps::initShaderCaps(int vendorID, const D3D12_FEATURE_DATA_D3D12_OPTIONS& optionsDesc) {
226    GrShaderCaps* shaderCaps = fShaderCaps.get();
227    shaderCaps->fVersionDeclString = "#version 330\n";
228
229    // Shader Model 5 supports all of the following:
230    shaderCaps->fUsesPrecisionModifiers = true;
231    shaderCaps->fFlatInterpolationSupport = true;
232    // Flat interpolation appears to be slow on Qualcomm GPUs. This was tested in GL and is assumed
233    // to be true with D3D as well.
234    shaderCaps->fPreferFlatInterpolation = kQualcomm_D3DVendor != vendorID;
235
236    shaderCaps->fSampleMaskSupport = true;
237
238    shaderCaps->fShaderDerivativeSupport = true;
239
240    shaderCaps->fDualSourceBlendingSupport = true;
241
242    shaderCaps->fIntegerSupport = true;
243    shaderCaps->fNonsquareMatrixSupport = true;
244    // TODO(skia:12352) HLSL does not expose asinh/acosh/atanh
245    shaderCaps->fInverseHyperbolicSupport = false;
246    shaderCaps->fVertexIDSupport = true;
247    shaderCaps->fInfinitySupport = true;
248    shaderCaps->fNonconstantArrayIndexSupport = true;
249    shaderCaps->fBitManipulationSupport = true;
250
251    shaderCaps->fFloatIs32Bits = true;
252    shaderCaps->fHalfIs32Bits =
253        D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE == optionsDesc.MinPrecisionSupport;
254
255    // See https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
256    // The maximum number of samplers in a shader-visible descriptor heap is 2048, but
257    // 16 of those are reserved for the driver.
258    shaderCaps->fMaxFragmentSamplers =
259        (D3D12_RESOURCE_BINDING_TIER_1 == optionsDesc.ResourceBindingTier) ? 16 : 2032;
260}
261
262void GrD3DCaps::applyDriverCorrectnessWorkarounds(int vendorID) {
263    // Nothing yet.
264}
265
266
267bool stencil_format_supported(ID3D12Device* device, DXGI_FORMAT format) {
268    D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupportDesc;
269    formatSupportDesc.Format = format;
270    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT,
271                                                     &formatSupportDesc,
272                                                     sizeof(formatSupportDesc)));
273    return SkToBool(D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL & formatSupportDesc.Support1);
274}
275
276void GrD3DCaps::initStencilFormat(ID3D12Device* device) {
277    if (stencil_format_supported(device, DXGI_FORMAT_D24_UNORM_S8_UINT)) {
278        fPreferredStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
279    } else {
280        SkASSERT(stencil_format_supported(device, DXGI_FORMAT_D32_FLOAT_S8X24_UINT));
281        fPreferredStencilFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
282    }
283}
284
285// These are all the valid DXGI_FORMATs that we support in Skia. They are roughly ordered from most
286// frequently used to least to improve look up times in arrays.
287static constexpr DXGI_FORMAT kDxgiFormats[] = {
288    DXGI_FORMAT_R8G8B8A8_UNORM,
289    DXGI_FORMAT_R8_UNORM,
290    DXGI_FORMAT_B8G8R8A8_UNORM,
291    DXGI_FORMAT_B5G6R5_UNORM,
292    DXGI_FORMAT_R16G16B16A16_FLOAT,
293    DXGI_FORMAT_R16_FLOAT,
294    DXGI_FORMAT_R8G8_UNORM,
295    DXGI_FORMAT_R10G10B10A2_UNORM,
296    DXGI_FORMAT_B4G4R4A4_UNORM,
297    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
298    DXGI_FORMAT_BC1_UNORM,
299    DXGI_FORMAT_R16_UNORM,
300    DXGI_FORMAT_R16G16_UNORM,
301    DXGI_FORMAT_R16G16B16A16_UNORM,
302    DXGI_FORMAT_R16G16_FLOAT
303};
304
305void GrD3DCaps::setColorType(GrColorType colorType, std::initializer_list<DXGI_FORMAT> formats) {
306#ifdef SK_DEBUG
307    for (size_t i = 0; i < kNumDxgiFormats; ++i) {
308        const auto& formatInfo = fFormatTable[i];
309        for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
310            const auto& ctInfo = formatInfo.fColorTypeInfos[j];
311            if (ctInfo.fColorType == colorType &&
312                !SkToBool(ctInfo.fFlags & ColorTypeInfo::kWrappedOnly_Flag)) {
313                bool found = false;
314                for (auto it = formats.begin(); it != formats.end(); ++it) {
315                    if (kDxgiFormats[i] == *it) {
316                        found = true;
317                    }
318                }
319                SkASSERT(found);
320            }
321        }
322    }
323#endif
324    int idx = static_cast<int>(colorType);
325    for (auto it = formats.begin(); it != formats.end(); ++it) {
326        const auto& info = this->getFormatInfo(*it);
327        for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
328            if (info.fColorTypeInfos[i].fColorType == colorType) {
329                fColorTypeToFormatTable[idx] = *it;
330                return;
331            }
332        }
333    }
334}
335
336const GrD3DCaps::FormatInfo& GrD3DCaps::getFormatInfo(DXGI_FORMAT format) const {
337    GrD3DCaps* nonConstThis = const_cast<GrD3DCaps*>(this);
338    return nonConstThis->getFormatInfo(format);
339}
340
341GrD3DCaps::FormatInfo& GrD3DCaps::getFormatInfo(DXGI_FORMAT format) {
342    static_assert(SK_ARRAY_COUNT(kDxgiFormats) == GrD3DCaps::kNumDxgiFormats,
343                  "Size of DXGI_FORMATs array must match static value in header");
344    for (size_t i = 0; i < SK_ARRAY_COUNT(kDxgiFormats); ++i) {
345        if (kDxgiFormats[i] == format) {
346            return fFormatTable[i];
347        }
348    }
349    static FormatInfo kInvalidFormat;
350    return kInvalidFormat;
351}
352
353void GrD3DCaps::initFormatTable(const DXGI_ADAPTER_DESC& adapterDesc, ID3D12Device* device) {
354    static_assert(SK_ARRAY_COUNT(kDxgiFormats) == GrD3DCaps::kNumDxgiFormats,
355                  "Size of DXGI_FORMATs array must match static value in header");
356
357    std::fill_n(fColorTypeToFormatTable, kGrColorTypeCnt, DXGI_FORMAT_UNKNOWN);
358
359    // Go through all the formats and init their support surface and data GrColorTypes.
360    // Format: DXGI_FORMAT_R8G8B8A8_UNORM
361    {
362        constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
363        auto& info = this->getFormatInfo(format);
364        info.init(adapterDesc, device, format);
365        info.fFormatColorType = GrColorType::kRGBA_8888;
366        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
367            info.fColorTypeInfoCount = 2;
368            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
369            int ctIdx = 0;
370            // Format: DXGI_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
371            {
372                constexpr GrColorType ct = GrColorType::kRGBA_8888;
373                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
374                ctInfo.fColorType = ct;
375                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
376            }
377            // Format: DXGI_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
378            {
379                constexpr GrColorType ct = GrColorType::kRGB_888x;
380                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
381                ctInfo.fColorType = ct;
382                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
383                ctInfo.fReadSwizzle = GrSwizzle("rgb1");
384            }
385        }
386    }
387
388    // Format: DXGI_FORMAT_R8_UNORM
389    {
390        constexpr DXGI_FORMAT format = DXGI_FORMAT_R8_UNORM;
391        auto& info = this->getFormatInfo(format);
392        info.init(adapterDesc, device, format);
393        info.fFormatColorType = GrColorType::kR_8;
394        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
395            info.fColorTypeInfoCount = 2;
396            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
397            int ctIdx = 0;
398            // Format: DXGI_FORMAT_R8_UNORM, Surface: kAlpha_8
399            {
400                constexpr GrColorType ct = GrColorType::kAlpha_8;
401                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
402                ctInfo.fColorType = ct;
403                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
404                ctInfo.fReadSwizzle = GrSwizzle("000r");
405                ctInfo.fWriteSwizzle = GrSwizzle("a000");
406            }
407            // Format: DXGI_FORMAT_R8_UNORM, Surface: kGray_8
408            {
409                constexpr GrColorType ct = GrColorType::kGray_8;
410                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
411                ctInfo.fColorType = ct;
412                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
413                ctInfo.fReadSwizzle = GrSwizzle("rrr1");
414            }
415        }
416    }
417    // Format: DXGI_FORMAT_B8G8R8A8_UNORM
418    {
419        constexpr DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
420        auto& info = this->getFormatInfo(format);
421        info.init(adapterDesc, device, format);
422        info.fFormatColorType = GrColorType::kBGRA_8888;
423        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
424            info.fColorTypeInfoCount = 1;
425            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
426            int ctIdx = 0;
427            // Format: DXGI_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
428            {
429                constexpr GrColorType ct = GrColorType::kBGRA_8888;
430                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
431                ctInfo.fColorType = ct;
432                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
433            }
434        }
435    }
436    // Format: DXGI_FORMAT_B5G6R5_UNORM
437    {
438        constexpr DXGI_FORMAT format = DXGI_FORMAT_B5G6R5_UNORM;
439        auto& info = this->getFormatInfo(format);
440        info.init(adapterDesc, device, format);
441        info.fFormatColorType = GrColorType::kBGR_565;
442        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
443            info.fColorTypeInfoCount = 1;
444            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
445            int ctIdx = 0;
446            // Format: DXGI_FORMAT_B5G6R5_UNORM, Surface: kBGR_565
447            {
448                constexpr GrColorType ct = GrColorType::kBGR_565;
449                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
450                ctInfo.fColorType = ct;
451                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
452            }
453        }
454    }
455    // Format: DXGI_FORMAT_R16G16B16A16_FLOAT
456    {
457        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16B16A16_FLOAT;
458        auto& info = this->getFormatInfo(format);
459        info.init(adapterDesc, device, format);
460        info.fFormatColorType = GrColorType::kRGBA_F16;
461        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
462            info.fColorTypeInfoCount = 2;
463            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
464            int ctIdx = 0;
465            // Format: DXGI_FORMAT_R16G16B16A16_FLOAT, Surface: GrColorType::kRGBA_F16
466            {
467                constexpr GrColorType ct = GrColorType::kRGBA_F16;
468                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
469                ctInfo.fColorType = ct;
470                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
471            }
472            // Format: DXGI_FORMAT_R16G16B16A16_FLOAT, Surface: GrColorType::kRGBA_F16_Clamped
473            {
474                constexpr GrColorType ct = GrColorType::kRGBA_F16_Clamped;
475                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
476                ctInfo.fColorType = ct;
477                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
478            }
479        }
480    }
481    // Format: DXGI_FORMAT_R16_FLOAT
482    {
483        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16_FLOAT;
484        auto& info = this->getFormatInfo(format);
485        info.init(adapterDesc, device, format);
486        info.fFormatColorType = GrColorType::kR_F16;
487        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
488            info.fColorTypeInfoCount = 1;
489            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
490            int ctIdx = 0;
491            // Format: DXGI_FORMAT_R16_FLOAT, Surface: kAlpha_F16
492            {
493                constexpr GrColorType ct = GrColorType::kAlpha_F16;
494                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
495                ctInfo.fColorType = ct;
496                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
497                ctInfo.fReadSwizzle = GrSwizzle("000r");
498                ctInfo.fWriteSwizzle = GrSwizzle("a000");
499            }
500        }
501    }
502    // Format: DXGI_FORMAT_R8G8_UNORM
503    {
504        constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8_UNORM;
505        auto& info = this->getFormatInfo(format);
506        info.init(adapterDesc, device, format);
507        info.fFormatColorType = GrColorType::kRG_88;
508        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
509            info.fColorTypeInfoCount = 1;
510            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
511            int ctIdx = 0;
512            // Format: DXGI_FORMAT_R8G8_UNORM, Surface: kRG_88
513            {
514                constexpr GrColorType ct = GrColorType::kRG_88;
515                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
516                ctInfo.fColorType = ct;
517                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
518            }
519        }
520    }
521    // Format: DXGI_FORMAT_R10G10B10A2_UNORM
522    {
523        constexpr DXGI_FORMAT format = DXGI_FORMAT_R10G10B10A2_UNORM;
524        auto& info = this->getFormatInfo(format);
525        info.init(adapterDesc, device, format);
526        info.fFormatColorType = GrColorType::kRGBA_1010102;
527        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
528            info.fColorTypeInfoCount = 1;
529            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
530            int ctIdx = 0;
531            // Format: DXGI_FORMAT_R10G10B10A2_UNORM, Surface: kRGBA_1010102
532            {
533                constexpr GrColorType ct = GrColorType::kRGBA_1010102;
534                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
535                ctInfo.fColorType = ct;
536                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
537            }
538        }
539    }
540    // Format: DXGI_FORMAT_B4G4R4A4_UNORM
541    {
542        constexpr DXGI_FORMAT format = DXGI_FORMAT_B4G4R4A4_UNORM;
543        auto& info = this->getFormatInfo(format);
544        info.init(adapterDesc, device, format);
545        info.fFormatColorType = GrColorType::kBGRA_4444;
546        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
547            info.fColorTypeInfoCount = 1;
548            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
549            int ctIdx = 0;
550            // Format: DXGI_FORMAT_B4G4R4A4_UNORM, Surface: kABGR_4444
551            {
552                constexpr GrColorType ct = GrColorType::kABGR_4444;
553                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
554                ctInfo.fColorType = ct;
555                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
556                ctInfo.fReadSwizzle = GrSwizzle("argb");
557                ctInfo.fWriteSwizzle = GrSwizzle("gbar");
558            }
559        }
560    }
561    // Format: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
562    {
563        constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
564        auto& info = this->getFormatInfo(format);
565        info.init(adapterDesc, device, format);
566        info.fFormatColorType = GrColorType::kRGBA_8888_SRGB;
567        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
568            info.fColorTypeInfoCount = 1;
569            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
570            int ctIdx = 0;
571            // Format: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, Surface: kRGBA_8888_SRGB
572            {
573                constexpr GrColorType ct = GrColorType::kRGBA_8888_SRGB;
574                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
575                ctInfo.fColorType = ct;
576                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
577            }
578        }
579    }
580    // Format: DXGI_FORMAT_R16_UNORM
581    {
582        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16_UNORM;
583        auto& info = this->getFormatInfo(format);
584        info.init(adapterDesc, device, format);
585        info.fFormatColorType = GrColorType::kR_16;
586        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
587            info.fColorTypeInfoCount = 1;
588            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
589            int ctIdx = 0;
590            // Format: DXGI_FORMAT_R16_UNORM, Surface: kAlpha_16
591            {
592                constexpr GrColorType ct = GrColorType::kAlpha_16;
593                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
594                ctInfo.fColorType = ct;
595                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
596                ctInfo.fReadSwizzle = GrSwizzle("000r");
597                ctInfo.fWriteSwizzle = GrSwizzle("a000");
598            }
599        }
600    }
601    // Format: DXGI_FORMAT_R16G16_UNORM
602    {
603        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16_UNORM;
604        auto& info = this->getFormatInfo(format);
605        info.init(adapterDesc, device, format);
606        info.fFormatColorType = GrColorType::kRG_1616;
607        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
608            info.fColorTypeInfoCount = 1;
609            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
610            int ctIdx = 0;
611            // Format: DXGI_FORMAT_R16G16_UNORM, Surface: kRG_1616
612            {
613                constexpr GrColorType ct = GrColorType::kRG_1616;
614                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
615                ctInfo.fColorType = ct;
616                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
617            }
618        }
619    }
620    // Format: DXGI_FORMAT_R16G16B16A16_UNORM
621    {
622        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16B16A16_UNORM;
623        auto& info = this->getFormatInfo(format);
624        info.init(adapterDesc, device, format);
625        info.fFormatColorType = GrColorType::kRGBA_16161616;
626        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
627            info.fColorTypeInfoCount = 1;
628            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
629            int ctIdx = 0;
630            // Format: DXGI_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
631            {
632                constexpr GrColorType ct = GrColorType::kRGBA_16161616;
633                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
634                ctInfo.fColorType = ct;
635                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
636            }
637        }
638    }
639    // Format: DXGI_FORMAT_R16G16_FLOAT
640    {
641        constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16_FLOAT;
642        auto& info = this->getFormatInfo(format);
643        info.init(adapterDesc, device, format);
644        info.fFormatColorType = GrColorType::kRG_F16;
645        if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) {
646            info.fColorTypeInfoCount = 1;
647            info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
648            int ctIdx = 0;
649            // Format: DXGI_FORMAT_R16G16_FLOAT, Surface: kRG_F16
650            {
651                constexpr GrColorType ct = GrColorType::kRG_F16;
652                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
653                ctInfo.fColorType = ct;
654                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
655            }
656        }
657    }
658
659    // Format: DXGI_FORMAT_BC1_UNORM
660    {
661        constexpr DXGI_FORMAT format = DXGI_FORMAT_BC1_UNORM;
662        auto& info = this->getFormatInfo(format);
663        info.init(adapterDesc, device, format);
664        // No supported GrColorTypes.
665    }
666
667    ////////////////////////////////////////////////////////////////////////////
668    // Map GrColorTypes (used for creating GrSurfaces) to DXGI_FORMATs. The order in which the
669    // formats are passed into the setColorType function indicates the priority in selecting which
670    // format we use for a given GrcolorType.
671
672    this->setColorType(GrColorType::kAlpha_8, { DXGI_FORMAT_R8_UNORM });
673    this->setColorType(GrColorType::kBGR_565, { DXGI_FORMAT_B5G6R5_UNORM });
674    this->setColorType(GrColorType::kABGR_4444, { DXGI_FORMAT_B4G4R4A4_UNORM });
675    this->setColorType(GrColorType::kRGBA_8888, { DXGI_FORMAT_R8G8B8A8_UNORM });
676    this->setColorType(GrColorType::kRGBA_8888_SRGB, { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB });
677    this->setColorType(GrColorType::kRGB_888x, { DXGI_FORMAT_R8G8B8A8_UNORM });
678    this->setColorType(GrColorType::kRG_88, { DXGI_FORMAT_R8G8_UNORM });
679    this->setColorType(GrColorType::kBGRA_8888, { DXGI_FORMAT_B8G8R8A8_UNORM });
680    this->setColorType(GrColorType::kRGBA_1010102, { DXGI_FORMAT_R10G10B10A2_UNORM });
681    this->setColorType(GrColorType::kGray_8, { DXGI_FORMAT_R8_UNORM });
682    this->setColorType(GrColorType::kAlpha_F16, { DXGI_FORMAT_R16_FLOAT });
683    this->setColorType(GrColorType::kRGBA_F16, { DXGI_FORMAT_R16G16B16A16_FLOAT });
684    this->setColorType(GrColorType::kRGBA_F16_Clamped, { DXGI_FORMAT_R16G16B16A16_FLOAT });
685    this->setColorType(GrColorType::kAlpha_16, { DXGI_FORMAT_R16_UNORM });
686    this->setColorType(GrColorType::kRG_1616, { DXGI_FORMAT_R16G16_UNORM });
687    this->setColorType(GrColorType::kRGBA_16161616, { DXGI_FORMAT_R16G16B16A16_UNORM });
688    this->setColorType(GrColorType::kRG_F16, { DXGI_FORMAT_R16G16_FLOAT });
689}
690
691void GrD3DCaps::FormatInfo::InitFormatFlags(const D3D12_FEATURE_DATA_FORMAT_SUPPORT& formatSupport,
692                                            uint16_t* flags) {
693    if (SkToBool(D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE & formatSupport.Support1)) {
694        *flags = *flags | kTexturable_Flag;
695
696        // Ganesh assumes that all renderable surfaces are also texturable
697        if (SkToBool(D3D12_FORMAT_SUPPORT1_RENDER_TARGET & formatSupport.Support1) &&
698            SkToBool(D3D12_FORMAT_SUPPORT1_BLENDABLE & formatSupport.Support1)) {
699            *flags = *flags | kRenderable_Flag;
700        }
701    }
702
703    if (SkToBool(D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET & formatSupport.Support1)) {
704        *flags = *flags | kMSAA_Flag;
705    }
706
707    if (SkToBool(D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE & formatSupport.Support1)) {
708        *flags = *flags | kResolve_Flag;
709    }
710
711    if (SkToBool(D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW & formatSupport.Support1)) {
712        *flags = *flags | kUnorderedAccess_Flag;
713    }
714}
715
716static bool multisample_count_supported(ID3D12Device* device, DXGI_FORMAT format, int sampleCount) {
717    D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msqLevels;
718    msqLevels.Format = format;
719    msqLevels.SampleCount = sampleCount;
720    msqLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
721    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
722                                                     &msqLevels, sizeof(msqLevels)));
723
724    return msqLevels.NumQualityLevels > 0;
725}
726
727void GrD3DCaps::FormatInfo::initSampleCounts(const DXGI_ADAPTER_DESC& adapterDesc,
728                                             ID3D12Device* device, DXGI_FORMAT format) {
729    if (multisample_count_supported(device, format, 1)) {
730        fColorSampleCounts.push_back(1);
731    }
732    // TODO: test these
733    //if (kImagination_D3DVendor == adapterDesc.VendorId) {
734    //    // MSAA does not work on imagination
735    //    return;
736    //}
737    //if (kIntel_D3DVendor == adapterDesc.VendorId) {
738    //    // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
739    //    return;
740    //}
741    if (multisample_count_supported(device, format, 2)) {
742        fColorSampleCounts.push_back(2);
743    }
744    if (multisample_count_supported(device, format, 4)) {
745        fColorSampleCounts.push_back(4);
746    }
747    if (multisample_count_supported(device, format, 8)) {
748        fColorSampleCounts.push_back(8);
749    }
750    if (multisample_count_supported(device, format, 16)) {
751        fColorSampleCounts.push_back(16);
752    }
753    // Standard sample locations are not defined for more than 16 samples, and we don't need more
754    // than 16. Omit 32 and 64.
755}
756
757void GrD3DCaps::FormatInfo::init(const DXGI_ADAPTER_DESC& adapterDesc, ID3D12Device* device,
758                                 DXGI_FORMAT format) {
759    D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupportDesc;
760    formatSupportDesc.Format = format;
761    GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT,
762                                                     &formatSupportDesc,
763                                                     sizeof(formatSupportDesc)));
764
765    InitFormatFlags(formatSupportDesc, &fFlags);
766    if (fFlags & kRenderable_Flag) {
767        this->initSampleCounts(adapterDesc, device, format);
768    }
769}
770
771bool GrD3DCaps::isFormatSRGB(const GrBackendFormat& format) const {
772    DXGI_FORMAT dxgiFormat;
773    if (!format.asDxgiFormat(&dxgiFormat)) {
774        return false;
775    }
776
777    switch (dxgiFormat) {
778        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
779            return true;
780        default:
781            return false;
782    }
783}
784
785bool GrD3DCaps::isFormatTexturable(const GrBackendFormat& format, GrTextureType) const {
786    DXGI_FORMAT dxgiFormat;
787    if (!format.asDxgiFormat(&dxgiFormat)) {
788        return false;
789    }
790
791    return this->isFormatTexturable(dxgiFormat);
792}
793
794bool GrD3DCaps::isFormatTexturable(DXGI_FORMAT format) const {
795    const FormatInfo& info = this->getFormatInfo(format);
796    return SkToBool(FormatInfo::kTexturable_Flag & info.fFlags);
797}
798
799bool GrD3DCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format,
800                                             int sampleCount) const {
801    DXGI_FORMAT dxgiFormat;
802    if (!format.asDxgiFormat(&dxgiFormat)) {
803        return false;
804    }
805    if (!this->isFormatRenderable(dxgiFormat, sampleCount)) {
806        return false;
807    }
808    const auto& info = this->getFormatInfo(dxgiFormat);
809    if (!SkToBool(info.colorTypeFlags(ct) & ColorTypeInfo::kRenderable_Flag)) {
810        return false;
811    }
812    return true;
813}
814
815bool GrD3DCaps::isFormatRenderable(const GrBackendFormat& format, int sampleCount) const {
816    DXGI_FORMAT dxgiFormat;
817    if (!format.asDxgiFormat(&dxgiFormat)) {
818        return false;
819    }
820    return this->isFormatRenderable(dxgiFormat, sampleCount);
821}
822
823bool GrD3DCaps::isFormatRenderable(DXGI_FORMAT format, int sampleCount) const {
824    return sampleCount <= this->maxRenderTargetSampleCount(format);
825}
826
827bool GrD3DCaps::isFormatUnorderedAccessible(DXGI_FORMAT format) const {
828    const FormatInfo& info = this->getFormatInfo(format);
829    return SkToBool(FormatInfo::kUnorderedAccess_Flag & info.fFlags);
830}
831
832int GrD3DCaps::getRenderTargetSampleCount(int requestedCount,
833                                         const GrBackendFormat& format) const {
834    DXGI_FORMAT dxgiFormat;
835    if (!format.asDxgiFormat(&dxgiFormat)) {
836        return 0;
837    }
838
839    return this->getRenderTargetSampleCount(requestedCount, dxgiFormat);
840}
841
842int GrD3DCaps::getRenderTargetSampleCount(int requestedCount, DXGI_FORMAT format) const {
843    requestedCount = std::max(1, requestedCount);
844
845    const FormatInfo& info = this->getFormatInfo(format);
846
847    int count = info.fColorSampleCounts.count();
848
849    if (!count) {
850        return 0;
851    }
852
853    if (1 == requestedCount) {
854        SkASSERT(info.fColorSampleCounts.count() && info.fColorSampleCounts[0] == 1);
855        return 1;
856    }
857
858    for (int i = 0; i < count; ++i) {
859        if (info.fColorSampleCounts[i] >= requestedCount) {
860            return info.fColorSampleCounts[i];
861        }
862    }
863    return 0;
864}
865
866int GrD3DCaps::maxRenderTargetSampleCount(const GrBackendFormat& format) const {
867    DXGI_FORMAT dxgiFormat;
868    if (!format.asDxgiFormat(&dxgiFormat)) {
869        return 0;
870    }
871    return this->maxRenderTargetSampleCount(dxgiFormat);
872}
873
874int GrD3DCaps::maxRenderTargetSampleCount(DXGI_FORMAT format) const {
875    const FormatInfo& info = this->getFormatInfo(format);
876
877    const auto& table = info.fColorSampleCounts;
878    if (!table.count()) {
879        return 0;
880    }
881    return table[table.count() - 1];
882}
883
884GrColorType GrD3DCaps::getFormatColorType(DXGI_FORMAT format) const {
885    const FormatInfo& info = this->getFormatInfo(format);
886    return info.fFormatColorType;
887}
888
889GrCaps::SupportedWrite GrD3DCaps::supportedWritePixelsColorType(
890        GrColorType surfaceColorType, const GrBackendFormat& surfaceFormat,
891        GrColorType srcColorType) const {
892    DXGI_FORMAT dxgiFormat;
893    if (!surfaceFormat.asDxgiFormat(&dxgiFormat)) {
894        return { GrColorType::kUnknown, 0 };
895    }
896
897    // Any buffer data needs to be aligned to 512 bytes and that of a single texel.
898    size_t offsetAlignment = SkAlignTo(GrDxgiFormatBytesPerBlock(dxgiFormat),
899                                       D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
900
901    const auto& info = this->getFormatInfo(dxgiFormat);
902    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
903        const auto& ctInfo = info.fColorTypeInfos[i];
904        if (ctInfo.fColorType == surfaceColorType) {
905            return { surfaceColorType, offsetAlignment };
906        }
907    }
908    return { GrColorType::kUnknown, 0 };
909}
910
911GrCaps::SurfaceReadPixelsSupport GrD3DCaps::surfaceSupportsReadPixels(
912        const GrSurface* surface) const {
913    if (surface->isProtected()) {
914        return SurfaceReadPixelsSupport::kUnsupported;
915    }
916    if (auto tex = static_cast<const GrD3DTexture*>(surface->asTexture())) {
917        // We can't directly read from a compressed format
918        if (GrDxgiFormatIsCompressed(tex->dxgiFormat())) {
919            return SurfaceReadPixelsSupport::kCopyToTexture2D;
920        }
921        return SurfaceReadPixelsSupport::kSupported;
922    } else if (auto rt = static_cast<const GrD3DRenderTarget*>(surface->asRenderTarget())) {
923        if (rt->numSamples() > 1) {
924            return SurfaceReadPixelsSupport::kCopyToTexture2D;
925        }
926        return SurfaceReadPixelsSupport::kSupported;
927    }
928    return SurfaceReadPixelsSupport::kUnsupported;
929}
930
931bool GrD3DCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
932    if (auto rt = surface->asRenderTarget()) {
933        return rt->numSamples() <= 1 && SkToBool(surface->asTexture());
934    }
935    return true;
936}
937
938bool GrD3DCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
939                                                  const GrBackendFormat& format) const {
940    DXGI_FORMAT dxgiFormat;
941    if (!format.asDxgiFormat(&dxgiFormat)) {
942        return false;
943    }
944
945    const auto& info = this->getFormatInfo(dxgiFormat);
946    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
947        if (info.fColorTypeInfos[i].fColorType == ct) {
948            return true;
949        }
950    }
951    return false;
952}
953
954GrBackendFormat GrD3DCaps::onGetDefaultBackendFormat(GrColorType ct) const {
955    DXGI_FORMAT format = this->getFormatFromColorType(ct);
956    if (format == DXGI_FORMAT_UNKNOWN) {
957        return {};
958    }
959    return GrBackendFormat::MakeDxgi(format);
960}
961
962GrBackendFormat GrD3DCaps::getBackendFormatFromCompressionType(
963    SkImage::CompressionType compressionType) const {
964    switch (compressionType) {
965        case SkImage::CompressionType::kBC1_RGBA8_UNORM:
966            if (this->isFormatTexturable(DXGI_FORMAT_BC1_UNORM)) {
967                return GrBackendFormat::MakeDxgi(DXGI_FORMAT_BC1_UNORM);
968            }
969            return {};
970        default:
971            return {};
972    }
973
974    SkUNREACHABLE;
975}
976
977GrSwizzle GrD3DCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
978    DXGI_FORMAT dxgiFormat;
979    SkAssertResult(format.asDxgiFormat(&dxgiFormat));
980    const auto& info = this->getFormatInfo(dxgiFormat);
981    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
982        const auto& ctInfo = info.fColorTypeInfos[i];
983        if (ctInfo.fColorType == colorType) {
984            return ctInfo.fReadSwizzle;
985        }
986    }
987    SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.",
988                 (int)colorType, (int)dxgiFormat);
989    return {};
990}
991
992GrSwizzle GrD3DCaps::getWriteSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
993    DXGI_FORMAT dxgiFormat;
994    SkAssertResult(format.asDxgiFormat(&dxgiFormat));
995    const auto& info = this->getFormatInfo(dxgiFormat);
996    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
997        const auto& ctInfo = info.fColorTypeInfos[i];
998        if (ctInfo.fColorType == colorType) {
999            return ctInfo.fWriteSwizzle;
1000        }
1001    }
1002    SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.",
1003                 (int)colorType, (int)dxgiFormat);
1004    return {};
1005}
1006
1007uint64_t GrD3DCaps::computeFormatKey(const GrBackendFormat& format) const {
1008    DXGI_FORMAT dxgiFormat;
1009    SkAssertResult(format.asDxgiFormat(&dxgiFormat));
1010
1011    return (uint64_t)dxgiFormat;
1012}
1013
1014GrCaps::SupportedRead GrD3DCaps::onSupportedReadPixelsColorType(
1015        GrColorType srcColorType, const GrBackendFormat& srcBackendFormat,
1016        GrColorType dstColorType) const {
1017    DXGI_FORMAT dxgiFormat;
1018    if (!srcBackendFormat.asDxgiFormat(&dxgiFormat)) {
1019        return { GrColorType::kUnknown, 0 };
1020    }
1021
1022    SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat);
1023    if (compression != SkImage::CompressionType::kNone) {
1024        return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
1025                                                        : GrColorType::kRGBA_8888, 0 };
1026    }
1027
1028    // Any subresource buffer data offset we copy to needs to be aligned to 512 bytes.
1029    size_t offsetAlignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
1030
1031    const auto& info = this->getFormatInfo(dxgiFormat);
1032    for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1033        const auto& ctInfo = info.fColorTypeInfos[i];
1034        if (ctInfo.fColorType == srcColorType) {
1035            return { srcColorType, offsetAlignment };
1036        }
1037    }
1038    return { GrColorType::kUnknown, 0 };
1039}
1040
1041void GrD3DCaps::addExtraSamplerKey(GrProcessorKeyBuilder* b,
1042                                   GrSamplerState samplerState,
1043                                   const GrBackendFormat& format) const {
1044    // TODO
1045}
1046
1047/**
1048 * TODO: Determine what goes in the ProgramDesc
1049 */
1050GrProgramDesc GrD3DCaps::makeDesc(GrRenderTarget* rt,
1051                                  const GrProgramInfo& programInfo,
1052                                  ProgramDescOverrideFlags overrideFlags) const {
1053    SkASSERT(overrideFlags == ProgramDescOverrideFlags::kNone);
1054    GrProgramDesc desc;
1055    GrProgramDesc::Build(&desc, programInfo, *this);
1056
1057    GrProcessorKeyBuilder b(desc.key());
1058
1059    GrD3DRenderTarget* d3dRT = (GrD3DRenderTarget*) rt;
1060    d3dRT->genKey(&b);
1061
1062    GrStencilSettings stencil = programInfo.nonGLStencilSettings();
1063    stencil.genKey(&b, false);
1064
1065    programInfo.pipeline().genKey(&b, *this);
1066    // The num samples is already added in the render target key so we don't need to add it here.
1067
1068    // D3D requires the full primitive type as part of its key
1069    b.add32(programInfo.primitiveTypeKey());
1070
1071    b.flush();
1072    return desc;
1073}
1074
1075#if GR_TEST_UTILS
1076std::vector<GrCaps::TestFormatColorTypeCombination> GrD3DCaps::getTestingCombinations() const {
1077    std::vector<GrCaps::TestFormatColorTypeCombination> combos = {
1078        {GrColorType::kAlpha_8,        GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8_UNORM)           },
1079        {GrColorType::kBGR_565,        GrBackendFormat::MakeDxgi(DXGI_FORMAT_B5G6R5_UNORM)       },
1080        {GrColorType::kABGR_4444,      GrBackendFormat::MakeDxgi(DXGI_FORMAT_B4G4R4A4_UNORM)     },
1081        {GrColorType::kRGBA_8888,      GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM)     },
1082        {GrColorType::kRGBA_8888_SRGB, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)},
1083        {GrColorType::kRGB_888x,       GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM)     },
1084        {GrColorType::kRG_88,          GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8_UNORM)         },
1085        {GrColorType::kBGRA_8888,      GrBackendFormat::MakeDxgi(DXGI_FORMAT_B8G8R8A8_UNORM)     },
1086        {GrColorType::kRGBA_1010102,   GrBackendFormat::MakeDxgi(DXGI_FORMAT_R10G10B10A2_UNORM)  },
1087        {GrColorType::kGray_8,         GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8_UNORM)           },
1088        {GrColorType::kAlpha_F16,      GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16_FLOAT)          },
1089        {GrColorType::kRGBA_F16,       GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_FLOAT) },
1090        {GrColorType::kRGBA_F16_Clamped, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_FLOAT)},
1091        {GrColorType::kAlpha_16,       GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16_UNORM)          },
1092        {GrColorType::kRG_1616,        GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16_UNORM)       },
1093        {GrColorType::kRGBA_16161616,  GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_UNORM) },
1094        {GrColorType::kRG_F16,         GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16_FLOAT)       },
1095        {GrColorType::kRGBA_8888,      GrBackendFormat::MakeDxgi(DXGI_FORMAT_BC1_UNORM)          },
1096    };
1097
1098    return combos;
1099}
1100#endif
1101