From 62bb6437187b439d5959ccab094762163713a992 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Mon, 11 May 2015 14:23:49 +0800 Subject: [PATCH] ilo: add ilo_state_cc We want to replace ilo_dsa_state and ilo_blend_state with ilo_state_cc. --- src/gallium/drivers/ilo/Makefile.sources | 2 + src/gallium/drivers/ilo/core/ilo_state_cc.c | 890 ++++++++++++++++++++ src/gallium/drivers/ilo/core/ilo_state_cc.h | 199 +++++ 3 files changed, 1091 insertions(+) create mode 100644 src/gallium/drivers/ilo/core/ilo_state_cc.c create mode 100644 src/gallium/drivers/ilo/core/ilo_state_cc.h diff --git a/src/gallium/drivers/ilo/Makefile.sources b/src/gallium/drivers/ilo/Makefile.sources index b4b4498a024..e1f6d22b0f6 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_cc.c \ + core/ilo_state_cc.h \ core/ilo_state_raster.c \ core/ilo_state_raster.h \ core/ilo_state_sampler.c \ diff --git a/src/gallium/drivers/ilo/core/ilo_state_cc.c b/src/gallium/drivers/ilo/core/ilo_state_cc.c new file mode 100644 index 00000000000..83ee8de979c --- /dev/null +++ b/src/gallium/drivers/ilo/core/ilo_state_cc.c @@ -0,0 +1,890 @@ +/* + * 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 "ilo_debug.h" +#include "ilo_state_cc.h" + +static bool +cc_validate_gen6_stencil(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_stencil_info *stencil = &info->stencil; + + ILO_DEV_ASSERT(dev, 6, 8); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 359: + * + * "If the Depth Buffer is either undefined or does not have a surface + * format of D32_FLOAT_S8X24_UINT or D24_UNORM_S8_UINT and separate + * stencil buffer is disabled, Stencil Test Enable must be DISABLED" + * + * From the Sandy Bridge PRM, volume 2 part 1, page 370: + * + * "This field (Stencil Test Enable) cannot be enabled if Surface + * Format in 3DSTATE_DEPTH_BUFFER is set to D16_UNORM." + */ + if (stencil->test_enable) + assert(stencil->cv_has_buffer); + + return true; +} + +static bool +cc_validate_gen6_depth(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_depth_info *depth = &info->depth; + + ILO_DEV_ASSERT(dev, 6, 8); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 360: + * + * "Enabling the Depth Test function without defining a Depth Buffer is + * UNDEFINED." + * + * From the Sandy Bridge PRM, volume 2 part 1, page 375: + * + * "A Depth Buffer must be defined before enabling writes to it, or + * operation is UNDEFINED." + */ + if (depth->test_enable || depth->write_enable) + assert(depth->cv_has_buffer); + + return true; +} + +static bool +cc_set_gen6_DEPTH_STENCIL_STATE(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_stencil_info *stencil = &info->stencil; + const struct ilo_state_cc_depth_info *depth = &info->depth; + const struct ilo_state_cc_params_info *params = &info->params; + uint32_t dw0, dw1, dw2; + + ILO_DEV_ASSERT(dev, 6, 7.5); + + if (!cc_validate_gen6_stencil(dev, info) || + !cc_validate_gen6_depth(dev, info)) + return false; + + dw0 = 0; + dw1 = 0; + if (stencil->test_enable) { + const struct ilo_state_cc_stencil_op_info *front = &stencil->front; + const struct ilo_state_cc_stencil_params_info *front_p = + ¶ms->stencil_front; + const struct ilo_state_cc_stencil_op_info *back; + const struct ilo_state_cc_stencil_params_info *back_p; + + dw0 |= GEN6_ZS_DW0_STENCIL_TEST_ENABLE; + + if (stencil->twosided_enable) { + dw0 |= GEN6_ZS_DW0_STENCIL1_ENABLE; + + back = &stencil->back; + back_p = ¶ms->stencil_back; + } else { + back = &stencil->front; + back_p = ¶ms->stencil_front; + } + + dw0 |= front->test_func << GEN6_ZS_DW0_STENCIL_FUNC__SHIFT | + front->fail_op << GEN6_ZS_DW0_STENCIL_FAIL_OP__SHIFT | + front->zfail_op << GEN6_ZS_DW0_STENCIL_ZFAIL_OP__SHIFT | + front->zpass_op << GEN6_ZS_DW0_STENCIL_ZPASS_OP__SHIFT | + back->test_func << GEN6_ZS_DW0_STENCIL1_FUNC__SHIFT | + back->fail_op << GEN6_ZS_DW0_STENCIL1_FAIL_OP__SHIFT | + back->zfail_op << GEN6_ZS_DW0_STENCIL1_ZFAIL_OP__SHIFT | + back->zpass_op << GEN6_ZS_DW0_STENCIL1_ZPASS_OP__SHIFT; + + /* + * From the Ivy Bridge PRM, volume 2 part 1, page 363: + * + * "If this field (Stencil Buffer Write Enable) is enabled, Stencil + * Test Enable must also be enabled." + * + * This is different from depth write enable, which is independent from + * depth test enable. + */ + if (front_p->write_mask || back_p->write_mask) + dw0 |= GEN6_ZS_DW0_STENCIL_WRITE_ENABLE; + + dw1 |= front_p->test_mask << GEN6_ZS_DW1_STENCIL_TEST_MASK__SHIFT | + front_p->write_mask << GEN6_ZS_DW1_STENCIL_WRITE_MASK__SHIFT | + back_p->test_mask << GEN6_ZS_DW1_STENCIL1_TEST_MASK__SHIFT | + back_p->write_mask << GEN6_ZS_DW1_STENCIL1_WRITE_MASK__SHIFT; + } + + dw2 = 0; + if (depth->test_enable) { + dw2 |= GEN6_ZS_DW2_DEPTH_TEST_ENABLE | + depth->test_func << GEN6_ZS_DW2_DEPTH_FUNC__SHIFT; + } else { + dw2 |= GEN6_COMPAREFUNCTION_ALWAYS << GEN6_ZS_DW2_DEPTH_FUNC__SHIFT; + } + + /* independent from depth->test_enable */ + if (depth->write_enable) + dw2 |= GEN6_ZS_DW2_DEPTH_WRITE_ENABLE; + + STATIC_ASSERT(ARRAY_SIZE(cc->ds) >= 3); + cc->ds[0] = dw0; + cc->ds[1] = dw1; + cc->ds[2] = dw2; + + return true; +} + +static bool +cc_set_gen8_3DSTATE_WM_DEPTH_STENCIL(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_stencil_info *stencil = &info->stencil; + const struct ilo_state_cc_depth_info *depth = &info->depth; + const struct ilo_state_cc_params_info *params = &info->params; + uint32_t dw1, dw2; + + ILO_DEV_ASSERT(dev, 8, 8); + + if (!cc_validate_gen6_stencil(dev, info) || + !cc_validate_gen6_depth(dev, info)) + return false; + + dw1 = 0; + dw2 = 0; + if (stencil->test_enable) { + const struct ilo_state_cc_stencil_op_info *front = &stencil->front; + const struct ilo_state_cc_stencil_params_info *front_p = + ¶ms->stencil_front; + const struct ilo_state_cc_stencil_op_info *back; + const struct ilo_state_cc_stencil_params_info *back_p; + + dw1 |= GEN8_ZS_DW1_STENCIL_TEST_ENABLE; + + if (stencil->twosided_enable) { + dw1 |= GEN8_ZS_DW1_STENCIL1_ENABLE; + + back = &stencil->back; + back_p = ¶ms->stencil_back; + } else { + back = &stencil->front; + back_p = ¶ms->stencil_front; + } + + dw1 |= front->fail_op << GEN8_ZS_DW1_STENCIL_FAIL_OP__SHIFT | + front->zfail_op << GEN8_ZS_DW1_STENCIL_ZFAIL_OP__SHIFT | + front->zpass_op << GEN8_ZS_DW1_STENCIL_ZPASS_OP__SHIFT | + back->test_func << GEN8_ZS_DW1_STENCIL1_FUNC__SHIFT | + back->fail_op << GEN8_ZS_DW1_STENCIL1_FAIL_OP__SHIFT | + back->zfail_op << GEN8_ZS_DW1_STENCIL1_ZFAIL_OP__SHIFT | + back->zpass_op << GEN8_ZS_DW1_STENCIL1_ZPASS_OP__SHIFT | + front->test_func << GEN8_ZS_DW1_STENCIL_FUNC__SHIFT; + + if (front_p->write_mask || back_p->write_mask) + dw1 |= GEN8_ZS_DW1_STENCIL_WRITE_ENABLE; + + dw2 |= front_p->test_mask << GEN8_ZS_DW2_STENCIL_TEST_MASK__SHIFT | + front_p->write_mask << GEN8_ZS_DW2_STENCIL_WRITE_MASK__SHIFT | + back_p->test_mask << GEN8_ZS_DW2_STENCIL1_TEST_MASK__SHIFT | + back_p->write_mask << GEN8_ZS_DW2_STENCIL1_WRITE_MASK__SHIFT; + } + + if (depth->test_enable) { + dw1 |= GEN8_ZS_DW1_DEPTH_TEST_ENABLE | + depth->test_func << GEN8_ZS_DW1_DEPTH_FUNC__SHIFT; + } else { + dw1 |= GEN6_COMPAREFUNCTION_ALWAYS << GEN8_ZS_DW1_DEPTH_FUNC__SHIFT; + } + + if (depth->write_enable) + dw1 |= GEN8_ZS_DW1_DEPTH_WRITE_ENABLE; + + STATIC_ASSERT(ARRAY_SIZE(cc->ds) >= 2); + cc->ds[0] = dw1; + cc->ds[1] = dw2; + + return true; +} + +static bool +is_dual_source_blend_factor(enum gen_blend_factor factor) +{ + switch (factor) { + case GEN6_BLENDFACTOR_SRC1_COLOR: + case GEN6_BLENDFACTOR_SRC1_ALPHA: + case GEN6_BLENDFACTOR_INV_SRC1_COLOR: + case GEN6_BLENDFACTOR_INV_SRC1_ALPHA: + return true; + default: + return false; + } +} + +static bool +cc_get_gen6_dual_source_blending(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_blend_info *blend = &info->blend; + bool dual_source_blending; + uint8_t i; + + ILO_DEV_ASSERT(dev, 6, 8); + + dual_source_blending = (blend->rt_count && + (is_dual_source_blend_factor(blend->rt[0].rgb_src) || + is_dual_source_blend_factor(blend->rt[0].rgb_dst) || + is_dual_source_blend_factor(blend->rt[0].a_src) || + is_dual_source_blend_factor(blend->rt[0].a_dst))); + + /* + * From the Ivy Bridge PRM, volume 2 part 1, page 356: + * + * "Dual Source Blending: When using "Dual Source" Render Target + * Write messages, the Source1 pixel color+alpha passed in the + * message can be selected as a src/dst blend factor. See Color + * Buffer Blending. In single-source mode, those blend factor + * selections are invalid. If SRC1 is included in a src/dst blend + * factor and a DualSource RT Write message is not utilized, + * results are UNDEFINED. (This reflects the same restriction in DX + * APIs, where undefined results are produced if "o1" is not + * written by a PS - there are no default values defined). If SRC1 + * is not included in a src/dst blend factor, dual source blending + * must be disabled." + * + * From the Ivy Bridge PRM, volume 4 part 1, page 356: + * + * "The single source message will not cause a write to the render + * target if Dual Source Blend Enable in 3DSTATE_WM is enabled." + * + * "The dual source message will revert to a single source message + * using source 0 if Dual Source Blend Enable in 3DSTATE_WM is + * disabled." + * + * Dual source blending must be enabled or disabled universally. + */ + for (i = 1; i < blend->rt_count; i++) { + assert(dual_source_blending == + (is_dual_source_blend_factor(blend->rt[i].rgb_src) || + is_dual_source_blend_factor(blend->rt[i].rgb_dst) || + is_dual_source_blend_factor(blend->rt[i].a_src) || + is_dual_source_blend_factor(blend->rt[i].a_dst))); + } + + return dual_source_blending; +} + +static bool +cc_validate_gen6_alpha(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_alpha_info *alpha = &info->alpha; + + ILO_DEV_ASSERT(dev, 6, 8); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 356: + * + * "Alpha values from the pixel shader are treated as FLOAT32 format + * for computing the AlphaToCoverage Mask." + * + * From the Sandy Bridge PRM, volume 2 part 1, page 378: + * + * "If set (AlphaToCoverage Enable), Source0 Alpha is converted to a + * temporary 1/2/4-bit coverage mask and the mask bit corresponding to + * the sample# ANDed with the sample mask bit. If set, sample coverage + * is computed based on src0 alpha value. Value of 0 disables all + * samples and value of 1 enables all samples for that pixel. The same + * coverage needs to apply to all the RTs in MRT case. Further, any + * value of src0 alpha between 0 and 1 monotonically increases the + * number of enabled pixels. + * + * The same coverage needs to be applied to all the RTs in MRT case." + * + * "If set (AlphaToOne Enable), Source0 Alpha is set to 1.0f after + * (possibly) being used to generate the AlphaToCoverage coverage + * mask. + * + * The same coverage needs to be applied to all the RTs in MRT case. + * + * If Dual Source Blending is enabled, this bit must be disabled." + * + * From the Sandy Bridge PRM, volume 2 part 1, page 382: + * + * "Alpha Test can only be enabled if Pixel Shader outputs a float + * alpha value. + * + * Alpha Test is applied independently on each render target by + * comparing that render target's alpha value against the alpha + * reference value. If the alpha test fails, the corresponding pixel + * write will be supressed only for that render target. The + * depth/stencil update will occur if alpha test passes for any render + * target." + * + * From the Sandy Bridge PRM, volume 4 part 1, page 194: + * + * "Multiple render targets are supported with the single source and + * replicate data messages. Each render target is accessed with a + * separate Render Target Write message, each with a different surface + * indicated (different binding table index). The depth buffer is + * written only by the message(s) to the last render target, indicated + * by the Last Render Target Select bit set to clear the pixel + * scoreboard bits." + * + * When AlphaToCoverage/AlphaToOne/AlphaTest is enabled, it is + * required/desirable for the RT write messages to set "Source0 Alpha + * Present to RenderTarget" in the MRT case. It is also required/desirable + * for the alpha values to be FLOAT32. + */ + if (alpha->alpha_to_coverage || alpha->alpha_to_one || alpha->test_enable) + assert(alpha->cv_float_source0_alpha); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 356: + * + * "[DevSNB]: When NumSamples = 1, AlphaToCoverage and AlphaTo + * Coverage Dither both must be disabled." + */ + if (ilo_dev_gen(dev) == ILO_GEN(6) && alpha->alpha_to_coverage) + assert(alpha->cv_sample_count_one); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 378: + * + * "If Dual Source Blending is enabled, this bit (AlphaToOne Enable) + * must be disabled." + */ + if (alpha->alpha_to_one) + assert(!cc_get_gen6_dual_source_blending(dev, info)); + + return true; +} + +static bool +cc_validate_gen6_blend(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_blend_info *blend = &info->blend; + + ILO_DEV_ASSERT(dev, 6, 8); + + assert(blend->rt_count <= ILO_STATE_CC_BLEND_MAX_RT_COUNT); + + return true; +} + +static enum gen_blend_factor +get_dst_alpha_one_blend_factor(enum gen_blend_factor factor, bool is_rgb) +{ + switch (factor) { + case GEN6_BLENDFACTOR_DST_ALPHA: + return GEN6_BLENDFACTOR_ONE; + case GEN6_BLENDFACTOR_INV_DST_ALPHA: + return GEN6_BLENDFACTOR_ZERO; + case GEN6_BLENDFACTOR_SRC_ALPHA_SATURATE: + return (is_rgb) ? GEN6_BLENDFACTOR_ZERO : GEN6_BLENDFACTOR_ONE; + default: + return factor; + } +} + +static void +cc_get_gen6_effective_rt(const struct ilo_dev *dev, + const struct ilo_state_cc_info *info, + uint8_t rt_index, + struct ilo_state_cc_blend_rt_info *dst) +{ + const struct ilo_state_cc_blend_rt_info *rt = &info->blend.rt[rt_index]; + + if (rt->logicop_enable || rt->blend_enable || + rt->argb_write_disables != 0xf) + assert(rt->cv_has_buffer); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 365: + * + * "Logic Ops are only supported on *_UNORM surfaces (excluding _SRGB + * variants), otherwise Logic Ops must be DISABLED." + * + * From the Broadwell PRM, volume 7, page 671: + * + * "Logic Ops are supported on all blendable render targets and render + * targets with *INT formats." + */ + if (ilo_dev_gen(dev) < ILO_GEN(8) && rt->logicop_enable) + assert(rt->cv_is_unorm); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 361: + * + * "Only certain surface formats support Color Buffer Blending. Refer + * to the Surface Format tables in Sampling Engine. Blending must be + * disabled on a RenderTarget if blending is not supported." + * + * From the Sandy Bridge PRM, volume 2 part 1, page 365: + * + * "Color Buffer Blending and Logic Ops must not be enabled + * simultaneously, or behavior is UNDEFINED." + */ + if (rt->blend_enable) + assert(!rt->cv_is_integer && !rt->logicop_enable); + + *dst = *rt; + if (rt->blend_enable) { + /* 0x0 is reserved in enum gen_blend_factor */ + assert(rt->rgb_src && rt->rgb_dst && rt->a_src && rt->a_dst); + + if (rt->force_dst_alpha_one) { + dst->rgb_src = get_dst_alpha_one_blend_factor(rt->rgb_src, true); + dst->rgb_dst = get_dst_alpha_one_blend_factor(rt->rgb_dst, true); + dst->a_src = get_dst_alpha_one_blend_factor(rt->a_src, false); + dst->a_dst = get_dst_alpha_one_blend_factor(rt->a_dst, false); + dst->force_dst_alpha_one = false; + } + } else { + dst->rgb_src = GEN6_BLENDFACTOR_ONE; + dst->rgb_dst = GEN6_BLENDFACTOR_ZERO; + dst->rgb_func = GEN6_BLENDFUNCTION_ADD; + dst->a_src = dst->rgb_src; + dst->a_dst = dst->rgb_dst; + dst->a_func = dst->rgb_func; + } +} + +static bool +cc_set_gen6_BLEND_STATE(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_alpha_info *alpha = &info->alpha; + const struct ilo_state_cc_blend_info *blend = &info->blend; + uint32_t dw_rt[2 * ILO_STATE_CC_BLEND_MAX_RT_COUNT], dw1_invariant; + uint32_t dw0, dw1; + uint8_t i; + + ILO_DEV_ASSERT(dev, 6, 7.5); + + if (!cc_validate_gen6_alpha(dev, info) || + !cc_validate_gen6_blend(dev, info)) + return false; + + /* + * According to the Sandy Bridge PRM, volume 2 part 1, page 360, pre-blend + * and post-blend color clamps must be enabled in most cases. For the + * other cases, they are either desirable or ignored. We can enable them + * unconditionally. + */ + dw1 = GEN6_RT_DW1_COLORCLAMP_RTFORMAT | + GEN6_RT_DW1_PRE_BLEND_CLAMP | + GEN6_RT_DW1_POST_BLEND_CLAMP; + + if (alpha->alpha_to_coverage) { + dw1 |= GEN6_RT_DW1_ALPHA_TO_COVERAGE; + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 379: + * + * "[DevSNB]: This bit (AlphaToCoverage Dither Enable) must be + * disabled." + */ + if (ilo_dev_gen(dev) >= ILO_GEN(7)) + dw1 |= GEN6_RT_DW1_ALPHA_TO_COVERAGE_DITHER; + } + + if (alpha->alpha_to_one) + dw1 |= GEN6_RT_DW1_ALPHA_TO_ONE; + + if (alpha->test_enable) { + dw1 |= GEN6_RT_DW1_ALPHA_TEST_ENABLE | + alpha->test_func << GEN6_RT_DW1_ALPHA_TEST_FUNC__SHIFT; + } else { + /* + * From the Ivy Bridge PRM, volume 2 part 1, page 371: + * + * "When Alpha Test is disabled, Alpha Test Function must be + * COMPAREFUNCTION_ALWAYS." + */ + dw1 |= GEN6_COMPAREFUNCTION_ALWAYS << + GEN6_RT_DW1_ALPHA_TEST_FUNC__SHIFT; + } + + if (blend->dither_enable) + dw1 |= GEN6_RT_DW1_DITHER_ENABLE; + + dw1_invariant = dw1; + + for (i = 0; i < blend->rt_count; i++) { + struct ilo_state_cc_blend_rt_info rt; + + cc_get_gen6_effective_rt(dev, info, i, &rt); + + /* 0x0 is reserved for blend factors and we have to set them all */ + dw0 = rt.a_func << GEN6_RT_DW0_ALPHA_FUNC__SHIFT | + rt.a_src << GEN6_RT_DW0_SRC_ALPHA_FACTOR__SHIFT | + rt.a_dst << GEN6_RT_DW0_DST_ALPHA_FACTOR__SHIFT | + rt.rgb_func << GEN6_RT_DW0_COLOR_FUNC__SHIFT | + rt.rgb_src << GEN6_RT_DW0_SRC_COLOR_FACTOR__SHIFT | + rt.rgb_dst << GEN6_RT_DW0_DST_COLOR_FACTOR__SHIFT; + + if (rt.blend_enable) { + dw0 |= GEN6_RT_DW0_BLEND_ENABLE; + + if (rt.a_src != rt.rgb_src || + rt.a_dst != rt.rgb_dst || + rt.a_func != rt.rgb_func) + dw0 |= GEN6_RT_DW0_INDEPENDENT_ALPHA_ENABLE; + } + + dw1 = dw1_invariant | + rt.argb_write_disables << GEN6_RT_DW1_WRITE_DISABLES__SHIFT; + + if (rt.logicop_enable) { + dw1 |= GEN6_RT_DW1_LOGICOP_ENABLE | + rt.logicop_func << GEN6_RT_DW1_LOGICOP_FUNC__SHIFT; + } + + dw_rt[2 * i + 0] = dw0; + dw_rt[2 * i + 1] = dw1; + } + + + STATIC_ASSERT(ARRAY_SIZE(cc->blend) >= ARRAY_SIZE(dw_rt)); + memcpy(&cc->blend[0], dw_rt, sizeof(uint32_t) * 2 * blend->rt_count); + cc->blend_state_count = info->blend.rt_count; + + return true; +} + +static bool +cc_set_gen8_BLEND_STATE(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_alpha_info *alpha = &info->alpha; + const struct ilo_state_cc_blend_info *blend = &info->blend; + uint32_t dw_rt[2 * ILO_STATE_CC_BLEND_MAX_RT_COUNT], dw0, dw1; + bool indep_alpha_enable; + uint8_t i; + + ILO_DEV_ASSERT(dev, 8, 8); + + if (!cc_validate_gen6_alpha(dev, info) || + !cc_validate_gen6_blend(dev, info)) + return false; + + indep_alpha_enable = false; + for (i = 0; i < blend->rt_count; i++) { + struct ilo_state_cc_blend_rt_info rt; + + cc_get_gen6_effective_rt(dev, info, i, &rt); + + dw0 = rt.rgb_src << GEN8_RT_DW0_SRC_COLOR_FACTOR__SHIFT | + rt.rgb_dst << GEN8_RT_DW0_DST_COLOR_FACTOR__SHIFT | + rt.rgb_func << GEN8_RT_DW0_COLOR_FUNC__SHIFT | + rt.a_src << GEN8_RT_DW0_SRC_ALPHA_FACTOR__SHIFT | + rt.a_dst << GEN8_RT_DW0_DST_ALPHA_FACTOR__SHIFT | + rt.a_func << GEN8_RT_DW0_ALPHA_FUNC__SHIFT | + rt.argb_write_disables << GEN8_RT_DW0_WRITE_DISABLES__SHIFT; + + if (rt.blend_enable) { + dw0 |= GEN8_RT_DW0_BLEND_ENABLE; + + if (rt.a_src != rt.rgb_src || + rt.a_dst != rt.rgb_dst || + rt.a_func != rt.rgb_func) + indep_alpha_enable = true; + } + + dw1 = GEN8_RT_DW1_COLORCLAMP_RTFORMAT | + GEN8_RT_DW1_PRE_BLEND_CLAMP | + GEN8_RT_DW1_POST_BLEND_CLAMP; + + if (rt.logicop_enable) { + dw1 |= GEN8_RT_DW1_LOGICOP_ENABLE | + rt.logicop_func << GEN8_RT_DW1_LOGICOP_FUNC__SHIFT; + } + + dw_rt[2 * i + 0] = dw0; + dw_rt[2 * i + 1] = dw1; + } + + dw0 = 0; + + if (alpha->alpha_to_coverage) { + dw0 |= GEN8_BLEND_DW0_ALPHA_TO_COVERAGE | + GEN8_BLEND_DW0_ALPHA_TO_COVERAGE_DITHER; + } + + if (indep_alpha_enable) + dw0 |= GEN8_BLEND_DW0_INDEPENDENT_ALPHA_ENABLE; + + if (alpha->alpha_to_one) + dw0 |= GEN8_BLEND_DW0_ALPHA_TO_ONE; + + if (alpha->test_enable) { + dw0 |= GEN8_BLEND_DW0_ALPHA_TEST_ENABLE | + alpha->test_func << GEN8_BLEND_DW0_ALPHA_TEST_FUNC__SHIFT; + } else { + dw0 |= GEN6_COMPAREFUNCTION_ALWAYS << + GEN8_BLEND_DW0_ALPHA_TEST_FUNC__SHIFT; + } + + if (blend->dither_enable) + dw0 |= GEN8_BLEND_DW0_DITHER_ENABLE; + + STATIC_ASSERT(ARRAY_SIZE(cc->blend) >= 2 + ARRAY_SIZE(dw_rt)); + cc->blend[1] = dw0; + memcpy(&cc->blend[2], dw_rt, sizeof(uint32_t) * 2 * blend->rt_count); + cc->blend_state_count = info->blend.rt_count; + + return true; +} + +static bool +cc_set_gen8_3DSTATE_PS_BLEND(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + const struct ilo_state_cc_alpha_info *alpha = &info->alpha; + const struct ilo_state_cc_blend_info *blend = &info->blend; + uint32_t dw1; + + ILO_DEV_ASSERT(dev, 8, 8); + + dw1 = 0; + + if (alpha->alpha_to_coverage) + dw1 |= GEN8_PS_BLEND_DW1_ALPHA_TO_COVERAGE; + + if (alpha->test_enable) + dw1 |= GEN8_PS_BLEND_DW1_ALPHA_TEST_ENABLE; + + if (blend->rt_count) { + struct ilo_state_cc_blend_rt_info rt0; + uint8_t i; + + cc_get_gen6_effective_rt(dev, info, 0, &rt0); + + /* 0x0 is reserved for blend factors and we have to set them all */ + dw1 |= rt0.a_src << GEN8_PS_BLEND_DW1_SRC_ALPHA_FACTOR__SHIFT | + rt0.a_dst << GEN8_PS_BLEND_DW1_DST_ALPHA_FACTOR__SHIFT | + rt0.rgb_src << GEN8_PS_BLEND_DW1_SRC_COLOR_FACTOR__SHIFT | + rt0.rgb_dst << GEN8_PS_BLEND_DW1_DST_COLOR_FACTOR__SHIFT; + + for (i = 0; i < blend->rt_count; i++) { + if (blend->rt[i].argb_write_disables != 0xf) { + dw1 |= GEN8_PS_BLEND_DW1_WRITABLE_RT; + break; + } + } + + if (rt0.blend_enable) { + dw1 |= GEN8_PS_BLEND_DW1_BLEND_ENABLE; + + if (rt0.a_src != rt0.rgb_src || rt0.a_dst != rt0.rgb_dst) + dw1 |= GEN8_PS_BLEND_DW1_INDEPENDENT_ALPHA_ENABLE; + } + } + + STATIC_ASSERT(ARRAY_SIZE(cc->blend) >= 1); + cc->blend[0] = dw1; + + return true; +} + +static bool +cc_params_set_gen6_COLOR_CALC_STATE(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_params_info *params) +{ + uint32_t dw0; + + ILO_DEV_ASSERT(dev, 6, 8); + + dw0 = params->stencil_front.test_ref << GEN6_CC_DW0_STENCIL_REF__SHIFT | + params->stencil_back.test_ref << GEN6_CC_DW0_STENCIL1_REF__SHIFT | + GEN6_CC_DW0_ALPHATEST_FLOAT32; + + STATIC_ASSERT(ARRAY_SIZE(cc->cc) >= 6); + cc->cc[0] = dw0; + cc->cc[1] = fui(params->alpha_ref); + cc->cc[2] = fui(params->blend_rgba[0]); + cc->cc[3] = fui(params->blend_rgba[1]); + cc->cc[4] = fui(params->blend_rgba[2]); + cc->cc[5] = fui(params->blend_rgba[3]); + + return true; +} + +bool +ilo_state_cc_init(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + assert(ilo_is_zeroed(cc, sizeof(*cc))); + return ilo_state_cc_set_info(cc, dev, info); +} + +bool +ilo_state_cc_set_info(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info) +{ + bool ret = true; + + if (ilo_dev_gen(dev) >= ILO_GEN(8)) { + ret &= cc_set_gen8_3DSTATE_WM_DEPTH_STENCIL(cc, dev, info); + ret &= cc_set_gen8_BLEND_STATE(cc, dev, info); + ret &= cc_set_gen8_3DSTATE_PS_BLEND(cc, dev, info); + } else { + ret &= cc_set_gen6_DEPTH_STENCIL_STATE(cc, dev, info); + ret &= cc_set_gen6_BLEND_STATE(cc, dev, info); + } + + ret &= cc_params_set_gen6_COLOR_CALC_STATE(cc, dev, &info->params); + + assert(ret); + + return ret; +} + +bool +ilo_state_cc_set_params(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_params_info *params) +{ + /* modify stencil masks */ + if (ilo_dev_gen(dev) >= ILO_GEN(8)) { + uint32_t dw1 = cc->ds[0]; + uint32_t dw2 = cc->ds[1]; + + if (dw1 & GEN8_ZS_DW1_STENCIL_TEST_ENABLE) { + const bool twosided_enable = (dw1 & GEN8_ZS_DW1_STENCIL1_ENABLE); + const struct ilo_state_cc_stencil_params_info *front_p = + ¶ms->stencil_front; + const struct ilo_state_cc_stencil_params_info *back_p = + (twosided_enable) ? ¶ms->stencil_back : + ¶ms->stencil_front; + + if (front_p->write_mask || back_p->write_mask) + dw1 |= GEN8_ZS_DW1_STENCIL_WRITE_ENABLE; + else + dw1 &= ~GEN8_ZS_DW1_STENCIL_WRITE_ENABLE; + + dw2 = + front_p->test_mask << GEN8_ZS_DW2_STENCIL_TEST_MASK__SHIFT | + front_p->write_mask << GEN8_ZS_DW2_STENCIL_WRITE_MASK__SHIFT | + back_p->test_mask << GEN8_ZS_DW2_STENCIL1_TEST_MASK__SHIFT | + back_p->write_mask << GEN8_ZS_DW2_STENCIL1_WRITE_MASK__SHIFT; + } + + cc->ds[0] = dw1; + cc->ds[1] = dw2; + } else { + uint32_t dw0 = cc->ds[0]; + uint32_t dw1 = cc->ds[1]; + + if (dw0 & GEN6_ZS_DW0_STENCIL_TEST_ENABLE) { + const bool twosided_enable = (dw0 & GEN6_ZS_DW0_STENCIL1_ENABLE); + const struct ilo_state_cc_stencil_params_info *front_p = + ¶ms->stencil_front; + const struct ilo_state_cc_stencil_params_info *back_p = + (twosided_enable) ? ¶ms->stencil_back : + ¶ms->stencil_front; + + if (front_p->write_mask || back_p->write_mask) + dw0 |= GEN6_ZS_DW0_STENCIL_WRITE_ENABLE; + else + dw0 &= ~GEN6_ZS_DW0_STENCIL_WRITE_ENABLE; + + dw1 = + front_p->test_mask << GEN6_ZS_DW1_STENCIL_TEST_MASK__SHIFT | + front_p->write_mask << GEN6_ZS_DW1_STENCIL_WRITE_MASK__SHIFT | + back_p->test_mask << GEN6_ZS_DW1_STENCIL1_TEST_MASK__SHIFT | + back_p->write_mask << GEN6_ZS_DW1_STENCIL1_WRITE_MASK__SHIFT; + } + + cc->ds[0] = dw0; + cc->ds[1] = dw1; + } + + /* modify COLOR_CALC_STATE */ + cc_params_set_gen6_COLOR_CALC_STATE(cc, dev, params); + + return true; +} + +void +ilo_state_cc_full_delta(const struct ilo_state_cc *cc, + const struct ilo_dev *dev, + struct ilo_state_cc_delta *delta) +{ + delta->dirty = ILO_STATE_CC_BLEND_STATE | + ILO_STATE_CC_COLOR_CALC_STATE; + + if (ilo_dev_gen(dev) >= ILO_GEN(8)) { + delta->dirty |= ILO_STATE_CC_3DSTATE_WM_DEPTH_STENCIL | + ILO_STATE_CC_3DSTATE_PS_BLEND; + } else { + delta->dirty |= ILO_STATE_CC_DEPTH_STENCIL_STATE; + } +} + +void +ilo_state_cc_get_delta(const struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc *old, + struct ilo_state_cc_delta *delta) +{ + delta->dirty = 0; + + if (memcmp(cc->ds, old->ds, sizeof(cc->ds))) { + if (ilo_dev_gen(dev) >= ILO_GEN(8)) + delta->dirty |= ILO_STATE_CC_3DSTATE_WM_DEPTH_STENCIL; + else + delta->dirty |= ILO_STATE_CC_DEPTH_STENCIL_STATE; + } + + if (ilo_dev_gen(dev) >= ILO_GEN(8)) { + if (cc->blend[0] != old->blend[0]) + delta->dirty |= ILO_STATE_CC_3DSTATE_PS_BLEND; + + if (memcmp(&cc->blend[1], &old->blend[1], + sizeof(uint32_t) * (1 + 2 * cc->blend_state_count))) + delta->dirty |= ILO_STATE_CC_BLEND_STATE; + } else if (memcmp(cc->blend, old->blend, + sizeof(uint32_t) * 2 * cc->blend_state_count)) { + delta->dirty |= ILO_STATE_CC_BLEND_STATE; + } + + if (memcmp(cc->cc, old->cc, sizeof(cc->cc))) + delta->dirty |= ILO_STATE_CC_COLOR_CALC_STATE; +} diff --git a/src/gallium/drivers/ilo/core/ilo_state_cc.h b/src/gallium/drivers/ilo/core/ilo_state_cc.h new file mode 100644 index 00000000000..5b96a60f988 --- /dev/null +++ b/src/gallium/drivers/ilo/core/ilo_state_cc.h @@ -0,0 +1,199 @@ +/* + * 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_CC_H +#define ILO_STATE_CC_H + +#include "genhw/genhw.h" + +#include "ilo_core.h" +#include "ilo_dev.h" + +/* + * From the Sandy Bridge PRM, volume 2 part 1, page 38: + * + * "Render Target Index. Specifies the render target index that will be + * used to select blend state from BLEND_STATE. + * Format = U3" + */ +#define ILO_STATE_CC_BLEND_MAX_RT_COUNT 8 + +enum ilo_state_cc_dirty_bits { + ILO_STATE_CC_3DSTATE_WM_DEPTH_STENCIL = (1 << 0), + ILO_STATE_CC_3DSTATE_PS_BLEND = (1 << 1), + ILO_STATE_CC_DEPTH_STENCIL_STATE = (1 << 2), + ILO_STATE_CC_BLEND_STATE = (1 << 3), + ILO_STATE_CC_COLOR_CALC_STATE = (1 << 4), +}; + +/** + * AlphaCoverage and AlphaTest. + */ +struct ilo_state_cc_alpha_info { + bool cv_sample_count_one; + bool cv_float_source0_alpha; + + bool alpha_to_coverage; + bool alpha_to_one; + + bool test_enable; + enum gen_compare_function test_func; +}; + +struct ilo_state_cc_stencil_op_info { + enum gen_compare_function test_func; + enum gen_stencil_op fail_op; + enum gen_stencil_op zfail_op; + enum gen_stencil_op zpass_op; +}; + +/** + * StencilTest. + */ +struct ilo_state_cc_stencil_info { + bool cv_has_buffer; + + bool test_enable; + bool twosided_enable; + + struct ilo_state_cc_stencil_op_info front; + struct ilo_state_cc_stencil_op_info back; +}; + +/** + * DepthTest. + */ +struct ilo_state_cc_depth_info { + bool cv_has_buffer; + + bool test_enable; + /* independent from test_enable */ + bool write_enable; + + enum gen_compare_function test_func; +}; + +struct ilo_state_cc_blend_rt_info { + bool cv_has_buffer; + bool cv_is_unorm; + bool cv_is_integer; + + uint8_t argb_write_disables; + + bool logicop_enable; + enum gen_logic_op logicop_func; + + bool blend_enable; + bool force_dst_alpha_one; + enum gen_blend_factor rgb_src; + enum gen_blend_factor rgb_dst; + enum gen_blend_function rgb_func; + enum gen_blend_factor a_src; + enum gen_blend_factor a_dst; + enum gen_blend_function a_func; +}; + +/** + * ColorBufferBlending, Dithering, and LogicOps. + */ +struct ilo_state_cc_blend_info { + const struct ilo_state_cc_blend_rt_info *rt; + uint8_t rt_count; + + bool dither_enable; +}; + +struct ilo_state_cc_stencil_params_info { + uint8_t test_ref; + uint8_t test_mask; + uint8_t write_mask; +}; + +/** + * CC parameters. + */ +struct ilo_state_cc_params_info { + float alpha_ref; + + struct ilo_state_cc_stencil_params_info stencil_front; + struct ilo_state_cc_stencil_params_info stencil_back; + + float blend_rgba[4]; +}; + +/** + * Pixel processing. + */ +struct ilo_state_cc_info { + struct ilo_state_cc_alpha_info alpha; + struct ilo_state_cc_stencil_info stencil; + struct ilo_state_cc_depth_info depth; + struct ilo_state_cc_blend_info blend; + + struct ilo_state_cc_params_info params; +}; + +struct ilo_state_cc { + uint32_t ds[3]; + + uint8_t blend_state_count; + uint32_t blend[1 + 1 + 2 * ILO_STATE_CC_BLEND_MAX_RT_COUNT]; + + uint32_t cc[6]; +}; + +struct ilo_state_cc_delta { + uint32_t dirty; +}; + +bool +ilo_state_cc_init(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info); + +bool +ilo_state_cc_set_info(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_info *info); + +bool +ilo_state_cc_set_params(struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc_params_info *params); + +void +ilo_state_cc_full_delta(const struct ilo_state_cc *cc, + const struct ilo_dev *dev, + struct ilo_state_cc_delta *delta); + +void +ilo_state_cc_get_delta(const struct ilo_state_cc *cc, + const struct ilo_dev *dev, + const struct ilo_state_cc *old, + struct ilo_state_cc_delta *delta); + +#endif /* ILO_STATE_CC_H */ -- 2.30.2