2 * Copyright © 2017 Intel Corporation
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:
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
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
25 #include "anv_private.h"
27 #include "nir/nir_builder.h"
28 #include "nir/nir_vulkan.h"
32 nir_ssa_def
*image_size
;
33 nir_tex_instr
*origin_tex
;
34 nir_deref_instr
*tex_deref
;
35 struct anv_ycbcr_conversion
*conversion
;
38 /* TODO: we should probably replace this with a push constant/uniform. */
40 get_texture_size(struct ycbcr_state
*state
, nir_deref_instr
*texture
)
42 if (state
->image_size
)
43 return state
->image_size
;
45 nir_builder
*b
= state
->builder
;
46 const struct glsl_type
*type
= texture
->type
;
47 nir_tex_instr
*tex
= nir_tex_instr_create(b
->shader
, 1);
49 tex
->op
= nir_texop_txs
;
50 tex
->sampler_dim
= glsl_get_sampler_dim(type
);
51 tex
->is_array
= glsl_sampler_type_is_array(type
);
52 tex
->is_shadow
= glsl_sampler_type_is_shadow(type
);
53 tex
->dest_type
= nir_type_int
;
55 tex
->src
[0].src_type
= nir_tex_src_texture_deref
;
56 tex
->src
[0].src
= nir_src_for_ssa(&texture
->dest
.ssa
);
58 nir_ssa_dest_init(&tex
->instr
, &tex
->dest
,
59 nir_tex_instr_dest_size(tex
), 32, NULL
);
60 nir_builder_instr_insert(b
, &tex
->instr
);
62 state
->image_size
= nir_i2f32(b
, &tex
->dest
.ssa
);
64 return state
->image_size
;
68 implicit_downsampled_coord(nir_builder
*b
,
70 nir_ssa_def
*max_value
,
76 nir_imm_float(b
, 1.0f
),
78 nir_imm_float(b
, div_scale
),
83 implicit_downsampled_coords(struct ycbcr_state
*state
,
84 nir_ssa_def
*old_coords
,
85 const struct anv_format_plane
*plane_format
)
87 nir_builder
*b
= state
->builder
;
88 struct anv_ycbcr_conversion
*conversion
= state
->conversion
;
89 nir_ssa_def
*image_size
= get_texture_size(state
, state
->tex_deref
);
90 nir_ssa_def
*comp
[4] = { NULL
, };
93 for (c
= 0; c
< ARRAY_SIZE(conversion
->chroma_offsets
); c
++) {
94 if (plane_format
->denominator_scales
[c
] > 1 &&
95 conversion
->chroma_offsets
[c
] == VK_CHROMA_LOCATION_COSITED_EVEN
) {
96 comp
[c
] = implicit_downsampled_coord(b
,
97 nir_channel(b
, old_coords
, c
),
98 nir_channel(b
, image_size
, c
),
99 plane_format
->denominator_scales
[c
]);
101 comp
[c
] = nir_channel(b
, old_coords
, c
);
105 /* Leave other coordinates untouched */
106 for (; c
< old_coords
->num_components
; c
++)
107 comp
[c
] = nir_channel(b
, old_coords
, c
);
109 return nir_vec(b
, comp
, old_coords
->num_components
);
113 create_plane_tex_instr_implicit(struct ycbcr_state
*state
,
116 nir_builder
*b
= state
->builder
;
117 struct anv_ycbcr_conversion
*conversion
= state
->conversion
;
118 const struct anv_format_plane
*plane_format
=
119 &conversion
->format
->planes
[plane
];
120 nir_tex_instr
*old_tex
= state
->origin_tex
;
121 nir_tex_instr
*tex
= nir_tex_instr_create(b
->shader
, old_tex
->num_srcs
+ 1);
123 for (uint32_t i
= 0; i
< old_tex
->num_srcs
; i
++) {
124 tex
->src
[i
].src_type
= old_tex
->src
[i
].src_type
;
126 switch (old_tex
->src
[i
].src_type
) {
127 case nir_tex_src_coord
:
128 if (plane_format
->has_chroma
&& conversion
->chroma_reconstruction
) {
129 assert(old_tex
->src
[i
].src
.is_ssa
);
131 nir_src_for_ssa(implicit_downsampled_coords(state
,
132 old_tex
->src
[i
].src
.ssa
,
138 nir_src_copy(&tex
->src
[i
].src
, &old_tex
->src
[i
].src
, tex
);
142 tex
->src
[tex
->num_srcs
- 1].src
= nir_src_for_ssa(nir_imm_int(b
, plane
));
143 tex
->src
[tex
->num_srcs
- 1].src_type
= nir_tex_src_plane
;
145 tex
->sampler_dim
= old_tex
->sampler_dim
;
146 tex
->dest_type
= old_tex
->dest_type
;
148 tex
->op
= old_tex
->op
;
149 tex
->coord_components
= old_tex
->coord_components
;
150 tex
->is_new_style_shadow
= old_tex
->is_new_style_shadow
;
151 tex
->component
= old_tex
->component
;
153 tex
->texture_index
= old_tex
->texture_index
;
154 tex
->sampler_index
= old_tex
->sampler_index
;
155 tex
->is_array
= old_tex
->is_array
;
157 nir_ssa_dest_init(&tex
->instr
, &tex
->dest
,
158 old_tex
->dest
.ssa
.num_components
,
159 nir_dest_bit_size(old_tex
->dest
), NULL
);
160 nir_builder_instr_insert(b
, &tex
->instr
);
162 return &tex
->dest
.ssa
;
166 channel_to_component(enum isl_channel_select channel
)
169 case ISL_CHANNEL_SELECT_RED
:
171 case ISL_CHANNEL_SELECT_GREEN
:
173 case ISL_CHANNEL_SELECT_BLUE
:
175 case ISL_CHANNEL_SELECT_ALPHA
:
178 unreachable("invalid channel");
183 static enum isl_channel_select
184 swizzle_channel(struct isl_swizzle swizzle
, unsigned channel
)
196 unreachable("invalid channel");
202 try_lower_tex_ycbcr(const struct anv_pipeline_layout
*layout
,
203 nir_builder
*builder
,
206 int deref_src_idx
= nir_tex_instr_src_index(tex
, nir_tex_src_texture_deref
);
207 assert(deref_src_idx
>= 0);
208 nir_deref_instr
*deref
= nir_src_as_deref(tex
->src
[deref_src_idx
].src
);
210 nir_variable
*var
= nir_deref_instr_get_variable(deref
);
211 const struct anv_descriptor_set_layout
*set_layout
=
212 layout
->set
[var
->data
.descriptor_set
].layout
;
213 const struct anv_descriptor_set_binding_layout
*binding
=
214 &set_layout
->binding
[var
->data
.binding
];
216 /* For the following instructions, we don't apply any change and let the
217 * instruction apply to the first plane.
219 if (tex
->op
== nir_texop_txs
||
220 tex
->op
== nir_texop_query_levels
||
221 tex
->op
== nir_texop_lod
)
224 if (binding
->immutable_samplers
== NULL
)
227 assert(tex
->texture_index
== 0);
228 unsigned array_index
= 0;
229 if (deref
->deref_type
!= nir_deref_type_var
) {
230 assert(deref
->deref_type
== nir_deref_type_array
);
231 if (!nir_src_is_const(deref
->arr
.index
))
233 array_index
= nir_src_as_uint(deref
->arr
.index
);
234 array_index
= MIN2(array_index
, binding
->array_size
- 1);
236 const struct anv_sampler
*sampler
= binding
->immutable_samplers
[array_index
];
238 if (sampler
->conversion
== NULL
)
241 struct ycbcr_state state
= {
245 .conversion
= sampler
->conversion
,
248 builder
->cursor
= nir_before_instr(&tex
->instr
);
250 const struct anv_format
*format
= state
.conversion
->format
;
251 const struct isl_format_layout
*y_isl_layout
= NULL
;
252 for (uint32_t p
= 0; p
< format
->n_planes
; p
++) {
253 if (!format
->planes
[p
].has_chroma
)
254 y_isl_layout
= isl_format_get_layout(format
->planes
[p
].isl_format
);
256 assert(y_isl_layout
!= NULL
);
257 uint8_t y_bpc
= y_isl_layout
->channels_array
[0].bits
;
259 /* |ycbcr_comp| holds components in the order : Cr-Y-Cb */
260 nir_ssa_def
*zero
= nir_imm_float(builder
, 0.0f
);
261 nir_ssa_def
*one
= nir_imm_float(builder
, 1.0f
);
262 /* Use extra 2 channels for following swizzle */
263 nir_ssa_def
*ycbcr_comp
[5] = { zero
, zero
, zero
, one
, zero
};
265 uint8_t ycbcr_bpcs
[5];
266 memset(ycbcr_bpcs
, y_bpc
, sizeof(ycbcr_bpcs
));
268 /* Go through all the planes and gather the samples into a |ycbcr_comp|
269 * while applying a swizzle required by the spec:
271 * R, G, B should respectively map to Cr, Y, Cb
273 for (uint32_t p
= 0; p
< format
->n_planes
; p
++) {
274 const struct anv_format_plane
*plane_format
= &format
->planes
[p
];
275 nir_ssa_def
*plane_sample
= create_plane_tex_instr_implicit(&state
, p
);
277 for (uint32_t pc
= 0; pc
< 4; pc
++) {
278 enum isl_channel_select ycbcr_swizzle
=
279 swizzle_channel(plane_format
->ycbcr_swizzle
, pc
);
280 if (ycbcr_swizzle
== ISL_CHANNEL_SELECT_ZERO
)
283 unsigned ycbcr_component
= channel_to_component(ycbcr_swizzle
);
284 ycbcr_comp
[ycbcr_component
] = nir_channel(builder
, plane_sample
, pc
);
286 /* Also compute the number of bits for each component. */
287 const struct isl_format_layout
*isl_layout
=
288 isl_format_get_layout(plane_format
->isl_format
);
289 ycbcr_bpcs
[ycbcr_component
] = isl_layout
->channels_array
[pc
].bits
;
293 /* Now remaps components to the order specified by the conversion. */
294 nir_ssa_def
*swizzled_comp
[4] = { NULL
, };
295 uint32_t swizzled_bpcs
[4] = { 0, };
297 for (uint32_t i
= 0; i
< ARRAY_SIZE(state
.conversion
->mapping
); i
++) {
298 /* Maps to components in |ycbcr_comp| */
299 static const uint32_t swizzle_mapping
[] = {
300 [VK_COMPONENT_SWIZZLE_ZERO
] = 4,
301 [VK_COMPONENT_SWIZZLE_ONE
] = 3,
302 [VK_COMPONENT_SWIZZLE_R
] = 0,
303 [VK_COMPONENT_SWIZZLE_G
] = 1,
304 [VK_COMPONENT_SWIZZLE_B
] = 2,
305 [VK_COMPONENT_SWIZZLE_A
] = 3,
307 const VkComponentSwizzle m
= state
.conversion
->mapping
[i
];
309 if (m
== VK_COMPONENT_SWIZZLE_IDENTITY
) {
310 swizzled_comp
[i
] = ycbcr_comp
[i
];
311 swizzled_bpcs
[i
] = ycbcr_bpcs
[i
];
313 swizzled_comp
[i
] = ycbcr_comp
[swizzle_mapping
[m
]];
314 swizzled_bpcs
[i
] = ycbcr_bpcs
[swizzle_mapping
[m
]];
318 nir_ssa_def
*result
= nir_vec(builder
, swizzled_comp
, 4);
319 if (state
.conversion
->ycbcr_model
!= VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY
) {
320 result
= nir_convert_ycbcr_to_rgb(builder
,
321 state
.conversion
->ycbcr_model
,
322 state
.conversion
->ycbcr_range
,
327 nir_ssa_def_rewrite_uses(&tex
->dest
.ssa
, nir_src_for_ssa(result
));
328 nir_instr_remove(&tex
->instr
);
334 anv_nir_lower_ycbcr_textures(nir_shader
*shader
,
335 const struct anv_pipeline_layout
*layout
)
337 bool progress
= false;
339 nir_foreach_function(function
, shader
) {
343 bool function_progress
= false;
345 nir_builder_init(&builder
, function
->impl
);
347 nir_foreach_block(block
, function
->impl
) {
348 nir_foreach_instr_safe(instr
, block
) {
349 if (instr
->type
!= nir_instr_type_tex
)
352 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
353 function_progress
|= try_lower_tex_ycbcr(layout
, &builder
, tex
);
357 if (function_progress
) {
358 nir_metadata_preserve(function
->impl
,
359 nir_metadata_block_index
|
360 nir_metadata_dominance
);
363 progress
|= function_progress
;