Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
VkYcbcrSamplerHelper.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
9
10#ifdef SK_VULKAN
11
17
18int VkYcbcrSamplerHelper::GetExpectedY(int x, int y, int width, int height) {
19 return 16 + (x + y) * 219 / (width + height - 2);
20}
21
22std::pair<int, int> VkYcbcrSamplerHelper::GetExpectedUV(int x, int y, int width, int height) {
23 return { 16 + x * 224 / (width - 1), 16 + y * 224 / (height - 1) };
24}
25
26GrVkGpu* VkYcbcrSamplerHelper::vkGpu() {
27 return (GrVkGpu*) fDContext->priv().getGpu();
28}
29
30VkYcbcrSamplerHelper::VkYcbcrSamplerHelper(GrDirectContext* dContext) : fDContext(dContext) {
32}
33
34VkYcbcrSamplerHelper::~VkYcbcrSamplerHelper() {
35 GrVkGpu* vkGpu = this->vkGpu();
36
37 if (fImage != VK_NULL_HANDLE) {
38 GR_VK_CALL(vkGpu->vkInterface(), DestroyImage(vkGpu->device(), fImage, nullptr));
39 fImage = VK_NULL_HANDLE;
40 }
41 if (fImageMemory != VK_NULL_HANDLE) {
42 GR_VK_CALL(vkGpu->vkInterface(), FreeMemory(vkGpu->device(), fImageMemory, nullptr));
43 fImageMemory = VK_NULL_HANDLE;
44 }
45}
46
47bool VkYcbcrSamplerHelper::isYCbCrSupported() {
48 GrVkGpu* vkGpu = this->vkGpu();
49
50 if (!vkGpu->vkCaps().supportsYcbcrConversion()) {
51 return false;
52 }
53
54 // The createBackendTexture call (which is the point of this helper class) requires linear
55 // support for VK_FORMAT_G8_B8R8_2PLANE_420_UNORM including sampling and cosited chroma.
56 // Verify that the image format is supported.
57 VkFormatProperties formatProperties;
58 GR_VK_CALL(vkGpu->vkInterface(),
59 GetPhysicalDeviceFormatProperties(vkGpu->physicalDevice(),
61 &formatProperties));
62 auto linFlags = formatProperties.linearTilingFeatures;
63 if (!(linFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ||
67 // VK_FORMAT_G8_B8R8_2PLANE_420_UNORM is not supported
68 return false;
69 }
70
71 return true;
72}
73
74bool VkYcbcrSamplerHelper::createBackendTexture(uint32_t width, uint32_t height) {
75 GrVkGpu* vkGpu = this->vkGpu();
77
78 // Create YCbCr image.
79 VkImageCreateInfo vkImageInfo = {};
81 vkImageInfo.imageType = VK_IMAGE_TYPE_2D;
83 vkImageInfo.extent = VkExtent3D{width, height, 1};
84 vkImageInfo.mipLevels = 1;
85 vkImageInfo.arrayLayers = 1;
86 vkImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
87 vkImageInfo.tiling = VK_IMAGE_TILING_LINEAR;
92
93 SkASSERT(fImage == VK_NULL_HANDLE);
94 GR_VK_CALL_RESULT(vkGpu, result, CreateImage(vkGpu->device(), &vkImageInfo, nullptr, &fImage));
95 if (result != VK_SUCCESS) {
96 return false;
97 }
98
99 VkMemoryRequirements requirements;
100 GR_VK_CALL(vkGpu->vkInterface(), GetImageMemoryRequirements(vkGpu->device(),
101 fImage,
102 &requirements));
103
104 uint32_t memoryTypeIndex = 0;
105 bool foundHeap = false;
107 GR_VK_CALL(vkGpu->vkInterface(), GetPhysicalDeviceMemoryProperties(vkGpu->physicalDevice(),
108 &phyDevMemProps));
109 for (uint32_t i = 0; i < phyDevMemProps.memoryTypeCount && !foundHeap; ++i) {
110 if (requirements.memoryTypeBits & (1 << i)) {
111 // Map host-visible memory.
113 memoryTypeIndex = i;
114 foundHeap = true;
115 }
116 }
117 }
118 if (!foundHeap) {
119 return false;
120 }
121
122 VkMemoryAllocateInfo allocInfo = {};
124 allocInfo.allocationSize = requirements.size;
125 allocInfo.memoryTypeIndex = memoryTypeIndex;
126
127 SkASSERT(fImageMemory == VK_NULL_HANDLE);
128 GR_VK_CALL_RESULT(vkGpu, result, AllocateMemory(vkGpu->device(), &allocInfo,
129 nullptr, &fImageMemory));
130 if (result != VK_SUCCESS) {
131 return false;
132 }
133
134 void* mappedBuffer;
135 GR_VK_CALL_RESULT(vkGpu, result, MapMemory(vkGpu->device(), fImageMemory, 0u,
136 requirements.size, 0u, &mappedBuffer));
137 if (result != VK_SUCCESS) {
138 return false;
139 }
140
141 // Write Y channel.
142 VkImageSubresource subresource;
144 subresource.mipLevel = 0;
145 subresource.arrayLayer = 0;
146
147 VkSubresourceLayout yLayout;
148 GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage,
149 &subresource, &yLayout));
150 uint8_t* bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + yLayout.offset;
151 for (size_t y = 0; y < height; ++y) {
152 for (size_t x = 0; x < width; ++x) {
153 bufferData[y * yLayout.rowPitch + x] = GetExpectedY(x, y, width, height);
154 }
155 }
156
157 // Write UV channels.
159 VkSubresourceLayout uvLayout;
160 GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage,
161 &subresource, &uvLayout));
162 bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + uvLayout.offset;
163 for (size_t y = 0; y < height / 2; ++y) {
164 for (size_t x = 0; x < width / 2; ++x) {
165 auto [u, v] = GetExpectedUV(2*x, 2*y, width, height);
166 bufferData[y * uvLayout.rowPitch + x * 2] = u;
167 bufferData[y * uvLayout.rowPitch + x * 2 + 1] = v;
168 }
169 }
170
171 VkMappedMemoryRange flushRange;
173 flushRange.pNext = nullptr;
174 flushRange.memory = fImageMemory;
175 flushRange.offset = 0;
176 flushRange.size = VK_WHOLE_SIZE;
177 GR_VK_CALL_RESULT(vkGpu, result, FlushMappedMemoryRanges(vkGpu->device(), 1, &flushRange));
178 if (result != VK_SUCCESS) {
179 return false;
180 }
181 GR_VK_CALL(vkGpu->vkInterface(), UnmapMemory(vkGpu->device(), fImageMemory));
182
183 // Bind image memory.
184 GR_VK_CALL_RESULT(vkGpu, result, BindImageMemory(vkGpu->device(), fImage, fImageMemory, 0u));
185 if (result != VK_SUCCESS) {
186 return false;
187 }
188
189 // Wrap the image into SkImage.
190 VkFormatProperties formatProperties;
191 GR_VK_CALL(vkGpu->vkInterface(),
192 GetPhysicalDeviceFormatProperties(vkGpu->physicalDevice(),
194 &formatProperties));
195 SkDEBUGCODE(auto linFlags = formatProperties.linearTilingFeatures;)
200
201 GrVkYcbcrConversionInfo ycbcrInfo = {vkImageInfo.format,
202 /*externalFormat=*/0,
208 false,
209 formatProperties.linearTilingFeatures,
210 /*fComponents=*/{}};
211 skgpu::VulkanAlloc alloc;
212 alloc.fMemory = fImageMemory;
213 alloc.fOffset = 0;
214 alloc.fSize = requirements.size;
215
216 GrVkImageInfo imageInfo = {fImage,
217 alloc,
220 vkImageInfo.format,
221 vkImageInfo.usage,
222 1 /* sample count */,
223 1 /* levelCount */,
225 GrProtected::kNo,
226 ycbcrInfo};
227
228 fTexture = GrBackendTextures::MakeVk(width, height, imageInfo);
229 return true;
230}
231
232#endif // SK_VULKAN
#define GR_VK_CALL(IFACE, X)
Definition GrVkUtil.h:24
#define GR_VK_CALL_RESULT(GPU, RESULT, X)
Definition GrVkUtil.h:35
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
GrDirectContext * fDContext
SK_API GrBackendApi backend() const
GrDirectContextPriv priv()
bool supportsYcbcrConversion() const
Definition GrVkCaps.h:153
const GrVkCaps & vkCaps() const
Definition GrVkGpu.h:61
const skgpu::VulkanInterface * vkInterface() const
Definition GrVkGpu.h:60
VkDevice device() const
Definition GrVkGpu.h:71
VkPhysicalDevice physicalDevice() const
Definition GrVkGpu.h:70
GAsyncResult * result
double y
double x
SK_API GrBackendTexture MakeVk(int width, int height, const GrVkImageInfo &, std::string_view label={})
int32_t height
int32_t width
VkFormatFeatureFlags linearTilingFeatures
VkSharingMode sharingMode
VkImageLayout initialLayout
VkSampleCountFlagBits samples
VkImageType imageType
VkImageTiling tiling
VkStructureType sType
VkImageUsageFlags usage
VkImageAspectFlags aspectMask
VkDeviceSize offset
VkDeviceMemory memory
VkStructureType sType
VkStructureType sType
VkDeviceSize allocationSize
VkMemoryPropertyFlags propertyFlags
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]
VkDeviceSize rowPitch
VkDeviceSize offset
VkDeviceSize fSize
Definition VulkanTypes.h:40
VkDeviceMemory fMemory
Definition VulkanTypes.h:38
VkDeviceSize fOffset
Definition VulkanTypes.h:39
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
@ VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT
@ VK_IMAGE_LAYOUT_UNDEFINED
@ VK_SHARING_MODE_EXCLUSIVE
@ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
@ VK_IMAGE_TILING_LINEAR
@ VK_IMAGE_ASPECT_PLANE_0_BIT
@ VK_IMAGE_ASPECT_PLANE_1_BIT
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
@ VK_IMAGE_USAGE_SAMPLED_BIT
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
@ VK_SAMPLE_COUNT_1_BIT
@ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709
@ VK_CHROMA_LOCATION_COSITED_EVEN
@ VK_IMAGE_TYPE_2D
@ VK_SAMPLER_YCBCR_RANGE_ITU_NARROW
#define VK_WHOLE_SIZE
@ VK_FILTER_LINEAR
VkResult
@ VK_SUCCESS
#define VK_NULL_HANDLE
Definition vulkan_core.h:46
@ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
#define VK_QUEUE_FAMILY_IGNORED
@ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
@ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
@ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE