/* * 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 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 + kComponentBits; static constexpr int kComponentGShift = kComponentRShift + kComponentBits; static constexpr int kComponentBShift = kComponentGShift + kComponentBits; static constexpr int kComponentAShift = kComponentBShift + kComponentBits; 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; } // anonymous namespace sk_sp VulkanYcbcrConversion::Make( const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& conversionInfo) { if (!context->vulkanCaps().supportsYcbcrConversion()) { return nullptr; } VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo; skgpu::SetupSamplerYcbcrConversionInfo(&ycbcrCreateInfo, conversionInfo); #ifdef SK_BUILD_FOR_ANDROID VkExternalFormatANDROID externalFormat; if (conversionInfo.fExternalFormat) { // 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.fExternalFormat; SkASSERT(ycbcrCreateInfo.pNext == nullptr); ycbcrCreateInfo.pNext = &externalFormat; } #else // External images are supported only on Android. SkASSERT(!conversionInfo.fExternalFormat); #endif if (!conversionInfo.fExternalFormat) { SkASSERT(conversionInfo.fFormat != 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(new VulkanYcbcrConversion(context, conversion)); } ImmutableSamplerInfo VulkanYcbcrConversion::ToImmutableSamplerInfo( const VulkanYcbcrConversionInfo& conversionInfo) { SkASSERT(conversionInfo.isValid()); static_assert(kComponentAShift + kComponentBits <= 32); SkASSERT(conversionInfo.fYcbcrModel < (1u << kYcbcrModelBits )); SkASSERT(conversionInfo.fYcbcrRange < (1u << kYcbcrRangeBits )); SkASSERT(conversionInfo.fXChromaOffset < (1u << kXChromaOffsetBits )); SkASSERT(conversionInfo.fYChromaOffset < (1u << kYChromaOffsetBits )); SkASSERT(conversionInfo.fChromaFilter < (1u << kChromaFilterBits )); SkASSERT(conversionInfo.fForceExplicitReconstruction < (1u << kForceExplicitReconBits)); SkASSERT(conversionInfo.fComponents.r < (1u << kComponentBits )); SkASSERT(conversionInfo.fComponents.g < (1u << kComponentBits )); SkASSERT(conversionInfo.fComponents.b < (1u << kComponentBits )); SkASSERT(conversionInfo.fComponents.a < (1u << kComponentBits )); const bool usesExternalFormat = conversionInfo.fFormat == VK_FORMAT_UNDEFINED; ImmutableSamplerInfo info; info.fNonFormatYcbcrConversionInfo = (((uint32_t)(usesExternalFormat ) << kUsesExternalFormatShift) | ((uint32_t)(conversionInfo.fYcbcrModel ) << kYcbcrModelShift ) | ((uint32_t)(conversionInfo.fYcbcrRange ) << kYcbcrRangeShift ) | ((uint32_t)(conversionInfo.fXChromaOffset ) << kXChromaOffsetShift ) | ((uint32_t)(conversionInfo.fYChromaOffset ) << kYChromaOffsetShift ) | ((uint32_t)(conversionInfo.fChromaFilter ) << kChromaFilterShift ) | ((uint32_t)(conversionInfo.fForceExplicitReconstruction) << kForceExplicitReconShift) | ((uint32_t)(conversionInfo.fComponents.r ) << kComponentRShift ) | ((uint32_t)(conversionInfo.fComponents.g ) << kComponentGShift ) | ((uint32_t)(conversionInfo.fComponents.b ) << kComponentBShift ) | ((uint32_t)(conversionInfo.fComponents.a ) << kComponentAShift )); info.fFormat = usesExternalFormat ? conversionInfo.fExternalFormat : conversionInfo.fFormat; return info; } VulkanYcbcrConversionInfo VulkanYcbcrConversion::FromImmutableSamplerInfo( ImmutableSamplerInfo info) { const uint32_t nonFormatInfo = info.fNonFormatYcbcrConversionInfo; VulkanYcbcrConversionInfo vkInfo; const bool usesExternalFormat = (nonFormatInfo >> kUsesExternalFormatShift) & kUseExternalFormatMask; if (usesExternalFormat) { vkInfo.fFormat = VK_FORMAT_UNDEFINED; vkInfo.fExternalFormat = info.fFormat; } else { vkInfo.fFormat = static_cast(info.fFormat); vkInfo.fExternalFormat = 0; } vkInfo.fYcbcrModel = static_cast( (nonFormatInfo & kYcbcrModelMask) >> kYcbcrModelShift); vkInfo.fYcbcrRange = static_cast( (nonFormatInfo & kYcbcrRangeMask) >> kYcbcrRangeShift); vkInfo.fComponents = { static_cast( (nonFormatInfo & kComponentRMask) >> kComponentRShift), static_cast( (nonFormatInfo & kComponentGMask) >> kComponentGShift), static_cast( (nonFormatInfo & kComponentBMask) >> kComponentBShift), static_cast( (nonFormatInfo & kComponentAMask) >> kComponentAShift) }; vkInfo.fXChromaOffset = static_cast( (nonFormatInfo & kXChromaOffsetMask) >> kXChromaOffsetShift); vkInfo.fYChromaOffset = static_cast( (nonFormatInfo & kYChromaOffsetMask) >> kYChromaOffsetShift); vkInfo.fChromaFilter = static_cast( (nonFormatInfo & kChromaFilterMask) >> kChromaFilterShift); vkInfo.fForceExplicitReconstruction = static_cast( (nonFormatInfo & kForceExplicitReconMask) >> kForceExplicitReconShift); return vkInfo; } VulkanYcbcrConversion::VulkanYcbcrConversion(const VulkanSharedContext* context, VkSamplerYcbcrConversion ycbcrConversion) : Resource(context, Ownership::kOwned, /*gpuMemorySize=*/0) , fYcbcrConversion (ycbcrConversion) {} void VulkanYcbcrConversion::freeGpuData() { auto sharedContext = static_cast(this->sharedContext()); SkASSERT(fYcbcrConversion != VK_NULL_HANDLE); VULKAN_CALL(sharedContext->interface(), DestroySamplerYcbcrConversion(sharedContext->device(), fYcbcrConversion, nullptr)); } } // namespace skgpu::graphite