blob: 51b59d7820e9c2de26272112c1f77e1694fd25aa [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/VulkanGraphiteUtilsPriv.h"
#include "src/gpu/graphite/vk/VulkanSharedContext.h"
namespace skgpu::graphite {
sk_sp<VulkanYcbcrConversion> 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<VulkanYcbcrConversion>(new VulkanYcbcrConversion(context, conversion));
}
sk_sp<VulkanYcbcrConversion> VulkanYcbcrConversion::Make(const VulkanSharedContext* context,
uint32_t nonFormatInfo,
uint64_t format) {
VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
bool useExternalFormat = static_cast<bool>(
(nonFormatInfo & ycbcrPackaging::kUseExternalFormatMask) >>
ycbcrPackaging::kUsesExternalFormatShift);
ycbcrCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
ycbcrCreateInfo.pNext = nullptr;
ycbcrCreateInfo.format = useExternalFormat ? VK_FORMAT_UNDEFINED
: static_cast<VkFormat>(format);
ycbcrCreateInfo.ycbcrModel = static_cast<VkSamplerYcbcrModelConversion>(
(nonFormatInfo & ycbcrPackaging::kYcbcrModelMask) >>
ycbcrPackaging::kYcbcrModelShift);
ycbcrCreateInfo.ycbcrRange = static_cast<VkSamplerYcbcrRange>(
(nonFormatInfo & ycbcrPackaging::kYcbcrRangeMask) >>
ycbcrPackaging::kYcbcrRangeShift);
ycbcrCreateInfo.components = {
static_cast<VkComponentSwizzle>(
(nonFormatInfo & ycbcrPackaging::kComponentRMask) >>
ycbcrPackaging::kComponentRShift),
static_cast<VkComponentSwizzle>(
(nonFormatInfo & ycbcrPackaging::kComponentGMask) >>
ycbcrPackaging::kComponentGShift),
static_cast<VkComponentSwizzle>(
(nonFormatInfo & ycbcrPackaging::kComponentBMask) >>
ycbcrPackaging::kComponentBShift),
static_cast<VkComponentSwizzle>(
(nonFormatInfo & ycbcrPackaging::kComponentAMask) >>
ycbcrPackaging::kComponentAShift)};
ycbcrCreateInfo.xChromaOffset = static_cast<VkChromaLocation>(
(nonFormatInfo & ycbcrPackaging::kXChromaOffsetMask) >>
ycbcrPackaging::kXChromaOffsetShift);
ycbcrCreateInfo.yChromaOffset = static_cast<VkChromaLocation>(
(nonFormatInfo & ycbcrPackaging::kYChromaOffsetMask) >>
ycbcrPackaging::kYChromaOffsetShift);
ycbcrCreateInfo.chromaFilter = static_cast<VkFilter>(
(nonFormatInfo & ycbcrPackaging::kChromaFilterMask) >>
ycbcrPackaging::kChromaFilterShift);
ycbcrCreateInfo.forceExplicitReconstruction = static_cast<VkBool32>(
(nonFormatInfo & ycbcrPackaging::kForceExplicitReconMask) >>
ycbcrPackaging::kForceExplicitReconShift);
#ifdef SK_BUILD_FOR_ANDROID
VkExternalFormatANDROID externalFormat;
if (useExternalFormat) {
externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
externalFormat.pNext = nullptr;
externalFormat.externalFormat = format;
SkASSERT(ycbcrCreateInfo.pNext == nullptr);
ycbcrCreateInfo.pNext = &externalFormat;
}
#endif
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));
}
namespace {
// Define this anonymous helper to get a static resource type for YCbCr conversions regardless of
// which method is used to create it (from VulkanYcbcrConversionInfo or from SamplerDesc)
ResourceType conversion_rsrc_type() {
static const ResourceType conversionType = GraphiteResourceKey::GenerateResourceType();
return conversionType;
}
}
GraphiteResourceKey VulkanYcbcrConversion::MakeYcbcrConversionKey(
const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& info) {
bool useExternalFormat = info.fFormat == VK_FORMAT_UNDEFINED;
GraphiteResourceKey key;
GraphiteResourceKey::Builder builder(&key,
conversion_rsrc_type(),
ycbcrPackaging::numInt32sNeeded(info),
Shareable::kYes);
int i = 0;
builder[i++] = ycbcrPackaging::nonFormatInfoAsUInt32(info);
if (useExternalFormat) {
builder[i++] = (uint32_t)info.fExternalFormat;
builder[i++] = (uint32_t)(info.fExternalFormat >> 32);
} else {
builder[i++] = (uint32_t)info.fFormat;
}
SkASSERT(i == ycbcrPackaging::numInt32sNeeded(info));
builder.finish();
return key;
}
GraphiteResourceKey VulkanYcbcrConversion::GetKeyFromSamplerDesc(const SamplerDesc& samplerDesc) {
GraphiteResourceKey key;
const SkSpan<const uint32_t>& samplerData = samplerDesc.asSpan();
GraphiteResourceKey::Builder builder(&key, conversion_rsrc_type(), samplerData.size(),
Shareable::kYes);
// The first index of sampler data (sampler desc value) includes non-ycbcr information
// that needs to be shifted past in order to isolate the ycbcr information for this key.
builder[0] = samplerData[0] >> SamplerDesc::kImmutableSamplerInfoShift;
for (size_t i = 1; i < samplerData.size(); i++) {
builder[i] = samplerData[i];
}
builder.finish();
return key;
}
VulkanYcbcrConversion::VulkanYcbcrConversion(const VulkanSharedContext* context,
VkSamplerYcbcrConversion ycbcrConversion)
: Resource(context,
Ownership::kOwned,
skgpu::Budgeted::kYes, // Shareable, so must be budgeted
/*gpuMemorySize=*/0)
, fYcbcrConversion (ycbcrConversion) {}
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