• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2023 Alyssa Rosenzweig
3 * Copyright 2023 Valve Corporation
4 * SPDX-License-Identifier: MIT
5 */
6#include "libagx.h"
7#include <agx_pack.h>
8
9uint3
10libagx_txs(constant struct agx_texture_packed *ptr, uint16_t lod,
11           unsigned nr_comps, bool is_buffer, bool is_1d, bool is_2d,
12           bool is_cube, bool is_array)
13{
14   agx_unpack(NULL, ptr, TEXTURE, d);
15
16   /* From the Vulkan spec:
17    *
18    *    OpImageQuery*...  return 0 if the bound descriptor is a null descriptor
19    */
20   if (d.null)
21      return 0;
22
23   /* Buffer textures are lowered to 2D so the original size is irrecoverable.
24    * Instead, we stash it in the software-defined section.
25    */
26   if (is_buffer)
27      return d.software_defined;
28
29   /* Load standard dimensions */
30   uint3 size = (uint3)(d.width, d.height, d.depth);
31   lod += d.first_level;
32
33   /* Linear 2D arrays are special.
34    *
35    * TODO: Optimize this, since linear 2D arrays aren't needed for APIs and
36    * this just gets used internally for blits.
37    */
38   if (is_2d && is_array && d.layout == AGX_LAYOUT_LINEAR)
39      size.z = d.depth_linear;
40
41   /* 1D Arrays have their second component as the layer count */
42   if (is_1d && is_array)
43      size.y = size.z;
44
45   /* Adjust for LOD, do not adjust array size */
46   for (uint c = 0; c < (nr_comps - (uint)is_array); ++c)
47      size[c] = max(size[c] >> lod, 1u);
48
49   /* Cube maps have equal width and height, we save some instructions by only
50    * reading one. Dead code elimination will remove the redundant instructions.
51    */
52   if (is_cube)
53      size.y = size.x;
54
55   return size;
56}
57
58uint
59libagx_texture_samples(constant struct agx_texture_packed *ptr)
60{
61   agx_unpack(NULL, ptr, TEXTURE, d);
62
63   /* As above */
64   if (d.null)
65      return 0;
66
67   /* We may assume the input is multisampled, so just check the samples */
68   return (d.samples == AGX_SAMPLE_COUNT_2) ? 2 : 4;
69}
70
71uint
72libagx_texture_levels(constant struct agx_texture_packed *ptr)
73{
74   agx_unpack(NULL, ptr, TEXTURE, d);
75
76   /* As above */
77   if (d.null)
78      return 0;
79   else
80      return (d.last_level - d.first_level) + 1;
81}
82
83/*
84 * Fix robustness behaviour of txf with out-of-bounds LOD. The hardware
85 * returns the correct out-of-bounds colour for out-of-bounds coordinates,
86 * just not LODs. So translate out-of-bounds LOD into an out-of-bounds
87 * coordinate to get correct behaviour in 1 instruction.
88 *
89 * Returns the fixed X-coordinate.
90 *
91 * TODO: This looks like it might be an erratum workaround on G13 (Apple does
92 * it), maybe check if G15 is affected.
93 */
94uint
95libagx_lower_txf_robustness(constant struct agx_texture_packed *ptr, ushort lod,
96                            uint x)
97{
98   agx_unpack(NULL, ptr, TEXTURE, d);
99
100   bool oob = (lod > (d.last_level - d.first_level));
101   return oob ? 0xFFFF : x;
102}
103
104static uint32_t
105calculate_twiddled_coordinates(ushort2 coord, uint16_t tile_w_px,
106                               uint16_t tile_h_px, uint32_t width_tl)
107{
108   /* Modulo by the tile width/height to get the offsets within the tile */
109   ushort2 tile_mask_vec = (ushort2)(tile_w_px - 1, tile_h_px - 1);
110   uint32_t tile_mask = upsample(tile_mask_vec.y, tile_mask_vec.x);
111   uint32_t coord_xy = upsample(coord.y, coord.x);
112   ushort2 offs_px = as_ushort2(coord_xy & tile_mask);
113   uint32_t offset_within_tile_px = nir_interleave_agx(offs_px.x, offs_px.y);
114
115   /* Get the coordinates of the corner of the tile */
116   ushort2 tile_px = as_ushort2(coord_xy & ~tile_mask);
117
118   /* tile row start (px) =
119    *   (y // tile height) * (# of tiles/row) * (# of pix/tile) =
120    *   align_down(y, tile height) / tile height * width_tl *tile width *
121    *        tile height =
122    *   align_down(y, tile height) * width_tl * tile width
123    */
124   uint32_t tile_row_start_px = tile_px.y * width_tl * tile_w_px;
125
126   /* tile column start (px) =
127    *   (x // tile width) * (# of pix/tile) =
128    *   align_down(x, tile width) / tile width * tile width * tile height =
129    *   align_down(x, tile width) * tile height
130    */
131   uint32_t tile_col_start_px = tile_px.x * tile_h_px;
132
133   /* Get the total offset */
134   return tile_row_start_px + tile_col_start_px + offset_within_tile_px;
135}
136
137uint64_t
138libagx_image_texel_address(constant const struct agx_atomic_software_packed *ptr,
139                           uint4 coord, uint sample_idx,
140                           uint bytes_per_sample_B, bool is_msaa,
141                           bool is_layered, bool return_index)
142{
143   agx_unpack(NULL, ptr, ATOMIC_SOFTWARE, d);
144
145   /* We do not allow atomics on linear 2D or linear 2D arrays, as there are no
146    * known use cases. So we're twiddled in this path.
147    */
148   uint total_px = calculate_twiddled_coordinates(
149      convert_ushort2(coord.xy), d.tile_width, d.tile_height, d.tiles_per_row);
150
151   if (is_layered)
152      total_px += coord.z * d.layer_stride_pixels;
153
154   uint sample_count = is_msaa ? d.sample_count : 1;
155   uint total_sa = (total_px * d.sample_count) + sample_idx;
156
157   if (return_index)
158      return total_sa;
159   else
160      return d.base + (uint64_t)(total_sa * bytes_per_sample_B);
161}
162
163uint64_t
164libagx_buffer_texel_address(
165   constant const struct agx_pbe_buffer_software_packed *ptr, uint4 coord,
166   uint bytes_per_pixel_B)
167{
168   agx_unpack(NULL, ptr, PBE_BUFFER_SOFTWARE, d);
169   return d.base + (uint64_t)(coord.x * bytes_per_pixel_B);
170}
171
172/* Buffer texture lowerings */
173bool
174libagx_texture_is_rgb32(constant struct agx_texture_packed *ptr)
175{
176   agx_unpack(NULL, ptr, TEXTURE, d);
177   return d.channels == AGX_CHANNELS_R32G32B32_EMULATED;
178}
179
180uint4
181libagx_texture_load_rgb32(constant struct agx_texture_packed *ptr, uint coord,
182                          bool is_float)
183{
184   agx_unpack(NULL, ptr, TEXTURE, d);
185   global uint3 *data = (global uint3 *)(d.address + 12 * coord);
186
187   return (uint4)(*data, is_float ? as_uint(1.0f) : 1);
188}
189