xref: /aosp_15_r20/external/mesa3d/src/asahi/lib/shaders/texture.cl (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker/*
2*61046927SAndroid Build Coastguard Worker * Copyright 2023 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker * Copyright 2023 Valve Corporation
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker#include "libagx.h"
7*61046927SAndroid Build Coastguard Worker#include <agx_pack.h>
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Workeruint3
10*61046927SAndroid Build Coastguard Workerlibagx_txs(constant struct agx_texture_packed *ptr, uint16_t lod,
11*61046927SAndroid Build Coastguard Worker           unsigned nr_comps, bool is_buffer, bool is_1d, bool is_2d,
12*61046927SAndroid Build Coastguard Worker           bool is_cube, bool is_array)
13*61046927SAndroid Build Coastguard Worker{
14*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
15*61046927SAndroid Build Coastguard Worker
16*61046927SAndroid Build Coastguard Worker   /* From the Vulkan spec:
17*61046927SAndroid Build Coastguard Worker    *
18*61046927SAndroid Build Coastguard Worker    *    OpImageQuery*...  return 0 if the bound descriptor is a null descriptor
19*61046927SAndroid Build Coastguard Worker    */
20*61046927SAndroid Build Coastguard Worker   if (d.null)
21*61046927SAndroid Build Coastguard Worker      return 0;
22*61046927SAndroid Build Coastguard Worker
23*61046927SAndroid Build Coastguard Worker   /* Buffer textures are lowered to 2D so the original size is irrecoverable.
24*61046927SAndroid Build Coastguard Worker    * Instead, we stash it in the software-defined section.
25*61046927SAndroid Build Coastguard Worker    */
26*61046927SAndroid Build Coastguard Worker   if (is_buffer)
27*61046927SAndroid Build Coastguard Worker      return d.buffer_size_sw;
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker   /* Load standard dimensions */
30*61046927SAndroid Build Coastguard Worker   uint3 size = (uint3)(d.width, d.height, d.depth);
31*61046927SAndroid Build Coastguard Worker   lod += d.first_level;
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker   /* Linear 2D arrays are special.
34*61046927SAndroid Build Coastguard Worker    *
35*61046927SAndroid Build Coastguard Worker    * TODO: Optimize this, since linear 2D arrays aren't needed for APIs and
36*61046927SAndroid Build Coastguard Worker    * this just gets used internally for blits.
37*61046927SAndroid Build Coastguard Worker    */
38*61046927SAndroid Build Coastguard Worker   if (is_2d && is_array && d.layout == AGX_LAYOUT_LINEAR)
39*61046927SAndroid Build Coastguard Worker      size.z = d.depth_linear;
40*61046927SAndroid Build Coastguard Worker
41*61046927SAndroid Build Coastguard Worker   /* 1D Arrays have their second component as the layer count */
42*61046927SAndroid Build Coastguard Worker   if (is_1d && is_array)
43*61046927SAndroid Build Coastguard Worker      size.y = size.z;
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker   /* Adjust for LOD, do not adjust array size */
46*61046927SAndroid Build Coastguard Worker   for (uint c = 0; c < (nr_comps - (uint)is_array); ++c)
47*61046927SAndroid Build Coastguard Worker      size[c] = max(size[c] >> lod, 1u);
48*61046927SAndroid Build Coastguard Worker
49*61046927SAndroid Build Coastguard Worker   /* Cube maps have equal width and height, we save some instructions by only
50*61046927SAndroid Build Coastguard Worker    * reading one. Dead code elimination will remove the redundant instructions.
51*61046927SAndroid Build Coastguard Worker    */
52*61046927SAndroid Build Coastguard Worker   if (is_cube)
53*61046927SAndroid Build Coastguard Worker      size.y = size.x;
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker   return size;
56*61046927SAndroid Build Coastguard Worker}
57*61046927SAndroid Build Coastguard Worker
58*61046927SAndroid Build Coastguard Workeruint
59*61046927SAndroid Build Coastguard Workerlibagx_texture_samples(constant struct agx_texture_packed *ptr)
60*61046927SAndroid Build Coastguard Worker{
61*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
62*61046927SAndroid Build Coastguard Worker
63*61046927SAndroid Build Coastguard Worker   /* As above */
64*61046927SAndroid Build Coastguard Worker   if (d.null)
65*61046927SAndroid Build Coastguard Worker      return 0;
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker   /* We may assume the input is multisampled, so just check the samples */
68*61046927SAndroid Build Coastguard Worker   return (d.samples == AGX_SAMPLE_COUNT_2) ? 2 : 4;
69*61046927SAndroid Build Coastguard Worker}
70*61046927SAndroid Build Coastguard Worker
71*61046927SAndroid Build Coastguard Workeruint
72*61046927SAndroid Build Coastguard Workerlibagx_texture_levels(constant struct agx_texture_packed *ptr)
73*61046927SAndroid Build Coastguard Worker{
74*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
75*61046927SAndroid Build Coastguard Worker
76*61046927SAndroid Build Coastguard Worker   /* As above */
77*61046927SAndroid Build Coastguard Worker   if (d.null)
78*61046927SAndroid Build Coastguard Worker      return 0;
79*61046927SAndroid Build Coastguard Worker   else
80*61046927SAndroid Build Coastguard Worker      return (d.last_level - d.first_level) + 1;
81*61046927SAndroid Build Coastguard Worker}
82*61046927SAndroid Build Coastguard Worker
83*61046927SAndroid Build Coastguard Worker/*
84*61046927SAndroid Build Coastguard Worker * Fix robustness behaviour of txf with out-of-bounds LOD. The hardware
85*61046927SAndroid Build Coastguard Worker * returns the correct out-of-bounds colour for out-of-bounds coordinates,
86*61046927SAndroid Build Coastguard Worker * just not LODs. So translate out-of-bounds LOD into an out-of-bounds
87*61046927SAndroid Build Coastguard Worker * coordinate to get correct behaviour in 1 instruction.
88*61046927SAndroid Build Coastguard Worker *
89*61046927SAndroid Build Coastguard Worker * Returns the fixed X-coordinate.
90*61046927SAndroid Build Coastguard Worker *
91*61046927SAndroid Build Coastguard Worker * TODO: This looks like it might be an erratum workaround on G13 (Apple does
92*61046927SAndroid Build Coastguard Worker * it), maybe check if G15 is affected.
93*61046927SAndroid Build Coastguard Worker */
94*61046927SAndroid Build Coastguard Workeruint
95*61046927SAndroid Build Coastguard Workerlibagx_lower_txf_robustness(constant struct agx_texture_packed *ptr,
96*61046927SAndroid Build Coastguard Worker                            bool check_lod, ushort lod, bool check_layer,
97*61046927SAndroid Build Coastguard Worker                            uint layer, uint x)
98*61046927SAndroid Build Coastguard Worker{
99*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker   bool valid = true;
102*61046927SAndroid Build Coastguard Worker
103*61046927SAndroid Build Coastguard Worker   if (check_lod)
104*61046927SAndroid Build Coastguard Worker      valid &= lod <= (d.last_level - d.first_level);
105*61046927SAndroid Build Coastguard Worker
106*61046927SAndroid Build Coastguard Worker   if (check_layer) {
107*61046927SAndroid Build Coastguard Worker      bool linear = (d.layout == AGX_LAYOUT_LINEAR);
108*61046927SAndroid Build Coastguard Worker      valid &= layer < (linear ? d.depth_linear : d.depth);
109*61046927SAndroid Build Coastguard Worker   }
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker   /* The maximum tail offset is 0xF so by returning 0xFFF0 for out-of-bounds we
112*61046927SAndroid Build Coastguard Worker    * stay under 0xFFFF and keep robustness after offsetting.
113*61046927SAndroid Build Coastguard Worker    */
114*61046927SAndroid Build Coastguard Worker   return valid ? x : 0xFFF0;
115*61046927SAndroid Build Coastguard Worker}
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Workerstatic uint32_t
118*61046927SAndroid Build Coastguard Workercalculate_twiddled_coordinates(ushort2 coord, uint16_t tile_w_px,
119*61046927SAndroid Build Coastguard Worker                               uint16_t tile_h_px, uint32_t aligned_width_px)
120*61046927SAndroid Build Coastguard Worker{
121*61046927SAndroid Build Coastguard Worker   /* Modulo by the tile width/height to get the offsets within the tile */
122*61046927SAndroid Build Coastguard Worker   ushort2 tile_mask_vec = (ushort2)(tile_w_px - 1, tile_h_px - 1);
123*61046927SAndroid Build Coastguard Worker   uint32_t tile_mask = upsample(tile_mask_vec.y, tile_mask_vec.x);
124*61046927SAndroid Build Coastguard Worker   uint32_t coord_xy = upsample(coord.y, coord.x);
125*61046927SAndroid Build Coastguard Worker   ushort2 offs_px = as_ushort2(coord_xy & tile_mask);
126*61046927SAndroid Build Coastguard Worker   uint32_t offset_within_tile_px = nir_interleave_agx(offs_px.x, offs_px.y);
127*61046927SAndroid Build Coastguard Worker
128*61046927SAndroid Build Coastguard Worker   /* Get the coordinates of the corner of the tile */
129*61046927SAndroid Build Coastguard Worker   ushort2 tile_px = as_ushort2(coord_xy & ~tile_mask);
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker   /* tile row start (px) =
132*61046927SAndroid Build Coastguard Worker    *   (y // tile height) * (# of tiles/row) * (# of pix/tile) =
133*61046927SAndroid Build Coastguard Worker    *   align_down(y, tile height) / tile height * width_tl *tile width *
134*61046927SAndroid Build Coastguard Worker    *        tile height =
135*61046927SAndroid Build Coastguard Worker    *   align_down(y, tile height) * width_tl * tile width
136*61046927SAndroid Build Coastguard Worker    */
137*61046927SAndroid Build Coastguard Worker   uint32_t tile_row_start_px = tile_px.y * aligned_width_px;
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker   /* tile column start (px) =
140*61046927SAndroid Build Coastguard Worker    *   (x // tile width) * (# of pix/tile) =
141*61046927SAndroid Build Coastguard Worker    *   align_down(x, tile width) / tile width * tile width * tile height =
142*61046927SAndroid Build Coastguard Worker    *   align_down(x, tile width) * tile height
143*61046927SAndroid Build Coastguard Worker    */
144*61046927SAndroid Build Coastguard Worker   uint32_t tile_col_start_px = tile_px.x * tile_h_px;
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker   /* Get the total offset */
147*61046927SAndroid Build Coastguard Worker   return tile_row_start_px + tile_col_start_px + offset_within_tile_px;
148*61046927SAndroid Build Coastguard Worker}
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Workeruint64_t
151*61046927SAndroid Build Coastguard Workerlibagx_image_texel_address(constant const struct agx_pbe_packed *ptr,
152*61046927SAndroid Build Coastguard Worker                           uint4 coord, uint sample_idx,
153*61046927SAndroid Build Coastguard Worker                           uint bytes_per_sample_B, bool is_1d, bool is_msaa,
154*61046927SAndroid Build Coastguard Worker                           bool is_layered, bool return_index)
155*61046927SAndroid Build Coastguard Worker{
156*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, PBE, d);
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker   /* We do not allow atomics on linear 2D or linear 2D arrays, as there are no
159*61046927SAndroid Build Coastguard Worker    * known use cases. So we're twiddled in this path, unless we're handling a
160*61046927SAndroid Build Coastguard Worker    * 1D image which will be always linear, even if it uses a twiddled layout
161*61046927SAndroid Build Coastguard Worker    * degrading to linear-equivalent 1x1 tiles. (1D uses this path, not the
162*61046927SAndroid Build Coastguard Worker    * buffer path, for 1D arrays.)
163*61046927SAndroid Build Coastguard Worker    */
164*61046927SAndroid Build Coastguard Worker   uint total_px;
165*61046927SAndroid Build Coastguard Worker   if (is_1d) {
166*61046927SAndroid Build Coastguard Worker      total_px = coord.x;
167*61046927SAndroid Build Coastguard Worker   } else {
168*61046927SAndroid Build Coastguard Worker      uint aligned_width_px;
169*61046927SAndroid Build Coastguard Worker      if (is_msaa) {
170*61046927SAndroid Build Coastguard Worker         aligned_width_px = d.aligned_width_msaa_sw;
171*61046927SAndroid Build Coastguard Worker      } else {
172*61046927SAndroid Build Coastguard Worker         uint width_px = max(d.width >> d.level, 1u);
173*61046927SAndroid Build Coastguard Worker         aligned_width_px = align(width_px, d.tile_width_sw);
174*61046927SAndroid Build Coastguard Worker      }
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker      total_px = calculate_twiddled_coordinates(
177*61046927SAndroid Build Coastguard Worker         convert_ushort2(coord.xy), d.tile_width_sw, d.tile_height_sw,
178*61046927SAndroid Build Coastguard Worker         aligned_width_px);
179*61046927SAndroid Build Coastguard Worker   }
180*61046927SAndroid Build Coastguard Worker
181*61046927SAndroid Build Coastguard Worker   uint samples_log2 = is_msaa ? d.sample_count_log2_sw : 0;
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker   if (is_layered) {
184*61046927SAndroid Build Coastguard Worker      total_px += coord[is_1d ? 1 : 2] *
185*61046927SAndroid Build Coastguard Worker                  ((d.layer_stride_sw / bytes_per_sample_B) >> samples_log2);
186*61046927SAndroid Build Coastguard Worker   }
187*61046927SAndroid Build Coastguard Worker
188*61046927SAndroid Build Coastguard Worker   uint total_sa = (total_px << samples_log2) + sample_idx;
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker   if (return_index)
191*61046927SAndroid Build Coastguard Worker      return total_sa;
192*61046927SAndroid Build Coastguard Worker   else
193*61046927SAndroid Build Coastguard Worker      return (d.buffer + (is_msaa ? 0 : d.level_offset_sw)) +
194*61046927SAndroid Build Coastguard Worker             (uint64_t)(total_sa * bytes_per_sample_B);
195*61046927SAndroid Build Coastguard Worker}
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Workeruint64_t
198*61046927SAndroid Build Coastguard Workerlibagx_buffer_texel_address(constant const struct agx_pbe_packed *ptr,
199*61046927SAndroid Build Coastguard Worker                            uint4 coord, uint bytes_per_pixel_B)
200*61046927SAndroid Build Coastguard Worker{
201*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, PBE, d);
202*61046927SAndroid Build Coastguard Worker
203*61046927SAndroid Build Coastguard Worker   uint32_t x_el = d.buffer_offset_sw + coord.x;
204*61046927SAndroid Build Coastguard Worker   return d.buffer + (uint64_t)(x_el * bytes_per_pixel_B);
205*61046927SAndroid Build Coastguard Worker}
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker/* Buffer texture lowerings */
208*61046927SAndroid Build Coastguard Workerbool
209*61046927SAndroid Build Coastguard Workerlibagx_texture_is_rgb32(constant struct agx_texture_packed *ptr)
210*61046927SAndroid Build Coastguard Worker{
211*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
212*61046927SAndroid Build Coastguard Worker   return d.channels == AGX_CHANNELS_R32G32B32_EMULATED;
213*61046927SAndroid Build Coastguard Worker}
214*61046927SAndroid Build Coastguard Worker
215*61046927SAndroid Build Coastguard Workeruint4
216*61046927SAndroid Build Coastguard Workerlibagx_texture_load_rgb32(constant struct agx_texture_packed *ptr, uint coord,
217*61046927SAndroid Build Coastguard Worker                          bool is_float)
218*61046927SAndroid Build Coastguard Worker{
219*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
220*61046927SAndroid Build Coastguard Worker   global uint3 *data = (global uint3 *)(d.address + 12 * coord);
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker   return (uint4)(*data, is_float ? as_uint(1.0f) : 1);
223*61046927SAndroid Build Coastguard Worker}
224*61046927SAndroid Build Coastguard Worker
225*61046927SAndroid Build Coastguard Workeruint
226*61046927SAndroid Build Coastguard Workerlibagx_buffer_texture_offset(constant struct agx_texture_packed *ptr, uint x)
227*61046927SAndroid Build Coastguard Worker{
228*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, TEXTURE, d);
229*61046927SAndroid Build Coastguard Worker
230*61046927SAndroid Build Coastguard Worker   return x + d.buffer_offset_sw;
231*61046927SAndroid Build Coastguard Worker}
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Workeruint
234*61046927SAndroid Build Coastguard Workerlibagx_buffer_image_offset(constant struct agx_pbe_packed *ptr, uint x)
235*61046927SAndroid Build Coastguard Worker{
236*61046927SAndroid Build Coastguard Worker   agx_unpack(NULL, ptr, PBE, d);
237*61046927SAndroid Build Coastguard Worker
238*61046927SAndroid Build Coastguard Worker   return x + d.buffer_offset_sw;
239*61046927SAndroid Build Coastguard Worker}
240