blob: 6c342bc7564460880b34ff98de79cb197eba1f19 [file] [log] [blame]
/*
* 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