1 /*
2 * Copyright 2023 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/graphite/vk/VulkanYcbcrConversion.h"
9
10 #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
11 #include "src/gpu/graphite/vk/VulkanCaps.h"
12 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
13 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
14
15 namespace skgpu::graphite {
16
Make(const VulkanSharedContext * context,const VulkanYcbcrConversionInfo & conversionInfo)17 sk_sp<VulkanYcbcrConversion> VulkanYcbcrConversion::Make(
18 const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& conversionInfo) {
19 if (!context->vulkanCaps().supportsYcbcrConversion()) {
20 return nullptr;
21 }
22
23 VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
24 skgpu::SetupSamplerYcbcrConversionInfo(&ycbcrCreateInfo, conversionInfo);
25
26 #ifdef SK_BUILD_FOR_ANDROID
27 VkExternalFormatANDROID externalFormat;
28 if (conversionInfo.fExternalFormat) {
29 // Format must not be specified for external images.
30 SkASSERT(conversionInfo.fFormat == VK_FORMAT_UNDEFINED);
31 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
32 externalFormat.pNext = nullptr;
33 externalFormat.externalFormat = conversionInfo.fExternalFormat;
34 SkASSERT(ycbcrCreateInfo.pNext == nullptr);
35 ycbcrCreateInfo.pNext = &externalFormat;
36 }
37 #else
38 // External images are supported only on Android.
39 SkASSERT(!conversionInfo.fExternalFormat);
40 #endif
41
42 if (!conversionInfo.fExternalFormat) {
43 SkASSERT(conversionInfo.fFormat != VK_FORMAT_UNDEFINED);
44 }
45
46 VkSamplerYcbcrConversion conversion;
47 VkResult result;
48 VULKAN_CALL_RESULT(context,
49 result,
50 CreateSamplerYcbcrConversion(
51 context->device(), &ycbcrCreateInfo, nullptr, &conversion));
52 if (result != VK_SUCCESS) {
53 return nullptr;
54 }
55 return sk_sp<VulkanYcbcrConversion>(new VulkanYcbcrConversion(context, conversion));
56 }
57
Make(const VulkanSharedContext * context,uint32_t nonFormatInfo,uint64_t format)58 sk_sp<VulkanYcbcrConversion> VulkanYcbcrConversion::Make(const VulkanSharedContext* context,
59 uint32_t nonFormatInfo,
60 uint64_t format) {
61 VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
62
63 bool useExternalFormat = static_cast<bool>(
64 (nonFormatInfo & ycbcrPackaging::kUseExternalFormatMask) >>
65 ycbcrPackaging::kUsesExternalFormatShift);
66
67 ycbcrCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
68 ycbcrCreateInfo.pNext = nullptr;
69 ycbcrCreateInfo.format = useExternalFormat ? VK_FORMAT_UNDEFINED
70 : static_cast<VkFormat>(format);
71
72 ycbcrCreateInfo.ycbcrModel = static_cast<VkSamplerYcbcrModelConversion>(
73 (nonFormatInfo & ycbcrPackaging::kYcbcrModelMask) >>
74 ycbcrPackaging::kYcbcrModelShift);
75 ycbcrCreateInfo.ycbcrRange = static_cast<VkSamplerYcbcrRange>(
76 (nonFormatInfo & ycbcrPackaging::kYcbcrRangeMask) >>
77 ycbcrPackaging::kYcbcrRangeShift);
78 ycbcrCreateInfo.components = {
79 static_cast<VkComponentSwizzle>(
80 (nonFormatInfo & ycbcrPackaging::kComponentRMask) >>
81 ycbcrPackaging::kComponentRShift),
82 static_cast<VkComponentSwizzle>(
83 (nonFormatInfo & ycbcrPackaging::kComponentGMask) >>
84 ycbcrPackaging::kComponentGShift),
85 static_cast<VkComponentSwizzle>(
86 (nonFormatInfo & ycbcrPackaging::kComponentBMask) >>
87 ycbcrPackaging::kComponentBShift),
88 static_cast<VkComponentSwizzle>(
89 (nonFormatInfo & ycbcrPackaging::kComponentAMask) >>
90 ycbcrPackaging::kComponentAShift)};
91 ycbcrCreateInfo.xChromaOffset = static_cast<VkChromaLocation>(
92 (nonFormatInfo & ycbcrPackaging::kXChromaOffsetMask) >>
93 ycbcrPackaging::kXChromaOffsetShift);
94 ycbcrCreateInfo.yChromaOffset = static_cast<VkChromaLocation>(
95 (nonFormatInfo & ycbcrPackaging::kYChromaOffsetMask) >>
96 ycbcrPackaging::kYChromaOffsetShift);
97 ycbcrCreateInfo.chromaFilter = static_cast<VkFilter>(
98 (nonFormatInfo & ycbcrPackaging::kChromaFilterMask) >>
99 ycbcrPackaging::kChromaFilterShift);
100 ycbcrCreateInfo.forceExplicitReconstruction = static_cast<VkBool32>(
101 (nonFormatInfo & ycbcrPackaging::kForceExplicitReconMask) >>
102 ycbcrPackaging::kForceExplicitReconShift);
103
104 #ifdef SK_BUILD_FOR_ANDROID
105 VkExternalFormatANDROID externalFormat;
106 if (useExternalFormat) {
107 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
108 externalFormat.pNext = nullptr;
109 externalFormat.externalFormat = format;
110 SkASSERT(ycbcrCreateInfo.pNext == nullptr);
111 ycbcrCreateInfo.pNext = &externalFormat;
112 }
113 #endif
114
115 VkSamplerYcbcrConversion conversion;
116 VkResult result;
117 VULKAN_CALL_RESULT(context,
118 result,
119 CreateSamplerYcbcrConversion(
120 context->device(), &ycbcrCreateInfo, nullptr, &conversion));
121 if (result != VK_SUCCESS) {
122 return nullptr;
123 }
124 return sk_sp<VulkanYcbcrConversion>(new VulkanYcbcrConversion(context, conversion));
125 }
126
127 namespace {
128 // Define this anonymous helper to get a static resource type for YCbCr conversions regardless of
129 // which method is used to create it (from VulkanYcbcrConversionInfo or from SamplerDesc)
conversion_rsrc_type()130 ResourceType conversion_rsrc_type() {
131 static const ResourceType conversionType = GraphiteResourceKey::GenerateResourceType();
132 return conversionType;
133 }
134 }
MakeYcbcrConversionKey(const VulkanSharedContext * context,const VulkanYcbcrConversionInfo & info)135 GraphiteResourceKey VulkanYcbcrConversion::MakeYcbcrConversionKey(
136 const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& info) {
137 bool useExternalFormat = info.fFormat == VK_FORMAT_UNDEFINED;
138 GraphiteResourceKey key;
139 GraphiteResourceKey::Builder builder(&key,
140 conversion_rsrc_type(),
141 ycbcrPackaging::numInt32sNeeded(info),
142 Shareable::kYes);
143 int i = 0;
144 builder[i++] = ycbcrPackaging::nonFormatInfoAsUInt32(info);
145 if (useExternalFormat) {
146 builder[i++] = (uint32_t)info.fExternalFormat;
147 builder[i++] = (uint32_t)(info.fExternalFormat >> 32);
148 } else {
149 builder[i++] = (uint32_t)info.fFormat;
150 }
151 SkASSERT(i == ycbcrPackaging::numInt32sNeeded(info));
152
153 builder.finish();
154 return key;
155 }
156
GetKeyFromSamplerDesc(const SamplerDesc & samplerDesc)157 GraphiteResourceKey VulkanYcbcrConversion::GetKeyFromSamplerDesc(const SamplerDesc& samplerDesc) {
158 GraphiteResourceKey key;
159 const SkSpan<const uint32_t>& samplerData = samplerDesc.asSpan();
160 GraphiteResourceKey::Builder builder(&key, conversion_rsrc_type(), samplerData.size(),
161 Shareable::kYes);
162
163 // The first index of sampler data (sampler desc value) includes non-ycbcr information
164 // that needs to be shifted past in order to isolate the ycbcr information for this key.
165 builder[0] = samplerData[0] >> SamplerDesc::kImmutableSamplerInfoShift;
166 for (size_t i = 1; i < samplerData.size(); i++) {
167 builder[i] = samplerData[i];
168 }
169
170 builder.finish();
171 return key;
172 }
173
VulkanYcbcrConversion(const VulkanSharedContext * context,VkSamplerYcbcrConversion ycbcrConversion)174 VulkanYcbcrConversion::VulkanYcbcrConversion(const VulkanSharedContext* context,
175 VkSamplerYcbcrConversion ycbcrConversion)
176 : Resource(context,
177 Ownership::kOwned,
178 skgpu::Budgeted::kYes, // Shareable, so must be budgeted
179 /*gpuMemorySize=*/0)
180 , fYcbcrConversion (ycbcrConversion) {}
181
freeGpuData()182 void VulkanYcbcrConversion::freeGpuData() {
183 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
184 SkASSERT(fYcbcrConversion != VK_NULL_HANDLE);
185 VULKAN_CALL(sharedContext->interface(),
186 DestroySamplerYcbcrConversion(sharedContext->device(), fYcbcrConversion, nullptr));
187 }
188
189 } // namespace skgpu::graphite
190
191