1/*
2 * Copyright 2018 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/vk/GrVkSamplerYcbcrConversion.h"
9
10#include "src/gpu/vk/GrVkGpu.h"
11
12GrVkSamplerYcbcrConversion* GrVkSamplerYcbcrConversion::Create(
13        GrVkGpu* gpu, const GrVkYcbcrConversionInfo& info) {
14    if (!gpu->vkCaps().supportsYcbcrConversion()) {
15        return nullptr;
16    }
17
18#ifdef SK_DEBUG
19    const VkFormatFeatureFlags& featureFlags = info.fFormatFeatures;
20    if (info.fXChromaOffset == VK_CHROMA_LOCATION_MIDPOINT ||
21        info.fYChromaOffset == VK_CHROMA_LOCATION_MIDPOINT) {
22        SkASSERT(featureFlags & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT);
23    }
24    if (info.fXChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN ||
25        info.fYChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN) {
26        SkASSERT(featureFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT);
27    }
28    if (info.fChromaFilter == VK_FILTER_LINEAR) {
29        SkASSERT(featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT);
30    }
31    if (info.fForceExplicitReconstruction) {
32        SkASSERT(featureFlags &
33                 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT);
34    }
35#endif
36
37
38    VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
39    ycbcrCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
40    ycbcrCreateInfo.pNext = nullptr;
41    ycbcrCreateInfo.format = info.fFormat;
42    ycbcrCreateInfo.ycbcrModel = info.fYcbcrModel;
43    ycbcrCreateInfo.ycbcrRange = info.fYcbcrRange;
44
45    // Components is ignored for external format conversions. For all other formats identity swizzle
46    // is used. It can be added to GrVkYcbcrConversionInfo if necessary.
47    ycbcrCreateInfo.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
48                                  VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
49    ycbcrCreateInfo.xChromaOffset = info.fXChromaOffset;
50    ycbcrCreateInfo.yChromaOffset = info.fYChromaOffset;
51    ycbcrCreateInfo.chromaFilter = info.fChromaFilter;
52    ycbcrCreateInfo.forceExplicitReconstruction = info.fForceExplicitReconstruction;
53
54#ifdef SK_BUILD_FOR_ANDROID
55    VkExternalFormatANDROID externalFormat;
56    if (info.fExternalFormat) {
57        // Format must not be specified for external images.
58        SkASSERT(info.fFormat == VK_FORMAT_UNDEFINED);
59        externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
60        externalFormat.pNext = nullptr;
61        externalFormat.externalFormat = info.fExternalFormat;
62        ycbcrCreateInfo.pNext = &externalFormat;
63    }
64#elif defined(VK_USE_PLATFORM_OHOS)
65    VkExternalFormatOHOS externalFormat;
66    if (info.fExternalFormat) {
67        // Format must not be specified for external images.
68        SkASSERT(info.fFormat == VK_FORMAT_UNDEFINED);
69        externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS;
70        externalFormat.pNext = nullptr;
71        externalFormat.externalFormat = info.fExternalFormat;
72        ycbcrCreateInfo.pNext = &externalFormat;
73    }
74#else
75    // External images are supported only on Android/OpenHarmony;
76    SkASSERT(!info.fExternalFormat);
77#endif
78
79    if (!info.fExternalFormat) {
80        SkASSERT(info.fFormat != VK_FORMAT_UNDEFINED);
81    }
82
83    VkSamplerYcbcrConversion conversion;
84    VkResult result;
85    GR_VK_CALL_RESULT(gpu, result, CreateSamplerYcbcrConversion(gpu->device(), &ycbcrCreateInfo,
86                                                                nullptr, &conversion));
87    if (result != VK_SUCCESS) {
88        return nullptr;
89    }
90
91    return new GrVkSamplerYcbcrConversion(gpu, conversion, GenerateKey(info));
92}
93
94void GrVkSamplerYcbcrConversion::freeGPUData() const {
95    SkASSERT(fYcbcrConversion);
96    GR_VK_CALL(fGpu->vkInterface(), DestroySamplerYcbcrConversion(fGpu->device(),
97                                                                  fYcbcrConversion, nullptr));
98}
99
100GrVkSamplerYcbcrConversion::Key GrVkSamplerYcbcrConversion::GenerateKey(
101        const GrVkYcbcrConversionInfo& ycbcrInfo) {
102    SkASSERT(static_cast<int>(ycbcrInfo.fYcbcrModel <= 7));
103    static const int kRangeShift = 3;
104    SkASSERT(static_cast<int>(ycbcrInfo.fYcbcrRange) <= 1);
105    static const int kXChromaOffsetShift = kRangeShift + 1;
106    SkASSERT(static_cast<int>(ycbcrInfo.fXChromaOffset) <= 1);
107    static const int kYChromaOffsetShift = kXChromaOffsetShift + 1;
108    SkASSERT(static_cast<int>(ycbcrInfo.fXChromaOffset) <= 1);
109    static const int kChromaFilterShift = kYChromaOffsetShift + 1;
110    SkASSERT(static_cast<int>(ycbcrInfo.fChromaFilter) <= 1);
111    static const int kReconShift = kChromaFilterShift + 1;
112    SkASSERT(static_cast<int>(ycbcrInfo.fForceExplicitReconstruction) <= 1);
113    static_assert(kReconShift <= 7);
114
115    uint8_t ycbcrKey = static_cast<uint8_t>(ycbcrInfo.fYcbcrModel);
116    ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fYcbcrRange) << kRangeShift);
117    ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fXChromaOffset) << kXChromaOffsetShift);
118    ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fYChromaOffset) << kYChromaOffsetShift);
119    ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fChromaFilter) << kChromaFilterShift);
120    ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fForceExplicitReconstruction) << kReconShift);
121
122    return Key{ycbcrInfo.fFormat, ycbcrInfo.fExternalFormat, ycbcrKey};
123}
124