From 61fea171af64288bdf622e7ecf07e3ca42f83974 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Wed, 13 May 2015 13:10:54 +0800 Subject: [PATCH] ilo: add ilo_state_sampler We want to replace ilo_sampler_cso with ilo_state_sampler. --- src/gallium/drivers/ilo/Makefile.sources | 2 + .../drivers/ilo/core/ilo_state_sampler.c | 742 ++++++++++++++++++ .../drivers/ilo/core/ilo_state_sampler.h | 103 +++ 3 files changed, 847 insertions(+) create mode 100644 src/gallium/drivers/ilo/core/ilo_state_sampler.c create mode 100644 src/gallium/drivers/ilo/core/ilo_state_sampler.h diff --git a/src/gallium/drivers/ilo/Makefile.sources b/src/gallium/drivers/ilo/Makefile.sources index 587850eafdb..3bb3dde0e18 100644 --- a/src/gallium/drivers/ilo/Makefile.sources +++ b/src/gallium/drivers/ilo/Makefile.sources @@ -23,6 +23,8 @@ C_SOURCES := \ core/ilo_state_3d.h \ core/ilo_state_3d_bottom.c \ core/ilo_state_3d_top.c \ + core/ilo_state_sampler.c \ + core/ilo_state_sampler.h \ core/ilo_state_surface.c \ core/ilo_state_surface.h \ core/ilo_state_zs.c \ diff --git a/src/gallium/drivers/ilo/core/ilo_state_sampler.c b/src/gallium/drivers/ilo/core/ilo_state_sampler.c new file mode 100644 index 00000000000..3787f684fe8 --- /dev/null +++ b/src/gallium/drivers/ilo/core/ilo_state_sampler.c @@ -0,0 +1,742 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2012-2015 LunarG, Inc. + * + * 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 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Chia-I Wu + */ + +#include "util/u_half.h" + +#include "ilo_debug.h" +#include "ilo_state_surface.h" +#include "ilo_state_sampler.h" + +static bool +sampler_validate_gen6_non_normalized(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + const enum gen_texcoord_mode addr_ctrls[3] = { + info->tcx_ctrl, info->tcy_ctrl, info->tcz_ctrl, + }; + int i; + + ILO_DEV_ASSERT(dev, 6, 8); + + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 98: + * + * "The following state must be set as indicated if this field + * (Non-normalized Coordinate Enable) is enabled: + * + * - TCX/Y/Z Address Control Mode must be TEXCOORDMODE_CLAMP, + * TEXCOORDMODE_HALF_BORDER, or TEXCOORDMODE_CLAMP_BORDER. + * - Surface Type must be SURFTYPE_2D or SURFTYPE_3D. + * - Mag Mode Filter must be MAPFILTER_NEAREST or + * MAPFILTER_LINEAR. + * - Min Mode Filter must be MAPFILTER_NEAREST or + * MAPFILTER_LINEAR. + * - Mip Mode Filter must be MIPFILTER_NONE. + * - Min LOD must be 0. + * - Max LOD must be 0. + * - MIP Count must be 0. + * - Surface Min LOD must be 0. + * - Texture LOD Bias must be 0." + */ + for (i = 0; i < 3; i++) { + switch (addr_ctrls[i]) { + case GEN6_TEXCOORDMODE_CLAMP: + case GEN6_TEXCOORDMODE_CLAMP_BORDER: + case GEN8_TEXCOORDMODE_HALF_BORDER: + break; + default: + assert(!"bad non-normalized coordinate wrap mode"); + break; + } + } + + assert(info->mip_filter == GEN6_MIPFILTER_NONE); + + assert((info->min_filter == GEN6_MAPFILTER_NEAREST || + info->min_filter == GEN6_MAPFILTER_LINEAR) && + (info->mag_filter == GEN6_MAPFILTER_NEAREST || + info->mag_filter == GEN6_MAPFILTER_LINEAR)); + + assert(info->min_lod == 0.0f && + info->max_lod == 0.0f && + info->lod_bias == 0.0f); + + return true; +} + +static bool +sampler_validate_gen6_sampler(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + ILO_DEV_ASSERT(dev, 6, 8); + + if (info->non_normalized && + !sampler_validate_gen6_non_normalized(dev, info)) + return false; + + if (ilo_dev_gen(dev) < ILO_GEN(8)) { + assert(info->tcx_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER && + info->tcy_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER && + info->tcz_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER); + } + + return true; +} + +static uint32_t +sampler_get_gen6_integer_filters(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + /* + * From the Sandy Bridge PRM, volume 4 part 1, page 103: + * + * "MIPFILTER_LINEAR is not supported for surface formats that do not + * support "Sampling Engine Filtering" as indicated in the Surface + * Formats table unless using the sample_c message type." + * + * "Only MAPFILTER_NEAREST is supported for surface formats that do not + * support "Sampling Engine Filtering" as indicated in the Surface + * Formats table unless using the sample_c message type. + */ + const enum gen_mip_filter mip_filter = + (info->mip_filter == GEN6_MIPFILTER_LINEAR) ? + GEN6_MIPFILTER_NEAREST : info->mip_filter; + const enum gen_map_filter min_filter = GEN6_MAPFILTER_NEAREST; + const enum gen_map_filter mag_filter = GEN6_MAPFILTER_NEAREST; + + ILO_DEV_ASSERT(dev, 6, 8); + + return mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT | + mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT | + min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT; +} + +static uint32_t +sampler_get_gen6_3d_filters(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + const enum gen_mip_filter mip_filter = info->mip_filter; + /* + * From the Sandy Bridge PRM, volume 4 part 1, page 103: + * + * "Only MAPFILTER_NEAREST and MAPFILTER_LINEAR are supported for + * surfaces of type SURFTYPE_3D." + */ + const enum gen_map_filter min_filter = + (info->min_filter == GEN6_MAPFILTER_NEAREST || + info->min_filter == GEN6_MAPFILTER_LINEAR) ? + info->min_filter : GEN6_MAPFILTER_LINEAR; + const enum gen_map_filter mag_filter = + (info->mag_filter == GEN6_MAPFILTER_NEAREST || + info->mag_filter == GEN6_MAPFILTER_LINEAR) ? + info->mag_filter : GEN6_MAPFILTER_LINEAR; + + ILO_DEV_ASSERT(dev, 6, 8); + + return mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT | + mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT | + min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT; +} + +static uint32_t +get_gen6_addr_controls(const struct ilo_dev *dev, + enum gen_texcoord_mode tcx_ctrl, + enum gen_texcoord_mode tcy_ctrl, + enum gen_texcoord_mode tcz_ctrl) +{ + ILO_DEV_ASSERT(dev, 6, 8); + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + return tcx_ctrl << GEN7_SAMPLER_DW3_U_WRAP__SHIFT | + tcy_ctrl << GEN7_SAMPLER_DW3_V_WRAP__SHIFT | + tcz_ctrl << GEN7_SAMPLER_DW3_R_WRAP__SHIFT; + } else { + return tcx_ctrl << GEN6_SAMPLER_DW1_U_WRAP__SHIFT | + tcy_ctrl << GEN6_SAMPLER_DW1_V_WRAP__SHIFT | + tcz_ctrl << GEN6_SAMPLER_DW1_R_WRAP__SHIFT; + } +} + +static uint32_t +sampler_get_gen6_1d_addr_controls(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + const enum gen_texcoord_mode tcx_ctrl = + (info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE) ? + GEN6_TEXCOORDMODE_CLAMP : info->tcx_ctrl; + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 100: + * + * "If this field (TCY Address Control Mode) is set to + * TEXCOORDMODE_CLAMP_BORDER or TEXCOORDMODE_HALF_BORDER and a 1D + * surface is sampled, incorrect blending with the border color in the + * vertical direction may occur." + */ + const enum gen_texcoord_mode tcy_ctrl = GEN6_TEXCOORDMODE_CLAMP; + const enum gen_texcoord_mode tcz_ctrl = GEN6_TEXCOORDMODE_CLAMP; + + ILO_DEV_ASSERT(dev, 6, 8); + + return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl); +} + +static uint32_t +sampler_get_gen6_2d_3d_addr_controls(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + const enum gen_texcoord_mode tcx_ctrl = + (info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE) ? + GEN6_TEXCOORDMODE_CLAMP : info->tcx_ctrl; + const enum gen_texcoord_mode tcy_ctrl = + (info->tcy_ctrl == GEN6_TEXCOORDMODE_CUBE) ? + GEN6_TEXCOORDMODE_CLAMP : info->tcy_ctrl; + /* + * From the Sandy Bridge PRM, volume 4 part 1, page 108: + * + * "[DevSNB]: if this field (TCZ Address Control Mode) is set to + * TEXCOORDMODE_CLAMP_BORDER samples outside the map will clamp to 0 + * instead of boarder color" + * + * From the Ivy Bridge PRM, volume 4 part 1, page 100: + * + * "If this field is set to TEXCOORDMODE_CLAMP_BORDER for 3D maps on + * formats without an alpha channel, samples straddling the map in the + * Z direction may have their alpha channels off by 1." + * + * Do we want to do something here? + */ + const enum gen_texcoord_mode tcz_ctrl = + (info->tcz_ctrl == GEN6_TEXCOORDMODE_CUBE) ? + GEN6_TEXCOORDMODE_CLAMP : info->tcz_ctrl; + + ILO_DEV_ASSERT(dev, 6, 8); + + return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl); +} + +static uint32_t +sampler_get_gen6_cube_addr_controls(const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 99: + * + * "When using cube map texture coordinates, only TEXCOORDMODE_CLAMP + * and TEXCOORDMODE_CUBE settings are valid, and each TC component + * must have the same Address Control mode. + * + * When TEXCOORDMODE_CUBE is not used accessing a cube map, the map's + * Cube Face Enable field must be programmed to 111111b (all faces + * enabled)." + * + * From the Haswell PRM, volume 2d, page 278: + * + * "When using cube map texture coordinates, each TC component must + * have the same Address Control Mode. + * + * When TEXCOORDMODE_CUBE is not used accessing a cube map, the map's + * Cube Face Enable field must be programmed to 111111b (all faces + * enabled)." + * + * We always enable all cube faces and only need to make sure all address + * control modes are the same. + */ + const enum gen_texcoord_mode tcx_ctrl = + (ilo_dev_gen(dev) >= ILO_GEN(7.5) || + info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE || + info->tcx_ctrl == GEN6_TEXCOORDMODE_CLAMP) ? + info->tcx_ctrl : GEN6_TEXCOORDMODE_CLAMP; + const enum gen_texcoord_mode tcy_ctrl = tcx_ctrl; + const enum gen_texcoord_mode tcz_ctrl = tcx_ctrl; + + ILO_DEV_ASSERT(dev, 6, 8); + + return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl); +} + +static uint16_t +get_gen6_lod_bias(const struct ilo_dev *dev, float bias) +{ + /* [-16.0, 16.0) in S4.6 or S4.8 */ + const int fbits = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 8 : 6; + const float max = 16.0f; + const float scale = (float) (1 << fbits); + const int mask = (1 << (1 + 4 + fbits)) - 1; + const int scaled_max = (16 << fbits) - 1; + int scaled; + + ILO_DEV_ASSERT(dev, 6, 8); + + if (bias > max) + bias = max; + else if (bias < -max) + bias = -max; + + scaled = (int) (bias * scale); + if (scaled > scaled_max) + scaled = scaled_max; + + return (scaled & mask); +} + +static uint16_t +get_gen6_lod_clamp(const struct ilo_dev *dev, float clamp) +{ + /* [0.0, 13.0] in U4.6 or [0.0, 14.0] in U4.8 */ + const int fbits = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 8 : 6; + const float max = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 14.0f : 13.0f; + const float scale = (float) (1 << fbits); + + ILO_DEV_ASSERT(dev, 6, 8); + + if (clamp > max) + clamp = max; + else if (clamp < 0.0f) + clamp = 0.0f; + + return (int) (clamp * scale); +} + +static bool +sampler_set_gen6_SAMPLER_STATE(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + uint16_t lod_bias, max_lod, min_lod; + uint32_t dw0, dw1, dw3; + + ILO_DEV_ASSERT(dev, 6, 8); + + if (!sampler_validate_gen6_sampler(dev, info)) + return false; + + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 15: + * + * "The per-pixel LOD is computed in an implementation-dependent manner + * and approximates the log2 of the texel/pixel ratio at the given + * pixel. The computation is typically based on the differential + * texel-space distances associated with a one-pixel differential + * distance along the screen x- and y-axes. These texel-space + * distances are computed by evaluating neighboring pixel texture + * coordinates, these coordinates being in units of texels on the base + * MIP level (multiplied by the corresponding surface size in + * texels)." + * + * Judging from the LOD computation pseudocode on page 16-18, the "base MIP + * level" should be given by SurfMinLod. To summarize, for the "sample" + * message, + * + * 1) LOD is set to log2(texel/pixel ratio). The number of texels is + * measured against level SurfMinLod. + * 2) Bias is added to LOD. + * 3) if pre-clamp is enabled, LOD is clamped to [MinLod, MaxLod] first + * 4) LOD is compared with Base to determine whether magnification or + * minification is needed. + * 5) If magnification is needed, or no mipmapping is requested, LOD is + * set to floor(MinLod). + * 6) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD. + * + * As an example, we could set SurfMinLod to GL_TEXTURE_BASE_LEVEL and Base + * to 0 to match GL. But GL expects LOD to be set to 0, instead of + * floor(MinLod), in 5). Since this is only an issue when MinLod is + * greater than or equal to one, and, with Base being 0, a non-zero MinLod + * implies minification, we only need to deal with the case when mipmapping + * is disabled. We can thus do: + * + * if (MipFilter == MIPFILTER_NONE && MinLod) { + * MinLod = 0; + * MagFilter = MinFilter; + * } + */ + + lod_bias = get_gen6_lod_bias(dev, info->lod_bias); + min_lod = get_gen6_lod_clamp(dev, info->min_lod); + max_lod = get_gen6_lod_clamp(dev, info->max_lod); + + dw0 = GEN6_SAMPLER_DW0_LOD_PRECLAMP_ENABLE | + 0 << GEN6_SAMPLER_DW0_BASE_LOD__SHIFT | + info->mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT | + info->mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT | + info->min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT; + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + dw0 |= GEN7_SAMPLER_DW0_BORDER_COLOR_MODE_DX10_OGL | + lod_bias << GEN7_SAMPLER_DW0_LOD_BIAS__SHIFT; + + if (info->min_filter == GEN6_MAPFILTER_ANISOTROPIC || + info->mag_filter == GEN6_MAPFILTER_ANISOTROPIC) + dw0 |= GEN7_SAMPLER_DW0_ANISO_ALGO_EWA; + } else { + dw0 |= lod_bias << GEN6_SAMPLER_DW0_LOD_BIAS__SHIFT | + info->shadow_func << GEN6_SAMPLER_DW0_SHADOW_FUNC__SHIFT; + + /* + * From the Sandy Bridge PRM, volume 4 part 1, page 102: + * + * "(Min and Mag State Not Equal) Must be set to 1 if any of the + * following are true: + * + * - Mag Mode Filter and Min Mode Filter are not the same + * - Address Rounding Enable: U address mag filter and U address + * min filter are not the same + * - Address Rounding Enable: V address mag filter and V address + * min filter are not the same + * - Address Rounding Enable: R address mag filter and R address + * min filter are not the same" + * + * We set address rounding for U, V, and R uniformly. Only need to + * check the filters. + */ + if (info->min_filter != info->mag_filter) + dw0 |= GEN6_SAMPLER_DW0_MIN_MAG_NOT_EQUAL; + } + + dw1 = 0; + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 96: + * + * "This field (Cube Surface Control Mode) must be set to + * CUBECTRLMODE_PROGRAMMED" + */ + dw1 |= min_lod << GEN7_SAMPLER_DW1_MIN_LOD__SHIFT | + max_lod << GEN7_SAMPLER_DW1_MAX_LOD__SHIFT | + info->shadow_func << GEN7_SAMPLER_DW1_SHADOW_FUNC__SHIFT | + GEN7_SAMPLER_DW1_CUBECTRLMODE_PROGRAMMED; + } else { + dw1 |= min_lod << GEN6_SAMPLER_DW1_MIN_LOD__SHIFT | + max_lod << GEN6_SAMPLER_DW1_MAX_LOD__SHIFT | + GEN6_SAMPLER_DW1_CUBECTRLMODE_PROGRAMMED | + info->tcx_ctrl << GEN6_SAMPLER_DW1_U_WRAP__SHIFT | + info->tcy_ctrl << GEN6_SAMPLER_DW1_V_WRAP__SHIFT | + info->tcz_ctrl << GEN6_SAMPLER_DW1_R_WRAP__SHIFT; + } + + dw3 = info->max_anisotropy << GEN6_SAMPLER_DW3_MAX_ANISO__SHIFT; + + /* round the coordinates for linear filtering */ + if (info->min_filter != GEN6_MAPFILTER_NEAREST) { + dw3 |= GEN6_SAMPLER_DW3_U_MIN_ROUND | + GEN6_SAMPLER_DW3_V_MIN_ROUND | + GEN6_SAMPLER_DW3_R_MIN_ROUND; + } + if (info->mag_filter != GEN6_MAPFILTER_NEAREST) { + dw3 |= GEN6_SAMPLER_DW3_U_MAG_ROUND | + GEN6_SAMPLER_DW3_V_MAG_ROUND | + GEN6_SAMPLER_DW3_R_MAG_ROUND; + } + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + dw3 |= GEN7_SAMPLER_DW3_TRIQUAL_FULL | + info->tcx_ctrl << GEN7_SAMPLER_DW3_U_WRAP__SHIFT | + info->tcy_ctrl << GEN7_SAMPLER_DW3_V_WRAP__SHIFT | + info->tcz_ctrl << GEN7_SAMPLER_DW3_R_WRAP__SHIFT; + + if (info->non_normalized) + dw3 |= GEN7_SAMPLER_DW3_NON_NORMALIZED_COORD; + } else { + if (info->non_normalized) + dw3 |= GEN6_SAMPLER_DW3_NON_NORMALIZED_COORD; + } + + STATIC_ASSERT(ARRAY_SIZE(sampler->sampler) >= 3); + sampler->sampler[0] = dw0; + sampler->sampler[1] = dw1; + sampler->sampler[2] = dw3; + + sampler->filter_integer = sampler_get_gen6_integer_filters(dev, info); + sampler->filter_3d = sampler_get_gen6_3d_filters(dev, info); + sampler->addr_ctrl_1d = sampler_get_gen6_1d_addr_controls(dev, info); + sampler->addr_ctrl_2d_3d = sampler_get_gen6_2d_3d_addr_controls(dev, info); + sampler->addr_ctrl_cube = sampler_get_gen6_cube_addr_controls(dev, info); + + sampler->non_normalized = info->non_normalized; + + /* + * From the Sandy Bridge PRM, volume 4 part 1, page 21: + * + * "[DevSNB] Errata: Incorrect behavior is observed in cases where the + * min and mag mode filters are different and SurfMinLOD is nonzero. + * The determination of MagMode uses the following equation instead of + * the one in the above pseudocode: + * + * MagMode = (LOD + SurfMinLOD - Base <= 0)" + * + * As a way to work around that, request Base to be set to SurfMinLod. + */ + if (ilo_dev_gen(dev) == ILO_GEN(6) && + info->min_filter != info->mag_filter) + sampler->base_to_surf_min_lod = true; + + return true; +} + +static bool +sampler_border_set_gen6_SAMPLER_BORDER_COLOR_STATE(struct ilo_state_sampler_border *border, + const struct ilo_dev *dev, + const struct ilo_state_sampler_border_info *info) +{ + uint32_t dw[12]; + float rgba[4]; + + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 117: + * + * "For ([DevSNB]), if border color is used, all formats must be + * provided. Hardware will choose the appropriate format based on + * Surface Format and Texture Border Color Mode. The values + * represented by each format should be the same (other than being + * subject to range-based clamping and precision) to avoid unexpected + * behavior." + * + * XXX We do not honor info->is_integer yet. + */ + + ILO_DEV_ASSERT(dev, 6, 6); + + /* make a copy so that we can clamp for SNORM and UNORM */ + memcpy(rgba, info->rgba.f, sizeof(rgba)); + + /* IEEE_FP */ + dw[1] = fui(rgba[0]); + dw[2] = fui(rgba[1]); + dw[3] = fui(rgba[2]); + dw[4] = fui(rgba[3]); + + /* FLOAT_16 */ + dw[5] = util_float_to_half(rgba[0]) | + util_float_to_half(rgba[1]) << 16; + dw[6] = util_float_to_half(rgba[2]) | + util_float_to_half(rgba[3]) << 16; + + /* clamp to [-1.0f, 1.0f] */ + rgba[0] = CLAMP(rgba[0], -1.0f, 1.0f); + rgba[1] = CLAMP(rgba[1], -1.0f, 1.0f); + rgba[2] = CLAMP(rgba[2], -1.0f, 1.0f); + rgba[3] = CLAMP(rgba[3], -1.0f, 1.0f); + + /* SNORM16 */ + dw[9] = (int16_t) util_iround(rgba[0] * 32767.0f) | + (int16_t) util_iround(rgba[1] * 32767.0f) << 16; + dw[10] = (int16_t) util_iround(rgba[2] * 32767.0f) | + (int16_t) util_iround(rgba[3] * 32767.0f) << 16; + + /* SNORM8 */ + dw[11] = (int8_t) util_iround(rgba[0] * 127.0f) | + (int8_t) util_iround(rgba[1] * 127.0f) << 8 | + (int8_t) util_iround(rgba[2] * 127.0f) << 16 | + (int8_t) util_iround(rgba[3] * 127.0f) << 24; + + /* clamp to [0.0f, 1.0f] */ + rgba[0] = CLAMP(rgba[0], 0.0f, 1.0f); + rgba[1] = CLAMP(rgba[1], 0.0f, 1.0f); + rgba[2] = CLAMP(rgba[2], 0.0f, 1.0f); + rgba[3] = CLAMP(rgba[3], 0.0f, 1.0f); + + /* UNORM8 */ + dw[0] = (uint8_t) util_iround(rgba[0] * 255.0f) | + (uint8_t) util_iround(rgba[1] * 255.0f) << 8 | + (uint8_t) util_iround(rgba[2] * 255.0f) << 16 | + (uint8_t) util_iround(rgba[3] * 255.0f) << 24; + + /* UNORM16 */ + dw[7] = (uint16_t) util_iround(rgba[0] * 65535.0f) | + (uint16_t) util_iround(rgba[1] * 65535.0f) << 16; + dw[8] = (uint16_t) util_iround(rgba[2] * 65535.0f) | + (uint16_t) util_iround(rgba[3] * 65535.0f) << 16; + + STATIC_ASSERT(ARRAY_SIZE(border->color) >= 12); + memcpy(border->color, dw, sizeof(dw)); + + return true; +} + +static bool +sampler_border_set_gen7_SAMPLER_BORDER_COLOR_STATE(struct ilo_state_sampler_border *border, + const struct ilo_dev *dev, + const struct ilo_state_sampler_border_info *info) +{ + ILO_DEV_ASSERT(dev, 7, 8); + + /* + * From the Ivy Bridge PRM, volume 4 part 1, page 116: + * + * "In DX10/OGL mode, the format of the border color is + * R32G32B32A32_FLOAT, regardless of the surface format chosen." + * + * From the Haswell PRM, volume 2d, page 240: + * + * "So, SW will have to program the table in SAMPLER_BORDER_COLOR_STATE + * at offsets DWORD16 to 19, as per the integer surface format type." + * + * From the Broadwell PRM, volume 2d, page 297: + * + * "DX10/OGL mode: the format of the border color depends on the format + * of the surface being sampled. If the map format is UINT, then the + * border color format is R32G32B32A32_UINT. If the map format is + * SINT, then the border color format is R32G32B32A32_SINT. Otherwise, + * the border color format is R32G32B32A32_FLOAT." + * + * XXX every Gen is different + */ + + STATIC_ASSERT(ARRAY_SIZE(border->color) >= 4); + memcpy(border->color, info->rgba.f, sizeof(info->rgba.f)); + + return true; +} + +bool +ilo_state_sampler_init(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info) +{ + bool ret = true; + + assert(ilo_is_zeroed(sampler, sizeof(*sampler))); + + ret &= sampler_set_gen6_SAMPLER_STATE(sampler, dev, info); + + assert(ret); + + return ret; +} + +bool +ilo_state_sampler_init_disabled(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev) +{ + ILO_DEV_ASSERT(dev, 6, 8); + + assert(ilo_is_zeroed(sampler, sizeof(*sampler))); + + sampler->sampler[0] = GEN6_SAMPLER_DW0_DISABLE; + sampler->sampler[1] = 0; + sampler->sampler[2] = 0; + + return true; +} + +/** + * Modify \p sampler to work with \p surf. There will be loss of information. + * Callers should make a copy of the orignal sampler first. + */ +bool +ilo_state_sampler_set_surface(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev, + const struct ilo_state_surface *surf) +{ + uint32_t addr_ctrl; + + ILO_DEV_ASSERT(dev, 6, 8); + + if (sampler->non_normalized) { + /* see sampler_validate_gen6_non_normalized() */ + assert(surf->type == GEN6_SURFTYPE_2D || + surf->type == GEN6_SURFTYPE_3D); + assert(!surf->min_lod && !surf->mip_count); + } + + if (sampler->base_to_surf_min_lod) { + const uint8_t base = surf->min_lod << GEN6_SAMPLER_DW0_BASE_LOD__RADIX; + + sampler->sampler[0] = + (sampler->sampler[0] & ~GEN6_SAMPLER_DW0_BASE_LOD__MASK) | + base << GEN6_SAMPLER_DW0_BASE_LOD__SHIFT; + } + + if (surf->is_integer || surf->type == GEN6_SURFTYPE_3D) { + const uint32_t mask = (GEN6_SAMPLER_DW0_MIP_FILTER__MASK | + GEN6_SAMPLER_DW0_MIN_FILTER__MASK | + GEN6_SAMPLER_DW0_MAG_FILTER__MASK); + const uint32_t filter = (surf->is_integer) ? + sampler->filter_integer : sampler->filter_3d; + + assert((filter & mask) == filter); + sampler->sampler[0] = (sampler->sampler[0] & ~mask) | + filter; + } + + switch (surf->type) { + case GEN6_SURFTYPE_1D: + addr_ctrl = sampler->addr_ctrl_1d; + break; + case GEN6_SURFTYPE_2D: + case GEN6_SURFTYPE_3D: + addr_ctrl = sampler->addr_ctrl_2d_3d; + break; + case GEN6_SURFTYPE_CUBE: + addr_ctrl = sampler->addr_ctrl_cube; + break; + default: + assert(!"unexpected surface type"); + addr_ctrl = 0; + break; + } + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + const uint32_t mask = (GEN7_SAMPLER_DW3_U_WRAP__MASK | + GEN7_SAMPLER_DW3_V_WRAP__MASK | + GEN7_SAMPLER_DW3_R_WRAP__MASK); + + assert((addr_ctrl & mask) == addr_ctrl); + sampler->sampler[2] = (sampler->sampler[2] & ~mask) | + addr_ctrl; + } else { + const uint32_t mask = (GEN6_SAMPLER_DW1_U_WRAP__MASK | + GEN6_SAMPLER_DW1_V_WRAP__MASK | + GEN6_SAMPLER_DW1_R_WRAP__MASK); + + assert((addr_ctrl & mask) == addr_ctrl); + sampler->sampler[1] = (sampler->sampler[1] & ~mask) | + addr_ctrl; + } + + return true; +} + +bool +ilo_state_sampler_border_init(struct ilo_state_sampler_border *border, + const struct ilo_dev *dev, + const struct ilo_state_sampler_border_info *info) +{ + bool ret = true; + + if (ilo_dev_gen(dev) >= ILO_GEN(7)) { + ret &= sampler_border_set_gen7_SAMPLER_BORDER_COLOR_STATE(border, + dev, info); + } else { + ret &= sampler_border_set_gen6_SAMPLER_BORDER_COLOR_STATE(border, + dev, info); + } + + assert(ret); + + return ret; +} diff --git a/src/gallium/drivers/ilo/core/ilo_state_sampler.h b/src/gallium/drivers/ilo/core/ilo_state_sampler.h new file mode 100644 index 00000000000..75c7620a678 --- /dev/null +++ b/src/gallium/drivers/ilo/core/ilo_state_sampler.h @@ -0,0 +1,103 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2015 LunarG, Inc. + * + * 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 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Chia-I Wu + */ + +#ifndef ILO_STATE_SAMPLER_H +#define ILO_STATE_SAMPLER_H + +#include "genhw/genhw.h" + +#include "ilo_core.h" +#include "ilo_dev.h" + +struct ilo_state_surface; + +struct ilo_state_sampler_info { + bool non_normalized; + + float lod_bias; + float min_lod; + float max_lod; + + enum gen_mip_filter mip_filter; + enum gen_map_filter min_filter; + enum gen_map_filter mag_filter; + enum gen_aniso_ratio max_anisotropy; + + enum gen_texcoord_mode tcx_ctrl; + enum gen_texcoord_mode tcy_ctrl; + enum gen_texcoord_mode tcz_ctrl; + + enum gen_prefilter_op shadow_func; +}; + +struct ilo_state_sampler_border_info { + union { + float f[4]; + uint32_t ui[4]; + } rgba; + + bool is_integer; +}; + +struct ilo_state_sampler { + uint32_t sampler[3]; + + uint32_t filter_integer; + uint32_t filter_3d; + + uint32_t addr_ctrl_1d; + uint32_t addr_ctrl_2d_3d; + uint32_t addr_ctrl_cube; + + bool non_normalized; + bool base_to_surf_min_lod; +}; + +struct ilo_state_sampler_border { + uint32_t color[12]; +}; + +bool +ilo_state_sampler_init(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev, + const struct ilo_state_sampler_info *info); + +bool +ilo_state_sampler_init_disabled(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev); + +bool +ilo_state_sampler_set_surface(struct ilo_state_sampler *sampler, + const struct ilo_dev *dev, + const struct ilo_state_surface *surf); + +bool +ilo_state_sampler_border_init(struct ilo_state_sampler_border *border, + const struct ilo_dev *dev, + const struct ilo_state_sampler_border_info *info); + +#endif /* ILO_STATE_SAMPLER_H */ -- 2.30.2