1 /*
2 * Copyright © 2017 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 "nir_vulkan.h"
25 #include <math.h>
26
27 static nir_ssa_def *
y_range(nir_builder * b,nir_ssa_def * y_channel,int bpc,VkSamplerYcbcrRange range)28 y_range(nir_builder *b,
29 nir_ssa_def *y_channel,
30 int bpc,
31 VkSamplerYcbcrRange range)
32 {
33 switch (range) {
34 case VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
35 return y_channel;
36 case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
37 return nir_fmul(b,
38 nir_fadd(b,
39 nir_fmul(b, y_channel,
40 nir_imm_float(b, pow(2, bpc) - 1)),
41 nir_imm_float(b, -16.0f * pow(2, bpc - 8))),
42 nir_frcp(b, nir_imm_float(b, 219.0f * pow(2, bpc - 8))));
43 default:
44 unreachable("missing Ycbcr range");
45 return NULL;
46 }
47 }
48
49 static nir_ssa_def *
chroma_range(nir_builder * b,nir_ssa_def * chroma_channel,int bpc,VkSamplerYcbcrRange range)50 chroma_range(nir_builder *b,
51 nir_ssa_def *chroma_channel,
52 int bpc,
53 VkSamplerYcbcrRange range)
54 {
55 switch (range) {
56 case VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
57 return nir_fadd(b, chroma_channel,
58 nir_imm_float(b, -pow(2, bpc - 1) / (pow(2, bpc) - 1.0f)));
59 case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
60 return nir_fmul(b,
61 nir_fadd(b,
62 nir_fmul(b, chroma_channel,
63 nir_imm_float(b, pow(2, bpc) - 1)),
64 nir_imm_float(b, -128.0f * pow(2, bpc - 8))),
65 nir_frcp(b, nir_imm_float(b, 224.0f * pow(2, bpc - 8))));
66 default:
67 unreachable("missing Ycbcr range");
68 return NULL;
69 }
70 }
71
72 typedef struct nir_const_value_3_4 {
73 nir_const_value v[3][4];
74 } nir_const_value_3_4;
75
76 static const nir_const_value_3_4 *
ycbcr_model_to_rgb_matrix(VkSamplerYcbcrModelConversion model)77 ycbcr_model_to_rgb_matrix(VkSamplerYcbcrModelConversion model)
78 {
79 switch (model) {
80 case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601: {
81 static const nir_const_value_3_4 bt601 = { {
82 { { .f32 = 1.402f }, { .f32 = 1.0f }, { .f32 = 0.0f }, { .f32 = 0.0f } },
83 { { .f32 = -0.714136286201022f }, { .f32 = 1.0f }, { .f32 = -0.344136286201022f }, { .f32 = 0.0f } },
84 { { .f32 = 0.0f }, { .f32 = 1.0f }, { .f32 = 1.772f }, { .f32 = 0.0f } },
85 } };
86
87 return &bt601;
88 }
89 case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709: {
90 static const nir_const_value_3_4 bt709 = { {
91 { { .f32 = 1.5748031496063f }, { .f32 = 1.0f }, { .f32 = 0.0f }, { .f32 = 0.0f } },
92 { { .f32 = -0.468125209181067f }, { .f32 = 1.0f }, { .f32 = -0.187327487470334f }, { .f32 = 0.0f } },
93 { { .f32 = 0.0f }, { .f32 = 1.0f }, { .f32 = 1.85563184264242f }, { .f32 = 0.0f } },
94 } };
95
96 return &bt709;
97 }
98 case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020: {
99 static const nir_const_value_3_4 bt2020 = { {
100 { { .f32 = 1.4746f }, { .f32 = 1.0f }, { .f32 = 0.0f }, { .f32 = 0.0f } },
101 { { .f32 = -0.571353126843658f }, { .f32 = 1.0f }, { .f32 = -0.164553126843658f }, { .f32 = 0.0f } },
102 { { .f32 = 0.0f }, { .f32 = 1.0f }, { .f32 = 1.8814f }, { .f32 = 0.0f } },
103 } };
104
105 return &bt2020;
106 }
107 default:
108 unreachable("missing Ycbcr model");
109 return NULL;
110 }
111 }
112
113 nir_ssa_def *
nir_convert_ycbcr_to_rgb(nir_builder * b,VkSamplerYcbcrModelConversion model,VkSamplerYcbcrRange range,nir_ssa_def * raw_channels,uint32_t * bpcs)114 nir_convert_ycbcr_to_rgb(nir_builder *b,
115 VkSamplerYcbcrModelConversion model,
116 VkSamplerYcbcrRange range,
117 nir_ssa_def *raw_channels,
118 uint32_t *bpcs)
119 {
120 nir_ssa_def *expanded_channels =
121 nir_vec4(b,
122 chroma_range(b, nir_channel(b, raw_channels, 0), bpcs[0], range),
123 y_range(b, nir_channel(b, raw_channels, 1), bpcs[1], range),
124 chroma_range(b, nir_channel(b, raw_channels, 2), bpcs[2], range),
125 nir_channel(b, raw_channels, 3));
126
127 if (model == VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
128 return expanded_channels;
129
130 const nir_const_value_3_4 *conversion_matrix =
131 ycbcr_model_to_rgb_matrix(model);
132
133 nir_ssa_def *converted_channels[] = {
134 nir_fdot(b, expanded_channels, nir_build_imm(b, 4, 32, conversion_matrix->v[0])),
135 nir_fdot(b, expanded_channels, nir_build_imm(b, 4, 32, conversion_matrix->v[1])),
136 nir_fdot(b, expanded_channels, nir_build_imm(b, 4, 32, conversion_matrix->v[2]))
137 };
138
139 return nir_vec4(b,
140 converted_channels[0], converted_channels[1],
141 converted_channels[2], nir_channel(b, raw_channels, 3));
142 }
143