|
|
|
@@ -0,0 +1,621 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2023 Collabora, Ltd.
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "nak.h"
|
|
|
|
|
#include "nak_private.h"
|
|
|
|
|
#include "nil.h"
|
|
|
|
|
|
|
|
|
|
#include "nir_format_convert.h"
|
|
|
|
|
|
|
|
|
|
static nir_def *
|
|
|
|
|
build_load_su_info(nir_builder *b, nir_deref_instr *deref, uint32_t offset)
|
|
|
|
|
{
|
|
|
|
|
return nir_image_deref_load_info_nv(b, 1, &deref->def, .base = offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define load_su_info(b, d, field) \
|
|
|
|
|
build_load_su_info((b), (d), offsetof(struct nil_su_info, field))
|
|
|
|
|
|
|
|
|
|
static enum pipe_format
|
|
|
|
|
format_for_bits(unsigned bits)
|
|
|
|
|
{
|
|
|
|
|
switch (bits) {
|
|
|
|
|
case 8: return PIPE_FORMAT_R8_UINT;
|
|
|
|
|
case 16: return PIPE_FORMAT_R16_UINT;
|
|
|
|
|
case 32: return PIPE_FORMAT_R32_UINT;
|
|
|
|
|
case 64: return PIPE_FORMAT_R32G32_UINT;
|
|
|
|
|
case 128: return PIPE_FORMAT_R32G32B32A32_UINT;
|
|
|
|
|
default: unreachable("Unknown number of image format bits");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
sampler_dim_len(enum glsl_sampler_dim dim)
|
|
|
|
|
{
|
|
|
|
|
switch (dim) {
|
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
|
case GLSL_SAMPLER_DIM_BUF:
|
|
|
|
|
return 1;
|
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
|
case GLSL_SAMPLER_DIM_RECT:
|
|
|
|
|
case GLSL_SAMPLER_DIM_MS:
|
|
|
|
|
return 2;
|
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
|
return 3;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unhandled sampler dim");
|
|
|
|
|
return 1;// Never reached
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_def *
|
|
|
|
|
lower_formatted_image_load(nir_builder *b,
|
|
|
|
|
nir_intrinsic_instr *intrin,
|
|
|
|
|
enum pipe_format format)
|
|
|
|
|
{
|
|
|
|
|
if (format == PIPE_FORMAT_NONE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
unsigned bits = util_format_get_blocksizebits(format);
|
|
|
|
|
|
|
|
|
|
assert(intrin->intrinsic == nir_intrinsic_suldga_nv);
|
|
|
|
|
|
|
|
|
|
nir_intrinsic_set_format(intrin, format_for_bits(bits));
|
|
|
|
|
|
|
|
|
|
const unsigned num_raw_components = DIV_ROUND_UP(bits, 32);
|
|
|
|
|
intrin->num_components = num_raw_components;
|
|
|
|
|
intrin->def.num_components = num_raw_components;
|
|
|
|
|
|
|
|
|
|
b->cursor = nir_after_instr(&intrin->instr);
|
|
|
|
|
nir_def *rgba = NULL;
|
|
|
|
|
switch (format) {
|
|
|
|
|
case PIPE_FORMAT_R64_UINT:
|
|
|
|
|
case PIPE_FORMAT_R64_SINT:
|
|
|
|
|
rgba = nir_vec4(b, nir_pack_64_2x32(b, &intrin->def),
|
|
|
|
|
nir_imm_int64(b, 0),
|
|
|
|
|
nir_imm_int64(b, 0),
|
|
|
|
|
nir_imm_int64(b, 1));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
rgba = nir_format_unpack_rgba(b, &intrin->def, format);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rgba;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_def *
|
|
|
|
|
load_su_info_clamp(nir_builder *b, nir_deref_instr *deref,
|
|
|
|
|
unsigned xyz)
|
|
|
|
|
{
|
|
|
|
|
/* Array length is always stored in clamp_z */
|
|
|
|
|
enum glsl_sampler_dim dim = glsl_get_sampler_dim(deref->type);
|
|
|
|
|
if (dim == GLSL_SAMPLER_DIM_1D && xyz == 1)
|
|
|
|
|
return load_su_info(b, deref, clamp_z);
|
|
|
|
|
|
|
|
|
|
switch (xyz) {
|
|
|
|
|
case 0: return load_su_info(b, deref, clamp_x);
|
|
|
|
|
case 1: return load_su_info(b, deref, clamp_y);
|
|
|
|
|
case 2: return load_su_info(b, deref, clamp_z);
|
|
|
|
|
default: unreachable("Invalid image dimension");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_def *
|
|
|
|
|
clamp_coord(nir_builder *b, nir_deref_instr *deref,
|
|
|
|
|
nir_def* coord, int xyz)
|
|
|
|
|
{
|
|
|
|
|
nir_def *clamp = load_su_info_clamp(b, deref, xyz);
|
|
|
|
|
|
|
|
|
|
const struct nak_nir_suclamp_flags flags = {
|
|
|
|
|
.mode = NAK_SUCLAMP_MODE_STORED_DESCRIPTOR,
|
|
|
|
|
.round = NAK_SUCLAMP_ROUND_R1,
|
|
|
|
|
.is_s32 = false,
|
|
|
|
|
.is_2d = true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nir_def *dst = nir_suclamp_nv(b, coord, clamp,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
return nir_channel(b, dst, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
load_sample_size(nir_builder *b, nir_deref_instr *deref,
|
|
|
|
|
nir_def **sample_width_log2,
|
|
|
|
|
nir_def **sample_height_log2)
|
|
|
|
|
{
|
|
|
|
|
/* MS width and height are stored in the lower 8 bits of pitch */
|
|
|
|
|
nir_def *pitch = load_su_info(b, deref, pitch);
|
|
|
|
|
*sample_width_log2 = nir_ubitfield_extract_imm(b, pitch, 24, 4);
|
|
|
|
|
*sample_height_log2 = nir_ubitfield_extract_imm(b, pitch, 28, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Kepler only supports suldga, sustga, so we need to compute
|
|
|
|
|
// the raw address manually, this is done through a weird dance
|
|
|
|
|
// and custom ops.
|
|
|
|
|
// - each coordinate is clamped through suclamp
|
|
|
|
|
// - compute block offset using gob coordinates (y * pitch + x)
|
|
|
|
|
// - merge bitfields (output of suclamps)
|
|
|
|
|
// this will both merge the block coordinates, combine
|
|
|
|
|
// pixel coordinates (in GoB-space) and OR together the OOB
|
|
|
|
|
// predicate
|
|
|
|
|
// - compute the effective upper address by combining block_offset,
|
|
|
|
|
// bitfield and base_address
|
|
|
|
|
// - combine effective upper address and the combined bitfield that
|
|
|
|
|
// contains the lower 8 bits of global address
|
|
|
|
|
// - pass the combined values into suldga/sustga
|
|
|
|
|
//
|
|
|
|
|
// Linear Layout support:
|
|
|
|
|
// Shader cannot know at compile time if an image is in linear format
|
|
|
|
|
// or in block format, thus it needs to support both modes using the
|
|
|
|
|
// same opcodes, the only difference should be in descriptors.
|
|
|
|
|
// The address for linear layout is computed with:
|
|
|
|
|
// eff_addr = base_addr + (y * pitch + x)*el_size_B
|
|
|
|
|
// Here we first compute off = (y * pitch + x) with imadsp
|
|
|
|
|
// then we split what goes in the first 8 bits using subfm
|
|
|
|
|
// (in 0..8 it loads off << el_size_B.log2, in 16..32 it
|
|
|
|
|
// loads off >> el_size_B.log2)
|
|
|
|
|
// For this we need to emit eau = sueau bf.x, bf.y, off
|
|
|
|
|
// this would totally screw up block-linear calcs, but we can use
|
|
|
|
|
// is_3d=false to skip the third argument only in block-linear.
|
|
|
|
|
static void
|
|
|
|
|
compute_image_address(nir_builder *b,
|
|
|
|
|
nir_intrinsic_instr *intrin,
|
|
|
|
|
enum glsl_sampler_dim sampler_dim,
|
|
|
|
|
nir_def **addr,
|
|
|
|
|
nir_def **is_oob)
|
|
|
|
|
{
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
|
|
|
|
|
const unsigned dim = sampler_dim_len(sampler_dim);
|
|
|
|
|
const bool is_cube = sampler_dim == GLSL_SAMPLER_DIM_CUBE;
|
|
|
|
|
|
|
|
|
|
// A CubeMap is a 6-array of 2D images, a CubeMap array is just
|
|
|
|
|
// multiple CubeMap concatenated together, so the cube access is alway
|
|
|
|
|
// treated as an array
|
|
|
|
|
const bool is_array = nir_intrinsic_image_array(intrin) || is_cube;
|
|
|
|
|
|
|
|
|
|
// Prevent read/write for null-descriptors
|
|
|
|
|
nir_def *base_addr = load_su_info(b, deref, addr_shifted8);
|
|
|
|
|
*is_oob = nir_ieq_imm(b, base_addr, 0);
|
|
|
|
|
|
|
|
|
|
nir_def *coords[3];
|
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
|
coords[i] = nir_channel(b, intrin->src[1].ssa, i);
|
|
|
|
|
|
|
|
|
|
// Lower multi-sample coords
|
|
|
|
|
if (sampler_dim == GLSL_SAMPLER_DIM_MS) {
|
|
|
|
|
nir_def *s = intrin->src[2].ssa;
|
|
|
|
|
nir_def *sw_log2, *sh_log2;
|
|
|
|
|
load_sample_size(b, deref, &sw_log2, &sh_log2);
|
|
|
|
|
nir_def *s_map = load_su_info(b, deref, extra);// multi-sample table
|
|
|
|
|
nir_def *num_samples = nir_ishl(b, nir_imm_int(b, 1),
|
|
|
|
|
nir_iadd(b, sw_log2, sh_log2));
|
|
|
|
|
|
|
|
|
|
nir_def *s_xy = nir_ushr(b, s_map, nir_imul_imm(b, s, 4));
|
|
|
|
|
nir_def *sx = nir_ubitfield_extract_imm(b, s_xy, 0, 2);
|
|
|
|
|
nir_def *sy = nir_ubitfield_extract_imm(b, s_xy, 2, 2);
|
|
|
|
|
|
|
|
|
|
nir_def *sw = nir_ishl(b, nir_imm_int(b, 1), sw_log2);
|
|
|
|
|
nir_def *sh = nir_ishl(b, nir_imm_int(b, 1), sh_log2);
|
|
|
|
|
|
|
|
|
|
nir_def *x = nir_imad(b, coords[0], sw, sx);
|
|
|
|
|
nir_def *y = nir_imad(b, coords[1], sh, sy);
|
|
|
|
|
|
|
|
|
|
// Check if OOB
|
|
|
|
|
*is_oob = nir_ior(b, *is_oob, nir_uge(b, s, num_samples));
|
|
|
|
|
|
|
|
|
|
coords[0] = x;
|
|
|
|
|
coords[1] = y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clamp coordinates
|
|
|
|
|
// This computes a bitfield with the following info inside:
|
|
|
|
|
// - Block coordinates
|
|
|
|
|
// - GoB coordinates
|
|
|
|
|
// - predicate for OOB access
|
|
|
|
|
// - Wether the clamp is using pitch_linear
|
|
|
|
|
// - n. of block tiles for the coordinate
|
|
|
|
|
nir_def *clamped_x = clamp_coord(b, deref, coords[0], 0);
|
|
|
|
|
nir_def *clamped_y = dim >= 2 ? clamp_coord(b, deref, coords[1], 1) : nir_imm_int(b, 0);
|
|
|
|
|
nir_def *clamped_z = dim >= 3 ? clamp_coord(b, deref, coords[2], 2) : nir_imm_int(b, 0);
|
|
|
|
|
|
|
|
|
|
// For arrays the clamp is "plain", no bitfield is computed
|
|
|
|
|
// just the OOB predicate.
|
|
|
|
|
nir_def *array_idx = NULL;
|
|
|
|
|
if (is_array) {
|
|
|
|
|
nir_def *clamp = load_su_info_clamp(b, deref, dim);
|
|
|
|
|
nir_def *coord = coords[dim];
|
|
|
|
|
|
|
|
|
|
const struct nak_nir_suclamp_flags flags = {
|
|
|
|
|
.mode = NAK_SUCLAMP_MODE_PITCH_LINEAR,
|
|
|
|
|
.round = NAK_SUCLAMP_ROUND_R1,
|
|
|
|
|
.is_s32 = false,
|
|
|
|
|
.is_2d = false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nir_def *dst = nir_suclamp_nv(b, coord, clamp,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
array_idx = nir_channel(b, dst, 0);
|
|
|
|
|
*is_oob = nir_ior(b, *is_oob, nir_ine_imm(b, nir_channel(b, dst, 1), 0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute offset
|
|
|
|
|
// for Block-Linear: GOB coordinates (offset that contributes *64)
|
|
|
|
|
// for Pitch-Linear: offset in pixels (y * pitch) + x
|
|
|
|
|
// for Buffer: offset = x
|
|
|
|
|
nir_def *off;
|
|
|
|
|
if (dim == 1) {
|
|
|
|
|
// This can be only 16 bits because it's only tile coordinates
|
|
|
|
|
// (actually it's 20 bits in pitch-linear mode, we don't support
|
|
|
|
|
// images that big)
|
|
|
|
|
off = nir_iand_imm(b, clamped_x, 0xffff);
|
|
|
|
|
} else if (dim == 2) {
|
|
|
|
|
// off = clamped.y * pitch + clamped.x
|
|
|
|
|
nir_def *pitch = load_su_info(b, deref, pitch);
|
|
|
|
|
|
|
|
|
|
const struct nak_nir_imadsp_flags flags = {
|
|
|
|
|
.src0 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.src1 = NAK_IMAD_TYPE_U24,
|
|
|
|
|
.src2 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.params_from_src1 = false,
|
|
|
|
|
};
|
|
|
|
|
off = nir_imadsp_nv(b, clamped_y, pitch, clamped_x,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
} else {
|
|
|
|
|
assert(dim == 3);
|
|
|
|
|
// off = (clamped.z * height + clamped.y) * pitch + clamped.x
|
|
|
|
|
// height is the height in blocks, we can compute this by doing a
|
|
|
|
|
// block linear clamp with the maximum value.
|
|
|
|
|
// (block shift-right is applied by suclamp)
|
|
|
|
|
nir_def *dim_y = load_su_info_clamp(b, deref, 1);
|
|
|
|
|
const struct nak_nir_suclamp_flags clamp_flags = {
|
|
|
|
|
.mode = NAK_SUCLAMP_MODE_BLOCK_LINEAR,
|
|
|
|
|
.round = NAK_SUCLAMP_ROUND_R1,
|
|
|
|
|
.is_s32 = false,
|
|
|
|
|
.is_2d = false,
|
|
|
|
|
};
|
|
|
|
|
nir_def *max_y = nir_suclamp_nv(b, nir_imm_int(b, -1), dim_y,
|
|
|
|
|
.flags=NAK_AS_U32(clamp_flags));
|
|
|
|
|
|
|
|
|
|
// max_y is still a bitfield, we can add 1 but we must only use the
|
|
|
|
|
// lower 16 bits of height_b.
|
|
|
|
|
nir_def *height_b = nir_iadd_imm(b, nir_channel(b, max_y, 0), 1);
|
|
|
|
|
|
|
|
|
|
const struct nak_nir_imadsp_flags flags_zy = {
|
|
|
|
|
.src0 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.src1 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.src2 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.params_from_src1 = false,
|
|
|
|
|
};
|
|
|
|
|
nir_def *off_2d = nir_imadsp_nv(b, clamped_z, height_b, clamped_y,
|
|
|
|
|
.flags = NAK_AS_U32(flags_zy));
|
|
|
|
|
|
|
|
|
|
nir_def *pitch = load_su_info(b, deref, pitch);
|
|
|
|
|
const struct nak_nir_imadsp_flags flags = {
|
|
|
|
|
.src0 = NAK_IMAD_TYPE_U32,
|
|
|
|
|
.src1 = NAK_IMAD_TYPE_U24,
|
|
|
|
|
.src2 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.params_from_src1 = false,
|
|
|
|
|
};
|
|
|
|
|
off = nir_imadsp_nv(b, off_2d, pitch, clamped_x,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute merged bitfield
|
|
|
|
|
nir_def *bf;
|
|
|
|
|
{
|
|
|
|
|
// bf, pred = subfm clamped.x, clamped.y, clamped.z
|
|
|
|
|
nir_def *bfz;
|
|
|
|
|
bool is_3d = dim >= 3;
|
|
|
|
|
|
|
|
|
|
if (dim == 2 && !is_array) {
|
|
|
|
|
// Special case for pitch_linear support, see comment above.
|
|
|
|
|
bfz = off;
|
|
|
|
|
} else {
|
|
|
|
|
bfz = clamped_z;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nir_def *combined = nir_subfm_nv(b, clamped_x, clamped_y, bfz,
|
|
|
|
|
.flags = is_3d);
|
|
|
|
|
bf = nir_channel(b, combined, 0);
|
|
|
|
|
nir_def *bfm_oob = nir_ine_imm(b, nir_channel(b, combined, 1), 0);
|
|
|
|
|
*is_oob = nir_ior(b, *is_oob, bfm_oob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nir_def *eau = nir_sueau_nv(b, off, bf, base_addr);
|
|
|
|
|
|
|
|
|
|
// Apply array layer offset
|
|
|
|
|
if (is_array) {
|
|
|
|
|
nir_def *array_stride = load_su_info(b, deref, array_stride_shifted8);
|
|
|
|
|
|
|
|
|
|
// Note: this only works because array_idx has been plain-clamped
|
|
|
|
|
// so it's not a bitfield (and we can read more than u16)
|
|
|
|
|
const struct nak_nir_imadsp_flags flags = {
|
|
|
|
|
.src0 = NAK_IMAD_TYPE_U32,
|
|
|
|
|
.src1 = NAK_IMAD_TYPE_U24,
|
|
|
|
|
.src2 = NAK_IMAD_TYPE_U32,
|
|
|
|
|
.params_from_src1 = false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
eau = nir_imadsp_nv(b, array_idx, array_stride, eau,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*addr = nir_vec2(b, bf, eau);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Buffer address calculation is much simpler than images
|
|
|
|
|
// In the end we need the global address to reach in two registers
|
|
|
|
|
// The high register should have the highest 32-bit part of the address
|
|
|
|
|
// The lower register should have the lowest 8-bit part
|
|
|
|
|
// This computation can be summarized as:
|
|
|
|
|
// res = addr + clamp(x) * num_comps
|
|
|
|
|
// Unfortunately, given the weird register division, we need some weird
|
|
|
|
|
// ops. We abuse some special functions from image addressing to reduce
|
|
|
|
|
// the number of instructions.
|
|
|
|
|
//
|
|
|
|
|
// For null descriptors, we put bit 31 high in lower_addr,
|
|
|
|
|
// this is then passed on bfm and sets the oob predicate high.
|
|
|
|
|
// And that's how we get safe null descriptors for free.
|
|
|
|
|
//
|
|
|
|
|
// TODO: check if we can also use vector instructions, codegen used VSHL
|
|
|
|
|
// but it also didn't support sub-0x100 aligned buffers
|
|
|
|
|
static void
|
|
|
|
|
compute_buffer_address(nir_builder *b,
|
|
|
|
|
nir_intrinsic_instr *intrin,
|
|
|
|
|
enum glsl_sampler_dim sampler_dim,
|
|
|
|
|
nir_def **addr,
|
|
|
|
|
nir_def **is_oob)
|
|
|
|
|
{
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
|
|
|
|
|
nir_def *num_elems = load_su_info(b, deref, clamp_x);
|
|
|
|
|
nir_def *el_size_B = load_su_info(b, deref, pitch);
|
|
|
|
|
nir_def *lower_addr = load_su_info(b, deref, extra);
|
|
|
|
|
|
|
|
|
|
nir_def *raw_off = nir_channel(b, intrin->src[1].ssa, 0);
|
|
|
|
|
|
|
|
|
|
*is_oob = nir_uge(b, raw_off, num_elems);
|
|
|
|
|
|
|
|
|
|
nir_def *offset = nir_imad(b, raw_off, el_size_B, lower_addr);
|
|
|
|
|
nir_def *base_addr = load_su_info(b, deref, addr_shifted8);
|
|
|
|
|
|
|
|
|
|
*addr = nir_vec2(b, offset, base_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_def *
|
|
|
|
|
compute_address_from_ga_offset(nir_builder *b, nir_def *addr,
|
|
|
|
|
enum pipe_format format,
|
|
|
|
|
enum nak_su_ga_offset_mode offset_mode)
|
|
|
|
|
{
|
|
|
|
|
assert(offset_mode == NAK_SUGA_OFF_MODE_U32 ||
|
|
|
|
|
offset_mode == NAK_SUGA_OFF_MODE_U8);
|
|
|
|
|
// mode U8: addr_hi contains bits 8..40, addr_lo contains 0..8
|
|
|
|
|
// mode U32: addr_hi contains bits 8..40, addr_lo contains 0..32
|
|
|
|
|
// and they should be added to addr_hi
|
|
|
|
|
nir_def *lo_8;
|
|
|
|
|
nir_def *hi_32 = nir_channel(b, addr, 1);
|
|
|
|
|
|
|
|
|
|
// With what should we fill the lower 8 bits?
|
|
|
|
|
if (offset_mode == NAK_SUGA_OFF_MODE_U8) {
|
|
|
|
|
lo_8 = nir_channel(b, addr, 0);
|
|
|
|
|
} else {
|
|
|
|
|
lo_8 = nir_imm_int(b, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct the 64-bit address (hi_32 << 8 | lo_8)
|
|
|
|
|
nir_def *low = nir_prmt_nv(b, nir_imm_int(b, 0x6540), lo_8, hi_32);
|
|
|
|
|
nir_def *high = nir_prmt_nv(b, nir_imm_int(b, 0x0007),
|
|
|
|
|
nir_imm_int(b, 0), hi_32);
|
|
|
|
|
nir_def *full_addr = nir_pack_64_2x32_split(b, low, high);
|
|
|
|
|
|
|
|
|
|
if (offset_mode == NAK_SUGA_OFF_MODE_U32) {
|
|
|
|
|
full_addr = nir_iadd(b, full_addr, nir_u2u64(b, nir_channel(b, addr, 0)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return full_addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lower_image_access(nir_builder *b, nir_intrinsic_instr *intrin)
|
|
|
|
|
{
|
|
|
|
|
b->cursor = nir_instr_remove(&intrin->instr);
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
|
|
|
|
|
enum pipe_format format = nir_intrinsic_format(intrin);
|
|
|
|
|
|
|
|
|
|
if (format == PIPE_FORMAT_NONE)
|
|
|
|
|
format = nir_deref_instr_get_variable(deref)->data.image.format;
|
|
|
|
|
|
|
|
|
|
const unsigned int num_dst_components = intrin->def.num_components;
|
|
|
|
|
const enum glsl_sampler_dim sampler_dim = nir_intrinsic_image_dim(intrin);
|
|
|
|
|
enum nak_su_ga_offset_mode offset_mode;
|
|
|
|
|
|
|
|
|
|
nir_def *addr, *is_oob;
|
|
|
|
|
if (sampler_dim != GLSL_SAMPLER_DIM_BUF) {
|
|
|
|
|
compute_image_address(b, intrin, sampler_dim, &addr, &is_oob);
|
|
|
|
|
offset_mode = NAK_SUGA_OFF_MODE_U8;
|
|
|
|
|
} else {
|
|
|
|
|
compute_buffer_address(b, intrin, sampler_dim, &addr, &is_oob);
|
|
|
|
|
offset_mode = NAK_SUGA_OFF_MODE_U32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (intrin->intrinsic) {
|
|
|
|
|
case nir_intrinsic_image_deref_load: {
|
|
|
|
|
// .format intrinsic index is only used to pass how many bits to store
|
|
|
|
|
nir_def *fmt = load_su_info(b, deref, format_info);
|
|
|
|
|
nir_def *new_ssa = nir_suldga_nv(b, num_dst_components, addr, fmt,
|
|
|
|
|
is_oob,
|
|
|
|
|
.format = format,
|
|
|
|
|
.access = nir_intrinsic_access(intrin),
|
|
|
|
|
.flags = offset_mode);
|
|
|
|
|
|
|
|
|
|
nir_intrinsic_instr *parent = nir_instr_as_intrinsic(new_ssa->parent_instr);
|
|
|
|
|
new_ssa = lower_formatted_image_load(b, parent, format);
|
|
|
|
|
nir_def_rewrite_uses(&intrin->def, new_ssa);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case nir_intrinsic_image_deref_store: {
|
|
|
|
|
nir_def *fmt = load_su_info(b, deref, format_info);
|
|
|
|
|
nir_sustga_nv(b, addr, fmt, is_oob, intrin->src[3].ssa,
|
|
|
|
|
.access = nir_intrinsic_access(intrin),
|
|
|
|
|
.flags = offset_mode);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case nir_intrinsic_image_deref_atomic:
|
|
|
|
|
case nir_intrinsic_image_deref_atomic_swap: {
|
|
|
|
|
nir_atomic_op atomic_op = nir_intrinsic_atomic_op(intrin);
|
|
|
|
|
|
|
|
|
|
// suldga and sustga expect address as [low_8, high_32]
|
|
|
|
|
// while global_atomic expects a 64-bit address
|
|
|
|
|
nir_def *full_addr = compute_address_from_ga_offset(b, addr,
|
|
|
|
|
format,
|
|
|
|
|
offset_mode);
|
|
|
|
|
|
|
|
|
|
const unsigned bit_size = (format == PIPE_FORMAT_R64_UINT ||
|
|
|
|
|
format == PIPE_FORMAT_R64_SINT) ? 64 : 32;
|
|
|
|
|
|
|
|
|
|
nir_def *res, *res_ib, *res_oob;
|
|
|
|
|
nir_push_if(b, nir_inot(b, is_oob));
|
|
|
|
|
if (intrin->intrinsic == nir_intrinsic_image_deref_atomic) {
|
|
|
|
|
res_ib = nir_global_atomic(b, bit_size, full_addr,
|
|
|
|
|
intrin->src[3].ssa,
|
|
|
|
|
.atomic_op = atomic_op);
|
|
|
|
|
} else {
|
|
|
|
|
res_ib = nir_global_atomic_swap(b, bit_size, full_addr,
|
|
|
|
|
intrin->src[3].ssa,
|
|
|
|
|
intrin->src[4].ssa,
|
|
|
|
|
.atomic_op = atomic_op);
|
|
|
|
|
}
|
|
|
|
|
nir_push_else(b, NULL); {
|
|
|
|
|
res_oob = nir_imm_intN_t(b, 0, bit_size);
|
|
|
|
|
}
|
|
|
|
|
nir_pop_if(b, NULL);
|
|
|
|
|
res = nir_if_phi(b, res_ib, res_oob);
|
|
|
|
|
|
|
|
|
|
nir_def_rewrite_uses(&intrin->def, res);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unknown image intrinsic");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lower_image_size(nir_builder *b, nir_intrinsic_instr *intrin)
|
|
|
|
|
{
|
|
|
|
|
b->cursor = nir_instr_remove(&intrin->instr);
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
|
|
|
|
|
const unsigned dim = sampler_dim_len(nir_intrinsic_image_dim(intrin));
|
|
|
|
|
|
|
|
|
|
const bool is_array = nir_intrinsic_image_array(intrin);
|
|
|
|
|
const unsigned cdim = dim + is_array;
|
|
|
|
|
assert(cdim <= 3);
|
|
|
|
|
nir_def *comps[3];
|
|
|
|
|
|
|
|
|
|
nir_def *is_null = nir_ieq_imm(b, load_su_info(b, deref, addr_shifted8),
|
|
|
|
|
0);
|
|
|
|
|
nir_def *one_if_present = nir_bcsel(b, is_null, nir_imm_int(b, 0),
|
|
|
|
|
nir_imm_int(b, 1));
|
|
|
|
|
|
|
|
|
|
// In descriptors we don't really have the size, but the clamp
|
|
|
|
|
// since it's inclusive, it is size - 1.
|
|
|
|
|
// Also, clamp is a bitfield, we need to extract the lower 16 bits.
|
|
|
|
|
// We can do both operations (extraction and addition) with an imadsp.
|
|
|
|
|
// To handle null descriptors, the addition accumulator of the imadsp
|
|
|
|
|
// is 1 only for non-null descriptors.
|
|
|
|
|
for (int i = 0; i < cdim; i++) {
|
|
|
|
|
nir_def *clamp = load_su_info_clamp(b, deref, i);
|
|
|
|
|
const struct nak_nir_imadsp_flags flags = {
|
|
|
|
|
.src0 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.src1 = NAK_IMAD_TYPE_U24,
|
|
|
|
|
.src2 = NAK_IMAD_TYPE_U16_LO,
|
|
|
|
|
.params_from_src1 = false,
|
|
|
|
|
};
|
|
|
|
|
comps[i] = nir_imadsp_nv(b, clamp, one_if_present,
|
|
|
|
|
one_if_present,
|
|
|
|
|
.flags = NAK_AS_U32(flags));
|
|
|
|
|
}
|
|
|
|
|
// Clamp has multi-sampling already lowered, we need to de-lower it.
|
|
|
|
|
if (nir_intrinsic_image_dim(intrin) == GLSL_SAMPLER_DIM_MS) {
|
|
|
|
|
nir_def *ms_w_log2, *ms_h_log2;
|
|
|
|
|
load_sample_size(b, deref, &ms_w_log2, &ms_h_log2);
|
|
|
|
|
|
|
|
|
|
comps[0] = nir_ishr(b, comps[0], ms_w_log2);
|
|
|
|
|
comps[1] = nir_ishr(b, comps[1], ms_h_log2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nir_def_rewrite_uses(&intrin->def, nir_vec(b, comps, cdim));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lower_buffer_size(nir_builder *b, nir_intrinsic_instr *intrin)
|
|
|
|
|
{
|
|
|
|
|
b->cursor = nir_instr_remove(&intrin->instr);
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
nir_def *num_elems = load_su_info(b, deref, clamp_x);
|
|
|
|
|
|
|
|
|
|
nir_def_rewrite_uses(&intrin->def, num_elems);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lower_image_samples(nir_builder *b, nir_intrinsic_instr *intrin)
|
|
|
|
|
{
|
|
|
|
|
b->cursor = nir_instr_remove(&intrin->instr);
|
|
|
|
|
nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
|
|
|
|
|
|
|
|
|
|
nir_def *sw_log2, *sh_log2;
|
|
|
|
|
load_sample_size(b, deref, &sw_log2, &sh_log2);
|
|
|
|
|
|
|
|
|
|
nir_def *samples_log2 = nir_iadd(b, sw_log2, sh_log2);
|
|
|
|
|
nir_def *samples = nir_ishl(b, nir_imm_int(b, 1), samples_log2);
|
|
|
|
|
|
|
|
|
|
// Handle null descriptors
|
|
|
|
|
nir_def *addr = load_su_info(b, deref, addr_shifted8);
|
|
|
|
|
nir_def *is_null = nir_ieq_imm(b, addr, 0);
|
|
|
|
|
samples = nir_bcsel(b, is_null, nir_imm_int(b, 0), samples);
|
|
|
|
|
|
|
|
|
|
nir_def_rewrite_uses(&intrin->def, samples);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
lower_image_intrin(nir_builder *b,
|
|
|
|
|
nir_intrinsic_instr *intrin,
|
|
|
|
|
void *_data)
|
|
|
|
|
{
|
|
|
|
|
switch (intrin->intrinsic) {
|
|
|
|
|
case nir_intrinsic_image_deref_load:
|
|
|
|
|
case nir_intrinsic_image_deref_store:
|
|
|
|
|
case nir_intrinsic_image_deref_atomic:
|
|
|
|
|
case nir_intrinsic_image_deref_atomic_swap:
|
|
|
|
|
lower_image_access(b, intrin);
|
|
|
|
|
return true;
|
|
|
|
|
case nir_intrinsic_image_deref_size:
|
|
|
|
|
if (nir_intrinsic_image_dim(intrin) == GLSL_SAMPLER_DIM_BUF) {
|
|
|
|
|
lower_buffer_size(b, intrin);
|
|
|
|
|
} else {
|
|
|
|
|
lower_image_size(b, intrin);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
case nir_intrinsic_image_deref_samples:
|
|
|
|
|
lower_image_samples(b, intrin);
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
nak_nir_lower_image_addrs(nir_shader *nir,
|
|
|
|
|
const struct nak_compiler *nak)
|
|
|
|
|
{
|
|
|
|
|
return nir_shader_intrinsics_pass(nir, lower_image_intrin,
|
|
|
|
|
nir_metadata_none,
|
|
|
|
|
(void *)nak);
|
|
|
|
|
}
|