| /* |
| * Copyright 2020 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "src/gpu/ganesh/d3d/GrD3DCaps.h" |
| |
| #include "include/gpu/GrBackendSurface.h" |
| #include "include/gpu/GrContextOptions.h" |
| #include "include/gpu/d3d/GrD3DBackendContext.h" |
| #include "include/gpu/d3d/GrD3DTypes.h" |
| #include "src/core/SkCompressedDataUtils.h" |
| #include "src/gpu/KeyBuilder.h" |
| #include "src/gpu/ganesh/GrBackendUtils.h" |
| #include "src/gpu/ganesh/GrProgramDesc.h" |
| #include "src/gpu/ganesh/GrProgramInfo.h" |
| #include "src/gpu/ganesh/GrRenderTargetProxy.h" |
| #include "src/gpu/ganesh/GrShaderCaps.h" |
| #include "src/gpu/ganesh/GrStencilSettings.h" |
| #include "src/gpu/ganesh/TestFormatColorTypeCombination.h" |
| #include "src/gpu/ganesh/d3d/GrD3DGpu.h" |
| #include "src/gpu/ganesh/d3d/GrD3DRenderTarget.h" |
| #include "src/gpu/ganesh/d3d/GrD3DTexture.h" |
| #include "src/gpu/ganesh/d3d/GrD3DUtil.h" |
| |
| GrD3DCaps::GrD3DCaps(const GrContextOptions& contextOptions, IDXGIAdapter1* adapter, |
| ID3D12Device* device) |
| : INHERITED(contextOptions) { |
| /************************************************************************** |
| * GrCaps fields |
| **************************************************************************/ |
| fNPOTTextureTileSupport = true; // available in feature level 10_0 and up |
| fMipmapSupport = true; // always available in Direct3D |
| fAnisoSupport = true; // always available in Direct3D |
| fReuseScratchTextures = true; //TODO: figure this out |
| fGpuTracingSupport = false; //TODO: figure this out |
| fOversizedStencilSupport = false; //TODO: figure this out |
| fDrawInstancedSupport = true; |
| fNativeDrawIndirectSupport = true; |
| |
| fSemaphoreSupport = true; |
| fFenceSyncSupport = true; |
| // TODO: implement these |
| fCrossContextTextureSupport = false; |
| fHalfFloatVertexAttributeSupport = false; |
| |
| // We always copy in/out of a transfer buffer so it's trivial to support row bytes. |
| fReadPixelsRowBytesSupport = true; |
| fWritePixelsRowBytesSupport = true; |
| fTransferPixelsToRowBytesSupport = true; |
| |
| fTransferFromBufferToTextureSupport = true; |
| fTransferFromSurfaceToBufferSupport = true; |
| fTransferFromBufferToBufferSupport = true; |
| |
| fMaxRenderTargetSize = 16384; // minimum required by feature level 11_0 |
| fMaxTextureSize = 16384; // minimum required by feature level 11_0 |
| |
| fTransferBufferRowBytesAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; |
| |
| // TODO: implement |
| fDynamicStateArrayGeometryProcessorTextureSupport = false; |
| |
| fShaderCaps = std::make_unique<GrShaderCaps>(); |
| |
| this->init(contextOptions, adapter, device); |
| } |
| |
| bool GrD3DCaps::canCopyTexture(DXGI_FORMAT dstFormat, int dstSampleCnt, |
| DXGI_FORMAT srcFormat, int srcSampleCnt) const { |
| if ((dstSampleCnt > 1 || srcSampleCnt > 1) && dstSampleCnt != srcSampleCnt) { |
| return false; |
| } |
| |
| // D3D allows us to copy within the same format family but doesn't do conversions |
| // so we require strict identity. |
| return srcFormat == dstFormat; |
| } |
| |
| bool GrD3DCaps::canCopyAsResolve(DXGI_FORMAT dstFormat, int dstSampleCnt, |
| DXGI_FORMAT srcFormat, int srcSampleCnt) const { |
| // The src surface must be multisampled. |
| if (srcSampleCnt <= 1) { |
| return false; |
| } |
| |
| // The dst must not be multisampled. |
| if (dstSampleCnt > 1) { |
| return false; |
| } |
| |
| // Surfaces must have the same format. |
| // D3D12 can resolve between typeless and non-typeless formats, but we are not using |
| // typeless formats. It's not possible to resolve within the same format family otherwise. |
| if (srcFormat != dstFormat) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool GrD3DCaps::onCanCopySurface(const GrSurfaceProxy* dst, const SkIRect& dstRect, |
| const GrSurfaceProxy* src, const SkIRect& srcRect) const { |
| // D3D12 does not support scaling copies |
| if (srcRect.size() != dstRect.size()) { |
| return false; |
| } |
| if (src->isProtected() == GrProtected::kYes && dst->isProtected() != GrProtected::kYes) { |
| return false; |
| } |
| |
| int dstSampleCnt = 0; |
| int srcSampleCnt = 0; |
| if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) { |
| dstSampleCnt = rtProxy->numSamples(); |
| } |
| if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) { |
| srcSampleCnt = rtProxy->numSamples(); |
| } |
| SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy())); |
| SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy())); |
| |
| DXGI_FORMAT dstFormat, srcFormat; |
| SkAssertResult(dst->backendFormat().asDxgiFormat(&dstFormat)); |
| SkAssertResult(src->backendFormat().asDxgiFormat(&srcFormat)); |
| |
| return this->canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt) || |
| this->canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt); |
| } |
| |
| void GrD3DCaps::init(const GrContextOptions& contextOptions, IDXGIAdapter1* adapter, |
| ID3D12Device* device) { |
| D3D_FEATURE_LEVEL featureLevels[] = { |
| D3D_FEATURE_LEVEL_11_0, |
| D3D_FEATURE_LEVEL_11_1, |
| D3D_FEATURE_LEVEL_12_0, |
| D3D_FEATURE_LEVEL_12_1, |
| }; |
| D3D12_FEATURE_DATA_FEATURE_LEVELS flDesc = {}; |
| flDesc.NumFeatureLevels = _countof(featureLevels); |
| flDesc.pFeatureLevelsRequested = featureLevels; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &flDesc, |
| sizeof(flDesc))); |
| // This had better be true |
| SkASSERT(flDesc.MaxSupportedFeatureLevel >= D3D_FEATURE_LEVEL_11_0); |
| |
| DXGI_ADAPTER_DESC adapterDesc; |
| GR_D3D_CALL_ERRCHECK(adapter->GetDesc(&adapterDesc)); |
| |
| D3D12_FEATURE_DATA_D3D12_OPTIONS optionsDesc; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &optionsDesc, |
| sizeof(optionsDesc))); |
| |
| |
| // See https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support |
| if (D3D12_RESOURCE_BINDING_TIER_1 == optionsDesc.ResourceBindingTier) { |
| fMaxPerStageShaderResourceViews = 128; |
| if (D3D_FEATURE_LEVEL_11_0 == flDesc.MaxSupportedFeatureLevel) { |
| fMaxPerStageUnorderedAccessViews = 8; |
| } else { |
| fMaxPerStageUnorderedAccessViews = 64; |
| } |
| } else { |
| // The doc above says "full heap", but practically it seems like it should be |
| // limited by the maximum number of samplers in a heap |
| fMaxPerStageUnorderedAccessViews = 2032; |
| fMaxPerStageShaderResourceViews = 2032; |
| } |
| |
| fStandardSwizzleLayoutSupport = (optionsDesc.StandardSwizzle64KBSupported); |
| |
| D3D12_FEATURE_DATA_D3D12_OPTIONS2 optionsDesc2; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &optionsDesc2, |
| sizeof(optionsDesc2))); |
| fResolveSubresourceRegionSupport = (optionsDesc2.ProgrammableSamplePositionsTier != |
| D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED); |
| |
| this->initGrCaps(optionsDesc, device); |
| this->initShaderCaps(adapterDesc.VendorId, optionsDesc); |
| |
| this->initFormatTable(adapterDesc, device); |
| this->initStencilFormat(device); |
| |
| if (!contextOptions.fDisableDriverCorrectnessWorkarounds) { |
| this->applyDriverCorrectnessWorkarounds(adapterDesc.VendorId); |
| } |
| |
| this->finishInitialization(contextOptions); |
| } |
| |
| void GrD3DCaps::initGrCaps(const D3D12_FEATURE_DATA_D3D12_OPTIONS& optionsDesc, |
| ID3D12Device* device) { |
| // We assume a minimum of Shader Model 5.1, which allows at most 32 vertex inputs. |
| fMaxVertexAttributes = 32; |
| |
| // Can use standard sample locations |
| fSampleLocationsSupport = true; |
| |
| if (D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED != |
| optionsDesc.ConservativeRasterizationTier) { |
| fConservativeRasterSupport = true; |
| } |
| |
| fWireframeSupport = true; |
| |
| // Feature level 11_0 and up support up to 16K in texture dimension |
| fMaxTextureSize = 16384; |
| // There's no specific cap for RT size, so use texture size |
| fMaxRenderTargetSize = fMaxTextureSize; |
| // Our render targets are always created with textures as the color |
| // attachment, hence this min: |
| fMaxRenderTargetSize = fMaxTextureSize; |
| |
| fMaxPreferredRenderTargetSize = fMaxRenderTargetSize; |
| |
| // Assuming since we will always map in the end to upload the data we might as well just map |
| // from the get go. There is no hard data to suggest this is faster or slower. |
| fBufferMapThreshold = 0; |
| |
| fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag | kAsyncRead_MapFlag; |
| |
| fOversizedStencilSupport = true; |
| |
| fTwoSidedStencilRefsAndMasksMustMatch = true; |
| |
| // Advanced blend modes don't appear to be supported. |
| } |
| |
| void GrD3DCaps::initShaderCaps(int vendorID, const D3D12_FEATURE_DATA_D3D12_OPTIONS& optionsDesc) { |
| GrShaderCaps* shaderCaps = fShaderCaps.get(); |
| shaderCaps->fVersionDeclString = "#version 330\n"; |
| |
| // Shader Model 5 supports all of the following: |
| shaderCaps->fUsesPrecisionModifiers = true; |
| shaderCaps->fFlatInterpolationSupport = true; |
| // Flat interpolation appears to be slow on Qualcomm GPUs. This was tested in GL and is assumed |
| // to be true with D3D as well. |
| shaderCaps->fPreferFlatInterpolation = kQualcomm_D3DVendor != vendorID; |
| |
| shaderCaps->fSampleMaskSupport = true; |
| |
| shaderCaps->fShaderDerivativeSupport = true; |
| shaderCaps->fExplicitTextureLodSupport = true; |
| |
| shaderCaps->fDualSourceBlendingSupport = true; |
| |
| shaderCaps->fIntegerSupport = true; |
| shaderCaps->fNonsquareMatrixSupport = true; |
| // TODO(skia:12352) HLSL does not expose asinh/acosh/atanh |
| shaderCaps->fInverseHyperbolicSupport = false; |
| shaderCaps->fVertexIDSupport = true; |
| shaderCaps->fInfinitySupport = true; |
| shaderCaps->fNonconstantArrayIndexSupport = true; |
| shaderCaps->fBitManipulationSupport = true; |
| |
| shaderCaps->fFloatIs32Bits = true; |
| shaderCaps->fHalfIs32Bits = |
| D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE == optionsDesc.MinPrecisionSupport; |
| |
| // See https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support |
| // The maximum number of samplers in a shader-visible descriptor heap is 2048, but |
| // 16 of those are reserved for the driver. |
| shaderCaps->fMaxFragmentSamplers = |
| (D3D12_RESOURCE_BINDING_TIER_1 == optionsDesc.ResourceBindingTier) ? 16 : 2032; |
| } |
| |
| void GrD3DCaps::applyDriverCorrectnessWorkarounds(int vendorID) { |
| // Nothing yet. |
| } |
| |
| |
| bool stencil_format_supported(ID3D12Device* device, DXGI_FORMAT format) { |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupportDesc; |
| formatSupportDesc.Format = format; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, |
| &formatSupportDesc, |
| sizeof(formatSupportDesc))); |
| return SkToBool(D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL & formatSupportDesc.Support1); |
| } |
| |
| void GrD3DCaps::initStencilFormat(ID3D12Device* device) { |
| if (stencil_format_supported(device, DXGI_FORMAT_D24_UNORM_S8_UINT)) { |
| fPreferredStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; |
| } else { |
| SkASSERT(stencil_format_supported(device, DXGI_FORMAT_D32_FLOAT_S8X24_UINT)); |
| fPreferredStencilFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; |
| } |
| } |
| |
| // These are all the valid DXGI_FORMATs that we support in Skia. They are roughly ordered from most |
| // frequently used to least to improve look up times in arrays. |
| static constexpr DXGI_FORMAT kDxgiFormats[] = { |
| DXGI_FORMAT_R8G8B8A8_UNORM, |
| DXGI_FORMAT_R8_UNORM, |
| DXGI_FORMAT_B8G8R8A8_UNORM, |
| DXGI_FORMAT_B5G6R5_UNORM, |
| DXGI_FORMAT_R16G16B16A16_FLOAT, |
| DXGI_FORMAT_R16_FLOAT, |
| DXGI_FORMAT_R8G8_UNORM, |
| DXGI_FORMAT_R10G10B10A2_UNORM, |
| DXGI_FORMAT_B4G4R4A4_UNORM, |
| DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, |
| DXGI_FORMAT_BC1_UNORM, |
| DXGI_FORMAT_R16_UNORM, |
| DXGI_FORMAT_R16G16_UNORM, |
| DXGI_FORMAT_R16G16B16A16_UNORM, |
| DXGI_FORMAT_R16G16_FLOAT |
| }; |
| |
| void GrD3DCaps::setColorType(GrColorType colorType, std::initializer_list<DXGI_FORMAT> formats) { |
| #ifdef SK_DEBUG |
| for (size_t i = 0; i < kNumDxgiFormats; ++i) { |
| const auto& formatInfo = fFormatTable[i]; |
| for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) { |
| const auto& ctInfo = formatInfo.fColorTypeInfos[j]; |
| if (ctInfo.fColorType == colorType && |
| !SkToBool(ctInfo.fFlags & ColorTypeInfo::kWrappedOnly_Flag)) { |
| bool found = false; |
| for (auto it = formats.begin(); it != formats.end(); ++it) { |
| if (kDxgiFormats[i] == *it) { |
| found = true; |
| } |
| } |
| SkASSERT(found); |
| } |
| } |
| } |
| #endif |
| int idx = static_cast<int>(colorType); |
| for (auto it = formats.begin(); it != formats.end(); ++it) { |
| const auto& info = this->getFormatInfo(*it); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| if (info.fColorTypeInfos[i].fColorType == colorType) { |
| fColorTypeToFormatTable[idx] = *it; |
| return; |
| } |
| } |
| } |
| } |
| |
| const GrD3DCaps::FormatInfo& GrD3DCaps::getFormatInfo(DXGI_FORMAT format) const { |
| GrD3DCaps* nonConstThis = const_cast<GrD3DCaps*>(this); |
| return nonConstThis->getFormatInfo(format); |
| } |
| |
| GrD3DCaps::FormatInfo& GrD3DCaps::getFormatInfo(DXGI_FORMAT format) { |
| static_assert(std::size(kDxgiFormats) == GrD3DCaps::kNumDxgiFormats, |
| "Size of DXGI_FORMATs array must match static value in header"); |
| for (size_t i = 0; i < std::size(kDxgiFormats); ++i) { |
| if (kDxgiFormats[i] == format) { |
| return fFormatTable[i]; |
| } |
| } |
| static FormatInfo kInvalidFormat; |
| return kInvalidFormat; |
| } |
| |
| void GrD3DCaps::initFormatTable(const DXGI_ADAPTER_DESC& adapterDesc, ID3D12Device* device) { |
| static_assert(std::size(kDxgiFormats) == GrD3DCaps::kNumDxgiFormats, |
| "Size of DXGI_FORMATs array must match static value in header"); |
| |
| std::fill_n(fColorTypeToFormatTable, kGrColorTypeCnt, DXGI_FORMAT_UNKNOWN); |
| |
| // Go through all the formats and init their support surface and data GrColorTypes. |
| // Format: DXGI_FORMAT_R8G8B8A8_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRGBA_8888; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 2; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888 |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_8888; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| // Format: DXGI_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x |
| { |
| constexpr GrColorType ct = GrColorType::kRGB_888x; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("rgb1"); |
| } |
| } |
| } |
| |
| // Format: DXGI_FORMAT_R8_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R8_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kR_8; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 3; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R8_UNORM, Surface: kR_8 |
| { |
| constexpr GrColorType ct = GrColorType::kR_8; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| // Format: DXGI_FORMAT_R8_UNORM, Surface: kAlpha_8 |
| { |
| constexpr GrColorType ct = GrColorType::kAlpha_8; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("000r"); |
| ctInfo.fWriteSwizzle = skgpu::Swizzle("a000"); |
| } |
| // Format: DXGI_FORMAT_R8_UNORM, Surface: kGray_8 |
| { |
| constexpr GrColorType ct = GrColorType::kGray_8; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1"); |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_B8G8R8A8_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kBGRA_8888; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888 |
| { |
| constexpr GrColorType ct = GrColorType::kBGRA_8888; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_B5G6R5_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_B5G6R5_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kBGR_565; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_B5G6R5_UNORM, Surface: kBGR_565 |
| { |
| constexpr GrColorType ct = GrColorType::kBGR_565; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16G16B16A16_FLOAT |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16B16A16_FLOAT; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRGBA_F16; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 2; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16G16B16A16_FLOAT, Surface: GrColorType::kRGBA_F16 |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_F16; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| // Format: DXGI_FORMAT_R16G16B16A16_FLOAT, Surface: GrColorType::kRGBA_F16_Clamped |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_F16_Clamped; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16_FLOAT |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16_FLOAT; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kR_F16; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16_FLOAT, Surface: kAlpha_F16 |
| { |
| constexpr GrColorType ct = GrColorType::kAlpha_F16; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("000r"); |
| ctInfo.fWriteSwizzle = skgpu::Swizzle("a000"); |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R8G8_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRG_88; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R8G8_UNORM, Surface: kRG_88 |
| { |
| constexpr GrColorType ct = GrColorType::kRG_88; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R10G10B10A2_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R10G10B10A2_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRGBA_1010102; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R10G10B10A2_UNORM, Surface: kRGBA_1010102 |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_1010102; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_B4G4R4A4_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_B4G4R4A4_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kBGRA_4444; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_B4G4R4A4_UNORM, Surface: kABGR_4444 |
| { |
| constexpr GrColorType ct = GrColorType::kABGR_4444; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("argb"); |
| ctInfo.fWriteSwizzle = skgpu::Swizzle("gbar"); |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRGBA_8888_SRGB; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, Surface: kRGBA_8888_SRGB |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_8888_SRGB; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kR_16; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16_UNORM, Surface: kAlpha_16 |
| { |
| constexpr GrColorType ct = GrColorType::kAlpha_16; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| ctInfo.fReadSwizzle = skgpu::Swizzle("000r"); |
| ctInfo.fWriteSwizzle = skgpu::Swizzle("a000"); |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16G16_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRG_1616; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16G16_UNORM, Surface: kRG_1616 |
| { |
| constexpr GrColorType ct = GrColorType::kRG_1616; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16G16B16A16_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16B16A16_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRGBA_16161616; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616 |
| { |
| constexpr GrColorType ct = GrColorType::kRGBA_16161616; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| // Format: DXGI_FORMAT_R16G16_FLOAT |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_R16G16_FLOAT; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| info.fFormatColorType = GrColorType::kRG_F16; |
| if (SkToBool(info.fFlags & FormatInfo::kTexturable_Flag)) { |
| info.fColorTypeInfoCount = 1; |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); |
| int ctIdx = 0; |
| // Format: DXGI_FORMAT_R16G16_FLOAT, Surface: kRG_F16 |
| { |
| constexpr GrColorType ct = GrColorType::kRG_F16; |
| auto& ctInfo = info.fColorTypeInfos[ctIdx++]; |
| ctInfo.fColorType = ct; |
| ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag; |
| } |
| } |
| } |
| |
| // Format: DXGI_FORMAT_BC1_UNORM |
| { |
| constexpr DXGI_FORMAT format = DXGI_FORMAT_BC1_UNORM; |
| auto& info = this->getFormatInfo(format); |
| info.init(adapterDesc, device, format); |
| // No supported GrColorTypes. |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // Map GrColorTypes (used for creating GrSurfaces) to DXGI_FORMATs. The order in which the |
| // formats are passed into the setColorType function indicates the priority in selecting which |
| // format we use for a given GrcolorType. |
| |
| this->setColorType(GrColorType::kAlpha_8, { DXGI_FORMAT_R8_UNORM }); |
| this->setColorType(GrColorType::kBGR_565, { DXGI_FORMAT_B5G6R5_UNORM }); |
| this->setColorType(GrColorType::kABGR_4444, { DXGI_FORMAT_B4G4R4A4_UNORM }); |
| this->setColorType(GrColorType::kRGBA_8888, { DXGI_FORMAT_R8G8B8A8_UNORM }); |
| this->setColorType(GrColorType::kRGBA_8888_SRGB, { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB }); |
| this->setColorType(GrColorType::kRGB_888x, { DXGI_FORMAT_R8G8B8A8_UNORM }); |
| this->setColorType(GrColorType::kRG_88, { DXGI_FORMAT_R8G8_UNORM }); |
| this->setColorType(GrColorType::kBGRA_8888, { DXGI_FORMAT_B8G8R8A8_UNORM }); |
| this->setColorType(GrColorType::kRGBA_1010102, { DXGI_FORMAT_R10G10B10A2_UNORM }); |
| this->setColorType(GrColorType::kGray_8, { DXGI_FORMAT_R8_UNORM }); |
| this->setColorType(GrColorType::kAlpha_F16, { DXGI_FORMAT_R16_FLOAT }); |
| this->setColorType(GrColorType::kRGBA_F16, { DXGI_FORMAT_R16G16B16A16_FLOAT }); |
| this->setColorType(GrColorType::kRGBA_F16_Clamped, { DXGI_FORMAT_R16G16B16A16_FLOAT }); |
| this->setColorType(GrColorType::kAlpha_16, { DXGI_FORMAT_R16_UNORM }); |
| this->setColorType(GrColorType::kRG_1616, { DXGI_FORMAT_R16G16_UNORM }); |
| this->setColorType(GrColorType::kRGBA_16161616, { DXGI_FORMAT_R16G16B16A16_UNORM }); |
| this->setColorType(GrColorType::kRG_F16, { DXGI_FORMAT_R16G16_FLOAT }); |
| } |
| |
| void GrD3DCaps::FormatInfo::InitFormatFlags(const D3D12_FEATURE_DATA_FORMAT_SUPPORT& formatSupport, |
| uint16_t* flags) { |
| if (SkToBool(D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE & formatSupport.Support1)) { |
| *flags = *flags | kTexturable_Flag; |
| |
| // Ganesh assumes that all renderable surfaces are also texturable |
| if (SkToBool(D3D12_FORMAT_SUPPORT1_RENDER_TARGET & formatSupport.Support1) && |
| SkToBool(D3D12_FORMAT_SUPPORT1_BLENDABLE & formatSupport.Support1)) { |
| *flags = *flags | kRenderable_Flag; |
| } |
| } |
| |
| if (SkToBool(D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET & formatSupport.Support1)) { |
| *flags = *flags | kMSAA_Flag; |
| } |
| |
| if (SkToBool(D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE & formatSupport.Support1)) { |
| *flags = *flags | kResolve_Flag; |
| } |
| |
| if (SkToBool(D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW & formatSupport.Support1)) { |
| *flags = *flags | kUnorderedAccess_Flag; |
| } |
| } |
| |
| static bool multisample_count_supported(ID3D12Device* device, DXGI_FORMAT format, int sampleCount) { |
| D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msqLevels; |
| msqLevels.Format = format; |
| msqLevels.SampleCount = sampleCount; |
| msqLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, |
| &msqLevels, sizeof(msqLevels))); |
| |
| return msqLevels.NumQualityLevels > 0; |
| } |
| |
| void GrD3DCaps::FormatInfo::initSampleCounts(const DXGI_ADAPTER_DESC& adapterDesc, |
| ID3D12Device* device, DXGI_FORMAT format) { |
| if (multisample_count_supported(device, format, 1)) { |
| fColorSampleCounts.push_back(1); |
| } |
| // TODO: test these |
| //if (kImagination_D3DVendor == adapterDesc.VendorId) { |
| // // MSAA does not work on imagination |
| // return; |
| //} |
| //if (kIntel_D3DVendor == adapterDesc.VendorId) { |
| // // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926 |
| // return; |
| //} |
| if (multisample_count_supported(device, format, 2)) { |
| fColorSampleCounts.push_back(2); |
| } |
| if (multisample_count_supported(device, format, 4)) { |
| fColorSampleCounts.push_back(4); |
| } |
| if (multisample_count_supported(device, format, 8)) { |
| fColorSampleCounts.push_back(8); |
| } |
| if (multisample_count_supported(device, format, 16)) { |
| fColorSampleCounts.push_back(16); |
| } |
| // Standard sample locations are not defined for more than 16 samples, and we don't need more |
| // than 16. Omit 32 and 64. |
| } |
| |
| void GrD3DCaps::FormatInfo::init(const DXGI_ADAPTER_DESC& adapterDesc, ID3D12Device* device, |
| DXGI_FORMAT format) { |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupportDesc; |
| formatSupportDesc.Format = format; |
| GR_D3D_CALL_ERRCHECK(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, |
| &formatSupportDesc, |
| sizeof(formatSupportDesc))); |
| |
| InitFormatFlags(formatSupportDesc, &fFlags); |
| if (fFlags & kRenderable_Flag) { |
| this->initSampleCounts(adapterDesc, device, format); |
| } |
| } |
| |
| bool GrD3DCaps::isFormatSRGB(const GrBackendFormat& format) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return false; |
| } |
| |
| switch (dxgiFormat) { |
| case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool GrD3DCaps::isFormatTexturable(const GrBackendFormat& format, GrTextureType) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return false; |
| } |
| |
| return this->isFormatTexturable(dxgiFormat); |
| } |
| |
| bool GrD3DCaps::isFormatTexturable(DXGI_FORMAT format) const { |
| const FormatInfo& info = this->getFormatInfo(format); |
| return SkToBool(FormatInfo::kTexturable_Flag & info.fFlags); |
| } |
| |
| bool GrD3DCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format, |
| int sampleCount) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return false; |
| } |
| if (!this->isFormatRenderable(dxgiFormat, sampleCount)) { |
| return false; |
| } |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| if (!SkToBool(info.colorTypeFlags(ct) & ColorTypeInfo::kRenderable_Flag)) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool GrD3DCaps::isFormatRenderable(const GrBackendFormat& format, int sampleCount) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return false; |
| } |
| return this->isFormatRenderable(dxgiFormat, sampleCount); |
| } |
| |
| bool GrD3DCaps::isFormatRenderable(DXGI_FORMAT format, int sampleCount) const { |
| return sampleCount <= this->maxRenderTargetSampleCount(format); |
| } |
| |
| bool GrD3DCaps::isFormatUnorderedAccessible(DXGI_FORMAT format) const { |
| const FormatInfo& info = this->getFormatInfo(format); |
| return SkToBool(FormatInfo::kUnorderedAccess_Flag & info.fFlags); |
| } |
| |
| int GrD3DCaps::getRenderTargetSampleCount(int requestedCount, |
| const GrBackendFormat& format) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return 0; |
| } |
| |
| return this->getRenderTargetSampleCount(requestedCount, dxgiFormat); |
| } |
| |
| int GrD3DCaps::getRenderTargetSampleCount(int requestedCount, DXGI_FORMAT format) const { |
| requestedCount = std::max(1, requestedCount); |
| |
| const FormatInfo& info = this->getFormatInfo(format); |
| |
| int count = info.fColorSampleCounts.size(); |
| |
| if (!count) { |
| return 0; |
| } |
| |
| if (1 == requestedCount) { |
| SkASSERT(info.fColorSampleCounts.size() && info.fColorSampleCounts[0] == 1); |
| return 1; |
| } |
| |
| for (int i = 0; i < count; ++i) { |
| if (info.fColorSampleCounts[i] >= requestedCount) { |
| return info.fColorSampleCounts[i]; |
| } |
| } |
| return 0; |
| } |
| |
| int GrD3DCaps::maxRenderTargetSampleCount(const GrBackendFormat& format) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return 0; |
| } |
| return this->maxRenderTargetSampleCount(dxgiFormat); |
| } |
| |
| int GrD3DCaps::maxRenderTargetSampleCount(DXGI_FORMAT format) const { |
| const FormatInfo& info = this->getFormatInfo(format); |
| |
| const auto& table = info.fColorSampleCounts; |
| if (!table.size()) { |
| return 0; |
| } |
| return table[table.size() - 1]; |
| } |
| |
| GrColorType GrD3DCaps::getFormatColorType(DXGI_FORMAT format) const { |
| const FormatInfo& info = this->getFormatInfo(format); |
| return info.fFormatColorType; |
| } |
| |
| GrCaps::SupportedWrite GrD3DCaps::supportedWritePixelsColorType( |
| GrColorType surfaceColorType, const GrBackendFormat& surfaceFormat, |
| GrColorType srcColorType) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!surfaceFormat.asDxgiFormat(&dxgiFormat)) { |
| return { GrColorType::kUnknown, 0 }; |
| } |
| |
| // Any buffer data needs to be aligned to 512 bytes and that of a single texel. |
| size_t offsetAlignment = SkAlignTo(GrDxgiFormatBytesPerBlock(dxgiFormat), |
| D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); |
| |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| const auto& ctInfo = info.fColorTypeInfos[i]; |
| if (ctInfo.fColorType == surfaceColorType) { |
| return { surfaceColorType, offsetAlignment }; |
| } |
| } |
| return { GrColorType::kUnknown, 0 }; |
| } |
| |
| GrCaps::SurfaceReadPixelsSupport GrD3DCaps::surfaceSupportsReadPixels( |
| const GrSurface* surface) const { |
| if (surface->isProtected()) { |
| return SurfaceReadPixelsSupport::kUnsupported; |
| } |
| if (auto tex = static_cast<const GrD3DTexture*>(surface->asTexture())) { |
| // We can't directly read from a compressed format |
| if (GrDxgiFormatIsCompressed(tex->dxgiFormat())) { |
| return SurfaceReadPixelsSupport::kCopyToTexture2D; |
| } |
| return SurfaceReadPixelsSupport::kSupported; |
| } else if (auto rt = static_cast<const GrD3DRenderTarget*>(surface->asRenderTarget())) { |
| if (rt->numSamples() > 1) { |
| return SurfaceReadPixelsSupport::kCopyToTexture2D; |
| } |
| return SurfaceReadPixelsSupport::kSupported; |
| } |
| return SurfaceReadPixelsSupport::kUnsupported; |
| } |
| |
| bool GrD3DCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const { |
| if (auto rt = surface->asRenderTarget()) { |
| return rt->numSamples() <= 1 && SkToBool(surface->asTexture()); |
| } |
| return true; |
| } |
| |
| bool GrD3DCaps::onAreColorTypeAndFormatCompatible(GrColorType ct, |
| const GrBackendFormat& format) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!format.asDxgiFormat(&dxgiFormat)) { |
| return false; |
| } |
| |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| if (info.fColorTypeInfos[i].fColorType == ct) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| GrBackendFormat GrD3DCaps::onGetDefaultBackendFormat(GrColorType ct) const { |
| DXGI_FORMAT format = this->getFormatFromColorType(ct); |
| if (format == DXGI_FORMAT_UNKNOWN) { |
| return {}; |
| } |
| return GrBackendFormat::MakeDxgi(format); |
| } |
| |
| GrBackendFormat GrD3DCaps::getBackendFormatFromCompressionType( |
| SkImage::CompressionType compressionType) const { |
| switch (compressionType) { |
| case SkImage::CompressionType::kBC1_RGBA8_UNORM: |
| if (this->isFormatTexturable(DXGI_FORMAT_BC1_UNORM)) { |
| return GrBackendFormat::MakeDxgi(DXGI_FORMAT_BC1_UNORM); |
| } |
| return {}; |
| default: |
| return {}; |
| } |
| |
| SkUNREACHABLE; |
| } |
| |
| skgpu::Swizzle GrD3DCaps::onGetReadSwizzle(const GrBackendFormat& format, |
| GrColorType colorType) const { |
| DXGI_FORMAT dxgiFormat; |
| SkAssertResult(format.asDxgiFormat(&dxgiFormat)); |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| const auto& ctInfo = info.fColorTypeInfos[i]; |
| if (ctInfo.fColorType == colorType) { |
| return ctInfo.fReadSwizzle; |
| } |
| } |
| SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.", |
| (int)colorType, (int)dxgiFormat); |
| return {}; |
| } |
| |
| skgpu::Swizzle GrD3DCaps::getWriteSwizzle(const GrBackendFormat& format, |
| GrColorType colorType) const { |
| DXGI_FORMAT dxgiFormat; |
| SkAssertResult(format.asDxgiFormat(&dxgiFormat)); |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| const auto& ctInfo = info.fColorTypeInfos[i]; |
| if (ctInfo.fColorType == colorType) { |
| return ctInfo.fWriteSwizzle; |
| } |
| } |
| SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.", |
| (int)colorType, (int)dxgiFormat); |
| return {}; |
| } |
| |
| uint64_t GrD3DCaps::computeFormatKey(const GrBackendFormat& format) const { |
| DXGI_FORMAT dxgiFormat; |
| SkAssertResult(format.asDxgiFormat(&dxgiFormat)); |
| |
| return (uint64_t)dxgiFormat; |
| } |
| |
| GrCaps::SupportedRead GrD3DCaps::onSupportedReadPixelsColorType( |
| GrColorType srcColorType, const GrBackendFormat& srcBackendFormat, |
| GrColorType dstColorType) const { |
| DXGI_FORMAT dxgiFormat; |
| if (!srcBackendFormat.asDxgiFormat(&dxgiFormat)) { |
| return { GrColorType::kUnknown, 0 }; |
| } |
| |
| SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat); |
| if (compression != SkImage::CompressionType::kNone) { |
| return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x |
| : GrColorType::kRGBA_8888, 0 }; |
| } |
| |
| // Any subresource buffer data offset we copy to needs to be aligned to 512 bytes. |
| size_t offsetAlignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; |
| |
| const auto& info = this->getFormatInfo(dxgiFormat); |
| for (int i = 0; i < info.fColorTypeInfoCount; ++i) { |
| const auto& ctInfo = info.fColorTypeInfos[i]; |
| if (ctInfo.fColorType == srcColorType) { |
| return { srcColorType, offsetAlignment }; |
| } |
| } |
| return { GrColorType::kUnknown, 0 }; |
| } |
| |
| void GrD3DCaps::addExtraSamplerKey(skgpu::KeyBuilder* b, |
| GrSamplerState samplerState, |
| const GrBackendFormat& format) const { |
| // TODO |
| } |
| |
| /** |
| * TODO: Determine what goes in the ProgramDesc |
| */ |
| GrProgramDesc GrD3DCaps::makeDesc(GrRenderTarget* rt, |
| const GrProgramInfo& programInfo, |
| ProgramDescOverrideFlags overrideFlags) const { |
| SkASSERT(overrideFlags == ProgramDescOverrideFlags::kNone); |
| GrProgramDesc desc; |
| GrProgramDesc::Build(&desc, programInfo, *this); |
| |
| skgpu::KeyBuilder b(desc.key()); |
| |
| GrD3DRenderTarget* d3dRT = (GrD3DRenderTarget*) rt; |
| d3dRT->genKey(&b); |
| |
| GrStencilSettings stencil = programInfo.nonGLStencilSettings(); |
| stencil.genKey(&b, false); |
| |
| programInfo.pipeline().genKey(&b, *this); |
| // The num samples is already added in the render target key so we don't need to add it here. |
| |
| // D3D requires the full primitive type as part of its key |
| b.add32(programInfo.primitiveTypeKey()); |
| |
| b.flush(); |
| return desc; |
| } |
| |
| #if GR_TEST_UTILS |
| std::vector<GrTest::TestFormatColorTypeCombination> GrD3DCaps::getTestingCombinations() const { |
| std::vector<GrTest::TestFormatColorTypeCombination> combos = { |
| {GrColorType::kAlpha_8, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8_UNORM) }, |
| {GrColorType::kBGR_565, GrBackendFormat::MakeDxgi(DXGI_FORMAT_B5G6R5_UNORM) }, |
| {GrColorType::kABGR_4444, GrBackendFormat::MakeDxgi(DXGI_FORMAT_B4G4R4A4_UNORM) }, |
| {GrColorType::kRGBA_8888, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM) }, |
| {GrColorType::kRGBA_8888_SRGB, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)}, |
| {GrColorType::kRGB_888x, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8B8A8_UNORM) }, |
| {GrColorType::kRG_88, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8G8_UNORM) }, |
| {GrColorType::kBGRA_8888, GrBackendFormat::MakeDxgi(DXGI_FORMAT_B8G8R8A8_UNORM) }, |
| {GrColorType::kRGBA_1010102, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R10G10B10A2_UNORM) }, |
| {GrColorType::kGray_8, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R8_UNORM) }, |
| {GrColorType::kAlpha_F16, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16_FLOAT) }, |
| {GrColorType::kRGBA_F16, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_FLOAT) }, |
| {GrColorType::kRGBA_F16_Clamped, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_FLOAT)}, |
| {GrColorType::kAlpha_16, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16_UNORM) }, |
| {GrColorType::kRG_1616, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16_UNORM) }, |
| {GrColorType::kRGBA_16161616, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16B16A16_UNORM) }, |
| {GrColorType::kRG_F16, GrBackendFormat::MakeDxgi(DXGI_FORMAT_R16G16_FLOAT) }, |
| {GrColorType::kRGBA_8888, GrBackendFormat::MakeDxgi(DXGI_FORMAT_BC1_UNORM) }, |
| }; |
| |
| return combos; |
| } |
| #endif |