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