Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 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 | |
| 8 | #include "tools/gpu/vk/VkYcbcrSamplerHelper.h" |
| 9 | |
| 10 | #ifdef SK_VULKAN |
| 11 | |
Robert Phillips | 057c33f | 2020-07-17 11:59:01 -0400 | [diff] [blame] | 12 | #include "include/gpu/GrDirectContext.h" |
Adlai Holler | a069304 | 2020-10-14 11:23:11 -0400 | [diff] [blame] | 13 | #include "src/gpu/GrDirectContextPriv.h" |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 14 | #include "src/gpu/vk/GrVkGpu.h" |
| 15 | #include "src/gpu/vk/GrVkUtil.h" |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 16 | |
| 17 | int VkYcbcrSamplerHelper::GetExpectedY(int x, int y, int width, int height) { |
| 18 | return 16 + (x + y) * 219 / (width + height - 2); |
| 19 | } |
| 20 | |
| 21 | std::pair<int, int> VkYcbcrSamplerHelper::GetExpectedUV(int x, int y, int width, int height) { |
| 22 | return { 16 + x * 224 / (width - 1), 16 + y * 224 / (height - 1) }; |
| 23 | } |
| 24 | |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 25 | GrVkGpu* VkYcbcrSamplerHelper::vkGpu() { |
Robert Phillips | 057c33f | 2020-07-17 11:59:01 -0400 | [diff] [blame] | 26 | return (GrVkGpu*) fDContext->priv().getGpu(); |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 27 | } |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 28 | |
Robert Phillips | 057c33f | 2020-07-17 11:59:01 -0400 | [diff] [blame] | 29 | VkYcbcrSamplerHelper::VkYcbcrSamplerHelper(GrDirectContext* dContext) : fDContext(dContext) { |
| 30 | SkASSERT_RELEASE(dContext->backend() == GrBackendApi::kVulkan); |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 31 | } |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 32 | |
| 33 | VkYcbcrSamplerHelper::~VkYcbcrSamplerHelper() { |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 34 | GrVkGpu* vkGpu = this->vkGpu(); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 35 | |
| 36 | if (fImage != VK_NULL_HANDLE) { |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 37 | GR_VK_CALL(vkGpu->vkInterface(), DestroyImage(vkGpu->device(), fImage, nullptr)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 38 | fImage = VK_NULL_HANDLE; |
| 39 | } |
| 40 | if (fImageMemory != VK_NULL_HANDLE) { |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 41 | GR_VK_CALL(vkGpu->vkInterface(), FreeMemory(vkGpu->device(), fImageMemory, nullptr)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 42 | fImageMemory = VK_NULL_HANDLE; |
| 43 | } |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 44 | } |
| 45 | |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 46 | bool VkYcbcrSamplerHelper::isYCbCrSupported() { |
| 47 | GrVkGpu* vkGpu = this->vkGpu(); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 48 | |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 49 | return vkGpu->vkCaps().supportsYcbcrConversion(); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 50 | } |
| 51 | |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 52 | bool VkYcbcrSamplerHelper::createBackendTexture(uint32_t width, uint32_t height) { |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 53 | GrVkGpu* vkGpu = this->vkGpu(); |
| 54 | VkResult result; |
| 55 | |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 56 | // Verify that the image format is supported. |
| 57 | VkFormatProperties formatProperties; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 58 | GR_VK_CALL(vkGpu->vkInterface(), |
| 59 | GetPhysicalDeviceFormatProperties(vkGpu->physicalDevice(), |
| 60 | VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, |
| 61 | &formatProperties)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 62 | if (!(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { |
| 63 | // VK_FORMAT_G8_B8R8_2PLANE_420_UNORM is not supported |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 64 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | // Create YCbCr image. |
| 68 | VkImageCreateInfo vkImageInfo = {}; |
| 69 | vkImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| 70 | vkImageInfo.imageType = VK_IMAGE_TYPE_2D; |
| 71 | vkImageInfo.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| 72 | vkImageInfo.extent = VkExtent3D{width, height, 1}; |
| 73 | vkImageInfo.mipLevels = 1; |
| 74 | vkImageInfo.arrayLayers = 1; |
| 75 | vkImageInfo.samples = VK_SAMPLE_COUNT_1_BIT; |
| 76 | vkImageInfo.tiling = VK_IMAGE_TILING_LINEAR; |
Greg Daniel | 7b62dca | 2020-08-21 11:26:12 -0400 | [diff] [blame] | 77 | vkImageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| 78 | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 79 | vkImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| 80 | vkImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| 81 | |
| 82 | SkASSERT(fImage == VK_NULL_HANDLE); |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 83 | GR_VK_CALL_RESULT(vkGpu, result, CreateImage(vkGpu->device(), &vkImageInfo, nullptr, &fImage)); |
| 84 | if (result != VK_SUCCESS) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 85 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | VkMemoryRequirements requirements; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 89 | GR_VK_CALL(vkGpu->vkInterface(), GetImageMemoryRequirements(vkGpu->device(), |
| 90 | fImage, |
| 91 | &requirements)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 92 | |
| 93 | uint32_t memoryTypeIndex = 0; |
| 94 | bool foundHeap = false; |
| 95 | VkPhysicalDeviceMemoryProperties phyDevMemProps; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 96 | GR_VK_CALL(vkGpu->vkInterface(), GetPhysicalDeviceMemoryProperties(vkGpu->physicalDevice(), |
| 97 | &phyDevMemProps)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 98 | for (uint32_t i = 0; i < phyDevMemProps.memoryTypeCount && !foundHeap; ++i) { |
| 99 | if (requirements.memoryTypeBits & (1 << i)) { |
| 100 | // Map host-visible memory. |
| 101 | if (phyDevMemProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { |
| 102 | memoryTypeIndex = i; |
| 103 | foundHeap = true; |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | if (!foundHeap) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 108 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | VkMemoryAllocateInfo allocInfo = {}; |
| 112 | allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| 113 | allocInfo.allocationSize = requirements.size; |
| 114 | allocInfo.memoryTypeIndex = memoryTypeIndex; |
| 115 | |
| 116 | SkASSERT(fImageMemory == VK_NULL_HANDLE); |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 117 | GR_VK_CALL_RESULT(vkGpu, result, AllocateMemory(vkGpu->device(), &allocInfo, |
| 118 | nullptr, &fImageMemory)); |
| 119 | if (result != VK_SUCCESS) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 120 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | void* mappedBuffer; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 124 | GR_VK_CALL_RESULT(vkGpu, result, MapMemory(vkGpu->device(), fImageMemory, 0u, |
| 125 | requirements.size, 0u, &mappedBuffer)); |
| 126 | if (result != VK_SUCCESS) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 127 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | // Write Y channel. |
| 131 | VkImageSubresource subresource; |
| 132 | subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| 133 | subresource.mipLevel = 0; |
| 134 | subresource.arrayLayer = 0; |
| 135 | |
| 136 | VkSubresourceLayout yLayout; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 137 | GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage, |
| 138 | &subresource, &yLayout)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 139 | uint8_t* bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + yLayout.offset; |
| 140 | for (size_t y = 0; y < height; ++y) { |
| 141 | for (size_t x = 0; x < width; ++x) { |
| 142 | bufferData[y * yLayout.rowPitch + x] = GetExpectedY(x, y, width, height); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | // Write UV channels. |
| 147 | subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| 148 | VkSubresourceLayout uvLayout; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 149 | GR_VK_CALL(vkGpu->vkInterface(), GetImageSubresourceLayout(vkGpu->device(), fImage, |
| 150 | &subresource, &uvLayout)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 151 | bufferData = reinterpret_cast<uint8_t*>(mappedBuffer) + uvLayout.offset; |
| 152 | for (size_t y = 0; y < height / 2; ++y) { |
| 153 | for (size_t x = 0; x < width / 2; ++x) { |
| 154 | auto [u, v] = GetExpectedUV(2*x, 2*y, width, height); |
| 155 | bufferData[y * uvLayout.rowPitch + x * 2] = u; |
| 156 | bufferData[y * uvLayout.rowPitch + x * 2 + 1] = v; |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | VkMappedMemoryRange flushRange; |
| 161 | flushRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
| 162 | flushRange.pNext = nullptr; |
| 163 | flushRange.memory = fImageMemory; |
| 164 | flushRange.offset = 0; |
| 165 | flushRange.size = VK_WHOLE_SIZE; |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 166 | GR_VK_CALL_RESULT(vkGpu, result, FlushMappedMemoryRanges(vkGpu->device(), 1, &flushRange)); |
| 167 | if (result != VK_SUCCESS) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 168 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 169 | } |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 170 | GR_VK_CALL(vkGpu->vkInterface(), UnmapMemory(vkGpu->device(), fImageMemory)); |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 171 | |
| 172 | // Bind image memory. |
Robert Phillips | 85aa428 | 2020-06-11 10:54:43 -0400 | [diff] [blame] | 173 | GR_VK_CALL_RESULT(vkGpu, result, BindImageMemory(vkGpu->device(), fImage, fImageMemory, 0u)); |
| 174 | if (result != VK_SUCCESS) { |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 175 | return false; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | // Wrap the image into SkImage. |
Greg Daniel | 6a4e145 | 2020-08-20 14:35:18 -0400 | [diff] [blame] | 179 | GrVkYcbcrConversionInfo ycbcrInfo = {vkImageInfo.format, |
| 180 | /*externalFormat=*/0, |
| 181 | VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, |
| 182 | VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, |
| 183 | VK_CHROMA_LOCATION_COSITED_EVEN, |
| 184 | VK_CHROMA_LOCATION_COSITED_EVEN, |
| 185 | VK_FILTER_LINEAR, |
| 186 | false, |
| 187 | formatProperties.linearTilingFeatures}; |
| 188 | GrVkAlloc alloc; |
| 189 | alloc.fMemory = fImageMemory; |
| 190 | alloc.fOffset = 0; |
| 191 | alloc.fSize = requirements.size; |
| 192 | |
| 193 | GrVkImageInfo imageInfo = {fImage, |
| 194 | alloc, |
| 195 | VK_IMAGE_TILING_LINEAR, |
| 196 | VK_IMAGE_LAYOUT_UNDEFINED, |
| 197 | vkImageInfo.format, |
Greg Daniel | 7b62dca | 2020-08-21 11:26:12 -0400 | [diff] [blame] | 198 | vkImageInfo.usage, |
Brian Salomon | 57fd923 | 2020-09-28 17:02:49 -0400 | [diff] [blame] | 199 | 1 /* sample count */, |
Greg Daniel | 6a4e145 | 2020-08-20 14:35:18 -0400 | [diff] [blame] | 200 | 1 /* levelCount */, |
| 201 | VK_QUEUE_FAMILY_IGNORED, |
| 202 | GrProtected::kNo, |
| 203 | ycbcrInfo}; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 204 | |
| 205 | fTexture = GrBackendTexture(width, height, imageInfo); |
Robert Phillips | 5f0cda4 | 2020-06-15 14:26:58 -0400 | [diff] [blame] | 206 | return true; |
Robert Phillips | ae413d8 | 2020-06-10 11:04:51 -0400 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | #endif // SK_VULKAN |