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/VulkanGraphiteUtils.h"
13 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
14
15 namespace skgpu::graphite {
16
17 namespace {
18
19 static constexpr int kUsesExternalFormatBits = 1;
20 static constexpr int kYcbcrModelBits = 3;
21 static constexpr int kYcbcrRangeBits = 1;
22 static constexpr int kXChromaOffsetBits = 1;
23 static constexpr int kYChromaOffsetBits = 1;
24 static constexpr int kChromaFilterBits = 1;
25 static constexpr int kForceExplicitReconBits = 1;
26 static constexpr int kComponentBits = 3;
27
28 static constexpr int kUsesExternalFormatShift = 0;
29 static constexpr int kYcbcrModelShift = kUsesExternalFormatShift +
30 kUsesExternalFormatBits;
31 static constexpr int kYcbcrRangeShift = kYcbcrModelShift + kYcbcrModelBits;
32 static constexpr int kXChromaOffsetShift = kYcbcrRangeShift + kYcbcrRangeBits;
33 static constexpr int kYChromaOffsetShift = kXChromaOffsetShift + kXChromaOffsetBits;
34 static constexpr int kChromaFilterShift = kYChromaOffsetShift + kYChromaOffsetBits;
35 static constexpr int kForceExplicitReconShift = kChromaFilterShift + kChromaFilterBits;
36 static constexpr int kComponentRShift = kForceExplicitReconShift + kComponentBits;
37 static constexpr int kComponentGShift = kComponentRShift + kComponentBits;
38 static constexpr int kComponentBShift = kComponentGShift + kComponentBits;
39 static constexpr int kComponentAShift = kComponentBShift + kComponentBits;
40
41 static constexpr uint32_t kUseExternalFormatMask =
42 ((1 << kUsesExternalFormatBits) - 1) << kUsesExternalFormatShift;
43 static constexpr uint32_t kYcbcrModelMask =
44 ((1 << kYcbcrModelBits) - 1) << kYcbcrModelShift;
45 static constexpr uint32_t kYcbcrRangeMask =
46 ((1 << kYcbcrRangeBits) - 1) << kYcbcrRangeShift;
47 static constexpr uint32_t kXChromaOffsetMask =
48 ((1 << kXChromaOffsetBits) - 1) << kXChromaOffsetShift;
49 static constexpr uint32_t kYChromaOffsetMask =
50 ((1 << kYChromaOffsetBits) - 1) << kYChromaOffsetShift;
51 static constexpr uint32_t kChromaFilterMask =
52 ((1 << kChromaFilterBits) - 1) << kChromaFilterShift;
53 static constexpr uint32_t kForceExplicitReconMask =
54 ((1 << kForceExplicitReconBits) - 1) << kForceExplicitReconShift;
55 static constexpr uint32_t kComponentRMask = ((1 << kComponentBits) - 1) << kComponentRShift;
56 static constexpr uint32_t kComponentBMask = ((1 << kComponentBits) - 1) << kComponentGShift;
57 static constexpr uint32_t kComponentGMask = ((1 << kComponentBits) - 1) << kComponentBShift;
58 static constexpr uint32_t kComponentAMask = ((1 << kComponentBits) - 1) << kComponentAShift;
59
60 } // anonymous namespace
61
Make(const VulkanSharedContext * context,const VulkanYcbcrConversionInfo & conversionInfo)62 sk_sp<VulkanYcbcrConversion> VulkanYcbcrConversion::Make(
63 const VulkanSharedContext* context, const VulkanYcbcrConversionInfo& conversionInfo) {
64 if (!context->vulkanCaps().supportsYcbcrConversion()) {
65 return nullptr;
66 }
67
68 VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
69 skgpu::SetupSamplerYcbcrConversionInfo(&ycbcrCreateInfo, conversionInfo);
70
71 #ifdef SK_BUILD_FOR_ANDROID
72 VkExternalFormatANDROID externalFormat;
73 if (conversionInfo.fExternalFormat) {
74 // Format must not be specified for external images.
75 SkASSERT(conversionInfo.fFormat == VK_FORMAT_UNDEFINED);
76 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
77 externalFormat.pNext = nullptr;
78 externalFormat.externalFormat = conversionInfo.fExternalFormat;
79 SkASSERT(ycbcrCreateInfo.pNext == nullptr);
80 ycbcrCreateInfo.pNext = &externalFormat;
81 }
82 #else
83 // External images are supported only on Android.
84 SkASSERT(!conversionInfo.fExternalFormat);
85 #endif
86
87 if (!conversionInfo.fExternalFormat) {
88 SkASSERT(conversionInfo.fFormat != VK_FORMAT_UNDEFINED);
89 }
90
91 VkSamplerYcbcrConversion conversion;
92 VkResult result;
93 VULKAN_CALL_RESULT(context,
94 result,
95 CreateSamplerYcbcrConversion(
96 context->device(), &ycbcrCreateInfo, nullptr, &conversion));
97 if (result != VK_SUCCESS) {
98 return nullptr;
99 }
100 return sk_sp<VulkanYcbcrConversion>(new VulkanYcbcrConversion(context, conversion));
101 }
102
ToImmutableSamplerInfo(const VulkanYcbcrConversionInfo & conversionInfo)103 ImmutableSamplerInfo VulkanYcbcrConversion::ToImmutableSamplerInfo(
104 const VulkanYcbcrConversionInfo& conversionInfo) {
105 SkASSERT(conversionInfo.isValid());
106
107 static_assert(kComponentAShift + kComponentBits <= 32);
108
109 SkASSERT(conversionInfo.fYcbcrModel < (1u << kYcbcrModelBits ));
110 SkASSERT(conversionInfo.fYcbcrRange < (1u << kYcbcrRangeBits ));
111 SkASSERT(conversionInfo.fXChromaOffset < (1u << kXChromaOffsetBits ));
112 SkASSERT(conversionInfo.fYChromaOffset < (1u << kYChromaOffsetBits ));
113 SkASSERT(conversionInfo.fChromaFilter < (1u << kChromaFilterBits ));
114 SkASSERT(conversionInfo.fForceExplicitReconstruction < (1u << kForceExplicitReconBits));
115 SkASSERT(conversionInfo.fComponents.r < (1u << kComponentBits ));
116 SkASSERT(conversionInfo.fComponents.g < (1u << kComponentBits ));
117 SkASSERT(conversionInfo.fComponents.b < (1u << kComponentBits ));
118 SkASSERT(conversionInfo.fComponents.a < (1u << kComponentBits ));
119
120 const bool usesExternalFormat = conversionInfo.fFormat == VK_FORMAT_UNDEFINED;
121
122 ImmutableSamplerInfo info;
123 info.fNonFormatYcbcrConversionInfo =
124 (((uint32_t)(usesExternalFormat ) << kUsesExternalFormatShift) |
125 ((uint32_t)(conversionInfo.fYcbcrModel ) << kYcbcrModelShift ) |
126 ((uint32_t)(conversionInfo.fYcbcrRange ) << kYcbcrRangeShift ) |
127 ((uint32_t)(conversionInfo.fXChromaOffset ) << kXChromaOffsetShift ) |
128 ((uint32_t)(conversionInfo.fYChromaOffset ) << kYChromaOffsetShift ) |
129 ((uint32_t)(conversionInfo.fChromaFilter ) << kChromaFilterShift ) |
130 ((uint32_t)(conversionInfo.fForceExplicitReconstruction) << kForceExplicitReconShift) |
131 ((uint32_t)(conversionInfo.fComponents.r ) << kComponentRShift ) |
132 ((uint32_t)(conversionInfo.fComponents.g ) << kComponentGShift ) |
133 ((uint32_t)(conversionInfo.fComponents.b ) << kComponentBShift ) |
134 ((uint32_t)(conversionInfo.fComponents.a ) << kComponentAShift ));
135 info.fFormat = usesExternalFormat ? conversionInfo.fExternalFormat : conversionInfo.fFormat;
136 return info;
137 }
138
FromImmutableSamplerInfo(ImmutableSamplerInfo info)139 VulkanYcbcrConversionInfo VulkanYcbcrConversion::FromImmutableSamplerInfo(
140 ImmutableSamplerInfo info) {
141 const uint32_t nonFormatInfo = info.fNonFormatYcbcrConversionInfo;
142
143 VulkanYcbcrConversionInfo vkInfo;
144 const bool usesExternalFormat =
145 (nonFormatInfo >> kUsesExternalFormatShift) & kUseExternalFormatMask;
146 if (usesExternalFormat) {
147 vkInfo.fFormat = VK_FORMAT_UNDEFINED;
148 vkInfo.fExternalFormat = info.fFormat;
149 } else {
150 vkInfo.fFormat = static_cast<VkFormat>(info.fFormat);
151 vkInfo.fExternalFormat = 0;
152 }
153
154 vkInfo.fYcbcrModel = static_cast<VkSamplerYcbcrModelConversion>(
155 (nonFormatInfo & kYcbcrModelMask) >> kYcbcrModelShift);
156 vkInfo.fYcbcrRange = static_cast<VkSamplerYcbcrRange>(
157 (nonFormatInfo & kYcbcrRangeMask) >> kYcbcrRangeShift);
158 vkInfo.fComponents = { static_cast<VkComponentSwizzle>(
159 (nonFormatInfo & kComponentRMask) >> kComponentRShift),
160 static_cast<VkComponentSwizzle>(
161 (nonFormatInfo & kComponentGMask) >> kComponentGShift),
162 static_cast<VkComponentSwizzle>(
163 (nonFormatInfo & kComponentBMask) >> kComponentBShift),
164 static_cast<VkComponentSwizzle>(
165 (nonFormatInfo & kComponentAMask) >> kComponentAShift) };
166 vkInfo.fXChromaOffset = static_cast<VkChromaLocation>(
167 (nonFormatInfo & kXChromaOffsetMask) >> kXChromaOffsetShift);
168 vkInfo.fYChromaOffset = static_cast<VkChromaLocation>(
169 (nonFormatInfo & kYChromaOffsetMask) >> kYChromaOffsetShift);
170 vkInfo.fChromaFilter = static_cast<VkFilter>(
171 (nonFormatInfo & kChromaFilterMask) >> kChromaFilterShift);
172
173 vkInfo.fForceExplicitReconstruction = static_cast<VkBool32>(
174 (nonFormatInfo & kForceExplicitReconMask) >> kForceExplicitReconShift);
175
176 return vkInfo;
177 }
178
VulkanYcbcrConversion(const VulkanSharedContext * context,VkSamplerYcbcrConversion ycbcrConversion)179 VulkanYcbcrConversion::VulkanYcbcrConversion(const VulkanSharedContext* context,
180 VkSamplerYcbcrConversion ycbcrConversion)
181 : Resource(context,
182 Ownership::kOwned,
183 /*gpuMemorySize=*/0)
184 , fYcbcrConversion (ycbcrConversion) {}
185
freeGpuData()186 void VulkanYcbcrConversion::freeGpuData() {
187 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
188 SkASSERT(fYcbcrConversion != VK_NULL_HANDLE);
189 VULKAN_CALL(sharedContext->interface(),
190 DestroySamplerYcbcrConversion(sharedContext->device(), fYcbcrConversion, nullptr));
191 }
192
193 } // namespace skgpu::graphite
194