/* * Copyright 2018 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/vk/GrVkSamplerYcbcrConversion.h" #include "src/gpu/vk/GrVkGpu.h" GrVkSamplerYcbcrConversion* GrVkSamplerYcbcrConversion::Create( const GrVkGpu* gpu, const GrVkYcbcrConversionInfo& info) { if (!gpu->vkCaps().supportsYcbcrConversion()) { return nullptr; } // We only support creating ycbcr conversion for external formats; SkASSERT(info.fExternalFormat); #ifdef SK_DEBUG const VkFormatFeatureFlags& featureFlags = info.fExternalFormatFeatures; if (info.fXChromaOffset == VK_CHROMA_LOCATION_MIDPOINT || info.fYChromaOffset == VK_CHROMA_LOCATION_MIDPOINT) { SkASSERT(featureFlags & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT); } if (info.fXChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN || info.fYChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN) { SkASSERT(featureFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT); } if (info.fChromaFilter == VK_FILTER_LINEAR) { SkASSERT(featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT); } if (info.fForceExplicitReconstruction) { SkASSERT(featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT); } #endif #ifdef SK_BUILD_FOR_ANDROID VkExternalFormatANDROID externalFormat; externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; externalFormat.pNext = nullptr; externalFormat.externalFormat = info.fExternalFormat; VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo; memset(&ycbcrCreateInfo, 0, sizeof(VkSamplerYcbcrConversionCreateInfo)); ycbcrCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO; ycbcrCreateInfo.pNext = &externalFormat; ycbcrCreateInfo.format = VK_FORMAT_UNDEFINED; ycbcrCreateInfo.ycbcrModel = info.fYcbcrModel; ycbcrCreateInfo.ycbcrRange = info.fYcbcrRange; // Componets is ignored for external format conversions; // ycbcrCreateInfo.components = {0, 0, 0, 0}; ycbcrCreateInfo.xChromaOffset = info.fXChromaOffset; ycbcrCreateInfo.yChromaOffset = info.fYChromaOffset; ycbcrCreateInfo.chromaFilter = info.fChromaFilter; ycbcrCreateInfo.forceExplicitReconstruction = info.fForceExplicitReconstruction; VkSamplerYcbcrConversion conversion; GR_VK_CALL(gpu->vkInterface(), CreateSamplerYcbcrConversion(gpu->device(), &ycbcrCreateInfo, nullptr, &conversion)); if (conversion == VK_NULL_HANDLE) { return nullptr; } return new GrVkSamplerYcbcrConversion(conversion, GenerateKey(info)); #else return nullptr; #endif } void GrVkSamplerYcbcrConversion::freeGPUData(GrVkGpu* gpu) const { SkASSERT(fYcbcrConversion); GR_VK_CALL(gpu->vkInterface(), DestroySamplerYcbcrConversion(gpu->device(), fYcbcrConversion, nullptr)); } GrVkSamplerYcbcrConversion::Key GrVkSamplerYcbcrConversion::GenerateKey( const GrVkYcbcrConversionInfo& ycbcrInfo) { SkASSERT(static_cast(ycbcrInfo.fYcbcrModel <= 7)); static const int kRangeShift = 3; SkASSERT(static_cast(ycbcrInfo.fYcbcrRange) <= 1); static const int kXChromaOffsetShift = kRangeShift + 1; SkASSERT(static_cast(ycbcrInfo.fXChromaOffset) <= 1); static const int kYChromaOffsetShift = kXChromaOffsetShift + 1; SkASSERT(static_cast(ycbcrInfo.fXChromaOffset) <= 1); static const int kChromaFilterShift = kYChromaOffsetShift + 1; SkASSERT(static_cast(ycbcrInfo.fChromaFilter) <= 1); static const int kReconShift = kChromaFilterShift + 1; SkASSERT(static_cast(ycbcrInfo.fForceExplicitReconstruction) <= 1); GR_STATIC_ASSERT(kReconShift <= 7); uint8_t ycbcrKey = static_cast(ycbcrInfo.fYcbcrModel); ycbcrKey |= (static_cast(ycbcrInfo.fYcbcrRange) << kRangeShift); ycbcrKey |= (static_cast(ycbcrInfo.fXChromaOffset) << kXChromaOffsetShift); ycbcrKey |= (static_cast(ycbcrInfo.fYChromaOffset) << kYChromaOffsetShift); ycbcrKey |= (static_cast(ycbcrInfo.fChromaFilter) << kChromaFilterShift); ycbcrKey |= (static_cast(ycbcrInfo.fForceExplicitReconstruction) << kReconShift); return {ycbcrInfo.fExternalFormat, ycbcrKey}; }