xref: /aosp_15_r20/external/skia/src/gpu/graphite/vk/VulkanYcbcrConversion.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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