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