diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2015-11-22 02:46:45 +0000 |
commit | 0784c49c0f8fcc8b3abd4c9286d9fd8bc089dd7d (patch) | |
tree | a6394e3e264a0f80b57f4ce0f5d9526aa543d4b0 /lib/mesa/src/gallium/drivers/r300/r300_texture.c | |
parent | d91d0007eecf589ea5699e34aa4d748fce2c57b2 (diff) |
import Mesa 11.0.6
Diffstat (limited to 'lib/mesa/src/gallium/drivers/r300/r300_texture.c')
-rw-r--r-- | lib/mesa/src/gallium/drivers/r300/r300_texture.c | 1237 |
1 files changed, 1237 insertions, 0 deletions
diff --git a/lib/mesa/src/gallium/drivers/r300/r300_texture.c b/lib/mesa/src/gallium/drivers/r300/r300_texture.c new file mode 100644 index 000000000..5e4d50df2 --- /dev/null +++ b/lib/mesa/src/gallium/drivers/r300/r300_texture.c @@ -0,0 +1,1237 @@ +/* + * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com> + * Copyright 2010 Marek Olšák <maraeo@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Always include headers in the reverse order!! ~ M. */ +#include "r300_texture.h" + +#include "r300_context.h" +#include "r300_reg.h" +#include "r300_texture_desc.h" +#include "r300_transfer.h" +#include "r300_screen.h" + +#include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_mm.h" + +#include "pipe/p_screen.h" + +unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, + const unsigned char *swizzle_view, + boolean dxtc_swizzle) +{ + unsigned i; + unsigned char swizzle[4]; + unsigned result = 0; + const uint32_t swizzle_shift[4] = { + R300_TX_FORMAT_R_SHIFT, + R300_TX_FORMAT_G_SHIFT, + R300_TX_FORMAT_B_SHIFT, + R300_TX_FORMAT_A_SHIFT + }; + uint32_t swizzle_bit[4] = { + dxtc_swizzle ? R300_TX_FORMAT_Z : R300_TX_FORMAT_X, + R300_TX_FORMAT_Y, + dxtc_swizzle ? R300_TX_FORMAT_X : R300_TX_FORMAT_Z, + R300_TX_FORMAT_W + }; + + if (swizzle_view) { + /* Combine two sets of swizzles. */ + util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); + } else { + memcpy(swizzle, swizzle_format, 4); + } + + /* Get swizzle. */ + for (i = 0; i < 4; i++) { + switch (swizzle[i]) { + case UTIL_FORMAT_SWIZZLE_Y: + result |= swizzle_bit[1] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_Z: + result |= swizzle_bit[2] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_W: + result |= swizzle_bit[3] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_0: + result |= R300_TX_FORMAT_ZERO << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_1: + result |= R300_TX_FORMAT_ONE << swizzle_shift[i]; + break; + default: /* UTIL_FORMAT_SWIZZLE_X */ + result |= swizzle_bit[0] << swizzle_shift[i]; + } + } + return result; +} + +/* Translate a pipe_format into a useful texture format for sampling. + * + * Some special formats are translated directly using R300_EASY_TX_FORMAT, + * but the majority of them is translated in a generic way, automatically + * supporting all the formats hw can support. + * + * R300_EASY_TX_FORMAT swizzles the texture. + * Note the signature of R300_EASY_TX_FORMAT: + * R300_EASY_TX_FORMAT(B, G, R, A, FORMAT); + * + * The FORMAT specifies how the texture sampler will treat the texture, and + * makes available X, Y, Z, W, ZERO, and ONE for swizzling. */ +uint32_t r300_translate_texformat(enum pipe_format format, + const unsigned char *swizzle_view, + boolean is_r500, + boolean dxtc_swizzle) +{ + uint32_t result = 0; + const struct util_format_description *desc; + unsigned i; + boolean uniform = TRUE; + const uint32_t sign_bit[4] = { + R300_TX_FORMAT_SIGNED_W, + R300_TX_FORMAT_SIGNED_Z, + R300_TX_FORMAT_SIGNED_Y, + R300_TX_FORMAT_SIGNED_X, + }; + + desc = util_format_description(format); + + /* Colorspace (return non-RGB formats directly). */ + switch (desc->colorspace) { + /* Depth stencil formats. + * Swizzles are added in r300_merge_textures_and_samplers. */ + case UTIL_FORMAT_COLORSPACE_ZS: + switch (format) { + case PIPE_FORMAT_Z16_UNORM: + return R300_TX_FORMAT_X16; + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_UINT_Z24_UNORM: + if (is_r500) + return R500_TX_FORMAT_Y8X24; + else + return R300_TX_FORMAT_Y16X16; + default: + return ~0; /* Unsupported. */ + } + + /* YUV formats. */ + case UTIL_FORMAT_COLORSPACE_YUV: + result |= R300_TX_FORMAT_YUV_TO_RGB; + + switch (format) { + case PIPE_FORMAT_UYVY: + return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result; + case PIPE_FORMAT_YUYV: + return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result; + default: + return ~0; /* Unsupported/unknown. */ + } + + /* Add gamma correction. */ + case UTIL_FORMAT_COLORSPACE_SRGB: + result |= R300_TX_FORMAT_GAMMA; + break; + + default: + switch (format) { + /* Same as YUV but without the YUR->RGB conversion. */ + case PIPE_FORMAT_R8G8_B8G8_UNORM: + return R300_EASY_TX_FORMAT(X, Y, Z, ONE, YVYU422) | result; + case PIPE_FORMAT_G8R8_G8B8_UNORM: + return R300_EASY_TX_FORMAT(X, Y, Z, ONE, VYUY422) | result; + default:; + } + } + + /* Add swizzling. */ + /* The RGTC1_SNORM and LATC1_SNORM swizzle is done in the shader. */ + if (util_format_is_compressed(format) && + dxtc_swizzle && + format != PIPE_FORMAT_RGTC2_UNORM && + format != PIPE_FORMAT_RGTC2_SNORM && + format != PIPE_FORMAT_LATC2_UNORM && + format != PIPE_FORMAT_LATC2_SNORM && + format != PIPE_FORMAT_RGTC1_UNORM && + format != PIPE_FORMAT_RGTC1_SNORM && + format != PIPE_FORMAT_LATC1_UNORM && + format != PIPE_FORMAT_LATC1_SNORM) { + result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view, + TRUE); + } else { + result |= r300_get_swizzle_combined(desc->swizzle, swizzle_view, + FALSE); + } + + /* S3TC formats. */ + if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { + if (!util_format_s3tc_enabled) { + return ~0; /* Unsupported. */ + } + + switch (format) { + case PIPE_FORMAT_DXT1_RGB: + case PIPE_FORMAT_DXT1_RGBA: + case PIPE_FORMAT_DXT1_SRGB: + case PIPE_FORMAT_DXT1_SRGBA: + return R300_TX_FORMAT_DXT1 | result; + case PIPE_FORMAT_DXT3_RGBA: + case PIPE_FORMAT_DXT3_SRGBA: + return R300_TX_FORMAT_DXT3 | result; + case PIPE_FORMAT_DXT5_RGBA: + case PIPE_FORMAT_DXT5_SRGBA: + return R300_TX_FORMAT_DXT5 | result; + default: + return ~0; /* Unsupported/unknown. */ + } + } + + /* RGTC formats. */ + if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) { + switch (format) { + case PIPE_FORMAT_RGTC1_SNORM: + case PIPE_FORMAT_LATC1_SNORM: + result |= sign_bit[0]; + case PIPE_FORMAT_LATC1_UNORM: + case PIPE_FORMAT_RGTC1_UNORM: + return R500_TX_FORMAT_ATI1N | result; + + case PIPE_FORMAT_RGTC2_SNORM: + case PIPE_FORMAT_LATC2_SNORM: + result |= sign_bit[1] | sign_bit[0]; + case PIPE_FORMAT_RGTC2_UNORM: + case PIPE_FORMAT_LATC2_UNORM: + return R400_TX_FORMAT_ATI2N | result; + + default: + return ~0; /* Unsupported/unknown. */ + } + } + + /* This is truly a special format. + * It stores R8G8 and B is computed using sqrt(1 - R^2 - G^2) + * in the sampler unit. Also known as D3DFMT_CxV8U8. */ + if (format == PIPE_FORMAT_R8G8Bx_SNORM) { + return R300_TX_FORMAT_CxV8U8 | result; + } + + /* Integer and fixed-point 16.16 textures are not supported. */ + for (i = 0; i < 4; i++) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_FIXED || + ((desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED || + desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) && + (!desc->channel[i].normalized || + desc->channel[i].pure_integer))) { + return ~0; /* Unsupported/unknown. */ + } + } + + /* Add sign. */ + for (i = 0; i < desc->nr_channels; i++) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { + result |= sign_bit[i]; + } + } + + /* 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 R300_TX_FORMAT_Z5Y6X5 | result; + } + if (desc->channel[0].size == 5 && + desc->channel[1].size == 5 && + desc->channel[2].size == 6) { + return R300_TX_FORMAT_Z6Y5X5 | result; + } + if (desc->channel[0].size == 2 && + desc->channel[1].size == 3 && + desc->channel[2].size == 3) { + return R300_TX_FORMAT_Z3Y3X2 | result; + } + return ~0; /* Unsupported/unknown. */ + + case 4: + if (desc->channel[0].size == 5 && + desc->channel[1].size == 5 && + desc->channel[2].size == 5 && + desc->channel[3].size == 1) { + return R300_TX_FORMAT_W1Z5Y5X5 | result; + } + if (desc->channel[0].size == 10 && + desc->channel[1].size == 10 && + desc->channel[2].size == 10 && + desc->channel[3].size == 2) { + return R300_TX_FORMAT_W2Z10Y10X10 | result; + } + } + return ~0; /* Unsupported/unknown. */ + } + + /* Find the first non-VOID channel. */ + for (i = 0; i < 4; i++) { + if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { + break; + } + } + + if (i == 4) + return ~0; /* Unsupported/unknown. */ + + /* And finally, uniform formats. */ + switch (desc->channel[i].type) { + case UTIL_FORMAT_TYPE_UNSIGNED: + case UTIL_FORMAT_TYPE_SIGNED: + if (!desc->channel[i].normalized && + desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { + return ~0; + } + + switch (desc->channel[i].size) { + case 4: + switch (desc->nr_channels) { + case 2: + return R300_TX_FORMAT_Y4X4 | result; + case 4: + return R300_TX_FORMAT_W4Z4Y4X4 | result; + } + return ~0; + + case 8: + switch (desc->nr_channels) { + case 1: + return R300_TX_FORMAT_X8 | result; + case 2: + return R300_TX_FORMAT_Y8X8 | result; + case 4: + return R300_TX_FORMAT_W8Z8Y8X8 | result; + } + return ~0; + + case 16: + switch (desc->nr_channels) { + case 1: + return R300_TX_FORMAT_X16 | result; + case 2: + return R300_TX_FORMAT_Y16X16 | result; + case 4: + return R300_TX_FORMAT_W16Z16Y16X16 | result; + } + } + return ~0; + + case UTIL_FORMAT_TYPE_FLOAT: + switch (desc->channel[i].size) { + case 16: + switch (desc->nr_channels) { + case 1: + return R300_TX_FORMAT_16F | result; + case 2: + return R300_TX_FORMAT_16F_16F | result; + case 4: + return R300_TX_FORMAT_16F_16F_16F_16F | result; + } + return ~0; + + case 32: + switch (desc->nr_channels) { + case 1: + return R300_TX_FORMAT_32F | result; + case 2: + return R300_TX_FORMAT_32F_32F | result; + case 4: + return R300_TX_FORMAT_32F_32F_32F_32F | result; + } + } + } + + return ~0; /* Unsupported/unknown. */ +} + +uint32_t r500_tx_format_msb_bit(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_RGTC1_UNORM: + case PIPE_FORMAT_RGTC1_SNORM: + case PIPE_FORMAT_LATC1_UNORM: + case PIPE_FORMAT_LATC1_SNORM: + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_UINT_Z24_UNORM: + return R500_TXFORMAT_MSB; + default: + return 0; + } +} + +/* Buffer formats. */ + +/* Colorbuffer formats. This is the unswizzled format of the RB3D block's + * output. For the swizzling of the targets, check the shader's format. */ +static uint32_t r300_translate_colorformat(enum pipe_format format) +{ + switch (format) { + /* 8-bit buffers. */ + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_A8_SNORM: + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_I8_SNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SNORM: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return R300_COLOR_FORMAT_I8; + + /* 16-bit buffers. */ + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SNORM: + case PIPE_FORMAT_R8G8_UNORM: + case PIPE_FORMAT_R8G8_SNORM: + case PIPE_FORMAT_R8A8_UNORM: + case PIPE_FORMAT_R8A8_SNORM: + /* These formats work fine with UV88 if US_OUT_FMT is set correctly. */ + case PIPE_FORMAT_A16_UNORM: + case PIPE_FORMAT_A16_SNORM: + case PIPE_FORMAT_A16_FLOAT: + case PIPE_FORMAT_L16_UNORM: + case PIPE_FORMAT_L16_SNORM: + case PIPE_FORMAT_L16_FLOAT: + case PIPE_FORMAT_I16_UNORM: + case PIPE_FORMAT_I16_SNORM: + case PIPE_FORMAT_I16_FLOAT: + case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16_SNORM: + case PIPE_FORMAT_R16_FLOAT: + return R300_COLOR_FORMAT_UV88; + + case PIPE_FORMAT_B5G6R5_UNORM: + return R300_COLOR_FORMAT_RGB565; + + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + return R300_COLOR_FORMAT_ARGB1555; + + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + return R300_COLOR_FORMAT_ARGB4444; + + /* 32-bit buffers. */ + case PIPE_FORMAT_B8G8R8A8_UNORM: + /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/ + case PIPE_FORMAT_B8G8R8X8_UNORM: + /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/ + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_R8G8B8X8_SNORM: + /* These formats work fine with ARGB8888 if US_OUT_FMT is set + * correctly. */ + case PIPE_FORMAT_R16G16_UNORM: + case PIPE_FORMAT_R16G16_SNORM: + case PIPE_FORMAT_R16G16_FLOAT: + case PIPE_FORMAT_L16A16_UNORM: + case PIPE_FORMAT_L16A16_SNORM: + case PIPE_FORMAT_L16A16_FLOAT: + case PIPE_FORMAT_R16A16_UNORM: + case PIPE_FORMAT_R16A16_SNORM: + case PIPE_FORMAT_R16A16_FLOAT: + case PIPE_FORMAT_A32_FLOAT: + case PIPE_FORMAT_L32_FLOAT: + case PIPE_FORMAT_I32_FLOAT: + case PIPE_FORMAT_R32_FLOAT: + return R300_COLOR_FORMAT_ARGB8888; + + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_B10G10R10A2_UNORM: + case PIPE_FORMAT_B10G10R10X2_UNORM: + return R500_COLOR_FORMAT_ARGB2101010; /* R5xx-only? */ + + /* 64-bit buffers. */ + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + case PIPE_FORMAT_R16G16B16X16_UNORM: + case PIPE_FORMAT_R16G16B16X16_SNORM: + case PIPE_FORMAT_R16G16B16X16_FLOAT: + /* These formats work fine with ARGB16161616 if US_OUT_FMT is set + * correctly. */ + case PIPE_FORMAT_R32G32_FLOAT: + case PIPE_FORMAT_L32A32_FLOAT: + case PIPE_FORMAT_R32A32_FLOAT: + return R300_COLOR_FORMAT_ARGB16161616; + + /* 128-bit buffers. */ + case PIPE_FORMAT_R32G32B32A32_FLOAT: + case PIPE_FORMAT_R32G32B32X32_FLOAT: + return R300_COLOR_FORMAT_ARGB32323232; + + /* YUV buffers. */ + case PIPE_FORMAT_UYVY: + return R300_COLOR_FORMAT_YVYU; + case PIPE_FORMAT_YUYV: + return R300_COLOR_FORMAT_VYUY; + default: + return ~0; /* Unsupported. */ + } +} + +/* Depthbuffer and stencilbuffer. Thankfully, we only support two flavors. */ +static uint32_t r300_translate_zsformat(enum pipe_format format) +{ + switch (format) { + /* 16-bit depth, no stencil */ + case PIPE_FORMAT_Z16_UNORM: + return R300_DEPTHFORMAT_16BIT_INT_Z; + /* 24-bit depth, ignored stencil */ + case PIPE_FORMAT_X8Z24_UNORM: + /* 24-bit depth, 8-bit stencil */ + case PIPE_FORMAT_S8_UINT_Z24_UNORM: + return R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL; + default: + return ~0; /* Unsupported. */ + } +} + +/* Shader output formats. This is essentially the swizzle from the shader + * to the RB3D block. + * + * Note that formats are stored from C3 to C0. */ +static uint32_t r300_translate_out_fmt(enum pipe_format format) +{ + uint32_t modifier = 0; + unsigned i; + const struct util_format_description *desc; + boolean uniform_sign; + + desc = util_format_description(format); + + /* Find the first non-VOID channel. */ + for (i = 0; i < 4; i++) { + if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { + break; + } + } + + if (i == 4) + return ~0; /* Unsupported/unknown. */ + + /* Specifies how the shader output is written to the fog unit. */ + switch (desc->channel[i].type) { + case UTIL_FORMAT_TYPE_FLOAT: + switch (desc->channel[i].size) { + case 32: + switch (desc->nr_channels) { + case 1: + modifier |= R300_US_OUT_FMT_C_32_FP; + break; + case 2: + modifier |= R300_US_OUT_FMT_C2_32_FP; + break; + case 4: + modifier |= R300_US_OUT_FMT_C4_32_FP; + break; + } + break; + + case 16: + switch (desc->nr_channels) { + case 1: + modifier |= R300_US_OUT_FMT_C_16_FP; + break; + case 2: + modifier |= R300_US_OUT_FMT_C2_16_FP; + break; + case 4: + modifier |= R300_US_OUT_FMT_C4_16_FP; + break; + } + break; + } + break; + + default: + switch (desc->channel[i].size) { + case 16: + switch (desc->nr_channels) { + case 1: + modifier |= R300_US_OUT_FMT_C_16; + break; + case 2: + modifier |= R300_US_OUT_FMT_C2_16; + break; + case 4: + modifier |= R300_US_OUT_FMT_C4_16; + break; + } + break; + + case 10: + modifier |= R300_US_OUT_FMT_C4_10; + break; + + default: + /* C4_8 seems to be used for the formats whose pixel size + * is <= 32 bits. */ + modifier |= R300_US_OUT_FMT_C4_8; + break; + } + } + + /* Add sign. */ + uniform_sign = TRUE; + for (i = 0; i < desc->nr_channels; i++) + if (desc->channel[i].type != UTIL_FORMAT_TYPE_SIGNED) + uniform_sign = FALSE; + + if (uniform_sign) + modifier |= R300_OUT_SIGN(0xf); + + /* Add swizzles and return. */ + switch (format) { + /*** Special cases (non-standard channel mapping) ***/ + + /* X8 + * COLORFORMAT_I8 stores the Z component (C2). */ + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_A8_SNORM: + return modifier | R300_C2_SEL_A; + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_I8_SNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SNORM: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return modifier | R300_C2_SEL_R; + + /* X8Y8 + * COLORFORMAT_UV88 stores ZX (C2 and C0). */ + case PIPE_FORMAT_L8A8_SNORM: + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_R8A8_SNORM: + case PIPE_FORMAT_R8A8_UNORM: + return modifier | R300_C0_SEL_A | R300_C2_SEL_R; + case PIPE_FORMAT_R8G8_SNORM: + case PIPE_FORMAT_R8G8_UNORM: + return modifier | R300_C0_SEL_G | R300_C2_SEL_R; + + /* X32Y32 + * ARGB16161616 stores XZ for RG32F */ + case PIPE_FORMAT_R32G32_FLOAT: + return modifier | R300_C0_SEL_R | R300_C2_SEL_G; + + /*** Generic cases (standard channel mapping) ***/ + + /* BGRA outputs. */ + case PIPE_FORMAT_B5G6R5_UNORM: + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + case PIPE_FORMAT_B8G8R8A8_UNORM: + /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/ + case PIPE_FORMAT_B8G8R8X8_UNORM: + /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/ + case PIPE_FORMAT_B10G10R10A2_UNORM: + case PIPE_FORMAT_B10G10R10X2_UNORM: + return modifier | + R300_C0_SEL_B | R300_C1_SEL_G | + R300_C2_SEL_R | R300_C3_SEL_A; + + /* ARGB outputs. */ + case PIPE_FORMAT_A16_UNORM: + case PIPE_FORMAT_A16_SNORM: + case PIPE_FORMAT_A16_FLOAT: + case PIPE_FORMAT_A32_FLOAT: + return modifier | + R300_C0_SEL_A | R300_C1_SEL_R | + R300_C2_SEL_G | R300_C3_SEL_B; + + /* RGBA outputs. */ + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_R8G8B8X8_SNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16G16_UNORM: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16_SNORM: + case PIPE_FORMAT_R16G16_SNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + case PIPE_FORMAT_R16_FLOAT: + case PIPE_FORMAT_R16G16_FLOAT: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + case PIPE_FORMAT_R32_FLOAT: + case PIPE_FORMAT_R32G32B32A32_FLOAT: + case PIPE_FORMAT_R32G32B32X32_FLOAT: + case PIPE_FORMAT_L16_UNORM: + case PIPE_FORMAT_L16_SNORM: + case PIPE_FORMAT_L16_FLOAT: + case PIPE_FORMAT_L32_FLOAT: + case PIPE_FORMAT_I16_UNORM: + case PIPE_FORMAT_I16_SNORM: + case PIPE_FORMAT_I16_FLOAT: + case PIPE_FORMAT_I32_FLOAT: + case PIPE_FORMAT_R16G16B16X16_UNORM: + case PIPE_FORMAT_R16G16B16X16_SNORM: + case PIPE_FORMAT_R16G16B16X16_FLOAT: + return modifier | + R300_C0_SEL_R | R300_C1_SEL_G | + R300_C2_SEL_B | R300_C3_SEL_A; + + /* LA outputs. */ + case PIPE_FORMAT_L16A16_UNORM: + case PIPE_FORMAT_L16A16_SNORM: + case PIPE_FORMAT_L16A16_FLOAT: + case PIPE_FORMAT_R16A16_UNORM: + case PIPE_FORMAT_R16A16_SNORM: + case PIPE_FORMAT_R16A16_FLOAT: + case PIPE_FORMAT_L32A32_FLOAT: + case PIPE_FORMAT_R32A32_FLOAT: + return modifier | + R300_C0_SEL_R | R300_C1_SEL_A; + + default: + return ~0; /* Unsupported. */ + } +} + +static uint32_t r300_translate_colormask_swizzle(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_A8_SNORM: + case PIPE_FORMAT_A16_UNORM: + case PIPE_FORMAT_A16_SNORM: + case PIPE_FORMAT_A16_FLOAT: + case PIPE_FORMAT_A32_FLOAT: + return COLORMASK_AAAA; + + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_I8_SNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SNORM: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + case PIPE_FORMAT_R32_FLOAT: + case PIPE_FORMAT_L32_FLOAT: + case PIPE_FORMAT_I32_FLOAT: + return COLORMASK_RRRR; + + case PIPE_FORMAT_L8A8_SNORM: + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_R8A8_UNORM: + case PIPE_FORMAT_R8A8_SNORM: + case PIPE_FORMAT_L16A16_UNORM: + case PIPE_FORMAT_L16A16_SNORM: + case PIPE_FORMAT_L16A16_FLOAT: + case PIPE_FORMAT_R16A16_UNORM: + case PIPE_FORMAT_R16A16_SNORM: + case PIPE_FORMAT_R16A16_FLOAT: + case PIPE_FORMAT_L32A32_FLOAT: + case PIPE_FORMAT_R32A32_FLOAT: + return COLORMASK_ARRA; + + case PIPE_FORMAT_R8G8_SNORM: + case PIPE_FORMAT_R8G8_UNORM: + case PIPE_FORMAT_R16G16_UNORM: + case PIPE_FORMAT_R16G16_SNORM: + case PIPE_FORMAT_R16G16_FLOAT: + case PIPE_FORMAT_R32G32_FLOAT: + return COLORMASK_GRRG; + + case PIPE_FORMAT_B5G5R5X1_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/ + case PIPE_FORMAT_B10G10R10X2_UNORM: + return COLORMASK_BGRX; + + case PIPE_FORMAT_B5G6R5_UNORM: + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B8G8R8A8_UNORM: + /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/ + case PIPE_FORMAT_B10G10R10A2_UNORM: + return COLORMASK_BGRA; + + case PIPE_FORMAT_R8G8B8X8_UNORM: + /* RGBX_SNORM formats are broken for an unknown reason */ + /*case PIPE_FORMAT_R8G8B8X8_SNORM:*/ + /*case PIPE_FORMAT_R10G10B10X2_SNORM:*/ + case PIPE_FORMAT_R16G16B16X16_UNORM: + /*case PIPE_FORMAT_R16G16B16X16_SNORM:*/ + case PIPE_FORMAT_R16G16B16X16_FLOAT: + case PIPE_FORMAT_R32G32B32X32_FLOAT: + return COLORMASK_RGBX; + + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16_SNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + case PIPE_FORMAT_R16_FLOAT: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + case PIPE_FORMAT_R32G32B32A32_FLOAT: + case PIPE_FORMAT_L16_UNORM: + case PIPE_FORMAT_L16_SNORM: + case PIPE_FORMAT_L16_FLOAT: + case PIPE_FORMAT_I16_UNORM: + case PIPE_FORMAT_I16_SNORM: + case PIPE_FORMAT_I16_FLOAT: + return COLORMASK_RGBA; + + default: + return ~0; /* Unsupported. */ + } +} + +boolean r300_is_colorbuffer_format_supported(enum pipe_format format) +{ + return r300_translate_colorformat(format) != ~0 && + r300_translate_out_fmt(format) != ~0 && + r300_translate_colormask_swizzle(format) != ~0; +} + +boolean r300_is_zs_format_supported(enum pipe_format format) +{ + return r300_translate_zsformat(format) != ~0; +} + +boolean r300_is_sampler_format_supported(enum pipe_format format) +{ + return r300_translate_texformat(format, 0, TRUE, FALSE) != ~0; +} + +void r300_texture_setup_format_state(struct r300_screen *screen, + struct r300_resource *tex, + enum pipe_format format, + unsigned level, + unsigned width0_override, + unsigned height0_override, + struct r300_texture_format_state *out) +{ + struct pipe_resource *pt = &tex->b.b; + struct r300_texture_desc *desc = &tex->tex; + boolean is_r500 = screen->caps.is_r500; + unsigned width, height, depth; + unsigned txwidth, txheight, txdepth; + + width = u_minify(width0_override, level); + height = u_minify(height0_override, level); + depth = u_minify(desc->depth0, level); + + txwidth = (width - 1) & 0x7ff; + txheight = (height - 1) & 0x7ff; + txdepth = util_logbase2(depth) & 0xf; + + /* Mask out all the fields we change. */ + out->format0 = 0; + out->format1 &= ~R300_TX_FORMAT_TEX_COORD_TYPE_MASK; + out->format2 &= R500_TXFORMAT_MSB; + out->tile_config = 0; + + /* Set sampler state. */ + out->format0 = + R300_TX_WIDTH(txwidth) | + R300_TX_HEIGHT(txheight) | + R300_TX_DEPTH(txdepth); + + if (desc->uses_stride_addressing) { + unsigned stride = + r300_stride_to_width(format, desc->stride_in_bytes[level]); + /* rectangles love this */ + out->format0 |= R300_TX_PITCH_EN; + out->format2 = (stride - 1) & 0x1fff; + } + + if (pt->target == PIPE_TEXTURE_CUBE) { + out->format1 |= R300_TX_FORMAT_CUBIC_MAP; + } + if (pt->target == PIPE_TEXTURE_3D) { + out->format1 |= R300_TX_FORMAT_3D; + } + + /* large textures on r500 */ + if (is_r500) + { + unsigned us_width = txwidth; + unsigned us_height = txheight; + unsigned us_depth = txdepth; + + if (width > 2048) { + out->format2 |= R500_TXWIDTH_BIT11; + } + if (height > 2048) { + out->format2 |= R500_TXHEIGHT_BIT11; + } + + /* The US_FORMAT register fixes an R500 TX addressing bug. + * Don't ask why it must be set like this. I don't know it either. */ + if (width > 2048) { + us_width = (0x000007FF + us_width) >> 1; + us_depth |= 0x0000000D; + } + if (height > 2048) { + us_height = (0x000007FF + us_height) >> 1; + us_depth |= 0x0000000E; + } + + out->us_format0 = + R300_TX_WIDTH(us_width) | + R300_TX_HEIGHT(us_height) | + R300_TX_DEPTH(us_depth); + } + + out->tile_config = R300_TXO_MACRO_TILE(desc->macrotile[level]) | + R300_TXO_MICRO_TILE(desc->microtile); +} + +static void r300_texture_setup_fb_state(struct r300_surface *surf) +{ + struct r300_resource *tex = r300_resource(surf->base.texture); + unsigned level = surf->base.u.tex.level; + unsigned stride = + r300_stride_to_width(surf->base.format, tex->tex.stride_in_bytes[level]); + + /* Set framebuffer state. */ + if (util_format_is_depth_or_stencil(surf->base.format)) { + surf->pitch = + stride | + R300_DEPTHMACROTILE(tex->tex.macrotile[level]) | + R300_DEPTHMICROTILE(tex->tex.microtile); + surf->format = r300_translate_zsformat(surf->base.format); + surf->pitch_zmask = tex->tex.zmask_stride_in_pixels[level]; + surf->pitch_hiz = tex->tex.hiz_stride_in_pixels[level]; + } else { + enum pipe_format format = util_format_linear(surf->base.format); + + surf->pitch = + stride | + r300_translate_colorformat(format) | + R300_COLOR_TILE(tex->tex.macrotile[level]) | + R300_COLOR_MICROTILE(tex->tex.microtile); + surf->format = r300_translate_out_fmt(format); + surf->colormask_swizzle = + r300_translate_colormask_swizzle(format); + surf->pitch_cmask = tex->tex.cmask_stride_in_pixels; + } +} + +static void r300_texture_destroy(struct pipe_screen *screen, + struct pipe_resource* texture) +{ + struct r300_screen *rscreen = r300_screen(screen); + struct r300_resource* tex = (struct r300_resource*)texture; + + if (tex->tex.cmask_dwords) { + pipe_mutex_lock(rscreen->cmask_mutex); + if (texture == rscreen->cmask_resource) { + rscreen->cmask_resource = NULL; + } + pipe_mutex_unlock(rscreen->cmask_mutex); + } + pb_reference(&tex->buf, NULL); + FREE(tex); +} + +boolean r300_resource_get_handle(struct pipe_screen* screen, + struct pipe_resource *texture, + struct winsys_handle *whandle) +{ + struct radeon_winsys *rws = r300_screen(screen)->rws; + struct r300_resource* tex = (struct r300_resource*)texture; + + if (!tex) { + return FALSE; + } + + return rws->buffer_get_handle(tex->buf, + tex->tex.stride_in_bytes[0], whandle); +} + +static const struct u_resource_vtbl r300_texture_vtbl = +{ + NULL, /* get_handle */ + r300_texture_destroy, /* resource_destroy */ + r300_texture_transfer_map, /* transfer_map */ + NULL, /* transfer_flush_region */ + r300_texture_transfer_unmap, /* transfer_unmap */ + NULL /* transfer_inline_write */ +}; + +/* The common texture constructor. */ +static struct r300_resource* +r300_texture_create_object(struct r300_screen *rscreen, + const struct pipe_resource *base, + enum radeon_bo_layout microtile, + enum radeon_bo_layout macrotile, + unsigned stride_in_bytes_override, + struct pb_buffer *buffer) +{ + struct radeon_winsys *rws = rscreen->rws; + struct r300_resource *tex = NULL; + + tex = CALLOC_STRUCT(r300_resource); + if (!tex) { + goto fail; + } + + pipe_reference_init(&tex->b.b.reference, 1); + tex->b.b.screen = &rscreen->screen; + tex->b.b.usage = base->usage; + tex->b.b.bind = base->bind; + tex->b.b.flags = base->flags; + tex->b.vtbl = &r300_texture_vtbl; + tex->tex.microtile = microtile; + tex->tex.macrotile[0] = macrotile; + tex->tex.stride_in_bytes_override = stride_in_bytes_override; + tex->domain = (base->flags & R300_RESOURCE_FLAG_TRANSFER || + base->usage == PIPE_USAGE_STAGING) ? RADEON_DOMAIN_GTT : + base->nr_samples > 1 ? RADEON_DOMAIN_VRAM : + RADEON_DOMAIN_VRAM | RADEON_DOMAIN_GTT; + tex->buf = buffer; + + r300_texture_desc_init(rscreen, tex, base); + + /* Figure out the ideal placement for the texture.. */ + if (tex->domain & RADEON_DOMAIN_VRAM && + tex->tex.size_in_bytes >= rscreen->info.vram_size) { + tex->domain &= ~RADEON_DOMAIN_VRAM; + tex->domain |= RADEON_DOMAIN_GTT; + } + if (tex->domain & RADEON_DOMAIN_GTT && + tex->tex.size_in_bytes >= rscreen->info.gart_size) { + tex->domain &= ~RADEON_DOMAIN_GTT; + } + /* Just fail if the texture is too large. */ + if (!tex->domain) { + goto fail; + } + + /* Create the backing buffer if needed. */ + if (!tex->buf) { + tex->buf = rws->buffer_create(rws, tex->tex.size_in_bytes, 2048, TRUE, + tex->domain, 0); + + if (!tex->buf) { + goto fail; + } + } + + if (SCREEN_DBG_ON(rscreen, DBG_MSAA) && base->nr_samples > 1) { + fprintf(stderr, "r300: %ix MSAA %s buffer created\n", + base->nr_samples, + util_format_is_depth_or_stencil(base->format) ? "depth" : "color"); + } + + tex->cs_buf = rws->buffer_get_cs_handle(tex->buf); + + rws->buffer_set_tiling(tex->buf, NULL, + tex->tex.microtile, tex->tex.macrotile[0], + 0, 0, 0, 0, 0, 0, 0, + tex->tex.stride_in_bytes[0], false); + + return tex; + +fail: + FREE(tex); + if (buffer) + pb_reference(&buffer, NULL); + return NULL; +} + +/* Create a new texture. */ +struct pipe_resource *r300_texture_create(struct pipe_screen *screen, + const struct pipe_resource *base) +{ + struct r300_screen *rscreen = r300_screen(screen); + enum radeon_bo_layout microtile, macrotile; + + if ((base->flags & R300_RESOURCE_FLAG_TRANSFER) || + (base->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR))) { + microtile = RADEON_LAYOUT_LINEAR; + macrotile = RADEON_LAYOUT_LINEAR; + } else { + /* This will make the texture_create_function select the layout. */ + microtile = RADEON_LAYOUT_UNKNOWN; + macrotile = RADEON_LAYOUT_UNKNOWN; + } + + return (struct pipe_resource*) + r300_texture_create_object(rscreen, base, microtile, macrotile, + 0, NULL); +} + +struct pipe_resource *r300_texture_from_handle(struct pipe_screen *screen, + const struct pipe_resource *base, + struct winsys_handle *whandle) +{ + struct r300_screen *rscreen = r300_screen(screen); + struct radeon_winsys *rws = rscreen->rws; + struct pb_buffer *buffer; + enum radeon_bo_layout microtile, macrotile; + unsigned stride; + + /* Support only 2D textures without mipmaps */ + if ((base->target != PIPE_TEXTURE_2D && + base->target != PIPE_TEXTURE_RECT) || + base->depth0 != 1 || + base->last_level != 0) { + return NULL; + } + + buffer = rws->buffer_from_handle(rws, whandle, &stride); + if (!buffer) + return NULL; + + rws->buffer_get_tiling(buffer, µtile, ¯otile, NULL, NULL, NULL, + NULL, NULL, NULL); + + /* Enforce a microtiled zbuffer. */ + if (util_format_is_depth_or_stencil(base->format) && + microtile == RADEON_LAYOUT_LINEAR) { + switch (util_format_get_blocksize(base->format)) { + case 4: + microtile = RADEON_LAYOUT_TILED; + break; + + case 2: + microtile = RADEON_LAYOUT_SQUARETILED; + break; + } + } + + return (struct pipe_resource*) + r300_texture_create_object(rscreen, base, microtile, macrotile, + stride, buffer); +} + +/* Not required to implement u_resource_vtbl, consider moving to another file: + */ +struct pipe_surface* r300_create_surface_custom(struct pipe_context * ctx, + struct pipe_resource* texture, + const struct pipe_surface *surf_tmpl, + unsigned width0_override, + unsigned height0_override) +{ + struct r300_resource* tex = r300_resource(texture); + struct r300_surface* surface = CALLOC_STRUCT(r300_surface); + unsigned level = surf_tmpl->u.tex.level; + + assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); + + if (surface) { + uint32_t offset, tile_height; + + pipe_reference_init(&surface->base.reference, 1); + pipe_resource_reference(&surface->base.texture, texture); + surface->base.context = ctx; + surface->base.format = surf_tmpl->format; + surface->base.width = u_minify(width0_override, level); + surface->base.height = u_minify(height0_override, level); + surface->base.u.tex.level = level; + surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; + surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; + + surface->buf = tex->buf; + surface->cs_buf = tex->cs_buf; + + /* Prefer VRAM if there are multiple domains to choose from. */ + surface->domain = tex->domain; + if (surface->domain & RADEON_DOMAIN_VRAM) + surface->domain &= ~RADEON_DOMAIN_GTT; + + surface->offset = r300_texture_get_offset(tex, level, + surf_tmpl->u.tex.first_layer); + r300_texture_setup_fb_state(surface); + + /* Parameters for the CBZB clear. */ + surface->cbzb_allowed = tex->tex.cbzb_allowed[level]; + surface->cbzb_width = align(surface->base.width, 64); + + /* Height must be aligned to the size of a tile. */ + tile_height = r300_get_pixel_alignment(surface->base.format, + tex->b.b.nr_samples, + tex->tex.microtile, + tex->tex.macrotile[level], + DIM_HEIGHT, 0); + + surface->cbzb_height = align((surface->base.height + 1) / 2, + tile_height); + + /* Offset must be aligned to 2K and must point at the beginning + * of a scanline. */ + offset = surface->offset + + tex->tex.stride_in_bytes[level] * surface->cbzb_height; + surface->cbzb_midpoint_offset = offset & ~2047; + + surface->cbzb_pitch = surface->pitch & 0x1ffffc; + + if (util_format_get_blocksizebits(surface->base.format) == 32) + surface->cbzb_format = R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL; + else + surface->cbzb_format = R300_DEPTHFORMAT_16BIT_INT_Z; + + DBG(r300_context(ctx), DBG_CBZB, + "CBZB Allowed: %s, Dim: %ix%i, Misalignment: %i, Micro: %s, Macro: %s\n", + surface->cbzb_allowed ? "YES" : " NO", + surface->cbzb_width, surface->cbzb_height, + offset & 2047, + tex->tex.microtile ? "YES" : " NO", + tex->tex.macrotile[level] ? "YES" : " NO"); + } + + return &surface->base; +} + +struct pipe_surface* r300_create_surface(struct pipe_context * ctx, + struct pipe_resource* texture, + const struct pipe_surface *surf_tmpl) +{ + return r300_create_surface_custom(ctx, texture, surf_tmpl, + texture->width0, + texture->height0); +} + +/* Not required to implement u_resource_vtbl, consider moving to another file: + */ +void r300_surface_destroy(struct pipe_context *ctx, struct pipe_surface* s) +{ + pipe_resource_reference(&s->texture, NULL); + FREE(s); +} |