1 /*
2  * Copyright © 2020 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "vk_ycbcr_conversion.h"
25 
26 #include <vulkan/vulkan_android.h>
27 
28 #include "vk_common_entrypoints.h"
29 #include "vk_device.h"
30 #include "vk_format.h"
31 #include "vk_util.h"
32 
33 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_CreateSamplerYcbcrConversion(VkDevice _device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion)34 vk_common_CreateSamplerYcbcrConversion(VkDevice _device,
35                                        const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
36                                        const VkAllocationCallbacks *pAllocator,
37                                        VkSamplerYcbcrConversion *pYcbcrConversion)
38 {
39    VK_FROM_HANDLE(vk_device, device, _device);
40    struct vk_ycbcr_conversion *conversion;
41 
42    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
43 
44    conversion = vk_object_zalloc(device, pAllocator, sizeof(*conversion),
45                                  VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION);
46    if (!conversion)
47       return VK_ERROR_OUT_OF_HOST_MEMORY;
48 
49    struct vk_ycbcr_conversion_state *state = &conversion->state;
50 
51    state->format = pCreateInfo->format;
52    state->ycbcr_model = pCreateInfo->ycbcrModel;
53    state->ycbcr_range = pCreateInfo->ycbcrRange;
54 
55    /* Search for VkExternalFormatANDROID and resolve the format. */
56    const VkExternalFormatANDROID *android_ext_info =
57       vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_FORMAT_ANDROID);
58 
59    /* We assume that Android externalFormat is just a VkFormat */
60    if (android_ext_info && android_ext_info->externalFormat) {
61       assert(pCreateInfo->format == VK_FORMAT_UNDEFINED);
62       state->format = android_ext_info->externalFormat;
63    } else {
64       /* The Vulkan 1.1.95 spec says:
65        *
66        *    "When creating an external format conversion, the value of
67        *    components if ignored."
68        */
69       state->mapping[0] = pCreateInfo->components.r;
70       state->mapping[1] = pCreateInfo->components.g;
71       state->mapping[2] = pCreateInfo->components.b;
72       state->mapping[3] = pCreateInfo->components.a;
73    }
74 
75    state->chroma_offsets[0] = pCreateInfo->xChromaOffset;
76    state->chroma_offsets[1] = pCreateInfo->yChromaOffset;
77    state->chroma_filter = pCreateInfo->chromaFilter;
78 
79    const struct vk_format_ycbcr_info *ycbcr_info =
80       vk_format_get_ycbcr_info(state->format);
81 
82    bool has_chroma_subsampled = false;
83    if (ycbcr_info) {
84       for (uint32_t p = 0; p < ycbcr_info->n_planes; p++) {
85          if (ycbcr_info->planes[p].has_chroma &&
86              (ycbcr_info->planes[p].denominator_scales[0] > 1 ||
87               ycbcr_info->planes[p].denominator_scales[1] > 1))
88             has_chroma_subsampled = true;
89       }
90    }
91    state->chroma_reconstruction = has_chroma_subsampled &&
92       (state->chroma_offsets[0] == VK_CHROMA_LOCATION_COSITED_EVEN ||
93        state->chroma_offsets[1] == VK_CHROMA_LOCATION_COSITED_EVEN);
94 
95    *pYcbcrConversion = vk_ycbcr_conversion_to_handle(conversion);
96 
97    return VK_SUCCESS;
98 }
99 
100 VKAPI_ATTR void VKAPI_CALL
vk_common_DestroySamplerYcbcrConversion(VkDevice _device,VkSamplerYcbcrConversion YcbcrConversion,const VkAllocationCallbacks * pAllocator)101 vk_common_DestroySamplerYcbcrConversion(VkDevice _device,
102                                         VkSamplerYcbcrConversion YcbcrConversion,
103                                         const VkAllocationCallbacks *pAllocator)
104 {
105    VK_FROM_HANDLE(vk_device, device, _device);
106    VK_FROM_HANDLE(vk_ycbcr_conversion, conversion, YcbcrConversion);
107 
108    if (!conversion)
109       return;
110 
111    vk_object_free(device, pAllocator, conversion);
112 }
113