mesa/src/asahi/lib/shaders/texture.cl
Alyssa Rosenzweig bc6b2d087b agx: wire up texture_samples/image_samplers
CL makes this too easy, lmao

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26614>
2023-12-09 10:56:45 -04:00

155 lines
4.8 KiB
C

/*
* Copyright 2023 Alyssa Rosenzweig
* Copyright 2023 Valve Corporation
* SPDX-License-Identifier: MIT
*/
#include "libagx.h"
#include <agx_pack.h>
uint3
libagx_txs(constant struct agx_texture_packed *ptr, uint16_t lod,
unsigned nr_comps, bool is_buffer, bool is_1d, bool is_2d,
bool is_cube, bool is_array)
{
agx_unpack(NULL, ptr, TEXTURE, d);
/* From the Vulkan spec:
*
* OpImageQuery*... return 0 if the bound descriptor is a null descriptor
*/
if (d.null)
return 0;
/* Buffer textures are lowered to 2D so the original size is irrecoverable.
* Instead, we stash it in the software-defined section.
*/
if (is_buffer)
return d.software_defined;
/* Load standard dimensions */
uint3 size = (uint3)(d.width, d.height, d.depth);
lod += d.first_level;
/* Linear 2D arrays are special.
*
* TODO: Optimize this, since linear 2D arrays aren't needed for APIs and
* this just gets used internally for blits.
*/
if (is_2d && is_array && d.layout == AGX_LAYOUT_LINEAR)
size.z = d.depth_linear;
/* 1D Arrays have their second component as the layer count */
if (is_1d && is_array)
size.y = size.z;
/* Adjust for LOD, do not adjust array size */
for (uint c = 0; c < (nr_comps - (uint)is_array); ++c)
size[c] = max(size[c] >> lod, 1u);
/* Cube maps have equal width and height, we save some instructions by only
* reading one. Dead code elimination will remove the redundant instructions.
*/
if (is_cube)
size.y = size.x;
return size;
}
uint
libagx_texture_samples(constant struct agx_texture_packed *ptr)
{
agx_unpack(NULL, ptr, TEXTURE, d);
/* As above */
if (d.null)
return 0;
/* We may assume the input is multisampled, so just check the samples */
return (d.samples == AGX_SAMPLE_COUNT_2) ? 2 : 4;
}
static uint32_t
calculate_twiddled_coordinates(ushort2 coord, uint16_t tile_w_px,
uint16_t tile_h_px, uint32_t width_tl)
{
/* Modulo by the tile width/height to get the offsets within the tile */
ushort2 tile_mask_vec = (ushort2)(tile_w_px - 1, tile_h_px - 1);
uint32_t tile_mask = upsample(tile_mask_vec.y, tile_mask_vec.x);
uint32_t coord_xy = upsample(coord.y, coord.x);
ushort2 offs_px = as_ushort2(coord_xy & tile_mask);
uint32_t offset_within_tile_px = nir_interleave_agx(offs_px.x, offs_px.y);
/* Get the coordinates of the corner of the tile */
ushort2 tile_px = as_ushort2(coord_xy & ~tile_mask);
/* tile row start (px) =
* (y // tile height) * (# of tiles/row) * (# of pix/tile) =
* align_down(y, tile height) / tile height * width_tl *tile width *
* tile height =
* align_down(y, tile height) * width_tl * tile width
*/
uint32_t tile_row_start_px = tile_px.y * width_tl * tile_w_px;
/* tile column start (px) =
* (x // tile width) * (# of pix/tile) =
* align_down(x, tile width) / tile width * tile width * tile height =
* align_down(x, tile width) * tile height
*/
uint32_t tile_col_start_px = tile_px.x * tile_h_px;
/* Get the total offset */
return tile_row_start_px + tile_col_start_px + offset_within_tile_px;
}
uint64_t
libagx_image_texel_address(constant const struct agx_atomic_software_packed *ptr,
uint4 coord, uint sample_idx,
uint bytes_per_sample_B, bool is_msaa,
bool is_layered, bool return_index)
{
agx_unpack(NULL, ptr, ATOMIC_SOFTWARE, d);
/* We do not allow atomics on linear 2D or linear 2D arrays, as there are no
* known use cases. So we're twiddled in this path.
*/
uint total_px = calculate_twiddled_coordinates(
convert_ushort2(coord.xy), d.tile_width, d.tile_height, d.tiles_per_row);
if (is_layered)
total_px += coord.z * d.layer_stride_pixels;
uint sample_count = is_msaa ? d.sample_count : 1;
uint total_sa = (total_px * d.sample_count) + sample_idx;
if (return_index)
return total_sa;
else
return d.base + (uint64_t)(total_sa * bytes_per_sample_B);
}
uint64_t
libagx_buffer_texel_address(
constant const struct agx_pbe_buffer_software_packed *ptr, uint4 coord,
uint bytes_per_pixel_B)
{
agx_unpack(NULL, ptr, PBE_BUFFER_SOFTWARE, d);
return d.base + (uint64_t)(coord.x * bytes_per_pixel_B);
}
/* Buffer texture lowerings */
bool
libagx_texture_is_rgb32(constant struct agx_texture_packed *ptr)
{
agx_unpack(NULL, ptr, TEXTURE, d);
return d.channels == AGX_CHANNELS_R32G32B32_EMULATED;
}
uint4
libagx_texture_load_rgb32(constant struct agx_texture_packed *ptr, uint coord,
bool is_float)
{
agx_unpack(NULL, ptr, TEXTURE, d);
global uint3 *data = (global uint3 *)(d.address + 12 * coord);
return (uint4)(*data, is_float ? as_uint(1.0f) : 1);
}