| /* |
| * Copyright 2023 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/graphite/vk/VulkanYcbcrConversion.h" |
| |
| #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h" |
| #include "src/gpu/graphite/vk/VulkanCaps.h" |
| #include "src/gpu/graphite/vk/VulkanGraphiteUtils.h" |
| #include "src/gpu/graphite/vk/VulkanSharedContext.h" |
| |
| namespace skgpu::graphite { |
| |
| namespace { |
| |
| static constexpr int kUsesExternalFormatBits = 1; |
| static constexpr int kYcbcrModelBits = 3; |
| static constexpr int kYcbcrRangeBits = 1; |
| static constexpr int kXChromaOffsetBits = 1; |
| static constexpr int kYChromaOffsetBits = 1; |
| static constexpr int kChromaFilterBits = 1; |
| static constexpr int kForceExplicitReconBits = 1; |
| static constexpr int kComponentBits = 3; |
| static constexpr int kMatchChromaFilterBits = 1; |
| static constexpr int kSupportsLinearFilterBits = 1; |
| |
| |
| static constexpr int kUsesExternalFormatShift = 0; |
| static constexpr int kYcbcrModelShift = kUsesExternalFormatShift + |
| kUsesExternalFormatBits; |
| static constexpr int kYcbcrRangeShift = kYcbcrModelShift + kYcbcrModelBits; |
| static constexpr int kXChromaOffsetShift = kYcbcrRangeShift + kYcbcrRangeBits; |
| static constexpr int kYChromaOffsetShift = kXChromaOffsetShift + kXChromaOffsetBits; |
| static constexpr int kChromaFilterShift = kYChromaOffsetShift + kYChromaOffsetBits; |
| static constexpr int kForceExplicitReconShift = kChromaFilterShift + kChromaFilterBits; |
| static constexpr int kComponentRShift = kForceExplicitReconShift + |
| kForceExplicitReconBits; |
| static constexpr int kComponentGShift = kComponentRShift + kComponentBits; |
| static constexpr int kComponentBShift = kComponentGShift + kComponentBits; |
| static constexpr int kComponentAShift = kComponentBShift + kComponentBits; |
| static constexpr int kMatchChromaFilterShift = kComponentAShift + kComponentBits; |
| static constexpr int kSupportsLinearFilterShift = kMatchChromaFilterShift + kMatchChromaFilterBits; |
| |
| static constexpr uint32_t kUseExternalFormatMask = |
| ((1 << kUsesExternalFormatBits) - 1) << kUsesExternalFormatShift; |
| static constexpr uint32_t kYcbcrModelMask = |
| ((1 << kYcbcrModelBits) - 1) << kYcbcrModelShift; |
| static constexpr uint32_t kYcbcrRangeMask = |
| ((1 << kYcbcrRangeBits) - 1) << kYcbcrRangeShift; |
| static constexpr uint32_t kXChromaOffsetMask = |
| ((1 << kXChromaOffsetBits) - 1) << kXChromaOffsetShift; |
| static constexpr uint32_t kYChromaOffsetMask = |
| ((1 << kYChromaOffsetBits) - 1) << kYChromaOffsetShift; |
| static constexpr uint32_t kChromaFilterMask = |
| ((1 << kChromaFilterBits) - 1) << kChromaFilterShift; |
| static constexpr uint32_t kForceExplicitReconMask = |
| ((1 << kForceExplicitReconBits) - 1) << kForceExplicitReconShift; |
| static constexpr uint32_t kComponentRMask = ((1 << kComponentBits) - 1) << kComponentRShift; |
| static constexpr uint32_t kComponentBMask = ((1 << kComponentBits) - 1) << kComponentGShift; |
| static constexpr uint32_t kComponentGMask = ((1 << kComponentBits) - 1) << kComponentBShift; |
| static constexpr uint32_t kComponentAMask = ((1 << kComponentBits) - 1) << kComponentAShift; |
| static constexpr uint32_t kMatchChromaFilterMask = |
| ((1 << kMatchChromaFilterBits) - 1) << kMatchChromaFilterShift; |
| static constexpr uint32_t kSupportsLinearFilterMask = |
| ((1 << kSupportsLinearFilterBits) - 1) << kSupportsLinearFilterShift; |
| |
| } // anonymous namespace |
| |
| sk_sp<VulkanYcbcrConversion> VulkanYcbcrConversion::Make( |
| const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& conversionInfo) { |
| if (!context->vulkanCaps().supportsYcbcrConversion()) { |
| return nullptr; |
| } |
| |
| VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo; |
| std::optional<VkFilter> requiredSamplerFilter; |
| conversionInfo.toVkSamplerYcbcrConversionCreateInfo(&ycbcrCreateInfo, &requiredSamplerFilter); |
| |
| #ifdef SK_BUILD_FOR_ANDROID |
| VkExternalFormatANDROID externalFormat; |
| if (conversionInfo.hasExternalFormat()) { |
| // Format must not be specified for external images. |
| SkASSERT(conversionInfo.fFormat == VK_FORMAT_UNDEFINED); |
| externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; |
| externalFormat.pNext = nullptr; |
| externalFormat.externalFormat = conversionInfo.externalFormat(); |
| SkASSERT(ycbcrCreateInfo.pNext == nullptr); |
| ycbcrCreateInfo.pNext = &externalFormat; |
| } |
| #else |
| // External images are supported only on Android. |
| SkASSERT(!conversionInfo.hasExternalFormat()); |
| #endif |
| |
| if (!conversionInfo.hasExternalFormat()) { |
| SkASSERT(conversionInfo.format() != VK_FORMAT_UNDEFINED); |
| } |
| |
| VkSamplerYcbcrConversion conversion; |
| VkResult result; |
| VULKAN_CALL_RESULT(context, |
| result, |
| CreateSamplerYcbcrConversion( |
| context->device(), &ycbcrCreateInfo, nullptr, &conversion)); |
| if (result != VK_SUCCESS) { |
| return nullptr; |
| } |
| return sk_sp<VulkanYcbcrConversion>( |
| new VulkanYcbcrConversion(context, conversion, requiredSamplerFilter)); |
| } |
| |
| ImmutableSamplerInfo VulkanYcbcrConversion::ToImmutableSamplerInfo( |
| const VulkanYcbcrConversionInfo& conversionInfo) { |
| SkASSERT(conversionInfo.isValid()); |
| |
| static_assert(kSupportsLinearFilterShift + kSupportsLinearFilterBits <= 32); |
| |
| SkASSERT(conversionInfo.model() < (1u << kYcbcrModelBits )); |
| SkASSERT(conversionInfo.range() < (1u << kYcbcrRangeBits )); |
| SkASSERT(conversionInfo.xChromaOffset() < (1u << kXChromaOffsetBits )); |
| SkASSERT(conversionInfo.yChromaOffset() < (1u << kYChromaOffsetBits )); |
| SkASSERT(conversionInfo.chromaFilter() < (1u << kChromaFilterBits )); |
| SkASSERT(conversionInfo.forceExplicitReconstruction() < (1u << kForceExplicitReconBits )); |
| SkASSERT(conversionInfo.components().r < (1u << kComponentBits )); |
| SkASSERT(conversionInfo.components().g < (1u << kComponentBits )); |
| SkASSERT(conversionInfo.components().b < (1u << kComponentBits )); |
| SkASSERT(conversionInfo.components().a < (1u << kComponentBits )); |
| |
| const bool usesExternalFormat = conversionInfo.hasExternalFormat(); |
| const bool matchChroma = conversionInfo.fSamplerFilterMustMatchChromaFilter; |
| const bool supportsLinear = conversionInfo.fSupportsLinearFilter; |
| |
| ImmutableSamplerInfo info; |
| info.fNonFormatYcbcrConversionInfo = |
| (((uint32_t)(usesExternalFormat ) << kUsesExternalFormatShift ) | |
| ((uint32_t)(conversionInfo.model() ) << kYcbcrModelShift ) | |
| ((uint32_t)(conversionInfo.range() ) << kYcbcrRangeShift ) | |
| ((uint32_t)(conversionInfo.xChromaOffset() ) << kXChromaOffsetShift ) | |
| ((uint32_t)(conversionInfo.yChromaOffset() ) << kYChromaOffsetShift ) | |
| ((uint32_t)(conversionInfo.chromaFilter() ) << kChromaFilterShift ) | |
| ((uint32_t)(conversionInfo.forceExplicitReconstruction()) << kForceExplicitReconShift ) | |
| ((uint32_t)(conversionInfo.components().r ) << kComponentRShift ) | |
| ((uint32_t)(conversionInfo.components().g ) << kComponentGShift ) | |
| ((uint32_t)(conversionInfo.components().b ) << kComponentBShift ) | |
| ((uint32_t)(conversionInfo.components().a ) << kComponentAShift ) | |
| ((uint32_t)(matchChroma ) << kMatchChromaFilterShift ) | |
| ((uint32_t)(supportsLinear ) << kSupportsLinearFilterShift)); |
| |
| SkASSERT(info.fNonFormatYcbcrConversionInfo >> SamplerDesc::kMaxNumConversionInfoBits == 0); |
| |
| info.fFormat = usesExternalFormat ? conversionInfo.externalFormat() |
| : static_cast<uint64_t>(conversionInfo.format()); |
| return info; |
| } |
| |
| VulkanYcbcrConversionInfo VulkanYcbcrConversion::FromImmutableSamplerInfo( |
| ImmutableSamplerInfo info) { |
| const uint32_t nonFormatInfo = info.fNonFormatYcbcrConversionInfo; |
| |
| VkFormat format = VK_FORMAT_UNDEFINED; |
| uint64_t externalFormat = 0; |
| |
| const bool usesExternalFormat = |
| (nonFormatInfo >> kUsesExternalFormatShift) & kUseExternalFormatMask; |
| if (usesExternalFormat) { |
| externalFormat = info.fFormat; |
| } else { |
| format = static_cast<VkFormat>(info.fFormat); |
| } |
| |
| VkSamplerYcbcrModelConversion model = |
| static_cast<VkSamplerYcbcrModelConversion>( |
| (nonFormatInfo & kYcbcrModelMask) >> kYcbcrModelShift); |
| VkSamplerYcbcrRange range = |
| static_cast<VkSamplerYcbcrRange>( |
| (nonFormatInfo & kYcbcrRangeMask) >> kYcbcrRangeShift); |
| VkComponentMapping components = |
| { static_cast<VkComponentSwizzle>( |
| (nonFormatInfo & kComponentRMask) >> kComponentRShift), |
| static_cast<VkComponentSwizzle>( |
| (nonFormatInfo & kComponentGMask) >> kComponentGShift), |
| static_cast<VkComponentSwizzle>( |
| (nonFormatInfo & kComponentBMask) >> kComponentBShift), |
| static_cast<VkComponentSwizzle>( |
| (nonFormatInfo & kComponentAMask) >> kComponentAShift) }; |
| VkChromaLocation xChromaOffset = |
| static_cast<VkChromaLocation>( |
| (nonFormatInfo & kXChromaOffsetMask) >> kXChromaOffsetShift); |
| VkChromaLocation yChromaOffset = |
| static_cast<VkChromaLocation>( |
| (nonFormatInfo & kYChromaOffsetMask) >> kYChromaOffsetShift); |
| VkFilter chromaFilter = static_cast<VkFilter>( |
| (nonFormatInfo & kChromaFilterMask) >> kChromaFilterShift); |
| VkBool32 forceExplicitReconstruction = |
| static_cast<VkBool32>( |
| (nonFormatInfo & kForceExplicitReconMask) >> kForceExplicitReconShift); |
| |
| bool chromaMustMatch = |
| static_cast<bool>((nonFormatInfo & kMatchChromaFilterMask) >> kMatchChromaFilterShift); |
| bool supportsLinearFilter = |
| static_cast<bool>( |
| (nonFormatInfo & kSupportsLinearFilterMask) >> kSupportsLinearFilterShift); |
| |
| |
| VulkanYcbcrConversionInfo vkInfo(format, externalFormat, model, range, xChromaOffset, |
| yChromaOffset, chromaFilter, forceExplicitReconstruction, |
| components, chromaMustMatch, supportsLinearFilter); |
| |
| return vkInfo; |
| } |
| |
| VulkanYcbcrConversion::VulkanYcbcrConversion(const VulkanSharedContext* context, |
| VkSamplerYcbcrConversion ycbcrConversion, |
| std::optional<VkFilter> requiredFilter) |
| : Resource(context, |
| Ownership::kOwned, |
| /*gpuMemorySize=*/0, |
| /*reusableRequiresPurgeable=*/false) |
| , fYcbcrConversion(ycbcrConversion) |
| , fRequiredFilter(requiredFilter) {} |
| |
| void VulkanYcbcrConversion::freeGpuData() { |
| auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext()); |
| SkASSERT(fYcbcrConversion != VK_NULL_HANDLE); |
| VULKAN_CALL(sharedContext->interface(), |
| DestroySamplerYcbcrConversion(sharedContext->device(), fYcbcrConversion, nullptr)); |
| } |
| |
| } // namespace skgpu::graphite |