-
-static void
-sampler_init_border_color_gen6(const struct ilo_dev *dev,
- const union pipe_color_union *color,
- uint32_t *dw, int num_dwords)
-{
- float rgba[4] = {
- color->f[0], color->f[1], color->f[2], color->f[3],
- };
-
- ILO_DEV_ASSERT(dev, 6, 6);
-
- assert(num_dwords >= 12);
-
- /*
- * This state is not documented in the Sandy Bridge PRM, but in the
- * Ironlake PRM. SNORM8 seems to be in DW11 instead of DW1.
- */
-
- /* 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;
-}
-
-/**
- * Translate a pipe texture mipfilter to the matching hardware mipfilter.
- */
-static int
-gen6_translate_tex_mipfilter(unsigned filter)
-{
- switch (filter) {
- case PIPE_TEX_MIPFILTER_NEAREST: return GEN6_MIPFILTER_NEAREST;
- case PIPE_TEX_MIPFILTER_LINEAR: return GEN6_MIPFILTER_LINEAR;
- case PIPE_TEX_MIPFILTER_NONE: return GEN6_MIPFILTER_NONE;
- default:
- assert(!"unknown mipfilter");
- return GEN6_MIPFILTER_NONE;
- }
-}
-
-/**
- * Translate a pipe texture filter to the matching hardware mapfilter.
- */
-static int
-gen6_translate_tex_filter(unsigned filter)
-{
- switch (filter) {
- case PIPE_TEX_FILTER_NEAREST: return GEN6_MAPFILTER_NEAREST;
- case PIPE_TEX_FILTER_LINEAR: return GEN6_MAPFILTER_LINEAR;
- default:
- assert(!"unknown sampler filter");
- return GEN6_MAPFILTER_NEAREST;
- }
-}
-
-/**
- * Translate a pipe texture coordinate wrapping mode to the matching hardware
- * wrapping mode.
- */
-static int
-gen6_translate_tex_wrap(unsigned wrap)
-{
- switch (wrap) {
- case PIPE_TEX_WRAP_CLAMP: return GEN8_TEXCOORDMODE_HALF_BORDER;
- case PIPE_TEX_WRAP_REPEAT: return GEN6_TEXCOORDMODE_WRAP;
- case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return GEN6_TEXCOORDMODE_CLAMP;
- case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return GEN6_TEXCOORDMODE_CLAMP_BORDER;
- case PIPE_TEX_WRAP_MIRROR_REPEAT: return GEN6_TEXCOORDMODE_MIRROR;
- case PIPE_TEX_WRAP_MIRROR_CLAMP:
- case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
- case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
- default:
- assert(!"unknown sampler wrap mode");
- return GEN6_TEXCOORDMODE_WRAP;
- }
-}
-
-/**
- * Translate a pipe shadow compare function to the matching hardware shadow
- * function.
- */
-static int
-gen6_translate_shadow_func(unsigned func)
-{
- /*
- * For PIPE_FUNC_x, the reference value is on the left-hand side of the
- * comparison, and 1.0 is returned when the comparison is true.
- *
- * For GEN6_COMPAREFUNCTION_x, the reference value is on the right-hand side of
- * the comparison, and 0.0 is returned when the comparison is true.
- */
- switch (func) {
- case PIPE_FUNC_NEVER: return GEN6_COMPAREFUNCTION_ALWAYS;
- case PIPE_FUNC_LESS: return GEN6_COMPAREFUNCTION_LEQUAL;
- case PIPE_FUNC_EQUAL: return GEN6_COMPAREFUNCTION_NOTEQUAL;
- case PIPE_FUNC_LEQUAL: return GEN6_COMPAREFUNCTION_LESS;
- case PIPE_FUNC_GREATER: return GEN6_COMPAREFUNCTION_GEQUAL;
- case PIPE_FUNC_NOTEQUAL: return GEN6_COMPAREFUNCTION_EQUAL;
- case PIPE_FUNC_GEQUAL: return GEN6_COMPAREFUNCTION_GREATER;
- case PIPE_FUNC_ALWAYS: return GEN6_COMPAREFUNCTION_NEVER;
- default:
- assert(!"unknown shadow compare function");
- return GEN6_COMPAREFUNCTION_NEVER;
- }
-}
-
-void
-ilo_gpe_init_sampler_cso(const struct ilo_dev *dev,
- const struct pipe_sampler_state *state,
- struct ilo_sampler_cso *sampler)
-{
- int mip_filter, min_filter, mag_filter, max_aniso;
- int lod_bias, max_lod, min_lod;
- int wrap_s, wrap_t, wrap_r, wrap_cube;
- uint32_t dw0, dw1, dw3;
-
- ILO_DEV_ASSERT(dev, 6, 8);
-
- memset(sampler, 0, sizeof(*sampler));
-
- mip_filter = gen6_translate_tex_mipfilter(state->min_mip_filter);
- min_filter = gen6_translate_tex_filter(state->min_img_filter);
- mag_filter = gen6_translate_tex_filter(state->mag_img_filter);
-
- sampler->anisotropic = state->max_anisotropy;
-
- if (state->max_anisotropy >= 2 && state->max_anisotropy <= 16)
- max_aniso = state->max_anisotropy / 2 - 1;
- else if (state->max_anisotropy > 16)
- max_aniso = GEN6_ANISORATIO_16;
- else
- max_aniso = GEN6_ANISORATIO_2;
-
- /*
- *
- * Here is how the hardware calculate per-pixel LOD, from my reading of the
- * PRMs:
- *
- * 1) LOD is set to log2(ratio of texels to pixels) if not specified in
- * other ways. The number of texels is measured using level
- * SurfMinLod.
- * 2) Bias is added to LOD.
- * 3) LOD is clamped to [MinLod, MaxLod], and the clamped value is
- * compared with Base to determine whether magnification or
- * minification is needed. (if preclamp is disabled, LOD is compared
- * with Base before clamping)
- * 4) If magnification is needed, or no mipmapping is requested, LOD is
- * set to floor(MinLod).
- * 5) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD.
- *
- * With Gallium interface, Base is always zero and
- * pipe_sampler_view::u.tex.first_level specifies SurfMinLod.
- */
- if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
- const float scale = 256.0f;
-
- /* [-16.0, 16.0) in S4.8 */
- lod_bias = (int)
- (CLAMP(state->lod_bias, -16.0f, 15.9f) * scale);
- lod_bias &= 0x1fff;
-
- /* [0.0, 14.0] in U4.8 */
- max_lod = (int) (CLAMP(state->max_lod, 0.0f, 14.0f) * scale);
- min_lod = (int) (CLAMP(state->min_lod, 0.0f, 14.0f) * scale);
- }
- else {
- const float scale = 64.0f;
-
- /* [-16.0, 16.0) in S4.6 */
- lod_bias = (int)
- (CLAMP(state->lod_bias, -16.0f, 15.9f) * scale);
- lod_bias &= 0x7ff;
-
- /* [0.0, 13.0] in U4.6 */
- max_lod = (int) (CLAMP(state->max_lod, 0.0f, 13.0f) * scale);
- min_lod = (int) (CLAMP(state->min_lod, 0.0f, 13.0f) * scale);
- }
-
- /*
- * We want LOD to be clamped to determine magnification/minification, and
- * get set to zero when it is magnification or when mipmapping is disabled.
- * The hardware would set LOD to floor(MinLod) and that is a problem when
- * MinLod is greater than or equal to 1.0f.
- *
- * With Base being zero, it is always minification when MinLod is non-zero.
- * To achieve our goal, we just need to set MinLod to zero and set
- * MagFilter to MinFilter when mipmapping is disabled.
- */
- if (state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE && min_lod) {
- min_lod = 0;
- mag_filter = min_filter;
- }
-
- /* determine wrap s/t/r */
- wrap_s = gen6_translate_tex_wrap(state->wrap_s);
- wrap_t = gen6_translate_tex_wrap(state->wrap_t);
- wrap_r = gen6_translate_tex_wrap(state->wrap_r);
- if (ilo_dev_gen(dev) < ILO_GEN(8)) {
- /*
- * For nearest filtering, PIPE_TEX_WRAP_CLAMP means
- * PIPE_TEX_WRAP_CLAMP_TO_EDGE; for linear filtering,
- * PIPE_TEX_WRAP_CLAMP means PIPE_TEX_WRAP_CLAMP_TO_BORDER while
- * additionally clamping the texture coordinates to [0.0, 1.0].
- *
- * PIPE_TEX_WRAP_CLAMP is not supported natively until Gen8. The
- * clamping has to be taken care of in the shaders. There are two
- * filters here, but let the minification one has a say.
- */
- const bool clamp_is_to_edge =
- (state->min_img_filter == PIPE_TEX_FILTER_NEAREST);
-
- if (clamp_is_to_edge) {
- if (wrap_s == GEN8_TEXCOORDMODE_HALF_BORDER)
- wrap_s = GEN6_TEXCOORDMODE_CLAMP;
- if (wrap_t == GEN8_TEXCOORDMODE_HALF_BORDER)
- wrap_t = GEN6_TEXCOORDMODE_CLAMP;
- if (wrap_r == GEN8_TEXCOORDMODE_HALF_BORDER)
- wrap_r = GEN6_TEXCOORDMODE_CLAMP;
- } else {
- if (wrap_s == GEN8_TEXCOORDMODE_HALF_BORDER) {
- wrap_s = GEN6_TEXCOORDMODE_CLAMP_BORDER;
- sampler->saturate_s = true;
- }
- if (wrap_t == GEN8_TEXCOORDMODE_HALF_BORDER) {
- wrap_t = GEN6_TEXCOORDMODE_CLAMP_BORDER;
- sampler->saturate_t = true;
- }
- if (wrap_r == GEN8_TEXCOORDMODE_HALF_BORDER) {
- wrap_r = GEN6_TEXCOORDMODE_CLAMP_BORDER;
- sampler->saturate_r = true;
- }
- }
- }
-
- /*
- * From the Sandy Bridge PRM, volume 4 part 1, page 107:
- *
- * "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."
- *
- * From the Ivy Bridge PRM, volume 4 part 1, page 96:
- *
- * "This field (Cube Surface Control Mode) must be set to
- * CUBECTRLMODE_PROGRAMMED"
- *
- * Therefore, we cannot use "Cube Surface Control Mode" for semless cube
- * map filtering.
- */
- if (state->seamless_cube_map &&
- (state->min_img_filter != PIPE_TEX_FILTER_NEAREST ||
- state->mag_img_filter != PIPE_TEX_FILTER_NEAREST)) {
- wrap_cube = GEN6_TEXCOORDMODE_CUBE;
- }
- else {
- wrap_cube = GEN6_TEXCOORDMODE_CLAMP;
- }
-
- if (!state->normalized_coords) {
- /*
- * 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."
- */
- assert(wrap_s == GEN6_TEXCOORDMODE_CLAMP ||
- wrap_s == GEN6_TEXCOORDMODE_CLAMP_BORDER);
- assert(wrap_t == GEN6_TEXCOORDMODE_CLAMP ||
- wrap_t == GEN6_TEXCOORDMODE_CLAMP_BORDER);
- assert(wrap_r == GEN6_TEXCOORDMODE_CLAMP ||
- wrap_r == GEN6_TEXCOORDMODE_CLAMP_BORDER);
-
- assert(mag_filter == GEN6_MAPFILTER_NEAREST ||
- mag_filter == GEN6_MAPFILTER_LINEAR);
- assert(min_filter == GEN6_MAPFILTER_NEAREST ||
- min_filter == GEN6_MAPFILTER_LINEAR);
-
- /* work around a bug in util_blitter */
- mip_filter = GEN6_MIPFILTER_NONE;
-
- assert(mip_filter == GEN6_MIPFILTER_NONE);
- }
-
- if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
- dw0 = 1 << 28 |
- mip_filter << 20 |
- lod_bias << 1;
-
- sampler->dw_filter = mag_filter << 17 |
- min_filter << 14;
-
- sampler->dw_filter_aniso = GEN6_MAPFILTER_ANISOTROPIC << 17 |
- GEN6_MAPFILTER_ANISOTROPIC << 14 |
- 1;
-
- dw1 = min_lod << 20 |
- max_lod << 8;
-
- if (state->compare_mode != PIPE_TEX_COMPARE_NONE)
- dw1 |= gen6_translate_shadow_func(state->compare_func) << 1;
-
- dw3 = max_aniso << 19;
-
- /* round the coordinates for linear filtering */
- if (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 (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 (!state->normalized_coords)
- dw3 |= 1 << 10;
-
- sampler->dw_wrap = wrap_s << 6 |
- wrap_t << 3 |
- wrap_r;
-
- /*
- * As noted in the classic i965 driver, the HW may still reference
- * wrap_t and wrap_r for 1D textures. We need to set them to a safe
- * mode
- */
- sampler->dw_wrap_1d = wrap_s << 6 |
- GEN6_TEXCOORDMODE_WRAP << 3 |
- GEN6_TEXCOORDMODE_WRAP;
-
- sampler->dw_wrap_cube = wrap_cube << 6 |
- wrap_cube << 3 |
- wrap_cube;
-
- STATIC_ASSERT(Elements(sampler->payload) >= 7);
-
- sampler->payload[0] = dw0;
- sampler->payload[1] = dw1;
- sampler->payload[2] = dw3;
-
- memcpy(&sampler->payload[3],
- state->border_color.ui, sizeof(state->border_color.ui));
- }
- else {
- dw0 = 1 << 28 |
- mip_filter << 20 |
- lod_bias << 3;
-
- if (state->compare_mode != PIPE_TEX_COMPARE_NONE)
- dw0 |= gen6_translate_shadow_func(state->compare_func);
-
- sampler->dw_filter = (min_filter != mag_filter) << 27 |
- mag_filter << 17 |
- min_filter << 14;
-
- sampler->dw_filter_aniso = GEN6_MAPFILTER_ANISOTROPIC << 17 |
- GEN6_MAPFILTER_ANISOTROPIC << 14;
-
- dw1 = min_lod << 22 |
- max_lod << 12;
-
- sampler->dw_wrap = wrap_s << 6 |
- wrap_t << 3 |
- wrap_r;
-
- sampler->dw_wrap_1d = wrap_s << 6 |
- GEN6_TEXCOORDMODE_WRAP << 3 |
- GEN6_TEXCOORDMODE_WRAP;
-
- sampler->dw_wrap_cube = wrap_cube << 6 |
- wrap_cube << 3 |
- wrap_cube;
-
- dw3 = max_aniso << 19;
-
- /* round the coordinates for linear filtering */
- if (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 (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 (!state->normalized_coords)
- dw3 |= 1;
-
- STATIC_ASSERT(Elements(sampler->payload) >= 15);
-
- sampler->payload[0] = dw0;
- sampler->payload[1] = dw1;
- sampler->payload[2] = dw3;
-
- sampler_init_border_color_gen6(dev,
- &state->border_color, &sampler->payload[3], 12);
- }
-}