mesa/src/amd/common/ac_formats.c
2026-01-02 16:46:20 +00:00

968 lines
33 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2015 Advanced Micro Devices, Inc.
* Copyright 2024 Valve Corporation
*
* SPDX-License-Identifier: MIT
*/
#include "ac_gpu_info.h"
#include "ac_formats.h"
#include "ac_gpu_info.h"
#include "sid.h"
uint32_t
ac_translate_buffer_numformat(const struct util_format_description *desc,
int first_non_void)
{
if (desc->format == PIPE_FORMAT_R11G11B10_FLOAT)
return V_008F0C_BUF_NUM_FORMAT_FLOAT;
assert(first_non_void >= 0);
switch (desc->channel[first_non_void].type) {
case UTIL_FORMAT_TYPE_SIGNED:
case UTIL_FORMAT_TYPE_FIXED:
if (desc->channel[first_non_void].size >= 32 || desc->channel[first_non_void].pure_integer)
return V_008F0C_BUF_NUM_FORMAT_SINT;
else if (desc->channel[first_non_void].normalized)
return V_008F0C_BUF_NUM_FORMAT_SNORM;
else
return V_008F0C_BUF_NUM_FORMAT_SSCALED;
break;
case UTIL_FORMAT_TYPE_UNSIGNED:
if (desc->channel[first_non_void].size >= 32 || desc->channel[first_non_void].pure_integer)
return V_008F0C_BUF_NUM_FORMAT_UINT;
else if (desc->channel[first_non_void].normalized)
return V_008F0C_BUF_NUM_FORMAT_UNORM;
else
return V_008F0C_BUF_NUM_FORMAT_USCALED;
break;
case UTIL_FORMAT_TYPE_FLOAT:
default:
return V_008F0C_BUF_NUM_FORMAT_FLOAT;
}
}
uint32_t
ac_translate_buffer_dataformat(const struct util_format_description *desc,
int first_non_void)
{
int i;
if (desc->format == PIPE_FORMAT_R11G11B10_FLOAT)
return V_008F0C_BUF_DATA_FORMAT_10_11_11;
assert(first_non_void >= 0);
if (desc->nr_channels == 4 && desc->channel[0].size == 10 && desc->channel[1].size == 10 &&
desc->channel[2].size == 10 && desc->channel[3].size == 2)
return V_008F0C_BUF_DATA_FORMAT_2_10_10_10;
/* See whether the components are of the same size. */
for (i = 0; i < desc->nr_channels; i++) {
if (desc->channel[first_non_void].size != desc->channel[i].size)
return V_008F0C_BUF_DATA_FORMAT_INVALID;
}
switch (desc->channel[first_non_void].size) {
case 8:
switch (desc->nr_channels) {
case 1:
case 3: /* 3 loads */
return V_008F0C_BUF_DATA_FORMAT_8;
case 2:
return V_008F0C_BUF_DATA_FORMAT_8_8;
case 4:
return V_008F0C_BUF_DATA_FORMAT_8_8_8_8;
}
break;
case 16:
switch (desc->nr_channels) {
case 1:
case 3: /* 3 loads */
return V_008F0C_BUF_DATA_FORMAT_16;
case 2:
return V_008F0C_BUF_DATA_FORMAT_16_16;
case 4:
return V_008F0C_BUF_DATA_FORMAT_16_16_16_16;
}
break;
case 32:
switch (desc->nr_channels) {
case 1:
return V_008F0C_BUF_DATA_FORMAT_32;
case 2:
return V_008F0C_BUF_DATA_FORMAT_32_32;
case 3:
return V_008F0C_BUF_DATA_FORMAT_32_32_32;
case 4:
return V_008F0C_BUF_DATA_FORMAT_32_32_32_32;
}
break;
case 64:
/* Legacy double formats. */
switch (desc->nr_channels) {
case 1: /* 1 load */
return V_008F0C_BUF_DATA_FORMAT_32_32;
case 2: /* 1 load */
return V_008F0C_BUF_DATA_FORMAT_32_32_32_32;
case 3: /* 3 loads */
return V_008F0C_BUF_DATA_FORMAT_32_32;
case 4: /* 2 loads */
return V_008F0C_BUF_DATA_FORMAT_32_32_32_32;
}
break;
}
return V_008F0C_BUF_DATA_FORMAT_INVALID;
}
uint32_t
ac_translate_tex_numformat(const struct util_format_description *desc,
int first_non_void)
{
uint32_t num_format;
switch (desc->format) {
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
num_format = V_008F14_IMG_NUM_FORMAT_UNORM;
break;
default:
if (first_non_void < 0) {
if (util_format_is_compressed(desc->format)) {
switch (desc->format) {
case PIPE_FORMAT_DXT1_SRGB:
case PIPE_FORMAT_DXT1_SRGBA:
case PIPE_FORMAT_DXT3_SRGBA:
case PIPE_FORMAT_DXT5_SRGBA:
case PIPE_FORMAT_BPTC_SRGBA:
case PIPE_FORMAT_ETC2_SRGB8:
case PIPE_FORMAT_ETC2_SRGB8A1:
case PIPE_FORMAT_ETC2_SRGBA8:
num_format = V_008F14_IMG_NUM_FORMAT_SRGB;
break;
case PIPE_FORMAT_RGTC1_SNORM:
case PIPE_FORMAT_LATC1_SNORM:
case PIPE_FORMAT_RGTC2_SNORM:
case PIPE_FORMAT_LATC2_SNORM:
case PIPE_FORMAT_ETC2_R11_SNORM:
case PIPE_FORMAT_ETC2_RG11_SNORM:
/* implies float, so use SNORM/UNORM to determine
whether data is signed or not */
case PIPE_FORMAT_BPTC_RGB_FLOAT:
num_format = V_008F14_IMG_NUM_FORMAT_SNORM;
break;
default:
num_format = V_008F14_IMG_NUM_FORMAT_UNORM;
break;
}
} else if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
num_format = V_008F14_IMG_NUM_FORMAT_UNORM;
} else {
num_format = V_008F14_IMG_NUM_FORMAT_FLOAT;
}
} else if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
num_format = V_008F14_IMG_NUM_FORMAT_SRGB;
} else {
switch (desc->channel[first_non_void].type) {
case UTIL_FORMAT_TYPE_FLOAT:
num_format = V_008F14_IMG_NUM_FORMAT_FLOAT;
break;
case UTIL_FORMAT_TYPE_SIGNED:
if (desc->channel[first_non_void].normalized)
num_format = V_008F14_IMG_NUM_FORMAT_SNORM;
else if (desc->channel[first_non_void].pure_integer)
num_format = V_008F14_IMG_NUM_FORMAT_SINT;
else
num_format = V_008F14_IMG_NUM_FORMAT_SSCALED;
break;
case UTIL_FORMAT_TYPE_UNSIGNED:
if (desc->channel[first_non_void].normalized)
num_format = V_008F14_IMG_NUM_FORMAT_UNORM;
else if (desc->channel[first_non_void].pure_integer)
num_format = V_008F14_IMG_NUM_FORMAT_UINT;
else
num_format = V_008F14_IMG_NUM_FORMAT_USCALED;
break;
default:
num_format = V_008F14_IMG_NUM_FORMAT_UNORM;
break;
}
}
}
return num_format;
}
uint32_t
ac_translate_tex_dataformat(const struct radeon_info *info,
const struct util_format_description *desc,
int first_non_void)
{
bool uniform = true;
int i;
/* Colorspace (return non-RGB formats directly). */
switch (desc->colorspace) {
/* Depth stencil formats */
case UTIL_FORMAT_COLORSPACE_ZS:
switch (desc->format) {
case PIPE_FORMAT_Z16_UNORM:
return V_008F14_IMG_DATA_FORMAT_16;
case PIPE_FORMAT_X24S8_UINT:
case PIPE_FORMAT_S8X24_UINT:
/*
* Implemented as an 8_8_8_8 data format to fix texture
* gathers in stencil sampling. This affects at least
* GL45-CTS.texture_cube_map_array.sampling on GFX8.
*/
if (info->gfx_level <= GFX8)
return V_008F14_IMG_DATA_FORMAT_8_8_8_8;
if (desc->format == PIPE_FORMAT_X24S8_UINT)
return V_008F14_IMG_DATA_FORMAT_8_24;
else
return V_008F14_IMG_DATA_FORMAT_24_8;
case PIPE_FORMAT_Z24X8_UNORM:
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
return V_008F14_IMG_DATA_FORMAT_8_24;
case PIPE_FORMAT_X8Z24_UNORM:
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
return V_008F14_IMG_DATA_FORMAT_24_8;
case PIPE_FORMAT_S8_UINT:
return V_008F14_IMG_DATA_FORMAT_8;
case PIPE_FORMAT_Z32_FLOAT:
return V_008F14_IMG_DATA_FORMAT_32;
case PIPE_FORMAT_X32_S8X24_UINT:
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
return V_008F14_IMG_DATA_FORMAT_X24_8_32;
default:
return ~0;
}
case UTIL_FORMAT_COLORSPACE_YUV:
return ~0; /* TODO */
default:
break;
}
if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
switch (desc->format) {
case PIPE_FORMAT_RGTC1_SNORM:
case PIPE_FORMAT_LATC1_SNORM:
case PIPE_FORMAT_RGTC1_UNORM:
case PIPE_FORMAT_LATC1_UNORM:
return V_008F14_IMG_DATA_FORMAT_BC4;
case PIPE_FORMAT_RGTC2_SNORM:
case PIPE_FORMAT_LATC2_SNORM:
case PIPE_FORMAT_RGTC2_UNORM:
case PIPE_FORMAT_LATC2_UNORM:
return V_008F14_IMG_DATA_FORMAT_BC5;
default:
return ~0;
}
}
if (desc->layout == UTIL_FORMAT_LAYOUT_ETC) {
switch (desc->format) {
case PIPE_FORMAT_ETC1_RGB8:
case PIPE_FORMAT_ETC2_RGB8:
case PIPE_FORMAT_ETC2_SRGB8:
return V_008F14_IMG_DATA_FORMAT_ETC2_RGB;
case PIPE_FORMAT_ETC2_RGB8A1:
case PIPE_FORMAT_ETC2_SRGB8A1:
return V_008F14_IMG_DATA_FORMAT_ETC2_RGBA1;
case PIPE_FORMAT_ETC2_RGBA8:
case PIPE_FORMAT_ETC2_SRGBA8:
return V_008F14_IMG_DATA_FORMAT_ETC2_RGBA;
case PIPE_FORMAT_ETC2_R11_UNORM:
case PIPE_FORMAT_ETC2_R11_SNORM:
return V_008F14_IMG_DATA_FORMAT_ETC2_R;
case PIPE_FORMAT_ETC2_RG11_UNORM:
case PIPE_FORMAT_ETC2_RG11_SNORM:
return V_008F14_IMG_DATA_FORMAT_ETC2_RG;
default:
break;
}
}
if (desc->layout == UTIL_FORMAT_LAYOUT_BPTC) {
switch (desc->format) {
case PIPE_FORMAT_BPTC_RGBA_UNORM:
case PIPE_FORMAT_BPTC_SRGBA:
return V_008F14_IMG_DATA_FORMAT_BC7;
case PIPE_FORMAT_BPTC_RGB_FLOAT:
case PIPE_FORMAT_BPTC_RGB_UFLOAT:
return V_008F14_IMG_DATA_FORMAT_BC6;
default:
return ~0;
}
}
if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
switch (desc->format) {
case PIPE_FORMAT_R8G8_B8G8_UNORM:
case PIPE_FORMAT_G8R8_B8R8_UNORM:
case PIPE_FORMAT_B8G8_R8G8_UNORM:
return V_008F14_IMG_DATA_FORMAT_GB_GR;
case PIPE_FORMAT_G8R8_G8B8_UNORM:
case PIPE_FORMAT_R8G8_R8B8_UNORM:
case PIPE_FORMAT_G8B8_G8R8_UNORM:
return V_008F14_IMG_DATA_FORMAT_BG_RG;
default:
return ~0;
}
}
if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
switch (desc->format) {
case PIPE_FORMAT_DXT1_RGB:
case PIPE_FORMAT_DXT1_RGBA:
case PIPE_FORMAT_DXT1_SRGB:
case PIPE_FORMAT_DXT1_SRGBA:
return V_008F14_IMG_DATA_FORMAT_BC1;
case PIPE_FORMAT_DXT3_RGBA:
case PIPE_FORMAT_DXT3_SRGBA:
return V_008F14_IMG_DATA_FORMAT_BC2;
case PIPE_FORMAT_DXT5_RGBA:
case PIPE_FORMAT_DXT5_SRGBA:
return V_008F14_IMG_DATA_FORMAT_BC3;
default:
return ~0;
}
}
if (desc->format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
return V_008F14_IMG_DATA_FORMAT_5_9_9_9;
} else if (desc->format == PIPE_FORMAT_R11G11B10_FLOAT) {
return V_008F14_IMG_DATA_FORMAT_10_11_11;
}
/* hw cannot support mixed formats (except depth/stencil, since only
* depth is read).*/
if (desc->is_mixed && desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS)
return ~0;
if (first_non_void < 0 || first_non_void > 3)
return ~0;
/* See whether the components are of the same size. */
for (i = 1; i < desc->nr_channels; i++) {
uniform = uniform && desc->channel[0].size == desc->channel[i].size;
}
/* Non-uniform formats. */
if (!uniform) {
switch (desc->nr_channels) {
case 3:
if (desc->channel[0].size == 5 && desc->channel[1].size == 6 &&
desc->channel[2].size == 5) {
return V_008F14_IMG_DATA_FORMAT_5_6_5;
}
return ~0;
case 4:
/* 5551 and 1555 UINT formats fail on Gfx8/Carrizo´. */
if (info->family == CHIP_CARRIZO &&
desc->channel[1].size == 5 &&
desc->channel[2].size == 5 &&
desc->channel[first_non_void].type == UTIL_FORMAT_TYPE_UNSIGNED &&
desc->channel[first_non_void].pure_integer)
return ~0;
if (desc->channel[0].size == 5 && desc->channel[1].size == 5 &&
desc->channel[2].size == 5 && desc->channel[3].size == 1) {
return V_008F14_IMG_DATA_FORMAT_1_5_5_5;
}
if (desc->channel[0].size == 1 && desc->channel[1].size == 5 &&
desc->channel[2].size == 5 && desc->channel[3].size == 5) {
return V_008F14_IMG_DATA_FORMAT_5_5_5_1;
}
if (desc->channel[0].size == 10 && desc->channel[1].size == 10 &&
desc->channel[2].size == 10 && desc->channel[3].size == 2) {
return V_008F14_IMG_DATA_FORMAT_2_10_10_10;
}
return ~0;
}
return ~0;
}
/* uniform formats */
switch (desc->channel[first_non_void].size) {
case 4:
switch (desc->nr_channels) {
case 4:
/* 4444 UINT formats fail on Gfx8/Carrizo´. */
if (info->family == CHIP_CARRIZO &&
desc->channel[first_non_void].type == UTIL_FORMAT_TYPE_UNSIGNED &&
desc->channel[first_non_void].pure_integer)
return ~0;
return V_008F14_IMG_DATA_FORMAT_4_4_4_4;
}
break;
case 8:
switch (desc->nr_channels) {
case 1:
return V_008F14_IMG_DATA_FORMAT_8;
case 2:
return V_008F14_IMG_DATA_FORMAT_8_8;
case 4:
return V_008F14_IMG_DATA_FORMAT_8_8_8_8;
}
break;
case 16:
switch (desc->nr_channels) {
case 1:
return V_008F14_IMG_DATA_FORMAT_16;
case 2:
return V_008F14_IMG_DATA_FORMAT_16_16;
case 4:
return V_008F14_IMG_DATA_FORMAT_16_16_16_16;
}
break;
case 32:
switch (desc->nr_channels) {
case 1:
return V_008F14_IMG_DATA_FORMAT_32;
case 2:
return V_008F14_IMG_DATA_FORMAT_32_32;
/* Not supported for render targets */
case 3:
return V_008F14_IMG_DATA_FORMAT_32_32_32;
case 4:
return V_008F14_IMG_DATA_FORMAT_32_32_32_32;
}
break;
case 64:
if (desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT && desc->nr_channels == 1)
return V_008F14_IMG_DATA_FORMAT_32_32;
break;
}
return ~0;
}
unsigned
ac_get_cb_format(enum amd_gfx_level gfx_level, enum pipe_format format)
{
const struct util_format_description *desc = util_format_description(format);
#define HAS_SIZE(x, y, z, w) \
(desc->channel[0].size == (x) && desc->channel[1].size == (y) && \
desc->channel[2].size == (z) && desc->channel[3].size == (w))
if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */
return V_028C70_COLOR_10_11_11;
if (gfx_level >= GFX10_3 &&
format == PIPE_FORMAT_R9G9B9E5_FLOAT) /* isn't plain */
return V_028C70_COLOR_5_9_9_9;
if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
return V_028C70_COLOR_INVALID;
/* hw cannot support mixed formats (except depth/stencil, since
* stencil is not written to). */
if (desc->is_mixed && desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS)
return V_028C70_COLOR_INVALID;
int first_non_void = util_format_get_first_non_void_channel(format);
/* Reject SCALED formats because we don't implement them for CB. */
if (first_non_void >= 0 && first_non_void <= 3 &&
(desc->channel[first_non_void].type == UTIL_FORMAT_TYPE_UNSIGNED ||
desc->channel[first_non_void].type == UTIL_FORMAT_TYPE_SIGNED) &&
!desc->channel[first_non_void].normalized &&
!desc->channel[first_non_void].pure_integer)
return V_028C70_COLOR_INVALID;
switch (desc->nr_channels) {
case 1:
switch (desc->channel[0].size) {
case 8:
return V_028C70_COLOR_8;
case 16:
return V_028C70_COLOR_16;
case 32:
return V_028C70_COLOR_32;
case 64:
return V_028C70_COLOR_32_32;
}
break;
case 2:
if (desc->channel[0].size == desc->channel[1].size) {
switch (desc->channel[0].size) {
case 8:
return V_028C70_COLOR_8_8;
case 16:
return V_028C70_COLOR_16_16;
case 32:
return V_028C70_COLOR_32_32;
}
} else if (HAS_SIZE(8, 24, 0, 0)) {
return V_028C70_COLOR_24_8;
} else if (HAS_SIZE(24, 8, 0, 0)) {
return V_028C70_COLOR_8_24;
}
break;
case 3:
if (HAS_SIZE(5, 6, 5, 0)) {
return V_028C70_COLOR_5_6_5;
} else if (HAS_SIZE(32, 8, 24, 0)) {
return V_028C70_COLOR_X24_8_32_FLOAT;
}
break;
case 4:
if (desc->channel[0].size == desc->channel[1].size &&
desc->channel[0].size == desc->channel[2].size &&
desc->channel[0].size == desc->channel[3].size) {
switch (desc->channel[0].size) {
case 4:
return V_028C70_COLOR_4_4_4_4;
case 8:
return V_028C70_COLOR_8_8_8_8;
case 16:
return V_028C70_COLOR_16_16_16_16;
case 32:
return V_028C70_COLOR_32_32_32_32;
}
} else if (HAS_SIZE(5, 5, 5, 1)) {
return V_028C70_COLOR_1_5_5_5;
} else if (HAS_SIZE(1, 5, 5, 5)) {
return V_028C70_COLOR_5_5_5_1;
} else if (HAS_SIZE(10, 10, 10, 2)) {
return V_028C70_COLOR_2_10_10_10;
} else if (HAS_SIZE(2, 10, 10, 10)) {
return V_028C70_COLOR_10_10_10_2;
}
break;
}
return V_028C70_COLOR_INVALID;
}
unsigned ac_get_cb_number_type(enum pipe_format format)
{
const struct util_format_description *desc = util_format_description(format);
int chan = util_format_get_first_non_void_channel(format);
if (chan == -1 || desc->channel[chan].type == UTIL_FORMAT_TYPE_FLOAT) {
return V_028C70_NUMBER_FLOAT;
} else {
if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
return V_028C70_NUMBER_SRGB;
} else if (desc->channel[chan].type == UTIL_FORMAT_TYPE_SIGNED) {
return desc->channel[chan].pure_integer ? V_028C70_NUMBER_SINT : V_028C70_NUMBER_SNORM;
} else if (desc->channel[chan].type == UTIL_FORMAT_TYPE_UNSIGNED) {
return desc->channel[chan].pure_integer ? V_028C70_NUMBER_UINT : V_028C70_NUMBER_UNORM;
} else {
return V_028C70_NUMBER_UNORM;
}
}
}
unsigned
ac_translate_colorswap(enum amd_gfx_level gfx_level, enum pipe_format format, bool do_endian_swap)
{
const struct util_format_description *desc = util_format_description(format);
#define HAS_SWIZZLE(chan, swz) (desc->swizzle[chan] == PIPE_SWIZZLE_##swz)
if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */
return V_028C70_SWAP_STD;
if (gfx_level >= GFX10_3 &&
format == PIPE_FORMAT_R9G9B9E5_FLOAT) /* isn't plain */
return V_028C70_SWAP_STD;
if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
return ~0U;
switch (desc->nr_channels) {
case 1:
if (HAS_SWIZZLE(0, X))
return V_028C70_SWAP_STD; /* X___ */
else if (HAS_SWIZZLE(3, X))
return V_028C70_SWAP_ALT_REV; /* ___X */
break;
case 2:
if ((HAS_SWIZZLE(0, X) && HAS_SWIZZLE(1, Y)) || (HAS_SWIZZLE(0, X) && HAS_SWIZZLE(1, NONE)) ||
(HAS_SWIZZLE(0, NONE) && HAS_SWIZZLE(1, Y)))
return V_028C70_SWAP_STD; /* XY__ */
else if ((HAS_SWIZZLE(0, Y) && HAS_SWIZZLE(1, X)) ||
(HAS_SWIZZLE(0, Y) && HAS_SWIZZLE(1, NONE)) ||
(HAS_SWIZZLE(0, NONE) && HAS_SWIZZLE(1, X)))
/* YX__ */
return (do_endian_swap ? V_028C70_SWAP_STD : V_028C70_SWAP_STD_REV);
else if (HAS_SWIZZLE(0, X) && HAS_SWIZZLE(3, Y))
return V_028C70_SWAP_ALT; /* X__Y */
else if (HAS_SWIZZLE(0, Y) && HAS_SWIZZLE(3, X))
return V_028C70_SWAP_ALT_REV; /* Y__X */
break;
case 3:
if (HAS_SWIZZLE(0, X))
return (do_endian_swap ? V_028C70_SWAP_STD_REV : V_028C70_SWAP_STD);
else if (HAS_SWIZZLE(0, Z))
return V_028C70_SWAP_STD_REV; /* ZYX */
break;
case 4:
/* check the middle channels, the 1st and 4th channel can be NONE */
if (HAS_SWIZZLE(1, Y) && HAS_SWIZZLE(2, Z)) {
return V_028C70_SWAP_STD; /* XYZW */
} else if (HAS_SWIZZLE(1, Z) && HAS_SWIZZLE(2, Y)) {
return V_028C70_SWAP_STD_REV; /* WZYX */
} else if (HAS_SWIZZLE(1, Y) && HAS_SWIZZLE(2, X)) {
return V_028C70_SWAP_ALT; /* ZYXW */
} else if (HAS_SWIZZLE(1, Z) && HAS_SWIZZLE(2, W)) {
/* YZWX */
if (desc->is_array)
return V_028C70_SWAP_ALT_REV;
else
return (do_endian_swap ? V_028C70_SWAP_ALT : V_028C70_SWAP_ALT_REV);
}
break;
}
return ~0U;
}
bool
ac_is_colorbuffer_format_supported(enum amd_gfx_level gfx_level, enum pipe_format format)
{
return ac_get_cb_format(gfx_level, format) != V_028C70_COLOR_INVALID &&
ac_translate_colorswap(gfx_level, format, false) != ~0U;
}
uint32_t
ac_colorformat_endian_swap(uint32_t colorformat)
{
if (UTIL_ARCH_BIG_ENDIAN) {
switch (colorformat) {
/* 8-bit buffers. */
case V_028C70_COLOR_8:
return V_028C70_ENDIAN_NONE;
/* 16-bit buffers. */
case V_028C70_COLOR_5_6_5:
case V_028C70_COLOR_1_5_5_5:
case V_028C70_COLOR_4_4_4_4:
case V_028C70_COLOR_16:
case V_028C70_COLOR_8_8:
return V_028C70_ENDIAN_8IN16;
/* 32-bit buffers. */
case V_028C70_COLOR_8_8_8_8:
case V_028C70_COLOR_2_10_10_10:
case V_028C70_COLOR_10_10_10_2:
case V_028C70_COLOR_8_24:
case V_028C70_COLOR_24_8:
case V_028C70_COLOR_16_16:
return V_028C70_ENDIAN_8IN32;
/* 64-bit buffers. */
case V_028C70_COLOR_16_16_16_16:
return V_028C70_ENDIAN_8IN16;
case V_028C70_COLOR_32_32:
return V_028C70_ENDIAN_8IN32;
/* 128-bit buffers. */
case V_028C70_COLOR_32_32_32_32:
return V_028C70_ENDIAN_8IN32;
default:
return V_028C70_ENDIAN_NONE; /* Unsupported. */
}
} else {
return V_028C70_ENDIAN_NONE;
}
}
uint32_t
ac_translate_dbformat(enum pipe_format format)
{
switch (format) {
case PIPE_FORMAT_Z16_UNORM:
case PIPE_FORMAT_Z16_UNORM_S8_UINT:
return V_028040_Z_16;
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
case PIPE_FORMAT_X8Z24_UNORM:
case PIPE_FORMAT_Z24X8_UNORM:
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
return V_028040_Z_24; /* not present on GFX12 */
case PIPE_FORMAT_Z32_FLOAT:
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
return V_028040_Z_32_FLOAT;
default:
return V_028040_Z_INVALID;
}
}
bool
ac_is_zs_format_supported(enum pipe_format format)
{
return ac_translate_dbformat(format) != V_028040_Z_INVALID;
}
uint32_t
ac_border_color_swizzle(const struct util_format_description *desc)
{
unsigned bc_swizzle = V_008F20_BC_SWIZZLE_XYZW;
if (desc->format == PIPE_FORMAT_S8_UINT) {
/* Swizzle of 8-bit stencil format is defined as _x__ but the hw expects XYZW. */
assert(desc->swizzle[1] == PIPE_SWIZZLE_X);
return bc_swizzle;
}
if (desc->swizzle[3] == PIPE_SWIZZLE_X) {
/* For the pre-defined border color values (white, opaque
* black, transparent black), the only thing that matters is
* that the alpha channel winds up in the correct place
* (because the RGB channels are all the same) so either of
* these enumerations will work.
*/
if (desc->swizzle[2] == PIPE_SWIZZLE_Y)
bc_swizzle = V_008F20_BC_SWIZZLE_WZYX;
else
bc_swizzle = V_008F20_BC_SWIZZLE_WXYZ;
} else if (desc->swizzle[0] == PIPE_SWIZZLE_X) {
if (desc->swizzle[1] == PIPE_SWIZZLE_Y)
bc_swizzle = V_008F20_BC_SWIZZLE_XYZW;
else
bc_swizzle = V_008F20_BC_SWIZZLE_XWYZ;
} else if (desc->swizzle[1] == PIPE_SWIZZLE_X) {
bc_swizzle = V_008F20_BC_SWIZZLE_YXWZ;
} else if (desc->swizzle[2] == PIPE_SWIZZLE_X) {
bc_swizzle = V_008F20_BC_SWIZZLE_ZYXW;
}
return bc_swizzle;
}
/** Linearize and convert luminance/intensity to red. */
enum pipe_format
ac_simplify_cb_format(enum pipe_format format)
{
format = util_format_linear(format);
format = util_format_luminance_to_red(format);
return util_format_intensity_to_red(format);
}
bool
ac_alpha_is_on_msb(const struct radeon_info *info, enum pipe_format format)
{
if (info->gfx_level >= GFX11)
return false;
format = ac_simplify_cb_format(format);
const struct util_format_description *desc = util_format_description(format);
unsigned comp_swap = ac_translate_colorswap(info->gfx_level, format, false);
/* The following code matches the hw behavior. */
if (desc->nr_channels == 1) {
return (comp_swap == V_028C70_SWAP_ALT_REV) != (info->family == CHIP_RAVEN2 ||
info->family == CHIP_RENOIR);
}
return comp_swap != V_028C70_SWAP_STD_REV && comp_swap != V_028C70_SWAP_ALT_REV;
}
/* GFX6-8:
* - no integer format support
* - no depth format support (depth formats without shadow samplers are supported,
* but that's not enough)
* - only single-channel formats are supported
* - limitations of early chips (GFX6 only): no R9G9B9E5 support
*
* GFX9+:
* - all formats are supported
*/
bool
ac_is_reduction_mode_supported(const struct radeon_info *info, enum pipe_format format,
bool shadow_samplers)
{
const struct util_format_description *desc = util_format_description(format);
if (info->gfx_level <= GFX8) {
/* old HW limitations */
if (info->gfx_level == GFX6 && format == PIPE_FORMAT_R9G9B9E5_FLOAT)
return false;
/* reject if more than one channel */
if (desc->nr_channels > 1)
return false;
/* no integer or depth format support */
if (util_format_is_pure_integer(format) ||
(shadow_samplers && util_format_has_depth(desc)))
return false;
}
return true;
}
void
ac_set_sx_downconvert_state_for_mrt(enum amd_gfx_level gfx_level, bool is_null, unsigned cb_color_info,
unsigned cb_color_attrib, unsigned spi_shader_col_format,
unsigned cb_target_mask, unsigned mrt_index,
uint32_t *sx_ps_downconvert, uint32_t *sx_blend_opt_epsilon,
uint32_t *sx_blend_opt_control, uint32_t *fix_cb_target_mask)
{
if (is_null) {
/* If the color buffer is not set, the driver sets 32_R as the SPI color format, because
* the HW doesn't allow holes between color outputs, so also set this to enable RB+.
*/
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_32_R << (mrt_index * 4);
return;
}
unsigned cb_format = gfx_level >= GFX11 ? G_028C70_FORMAT_GFX11(cb_color_info):
G_028C70_FORMAT_GFX6(cb_color_info);
unsigned cb_swap = G_028C70_COMP_SWAP(cb_color_info);
unsigned spi_format = (spi_shader_col_format >> (mrt_index * 4)) & 0xf;
unsigned colormask = (cb_target_mask >> (mrt_index * 4)) & 0xf;
/* Set if RGB and A are present. */
bool has_alpha = !(gfx_level >= GFX11 ? G_028C74_FORCE_DST_ALPHA_1_GFX11(cb_color_attrib):
G_028C74_FORCE_DST_ALPHA_1_GFX6(cb_color_attrib));
bool has_rgb;
if (cb_format == V_028C70_COLOR_8 || cb_format == V_028C70_COLOR_16 || cb_format == V_028C70_COLOR_32)
has_rgb = !has_alpha;
else
has_rgb = true;
/* Check the colormask and export format. */
if (!(colormask & PIPE_MASK_RGB))
has_rgb = false;
if (!(colormask & PIPE_MASK_A))
has_alpha = false;
if (spi_format == V_028714_SPI_SHADER_ZERO) {
has_rgb = false;
has_alpha = false;
}
/* Disable value checking for disabled channels during SX blend optimizations (determining
* BLEND_BYPASS and DISCARD). These bits modify how BLEND_BYPASS and DISCARD are determined.
*
* When both DISABLE bits are set, the behavior is BLEND_BYPASS. When colormask is
* also 0, the SX export format must still be set, and then it behaves like DISCARD.
*
* When any DISABLE bit is not set, those components must succeed the corresponding MRTi blend
* opt test to get BLEND_BYPASS or DISCARD.
*/
if (!has_rgb)
*sx_blend_opt_control |= S_02875C_MRT0_COLOR_OPT_DISABLE(1) << (mrt_index * 4);
if (!has_alpha)
*sx_blend_opt_control |= S_02875C_MRT0_ALPHA_OPT_DISABLE(1) << (mrt_index * 4);
/* Enable export down-conversion for 32bpp and smaller formats, also called RB+, required
* for optimal pixel throughput. If this function doesn't set anything (the value stays at
* SX_RT_EXPORT_NO_CONVERSION=0), the pixel throughput will be the same as 64bpp.
*/
bool export_format_is_fp16 = spi_format == V_028714_SPI_SHADER_FP16_ABGR;
bool export_format_is_int16 = spi_format == V_028714_SPI_SHADER_UINT16_ABGR ||
spi_format == V_028714_SPI_SHADER_SINT16_ABGR;
bool export_format_is_norm16 = spi_format == V_028714_SPI_SHADER_UNORM16_ABGR ||
spi_format == V_028714_SPI_SHADER_SNORM16_ABGR;
switch (cb_format) {
case V_028C70_COLOR_8:
case V_028C70_COLOR_8_8:
case V_028C70_COLOR_8_8_8_8:
if (export_format_is_fp16 || export_format_is_int16) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_8_8_8_8 << (mrt_index * 4);
if (G_028C70_NUMBER_TYPE(cb_color_info) != V_028C70_NUMBER_SRGB)
*sx_blend_opt_epsilon |= V_028758_8BIT_FORMAT_0_5 << (mrt_index * 4);
}
break;
case V_028C70_COLOR_16:
case V_028C70_COLOR_16_16:
/* For 1-channel formats, use the superset thereof. */
if (export_format_is_fp16 || export_format_is_int16 || export_format_is_norm16) {
if (cb_swap == V_028C70_SWAP_STD || cb_swap == V_028C70_SWAP_STD_REV)
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_16_16_GR << (mrt_index * 4);
else
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_16_16_AR << (mrt_index * 4);
}
break;
case V_028C70_COLOR_32:
if (cb_swap == V_028C70_SWAP_STD && spi_format == V_028714_SPI_SHADER_32_R)
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_32_R << (mrt_index * 4);
else if (cb_swap == V_028C70_SWAP_ALT_REV && spi_format == V_028714_SPI_SHADER_32_AR)
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_32_A << (mrt_index * 4);
break;
case V_028C70_COLOR_5_6_5:
if (export_format_is_fp16) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_5_6_5 << (mrt_index * 4);
*sx_blend_opt_epsilon |= V_028758_6BIT_FORMAT_0_5 << (mrt_index * 4);
}
break;
case V_028C70_COLOR_1_5_5_5:
case V_028C70_COLOR_5_5_5_1:
if (export_format_is_fp16) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_1_5_5_5 << (mrt_index * 4);
*sx_blend_opt_epsilon |= V_028758_5BIT_FORMAT_0_5 << (mrt_index * 4);
}
break;
case V_028C70_COLOR_4_4_4_4:
if (export_format_is_fp16) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_4_4_4_4 << (mrt_index * 4);
*sx_blend_opt_epsilon |= V_028758_4BIT_FORMAT_0_5 << (mrt_index * 4);
}
break;
case V_028C70_COLOR_10_11_11:
case V_028C70_COLOR_11_11_10:
if (export_format_is_fp16)
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_10_11_11 << (mrt_index * 4);
break;
case V_028C70_COLOR_2_10_10_10:
case V_028C70_COLOR_10_10_10_2:
if (export_format_is_fp16 || export_format_is_int16) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_2_10_10_10 << (mrt_index * 4);
*sx_blend_opt_epsilon |= V_028758_10BIT_FORMAT_0_5 << (mrt_index * 4);
}
break;
case V_028C70_COLOR_5_9_9_9:
/* This only executes on GFX10.3+. */
assert(gfx_level >= GFX10_3);
if (export_format_is_fp16) {
if (gfx_level >= GFX12) {
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_9_9_9_E5 << (mrt_index * 4);
} else {
/* GFX10.3-11 have a bug where R9G9B9E5 is broken with RB+ when the color mask is neither
* full nor empty.
*
* If A is missing in the color mask, add it. If it's the only bit set, remove it.
*/
if (fix_cb_target_mask) {
if (colormask == PIPE_MASK_RGB) {
colormask |= PIPE_MASK_A;
*fix_cb_target_mask |= PIPE_MASK_A << (mrt_index * 4);
} else if (colormask == PIPE_MASK_A) {
colormask = 0;
*fix_cb_target_mask &= ~(PIPE_MASK_A << (mrt_index * 4));
}
}
/* Don't enable RB+ if the color mask is not full or empty, which is done by not
* setting SX_PS_DOWNCONVERT for that MRT. Even if the color mask is 0, we should
* still set a non-zero export format to make sure the pixels are discarded quickly.
*/
if (colormask == PIPE_MASK_RGBA || colormask == 0)
*sx_ps_downconvert |= V_028754_SX_RT_EXPORT_9_9_9_E5 << (mrt_index * 4);
}
}
break;
}
}