| /* | |
| * 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 "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/GrBackendUtils.h" | |
| #include "src/gpu/GrProgramDesc.h" | |
| #include "src/gpu/GrProgramInfo.h" | |
| #include "src/gpu/GrShaderCaps.h" | |
| #include "src/gpu/GrStencilSettings.h" | |
| #include "src/gpu/d3d/GrD3DCaps.h" | |
| #include "src/gpu/d3d/GrD3DGpu.h" | |
| #include "src/gpu/d3d/GrD3DRenderTarget.h" | |
| #include "src/gpu/d3d/GrD3DTexture.h" | |
| #include "src/gpu/d3d/GrD3DUtil.h" | |
| GrD3DCaps::GrD3DCaps(const GrContextOptions& contextOptions, IDXGIAdapter1* adapter, | |
| ID3D12Device* device) | |
| : INHERITED(contextOptions) { | |
| /************************************************************************** | |
| * GrCaps fields | |
| **************************************************************************/ | |
| fMipmapSupport = true; // always available in Direct3D | |
| fNPOTTextureTileSupport = true; // available in feature level 10_0 and up | |
| 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; | |
| fMaxRenderTargetSize = 16384; // minimum required by feature level 11_0 | |
| fMaxTextureSize = 16384; // minimum required by feature level 11_0 | |
| fTransferBufferAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; | |
| // TODO: implement | |
| fDynamicStateArrayGeometryProcessorTextureSupport = false; | |
| fShaderCaps.reset(new GrShaderCaps(contextOptions)); | |
| 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 GrSurfaceProxy* src, | |
| const SkIRect& srcRect, const SkIPoint& dstPoint) const { | |
| 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; | |
| } | |
| 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 0 | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS2 options2Desc; | |
| if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &options2Desc, | |
| sizeof(options2Desc))) && | |
| options2Desc.ProgrammableSamplePositionsTier != | |
| D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) { | |
| // We "disable" multisample by colocating all samples at pixel center. | |
| fMultisampleDisableSupport = true; | |
| } | |
| #endif | |
| 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; | |
| if (fDriverBugWorkarounds.max_texture_size_limit_4096) { | |
| fMaxTextureSize = std::min(fMaxTextureSize, 4096); | |
| } | |
| // 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->fGeometryShaderSupport = shaderCaps->fGSInvocationsSupport = true; | |
| shaderCaps->fDualSourceBlendingSupport = true; | |
| shaderCaps->fIntegerSupport = true; | |
| shaderCaps->fVertexIDSupport = true; | |
| shaderCaps->fInfinitySupport = 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(SK_ARRAY_COUNT(kDxgiFormats) == GrD3DCaps::kNumDxgiFormats, | |
| "Size of DXGI_FORMATs array must match static value in header"); | |
| for (size_t i = 0; i < SK_ARRAY_COUNT(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(SK_ARRAY_COUNT(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 = GrSwizzle("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 = 2; | |
| info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); | |
| int ctIdx = 0; | |
| // 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 = GrSwizzle("000r"); | |
| ctInfo.fWriteSwizzle = GrSwizzle("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 = GrSwizzle("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 = GrSwizzle("000r"); | |
| ctInfo.fWriteSwizzle = GrSwizzle("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 = GrSwizzle("argb"); | |
| ctInfo.fWriteSwizzle = GrSwizzle("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 = GrSwizzle("000r"); | |
| ctInfo.fWriteSwizzle = GrSwizzle("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.count(); | |
| if (!count) { | |
| return 0; | |
| } | |
| if (1 == requestedCount) { | |
| SkASSERT(info.fColorSampleCounts.count() && 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.count()) { | |
| return 0; | |
| } | |
| return table[table.count() - 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 = GrAlignTo(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; | |
| } | |
| GrSwizzle 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 {}; | |
| } | |
| GrSwizzle 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(GrProcessorKeyBuilder* 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); | |
| GrProcessorKeyBuilder 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<GrCaps::TestFormatColorTypeCombination> GrD3DCaps::getTestingCombinations() const { | |
| std::vector<GrCaps::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 |