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
27static nir_ssa_def *
28y_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
49static nir_ssa_def *
50chroma_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
72typedef struct nir_const_value_3_4 {
73   nir_const_value v[3][4];
74} nir_const_value_3_4;
75
76static const nir_const_value_3_4 *
77ycbcr_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
113nir_ssa_def *
114nir_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