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