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