mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-19 00:38:06 +02:00
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39093>
968 lines
33 KiB
C
968 lines
33 KiB
C
/*
|
||
* 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;
|
||
}
|
||
}
|