101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2014-2017 Broadcom
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
247ec681f3Smrg#include "util/format/u_format.h"
257ec681f3Smrg#include "util/half_float.h"
2601e04c3fSmrg#include "v3d_context.h"
2701e04c3fSmrg#include "broadcom/common/v3d_macros.h"
2801e04c3fSmrg#include "broadcom/cle/v3dx_pack.h"
2901e04c3fSmrg#include "broadcom/compiler/v3d_compiler.h"
3001e04c3fSmrg
3101e04c3fSmrgstatic uint8_t
3201e04c3fSmrgv3d_factor(enum pipe_blendfactor factor, bool dst_alpha_one)
3301e04c3fSmrg{
3401e04c3fSmrg        /* We may get a bad blendfactor when blending is disabled. */
3501e04c3fSmrg        if (factor == 0)
3601e04c3fSmrg                return V3D_BLEND_FACTOR_ZERO;
3701e04c3fSmrg
3801e04c3fSmrg        switch (factor) {
3901e04c3fSmrg        case PIPE_BLENDFACTOR_ZERO:
4001e04c3fSmrg                return V3D_BLEND_FACTOR_ZERO;
4101e04c3fSmrg        case PIPE_BLENDFACTOR_ONE:
4201e04c3fSmrg                return V3D_BLEND_FACTOR_ONE;
4301e04c3fSmrg        case PIPE_BLENDFACTOR_SRC_COLOR:
4401e04c3fSmrg                return V3D_BLEND_FACTOR_SRC_COLOR;
4501e04c3fSmrg        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
4601e04c3fSmrg                return V3D_BLEND_FACTOR_INV_SRC_COLOR;
4701e04c3fSmrg        case PIPE_BLENDFACTOR_DST_COLOR:
4801e04c3fSmrg                return V3D_BLEND_FACTOR_DST_COLOR;
4901e04c3fSmrg        case PIPE_BLENDFACTOR_INV_DST_COLOR:
5001e04c3fSmrg                return V3D_BLEND_FACTOR_INV_DST_COLOR;
5101e04c3fSmrg        case PIPE_BLENDFACTOR_SRC_ALPHA:
5201e04c3fSmrg                return V3D_BLEND_FACTOR_SRC_ALPHA;
5301e04c3fSmrg        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
5401e04c3fSmrg                return V3D_BLEND_FACTOR_INV_SRC_ALPHA;
5501e04c3fSmrg        case PIPE_BLENDFACTOR_DST_ALPHA:
5601e04c3fSmrg                return (dst_alpha_one ?
5701e04c3fSmrg                        V3D_BLEND_FACTOR_ONE :
5801e04c3fSmrg                        V3D_BLEND_FACTOR_DST_ALPHA);
5901e04c3fSmrg        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
6001e04c3fSmrg                return (dst_alpha_one ?
6101e04c3fSmrg                        V3D_BLEND_FACTOR_ZERO :
6201e04c3fSmrg                        V3D_BLEND_FACTOR_INV_DST_ALPHA);
6301e04c3fSmrg        case PIPE_BLENDFACTOR_CONST_COLOR:
6401e04c3fSmrg                return V3D_BLEND_FACTOR_CONST_COLOR;
6501e04c3fSmrg        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
6601e04c3fSmrg                return V3D_BLEND_FACTOR_INV_CONST_COLOR;
6701e04c3fSmrg        case PIPE_BLENDFACTOR_CONST_ALPHA:
6801e04c3fSmrg                return V3D_BLEND_FACTOR_CONST_ALPHA;
6901e04c3fSmrg        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
7001e04c3fSmrg                return V3D_BLEND_FACTOR_INV_CONST_ALPHA;
7101e04c3fSmrg        case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
7201e04c3fSmrg                return (dst_alpha_one ?
7301e04c3fSmrg                        V3D_BLEND_FACTOR_ZERO :
7401e04c3fSmrg                        V3D_BLEND_FACTOR_SRC_ALPHA_SATURATE);
7501e04c3fSmrg        default:
7601e04c3fSmrg                unreachable("Bad blend factor");
7701e04c3fSmrg        }
7801e04c3fSmrg}
7901e04c3fSmrg
8001e04c3fSmrgstatic inline uint16_t
8101e04c3fSmrgswizzled_border_color(const struct v3d_device_info *devinfo,
8201e04c3fSmrg                      struct pipe_sampler_state *sampler,
8301e04c3fSmrg                      struct v3d_sampler_view *sview,
8401e04c3fSmrg                      int chan)
8501e04c3fSmrg{
8601e04c3fSmrg        const struct util_format_description *desc =
8701e04c3fSmrg                util_format_description(sview->base.format);
8801e04c3fSmrg        uint8_t swiz = chan;
8901e04c3fSmrg
9001e04c3fSmrg        /* If we're doing swizzling in the sampler, then only rearrange the
917ec681f3Smrg         * border color for the mismatch between the V3D texture format and
9201e04c3fSmrg         * the PIPE_FORMAT, since GL_ARB_texture_swizzle will be handled by
9301e04c3fSmrg         * the sampler's swizzle.
9401e04c3fSmrg         *
9501e04c3fSmrg         * For swizzling in the shader, we don't do any pre-swizzling of the
9601e04c3fSmrg         * border color.
9701e04c3fSmrg         */
9801e04c3fSmrg        if (v3d_get_tex_return_size(devinfo, sview->base.format,
9901e04c3fSmrg                                    sampler->compare_mode) != 32)
10001e04c3fSmrg                swiz = desc->swizzle[swiz];
10101e04c3fSmrg
10201e04c3fSmrg        switch (swiz) {
10301e04c3fSmrg        case PIPE_SWIZZLE_0:
1047ec681f3Smrg                return _mesa_float_to_half(0.0);
10501e04c3fSmrg        case PIPE_SWIZZLE_1:
1067ec681f3Smrg                return _mesa_float_to_half(1.0);
10701e04c3fSmrg        default:
1087ec681f3Smrg                return _mesa_float_to_half(sampler->border_color.f[swiz]);
10901e04c3fSmrg        }
11001e04c3fSmrg}
11101e04c3fSmrg
11201e04c3fSmrg#if V3D_VERSION < 40
11301e04c3fSmrgstatic uint32_t
11401e04c3fSmrgtranslate_swizzle(unsigned char pipe_swizzle)
11501e04c3fSmrg{
11601e04c3fSmrg        switch (pipe_swizzle) {
11701e04c3fSmrg        case PIPE_SWIZZLE_0:
11801e04c3fSmrg                return 0;
11901e04c3fSmrg        case PIPE_SWIZZLE_1:
12001e04c3fSmrg                return 1;
12101e04c3fSmrg        case PIPE_SWIZZLE_X:
12201e04c3fSmrg        case PIPE_SWIZZLE_Y:
12301e04c3fSmrg        case PIPE_SWIZZLE_Z:
12401e04c3fSmrg        case PIPE_SWIZZLE_W:
12501e04c3fSmrg                return 2 + pipe_swizzle;
12601e04c3fSmrg        default:
12701e04c3fSmrg                unreachable("unknown swizzle");
12801e04c3fSmrg        }
12901e04c3fSmrg}
13001e04c3fSmrg
13101e04c3fSmrgstatic void
13201e04c3fSmrgemit_one_texture(struct v3d_context *v3d, struct v3d_texture_stateobj *stage_tex,
13301e04c3fSmrg                 int i)
13401e04c3fSmrg{
13501e04c3fSmrg        struct v3d_job *job = v3d->job;
13601e04c3fSmrg        struct pipe_sampler_state *psampler = stage_tex->samplers[i];
13701e04c3fSmrg        struct v3d_sampler_state *sampler = v3d_sampler_state(psampler);
13801e04c3fSmrg        struct pipe_sampler_view *psview = stage_tex->textures[i];
13901e04c3fSmrg        struct v3d_sampler_view *sview = v3d_sampler_view(psview);
14001e04c3fSmrg        struct pipe_resource *prsc = psview->texture;
14101e04c3fSmrg        struct v3d_resource *rsc = v3d_resource(prsc);
14201e04c3fSmrg        const struct v3d_device_info *devinfo = &v3d->screen->devinfo;
14301e04c3fSmrg
14401e04c3fSmrg        stage_tex->texture_state[i].offset =
14501e04c3fSmrg                v3d_cl_ensure_space(&job->indirect,
14601e04c3fSmrg                                    cl_packet_length(TEXTURE_SHADER_STATE),
14701e04c3fSmrg                                    32);
14801e04c3fSmrg        v3d_bo_set_reference(&stage_tex->texture_state[i].bo,
14901e04c3fSmrg                             job->indirect.bo);
15001e04c3fSmrg
15101e04c3fSmrg        uint32_t return_size = v3d_get_tex_return_size(devinfo, psview->format,
15201e04c3fSmrg                                                       psampler->compare_mode);
15301e04c3fSmrg
15401e04c3fSmrg        struct V3D33_TEXTURE_SHADER_STATE unpacked = {
15501e04c3fSmrg                /* XXX */
15601e04c3fSmrg                .border_color_red = swizzled_border_color(devinfo, psampler,
15701e04c3fSmrg                                                          sview, 0),
15801e04c3fSmrg                .border_color_green = swizzled_border_color(devinfo, psampler,
15901e04c3fSmrg                                                            sview, 1),
16001e04c3fSmrg                .border_color_blue = swizzled_border_color(devinfo, psampler,
16101e04c3fSmrg                                                           sview, 2),
16201e04c3fSmrg                .border_color_alpha = swizzled_border_color(devinfo, psampler,
16301e04c3fSmrg                                                            sview, 3),
16401e04c3fSmrg
16501e04c3fSmrg                /* In the normal texturing path, the LOD gets clamped between
16601e04c3fSmrg                 * min/max, and the base_level field (set in the sampler view
16701e04c3fSmrg                 * from first_level) only decides where the min/mag switch
16801e04c3fSmrg                 * happens, so we need to use the LOD clamps to keep us
16901e04c3fSmrg                 * between min and max.
17001e04c3fSmrg                 *
17101e04c3fSmrg                 * For txf, the LOD clamp is still used, despite GL not
17201e04c3fSmrg                 * wanting that.  We will need to have a separate
17301e04c3fSmrg                 * TEXTURE_SHADER_STATE that ignores psview->min/max_lod to
17401e04c3fSmrg                 * support txf properly.
17501e04c3fSmrg                 */
17601e04c3fSmrg                .min_level_of_detail = MIN2(psview->u.tex.first_level +
17701e04c3fSmrg                                            MAX2(psampler->min_lod, 0),
17801e04c3fSmrg                                            psview->u.tex.last_level),
17901e04c3fSmrg                .max_level_of_detail = MIN2(psview->u.tex.first_level +
1807ec681f3Smrg                                            MAX2(psampler->max_lod,
1817ec681f3Smrg                                                 psampler->min_lod),
18201e04c3fSmrg                                            psview->u.tex.last_level),
18301e04c3fSmrg
18401e04c3fSmrg                .texture_base_pointer = cl_address(rsc->bo,
18501e04c3fSmrg                                                   rsc->slices[0].offset),
18601e04c3fSmrg
18701e04c3fSmrg                .output_32_bit = return_size == 32,
18801e04c3fSmrg        };
18901e04c3fSmrg
19001e04c3fSmrg        /* Set up the sampler swizzle if we're doing 16-bit sampling.  For
19101e04c3fSmrg         * 32-bit, we leave swizzling up to the shader compiler.
19201e04c3fSmrg         *
19301e04c3fSmrg         * Note: Contrary to the docs, the swizzle still applies even if the
19401e04c3fSmrg         * return size is 32.  It's just that you probably want to swizzle in
19501e04c3fSmrg         * the shader, because you need the Y/Z/W channels to be defined.
19601e04c3fSmrg         */
19701e04c3fSmrg        if (return_size == 32) {
19801e04c3fSmrg                unpacked.swizzle_r = translate_swizzle(PIPE_SWIZZLE_X);
19901e04c3fSmrg                unpacked.swizzle_g = translate_swizzle(PIPE_SWIZZLE_Y);
20001e04c3fSmrg                unpacked.swizzle_b = translate_swizzle(PIPE_SWIZZLE_Z);
20101e04c3fSmrg                unpacked.swizzle_a = translate_swizzle(PIPE_SWIZZLE_W);
20201e04c3fSmrg        } else {
20301e04c3fSmrg                unpacked.swizzle_r = translate_swizzle(sview->swizzle[0]);
20401e04c3fSmrg                unpacked.swizzle_g = translate_swizzle(sview->swizzle[1]);
20501e04c3fSmrg                unpacked.swizzle_b = translate_swizzle(sview->swizzle[2]);
20601e04c3fSmrg                unpacked.swizzle_a = translate_swizzle(sview->swizzle[3]);
20701e04c3fSmrg        }
20801e04c3fSmrg
20901e04c3fSmrg        int min_img_filter = psampler->min_img_filter;
21001e04c3fSmrg        int min_mip_filter = psampler->min_mip_filter;
21101e04c3fSmrg        int mag_img_filter = psampler->mag_img_filter;
21201e04c3fSmrg
21301e04c3fSmrg        if (return_size == 32) {
21401e04c3fSmrg                min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
21501e04c3fSmrg                min_img_filter = PIPE_TEX_FILTER_NEAREST;
21601e04c3fSmrg                mag_img_filter = PIPE_TEX_FILTER_NEAREST;
21701e04c3fSmrg        }
21801e04c3fSmrg
21901e04c3fSmrg        bool min_nearest = min_img_filter == PIPE_TEX_FILTER_NEAREST;
22001e04c3fSmrg        switch (min_mip_filter) {
22101e04c3fSmrg        case PIPE_TEX_MIPFILTER_NONE:
22201e04c3fSmrg                unpacked.filter += min_nearest ? 2 : 0;
22301e04c3fSmrg                break;
22401e04c3fSmrg        case PIPE_TEX_MIPFILTER_NEAREST:
22501e04c3fSmrg                unpacked.filter += min_nearest ? 4 : 8;
22601e04c3fSmrg                break;
22701e04c3fSmrg        case PIPE_TEX_MIPFILTER_LINEAR:
22801e04c3fSmrg                unpacked.filter += min_nearest ? 4 : 8;
22901e04c3fSmrg                unpacked.filter += 2;
23001e04c3fSmrg                break;
23101e04c3fSmrg        }
23201e04c3fSmrg
23301e04c3fSmrg        if (mag_img_filter == PIPE_TEX_FILTER_NEAREST)
23401e04c3fSmrg                unpacked.filter++;
23501e04c3fSmrg
23601e04c3fSmrg        if (psampler->max_anisotropy > 8)
23701e04c3fSmrg                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_16_1;
23801e04c3fSmrg        else if (psampler->max_anisotropy > 4)
23901e04c3fSmrg                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_8_1;
24001e04c3fSmrg        else if (psampler->max_anisotropy > 2)
24101e04c3fSmrg                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_4_1;
24201e04c3fSmrg        else if (psampler->max_anisotropy)
24301e04c3fSmrg                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_2_1;
24401e04c3fSmrg
24501e04c3fSmrg        uint8_t packed[cl_packet_length(TEXTURE_SHADER_STATE)];
24601e04c3fSmrg        cl_packet_pack(TEXTURE_SHADER_STATE)(&job->indirect, packed, &unpacked);
24701e04c3fSmrg
24801e04c3fSmrg        for (int i = 0; i < ARRAY_SIZE(packed); i++)
24901e04c3fSmrg                packed[i] |= sview->texture_shader_state[i] | sampler->texture_shader_state[i];
25001e04c3fSmrg
25101e04c3fSmrg        /* TMU indirect structs need to be 32b aligned. */
25201e04c3fSmrg        v3d_cl_ensure_space(&job->indirect, ARRAY_SIZE(packed), 32);
25301e04c3fSmrg        cl_emit_prepacked(&job->indirect, &packed);
25401e04c3fSmrg}
25501e04c3fSmrg
25601e04c3fSmrgstatic void
25701e04c3fSmrgemit_textures(struct v3d_context *v3d, struct v3d_texture_stateobj *stage_tex)
25801e04c3fSmrg{
25901e04c3fSmrg        for (int i = 0; i < stage_tex->num_textures; i++) {
26001e04c3fSmrg                if (stage_tex->textures[i])
26101e04c3fSmrg                        emit_one_texture(v3d, stage_tex, i);
26201e04c3fSmrg        }
26301e04c3fSmrg}
26401e04c3fSmrg#endif /* V3D_VERSION < 40 */
26501e04c3fSmrg
26601e04c3fSmrgstatic uint32_t
26701e04c3fSmrgtranslate_colormask(struct v3d_context *v3d, uint32_t colormask, int rt)
26801e04c3fSmrg{
26901e04c3fSmrg        if (v3d->swap_color_rb & (1 << rt)) {
27001e04c3fSmrg                colormask = ((colormask & (2 | 8)) |
27101e04c3fSmrg                             ((colormask & 1) << 2) |
27201e04c3fSmrg                             ((colormask & 4) >> 2));
27301e04c3fSmrg        }
27401e04c3fSmrg
27501e04c3fSmrg        return (~colormask) & 0xf;
27601e04c3fSmrg}
27701e04c3fSmrg
27801e04c3fSmrgstatic void
27901e04c3fSmrgemit_rt_blend(struct v3d_context *v3d, struct v3d_job *job,
28001e04c3fSmrg              struct pipe_blend_state *blend, int rt)
28101e04c3fSmrg{
28201e04c3fSmrg        struct pipe_rt_blend_state *rtblend = &blend->rt[rt];
28301e04c3fSmrg
28401e04c3fSmrg#if V3D_VERSION >= 40
28501e04c3fSmrg        /* We don't need to emit blend state for disabled RTs. */
28601e04c3fSmrg        if (!rtblend->blend_enable)
28701e04c3fSmrg                return;
28801e04c3fSmrg#endif
28901e04c3fSmrg
29001e04c3fSmrg        cl_emit(&job->bcl, BLEND_CFG, config) {
29101e04c3fSmrg#if V3D_VERSION >= 40
29201e04c3fSmrg                if (blend->independent_blend_enable)
29301e04c3fSmrg                        config.render_target_mask = 1 << rt;
29401e04c3fSmrg                else
2959f464c52Smaya                        config.render_target_mask = (1 << V3D_MAX_DRAW_BUFFERS) - 1;
29601e04c3fSmrg#else
29701e04c3fSmrg                assert(rt == 0);
29801e04c3fSmrg#endif
29901e04c3fSmrg
30001e04c3fSmrg                config.color_blend_mode = rtblend->rgb_func;
30101e04c3fSmrg                config.color_blend_dst_factor =
30201e04c3fSmrg                        v3d_factor(rtblend->rgb_dst_factor,
30301e04c3fSmrg                                   v3d->blend_dst_alpha_one);
30401e04c3fSmrg                config.color_blend_src_factor =
30501e04c3fSmrg                        v3d_factor(rtblend->rgb_src_factor,
30601e04c3fSmrg                                   v3d->blend_dst_alpha_one);
30701e04c3fSmrg
30801e04c3fSmrg                config.alpha_blend_mode = rtblend->alpha_func;
30901e04c3fSmrg                config.alpha_blend_dst_factor =
31001e04c3fSmrg                        v3d_factor(rtblend->alpha_dst_factor,
31101e04c3fSmrg                                   v3d->blend_dst_alpha_one);
31201e04c3fSmrg                config.alpha_blend_src_factor =
31301e04c3fSmrg                        v3d_factor(rtblend->alpha_src_factor,
31401e04c3fSmrg                                   v3d->blend_dst_alpha_one);
31501e04c3fSmrg        }
31601e04c3fSmrg}
31701e04c3fSmrg
31801e04c3fSmrgstatic void
31901e04c3fSmrgemit_flat_shade_flags(struct v3d_job *job,
32001e04c3fSmrg                      int varying_offset,
32101e04c3fSmrg                      uint32_t varyings,
32201e04c3fSmrg                      enum V3DX(Varying_Flags_Action) lower,
32301e04c3fSmrg                      enum V3DX(Varying_Flags_Action) higher)
32401e04c3fSmrg{
32501e04c3fSmrg        cl_emit(&job->bcl, FLAT_SHADE_FLAGS, flags) {
32601e04c3fSmrg                flags.varying_offset_v0 = varying_offset;
32701e04c3fSmrg                flags.flat_shade_flags_for_varyings_v024 = varyings;
32801e04c3fSmrg                flags.action_for_flat_shade_flags_of_lower_numbered_varyings =
32901e04c3fSmrg                        lower;
33001e04c3fSmrg                flags.action_for_flat_shade_flags_of_higher_numbered_varyings =
33101e04c3fSmrg                        higher;
33201e04c3fSmrg        }
33301e04c3fSmrg}
33401e04c3fSmrg
33501e04c3fSmrg#if V3D_VERSION >= 40
33601e04c3fSmrgstatic void
33701e04c3fSmrgemit_noperspective_flags(struct v3d_job *job,
33801e04c3fSmrg                         int varying_offset,
33901e04c3fSmrg                         uint32_t varyings,
34001e04c3fSmrg                         enum V3DX(Varying_Flags_Action) lower,
34101e04c3fSmrg                         enum V3DX(Varying_Flags_Action) higher)
34201e04c3fSmrg{
34301e04c3fSmrg        cl_emit(&job->bcl, NON_PERSPECTIVE_FLAGS, flags) {
34401e04c3fSmrg                flags.varying_offset_v0 = varying_offset;
34501e04c3fSmrg                flags.non_perspective_flags_for_varyings_v024 = varyings;
34601e04c3fSmrg                flags.action_for_non_perspective_flags_of_lower_numbered_varyings =
34701e04c3fSmrg                        lower;
34801e04c3fSmrg                flags.action_for_non_perspective_flags_of_higher_numbered_varyings =
34901e04c3fSmrg                        higher;
35001e04c3fSmrg        }
35101e04c3fSmrg}
35201e04c3fSmrg
35301e04c3fSmrgstatic void
35401e04c3fSmrgemit_centroid_flags(struct v3d_job *job,
35501e04c3fSmrg                    int varying_offset,
35601e04c3fSmrg                    uint32_t varyings,
35701e04c3fSmrg                    enum V3DX(Varying_Flags_Action) lower,
35801e04c3fSmrg                    enum V3DX(Varying_Flags_Action) higher)
35901e04c3fSmrg{
36001e04c3fSmrg        cl_emit(&job->bcl, CENTROID_FLAGS, flags) {
36101e04c3fSmrg                flags.varying_offset_v0 = varying_offset;
36201e04c3fSmrg                flags.centroid_flags_for_varyings_v024 = varyings;
36301e04c3fSmrg                flags.action_for_centroid_flags_of_lower_numbered_varyings =
36401e04c3fSmrg                        lower;
36501e04c3fSmrg                flags.action_for_centroid_flags_of_higher_numbered_varyings =
36601e04c3fSmrg                        higher;
36701e04c3fSmrg        }
36801e04c3fSmrg}
36901e04c3fSmrg#endif /* V3D_VERSION >= 40 */
37001e04c3fSmrg
37101e04c3fSmrgstatic bool
37201e04c3fSmrgemit_varying_flags(struct v3d_job *job, uint32_t *flags,
37301e04c3fSmrg                   void (*flag_emit_callback)(struct v3d_job *job,
37401e04c3fSmrg                                              int varying_offset,
37501e04c3fSmrg                                              uint32_t flags,
37601e04c3fSmrg                                              enum V3DX(Varying_Flags_Action) lower,
37701e04c3fSmrg                                              enum V3DX(Varying_Flags_Action) higher))
37801e04c3fSmrg{
37901e04c3fSmrg        struct v3d_context *v3d = job->v3d;
38001e04c3fSmrg        bool emitted_any = false;
38101e04c3fSmrg
38201e04c3fSmrg        for (int i = 0; i < ARRAY_SIZE(v3d->prog.fs->prog_data.fs->flat_shade_flags); i++) {
38301e04c3fSmrg                if (!flags[i])
38401e04c3fSmrg                        continue;
38501e04c3fSmrg
38601e04c3fSmrg                if (emitted_any) {
38701e04c3fSmrg                        flag_emit_callback(job, i, flags[i],
38801e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED,
38901e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED);
39001e04c3fSmrg                } else if (i == 0) {
39101e04c3fSmrg                        flag_emit_callback(job, i, flags[i],
39201e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED,
39301e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_ZEROED);
39401e04c3fSmrg                } else {
39501e04c3fSmrg                        flag_emit_callback(job, i, flags[i],
39601e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_ZEROED,
39701e04c3fSmrg                                           V3D_VARYING_FLAGS_ACTION_ZEROED);
39801e04c3fSmrg                }
39901e04c3fSmrg                emitted_any = true;
40001e04c3fSmrg        }
40101e04c3fSmrg
40201e04c3fSmrg        return emitted_any;
40301e04c3fSmrg}
40401e04c3fSmrg
4057ec681f3Smrgstatic inline struct v3d_uncompiled_shader *
4067ec681f3Smrgget_tf_shader(struct v3d_context *v3d)
4077ec681f3Smrg{
4087ec681f3Smrg        if (v3d->prog.bind_gs)
4097ec681f3Smrg                return v3d->prog.bind_gs;
4107ec681f3Smrg        else
4117ec681f3Smrg                return v3d->prog.bind_vs;
4127ec681f3Smrg}
4137ec681f3Smrg
41401e04c3fSmrgvoid
41501e04c3fSmrgv3dX(emit_state)(struct pipe_context *pctx)
41601e04c3fSmrg{
41701e04c3fSmrg        struct v3d_context *v3d = v3d_context(pctx);
41801e04c3fSmrg        struct v3d_job *job = v3d->job;
41901e04c3fSmrg        bool rasterizer_discard = v3d->rasterizer->base.rasterizer_discard;
42001e04c3fSmrg
4217ec681f3Smrg        if (v3d->dirty & (V3D_DIRTY_SCISSOR | V3D_DIRTY_VIEWPORT |
4227ec681f3Smrg                          V3D_DIRTY_RASTERIZER)) {
42301e04c3fSmrg                float *vpscale = v3d->viewport.scale;
42401e04c3fSmrg                float *vptranslate = v3d->viewport.translate;
42501e04c3fSmrg                float vp_minx = -fabsf(vpscale[0]) + vptranslate[0];
42601e04c3fSmrg                float vp_maxx = fabsf(vpscale[0]) + vptranslate[0];
42701e04c3fSmrg                float vp_miny = -fabsf(vpscale[1]) + vptranslate[1];
42801e04c3fSmrg                float vp_maxy = fabsf(vpscale[1]) + vptranslate[1];
42901e04c3fSmrg
43001e04c3fSmrg                /* Clip to the scissor if it's enabled, but still clip to the
43101e04c3fSmrg                 * drawable regardless since that controls where the binner
43201e04c3fSmrg                 * tries to put things.
43301e04c3fSmrg                 *
43401e04c3fSmrg                 * Additionally, always clip the rendering to the viewport,
43501e04c3fSmrg                 * since the hardware does guardband clipping, meaning
43601e04c3fSmrg                 * primitives would rasterize outside of the view volume.
43701e04c3fSmrg                 */
43801e04c3fSmrg                uint32_t minx, miny, maxx, maxy;
43901e04c3fSmrg                if (!v3d->rasterizer->base.scissor) {
44001e04c3fSmrg                        minx = MAX2(vp_minx, 0);
44101e04c3fSmrg                        miny = MAX2(vp_miny, 0);
44201e04c3fSmrg                        maxx = MIN2(vp_maxx, job->draw_width);
44301e04c3fSmrg                        maxy = MIN2(vp_maxy, job->draw_height);
44401e04c3fSmrg                } else {
44501e04c3fSmrg                        minx = MAX2(vp_minx, v3d->scissor.minx);
44601e04c3fSmrg                        miny = MAX2(vp_miny, v3d->scissor.miny);
44701e04c3fSmrg                        maxx = MIN2(vp_maxx, v3d->scissor.maxx);
44801e04c3fSmrg                        maxy = MIN2(vp_maxy, v3d->scissor.maxy);
44901e04c3fSmrg                }
45001e04c3fSmrg
45101e04c3fSmrg                cl_emit(&job->bcl, CLIP_WINDOW, clip) {
45201e04c3fSmrg                        clip.clip_window_left_pixel_coordinate = minx;
45301e04c3fSmrg                        clip.clip_window_bottom_pixel_coordinate = miny;
45401e04c3fSmrg                        if (maxx > minx && maxy > miny) {
45501e04c3fSmrg                                clip.clip_window_width_in_pixels = maxx - minx;
45601e04c3fSmrg                                clip.clip_window_height_in_pixels = maxy - miny;
45701e04c3fSmrg                        } else if (V3D_VERSION < 41) {
45801e04c3fSmrg                                /* The HW won't entirely clip out when scissor
45901e04c3fSmrg                                 * w/h is 0.  Just treat it the same as
46001e04c3fSmrg                                 * rasterizer discard.
46101e04c3fSmrg                                 */
46201e04c3fSmrg                                rasterizer_discard = true;
46301e04c3fSmrg                                clip.clip_window_width_in_pixels = 1;
46401e04c3fSmrg                                clip.clip_window_height_in_pixels = 1;
46501e04c3fSmrg                        }
46601e04c3fSmrg                }
46701e04c3fSmrg
46801e04c3fSmrg                job->draw_min_x = MIN2(job->draw_min_x, minx);
46901e04c3fSmrg                job->draw_min_y = MIN2(job->draw_min_y, miny);
47001e04c3fSmrg                job->draw_max_x = MAX2(job->draw_max_x, maxx);
47101e04c3fSmrg                job->draw_max_y = MAX2(job->draw_max_y, maxy);
4727ec681f3Smrg
4737ec681f3Smrg                if (!v3d->rasterizer->base.scissor) {
4747ec681f3Smrg                    job->scissor.disabled = true;
4757ec681f3Smrg                } else if (!job->scissor.disabled &&
4767ec681f3Smrg                           (v3d->dirty & V3D_DIRTY_SCISSOR)) {
4777ec681f3Smrg                        if (job->scissor.count < MAX_JOB_SCISSORS) {
4787ec681f3Smrg                                job->scissor.rects[job->scissor.count].min_x =
4797ec681f3Smrg                                        v3d->scissor.minx;
4807ec681f3Smrg                                job->scissor.rects[job->scissor.count].min_y =
4817ec681f3Smrg                                        v3d->scissor.miny;
4827ec681f3Smrg                                job->scissor.rects[job->scissor.count].max_x =
4837ec681f3Smrg                                        v3d->scissor.maxx - 1;
4847ec681f3Smrg                                job->scissor.rects[job->scissor.count].max_y =
4857ec681f3Smrg                                        v3d->scissor.maxy - 1;
4867ec681f3Smrg                                job->scissor.count++;
4877ec681f3Smrg                        } else {
4887ec681f3Smrg                                job->scissor.disabled = true;
4897ec681f3Smrg                                perf_debug("Too many scissor rects.");
4907ec681f3Smrg                        }
4917ec681f3Smrg                }
49201e04c3fSmrg        }
49301e04c3fSmrg
4947ec681f3Smrg        if (v3d->dirty & (V3D_DIRTY_RASTERIZER |
4957ec681f3Smrg                          V3D_DIRTY_ZSA |
4967ec681f3Smrg                          V3D_DIRTY_BLEND |
4977ec681f3Smrg                          V3D_DIRTY_COMPILED_FS)) {
49801e04c3fSmrg                cl_emit(&job->bcl, CFG_BITS, config) {
49901e04c3fSmrg                        config.enable_forward_facing_primitive =
50001e04c3fSmrg                                !rasterizer_discard &&
50101e04c3fSmrg                                !(v3d->rasterizer->base.cull_face &
50201e04c3fSmrg                                  PIPE_FACE_FRONT);
50301e04c3fSmrg                        config.enable_reverse_facing_primitive =
50401e04c3fSmrg                                !rasterizer_discard &&
50501e04c3fSmrg                                !(v3d->rasterizer->base.cull_face &
50601e04c3fSmrg                                  PIPE_FACE_BACK);
50701e04c3fSmrg                        /* This seems backwards, but it's what gets the
50801e04c3fSmrg                         * clipflat test to pass.
50901e04c3fSmrg                         */
51001e04c3fSmrg                        config.clockwise_primitives =
51101e04c3fSmrg                                v3d->rasterizer->base.front_ccw;
51201e04c3fSmrg
51301e04c3fSmrg                        config.enable_depth_offset =
51401e04c3fSmrg                                v3d->rasterizer->base.offset_tri;
51501e04c3fSmrg
51601e04c3fSmrg                        /* V3D follows GL behavior where the sample mask only
51701e04c3fSmrg                         * applies when MSAA is enabled.  Gallium has sample
51801e04c3fSmrg                         * mask apply anyway, and the MSAA blit shaders will
51901e04c3fSmrg                         * set sample mask without explicitly setting
52001e04c3fSmrg                         * rasterizer oversample.  Just force it on here,
52101e04c3fSmrg                         * since the blit shaders are the only way to have
52201e04c3fSmrg                         * !multisample && samplemask != 0xf.
52301e04c3fSmrg                         */
52401e04c3fSmrg                        config.rasterizer_oversample_mode =
52501e04c3fSmrg                                v3d->rasterizer->base.multisample ||
52601e04c3fSmrg                                v3d->sample_mask != 0xf;
52701e04c3fSmrg
52801e04c3fSmrg                        config.direct3d_provoking_vertex =
52901e04c3fSmrg                                v3d->rasterizer->base.flatshade_first;
53001e04c3fSmrg
53101e04c3fSmrg                        config.blend_enable = v3d->blend->blend_enables;
53201e04c3fSmrg
53301e04c3fSmrg                        /* Note: EZ state may update based on the compiled FS,
53401e04c3fSmrg                         * along with ZSA
53501e04c3fSmrg                         */
53601e04c3fSmrg                        config.early_z_updates_enable =
5377ec681f3Smrg                                (job->ez_state != V3D_EZ_DISABLED);
5387ec681f3Smrg                        if (v3d->zsa->base.depth_enabled) {
53901e04c3fSmrg                                config.z_updates_enable =
5407ec681f3Smrg                                        v3d->zsa->base.depth_writemask;
54101e04c3fSmrg                                config.early_z_enable =
54201e04c3fSmrg                                        config.early_z_updates_enable;
54301e04c3fSmrg                                config.depth_test_function =
5447ec681f3Smrg                                        v3d->zsa->base.depth_func;
54501e04c3fSmrg                        } else {
54601e04c3fSmrg                                config.depth_test_function = PIPE_FUNC_ALWAYS;
54701e04c3fSmrg                        }
54801e04c3fSmrg
54901e04c3fSmrg                        config.stencil_enable =
55001e04c3fSmrg                                v3d->zsa->base.stencil[0].enabled;
5517ec681f3Smrg
5527ec681f3Smrg                        /* Use nicer line caps when line smoothing is
5537ec681f3Smrg                         * enabled
5547ec681f3Smrg                         */
5557ec681f3Smrg                        config.line_rasterization =
5567ec681f3Smrg                                v3d_line_smoothing_enabled(v3d) ? 1 : 0;
55701e04c3fSmrg                }
55801e04c3fSmrg
55901e04c3fSmrg        }
56001e04c3fSmrg
5617ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_RASTERIZER &&
56201e04c3fSmrg            v3d->rasterizer->base.offset_tri) {
56301e04c3fSmrg                if (job->zsbuf &&
56401e04c3fSmrg                    job->zsbuf->format == PIPE_FORMAT_Z16_UNORM) {
56501e04c3fSmrg                        cl_emit_prepacked_sized(&job->bcl,
56601e04c3fSmrg                                                v3d->rasterizer->depth_offset_z16,
56701e04c3fSmrg                                                cl_packet_length(DEPTH_OFFSET));
56801e04c3fSmrg                } else {
56901e04c3fSmrg                        cl_emit_prepacked_sized(&job->bcl,
57001e04c3fSmrg                                                v3d->rasterizer->depth_offset,
57101e04c3fSmrg                                                cl_packet_length(DEPTH_OFFSET));
57201e04c3fSmrg                }
57301e04c3fSmrg        }
57401e04c3fSmrg
5757ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_RASTERIZER) {
57601e04c3fSmrg                cl_emit(&job->bcl, POINT_SIZE, point_size) {
57701e04c3fSmrg                        point_size.point_size = v3d->rasterizer->point_size;
57801e04c3fSmrg                }
57901e04c3fSmrg
58001e04c3fSmrg                cl_emit(&job->bcl, LINE_WIDTH, line_width) {
5817ec681f3Smrg                        line_width.line_width = v3d_get_real_line_width(v3d);
58201e04c3fSmrg                }
58301e04c3fSmrg        }
58401e04c3fSmrg
5857ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_VIEWPORT) {
58601e04c3fSmrg                cl_emit(&job->bcl, CLIPPER_XY_SCALING, clip) {
58701e04c3fSmrg                        clip.viewport_half_width_in_1_256th_of_pixel =
58801e04c3fSmrg                                v3d->viewport.scale[0] * 256.0f;
58901e04c3fSmrg                        clip.viewport_half_height_in_1_256th_of_pixel =
59001e04c3fSmrg                                v3d->viewport.scale[1] * 256.0f;
59101e04c3fSmrg                }
59201e04c3fSmrg
59301e04c3fSmrg                cl_emit(&job->bcl, CLIPPER_Z_SCALE_AND_OFFSET, clip) {
59401e04c3fSmrg                        clip.viewport_z_offset_zc_to_zs =
59501e04c3fSmrg                                v3d->viewport.translate[2];
59601e04c3fSmrg                        clip.viewport_z_scale_zc_to_zs =
59701e04c3fSmrg                                v3d->viewport.scale[2];
59801e04c3fSmrg                }
59901e04c3fSmrg                cl_emit(&job->bcl, CLIPPER_Z_MIN_MAX_CLIPPING_PLANES, clip) {
60001e04c3fSmrg                        float z1 = (v3d->viewport.translate[2] -
60101e04c3fSmrg                                    v3d->viewport.scale[2]);
60201e04c3fSmrg                        float z2 = (v3d->viewport.translate[2] +
60301e04c3fSmrg                                    v3d->viewport.scale[2]);
60401e04c3fSmrg                        clip.minimum_zw = MIN2(z1, z2);
60501e04c3fSmrg                        clip.maximum_zw = MAX2(z1, z2);
60601e04c3fSmrg                }
60701e04c3fSmrg
60801e04c3fSmrg                cl_emit(&job->bcl, VIEWPORT_OFFSET, vp) {
60901e04c3fSmrg                        vp.viewport_centre_x_coordinate =
61001e04c3fSmrg                                v3d->viewport.translate[0];
61101e04c3fSmrg                        vp.viewport_centre_y_coordinate =
61201e04c3fSmrg                                v3d->viewport.translate[1];
61301e04c3fSmrg                }
61401e04c3fSmrg        }
61501e04c3fSmrg
6167ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_BLEND) {
61701e04c3fSmrg                struct v3d_blend_state *blend = v3d->blend;
61801e04c3fSmrg
61901e04c3fSmrg                if (blend->blend_enables) {
62001e04c3fSmrg#if V3D_VERSION >= 40
62101e04c3fSmrg                        cl_emit(&job->bcl, BLEND_ENABLES, enables) {
62201e04c3fSmrg                                enables.mask = blend->blend_enables;
62301e04c3fSmrg                        }
62401e04c3fSmrg#endif
62501e04c3fSmrg
62601e04c3fSmrg                        if (blend->base.independent_blend_enable) {
6279f464c52Smaya                                for (int i = 0; i < V3D_MAX_DRAW_BUFFERS; i++)
62801e04c3fSmrg                                        emit_rt_blend(v3d, job, &blend->base, i);
62901e04c3fSmrg                        } else {
63001e04c3fSmrg                                emit_rt_blend(v3d, job, &blend->base, 0);
63101e04c3fSmrg                        }
63201e04c3fSmrg                }
63301e04c3fSmrg        }
63401e04c3fSmrg
6357ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_BLEND) {
63601e04c3fSmrg                struct pipe_blend_state *blend = &v3d->blend->base;
63701e04c3fSmrg
63801e04c3fSmrg                cl_emit(&job->bcl, COLOR_WRITE_MASKS, mask) {
63901e04c3fSmrg                        for (int i = 0; i < 4; i++) {
64001e04c3fSmrg                                int rt = blend->independent_blend_enable ? i : 0;
64101e04c3fSmrg                                int rt_mask = blend->rt[rt].colormask;
64201e04c3fSmrg
64301e04c3fSmrg                                mask.mask |= translate_colormask(v3d, rt_mask,
64401e04c3fSmrg                                                                 i) << (4 * i);
64501e04c3fSmrg                        }
64601e04c3fSmrg                }
64701e04c3fSmrg        }
64801e04c3fSmrg
64901e04c3fSmrg        /* GFXH-1431: On V3D 3.x, writing BLEND_CONFIG resets the constant
65001e04c3fSmrg         * color.
65101e04c3fSmrg         */
6527ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_BLEND_COLOR ||
6537ec681f3Smrg            (V3D_VERSION < 41 && (v3d->dirty & V3D_DIRTY_BLEND))) {
65401e04c3fSmrg                cl_emit(&job->bcl, BLEND_CONSTANT_COLOR, color) {
65501e04c3fSmrg                        color.red_f16 = (v3d->swap_color_rb ?
65601e04c3fSmrg                                          v3d->blend_color.hf[2] :
65701e04c3fSmrg                                          v3d->blend_color.hf[0]);
65801e04c3fSmrg                        color.green_f16 = v3d->blend_color.hf[1];
65901e04c3fSmrg                        color.blue_f16 = (v3d->swap_color_rb ?
66001e04c3fSmrg                                           v3d->blend_color.hf[0] :
66101e04c3fSmrg                                           v3d->blend_color.hf[2]);
66201e04c3fSmrg                        color.alpha_f16 = v3d->blend_color.hf[3];
66301e04c3fSmrg                }
66401e04c3fSmrg        }
66501e04c3fSmrg
6667ec681f3Smrg        if (v3d->dirty & (V3D_DIRTY_ZSA | V3D_DIRTY_STENCIL_REF)) {
66701e04c3fSmrg                struct pipe_stencil_state *front = &v3d->zsa->base.stencil[0];
66801e04c3fSmrg                struct pipe_stencil_state *back = &v3d->zsa->base.stencil[1];
66901e04c3fSmrg
67001e04c3fSmrg                if (front->enabled) {
67101e04c3fSmrg                        cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
67201e04c3fSmrg                                               v3d->zsa->stencil_front, config) {
67301e04c3fSmrg                                config.stencil_ref_value =
67401e04c3fSmrg                                        v3d->stencil_ref.ref_value[0];
67501e04c3fSmrg                        }
67601e04c3fSmrg                }
67701e04c3fSmrg
67801e04c3fSmrg                if (back->enabled) {
67901e04c3fSmrg                        cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
68001e04c3fSmrg                                               v3d->zsa->stencil_back, config) {
68101e04c3fSmrg                                config.stencil_ref_value =
68201e04c3fSmrg                                        v3d->stencil_ref.ref_value[1];
68301e04c3fSmrg                        }
68401e04c3fSmrg                }
68501e04c3fSmrg        }
68601e04c3fSmrg
68701e04c3fSmrg#if V3D_VERSION < 40
68801e04c3fSmrg        /* Pre-4.x, we have texture state that depends on both the sampler and
68901e04c3fSmrg         * the view, so we merge them together at draw time.
69001e04c3fSmrg         */
6917ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_FRAGTEX)
6929f464c52Smaya                emit_textures(v3d, &v3d->tex[PIPE_SHADER_FRAGMENT]);
69301e04c3fSmrg
6947ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_GEOMTEX)
6957ec681f3Smrg                emit_textures(v3d, &v3d->tex[PIPE_SHADER_GEOMETRY]);
6967ec681f3Smrg
6977ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_VERTTEX)
6989f464c52Smaya                emit_textures(v3d, &v3d->tex[PIPE_SHADER_VERTEX]);
69901e04c3fSmrg#endif
70001e04c3fSmrg
7017ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_FLAT_SHADE_FLAGS) {
70201e04c3fSmrg                if (!emit_varying_flags(job,
70301e04c3fSmrg                                        v3d->prog.fs->prog_data.fs->flat_shade_flags,
70401e04c3fSmrg                                        emit_flat_shade_flags)) {
70501e04c3fSmrg                        cl_emit(&job->bcl, ZERO_ALL_FLAT_SHADE_FLAGS, flags);
70601e04c3fSmrg                }
70701e04c3fSmrg        }
70801e04c3fSmrg
70901e04c3fSmrg#if V3D_VERSION >= 40
7107ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_NOPERSPECTIVE_FLAGS) {
71101e04c3fSmrg                if (!emit_varying_flags(job,
71201e04c3fSmrg                                        v3d->prog.fs->prog_data.fs->noperspective_flags,
71301e04c3fSmrg                                        emit_noperspective_flags)) {
71401e04c3fSmrg                        cl_emit(&job->bcl, ZERO_ALL_NON_PERSPECTIVE_FLAGS, flags);
71501e04c3fSmrg                }
71601e04c3fSmrg        }
71701e04c3fSmrg
7187ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_CENTROID_FLAGS) {
71901e04c3fSmrg                if (!emit_varying_flags(job,
72001e04c3fSmrg                                        v3d->prog.fs->prog_data.fs->centroid_flags,
72101e04c3fSmrg                                        emit_centroid_flags)) {
72201e04c3fSmrg                        cl_emit(&job->bcl, ZERO_ALL_CENTROID_FLAGS, flags);
72301e04c3fSmrg                }
72401e04c3fSmrg        }
72501e04c3fSmrg#endif
72601e04c3fSmrg
72701e04c3fSmrg        /* Set up the transform feedback data specs (which VPM entries to
72801e04c3fSmrg         * output to which buffers).
72901e04c3fSmrg         */
7307ec681f3Smrg        if (v3d->dirty & (V3D_DIRTY_STREAMOUT |
7317ec681f3Smrg                          V3D_DIRTY_RASTERIZER |
7327ec681f3Smrg                          V3D_DIRTY_PRIM_MODE)) {
73301e04c3fSmrg                struct v3d_streamout_stateobj *so = &v3d->streamout;
73401e04c3fSmrg                if (so->num_targets) {
73501e04c3fSmrg                        bool psiz_per_vertex = (v3d->prim_mode == PIPE_PRIM_POINTS &&
73601e04c3fSmrg                                                v3d->rasterizer->base.point_size_per_vertex);
7377ec681f3Smrg                        struct v3d_uncompiled_shader *tf_shader =
7387ec681f3Smrg                                get_tf_shader(v3d);
73901e04c3fSmrg                        uint16_t *tf_specs = (psiz_per_vertex ?
7407ec681f3Smrg                                              tf_shader->tf_specs_psiz :
7417ec681f3Smrg                                              tf_shader->tf_specs);
74201e04c3fSmrg
74301e04c3fSmrg#if V3D_VERSION >= 40
7447ec681f3Smrg                        bool tf_enabled = v3d_transform_feedback_enabled(v3d);
74501e04c3fSmrg                        job->tf_enabled |= tf_enabled;
74601e04c3fSmrg
74701e04c3fSmrg                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
74801e04c3fSmrg                                tfe.number_of_16_bit_output_data_specs_following =
7497ec681f3Smrg                                        tf_shader->num_tf_specs;
75001e04c3fSmrg                                tfe.enable = tf_enabled;
75101e04c3fSmrg                        };
75201e04c3fSmrg#else /* V3D_VERSION < 40 */
75301e04c3fSmrg                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_ENABLE, tfe) {
75401e04c3fSmrg                                tfe.number_of_32_bit_output_buffer_address_following =
75501e04c3fSmrg                                        so->num_targets;
75601e04c3fSmrg                                tfe.number_of_16_bit_output_data_specs_following =
7577ec681f3Smrg                                        tf_shader->num_tf_specs;
75801e04c3fSmrg                        };
75901e04c3fSmrg#endif /* V3D_VERSION < 40 */
7607ec681f3Smrg                        for (int i = 0; i < tf_shader->num_tf_specs; i++) {
76101e04c3fSmrg                                cl_emit_prepacked(&job->bcl, &tf_specs[i]);
76201e04c3fSmrg                        }
76301e04c3fSmrg                } else {
76401e04c3fSmrg#if V3D_VERSION >= 40
76501e04c3fSmrg                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
76601e04c3fSmrg                                tfe.enable = false;
76701e04c3fSmrg                        };
76801e04c3fSmrg#endif /* V3D_VERSION >= 40 */
76901e04c3fSmrg                }
77001e04c3fSmrg        }
77101e04c3fSmrg
7727ec681f3Smrg        /* Set up the transform feedback buffers. */
7737ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_STREAMOUT) {
7747ec681f3Smrg                struct v3d_uncompiled_shader *tf_shader = get_tf_shader(v3d);
77501e04c3fSmrg                struct v3d_streamout_stateobj *so = &v3d->streamout;
77601e04c3fSmrg                for (int i = 0; i < so->num_targets; i++) {
77701e04c3fSmrg                        const struct pipe_stream_output_target *target =
77801e04c3fSmrg                                so->targets[i];
77901e04c3fSmrg                        struct v3d_resource *rsc = target ?
78001e04c3fSmrg                                v3d_resource(target->buffer) : NULL;
7817ec681f3Smrg                        struct pipe_shader_state *ss = &tf_shader->base;
7827ec681f3Smrg                        struct pipe_stream_output_info *info = &ss->stream_output;
78301e04c3fSmrg                        uint32_t offset = (v3d->streamout.offsets[i] *
78401e04c3fSmrg                                           info->stride[i] * 4);
78501e04c3fSmrg
78601e04c3fSmrg#if V3D_VERSION >= 40
78701e04c3fSmrg                        if (!target)
78801e04c3fSmrg                                continue;
78901e04c3fSmrg
79001e04c3fSmrg                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_BUFFER, output) {
79101e04c3fSmrg                                output.buffer_address =
79201e04c3fSmrg                                        cl_address(rsc->bo,
79301e04c3fSmrg                                                   target->buffer_offset +
79401e04c3fSmrg                                                   offset);
79501e04c3fSmrg                                output.buffer_size_in_32_bit_words =
79601e04c3fSmrg                                        (target->buffer_size - offset) >> 2;
79701e04c3fSmrg                                output.buffer_number = i;
79801e04c3fSmrg                        }
79901e04c3fSmrg#else /* V3D_VERSION < 40 */
80001e04c3fSmrg                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_OUTPUT_ADDRESS, output) {
80101e04c3fSmrg                                if (target) {
80201e04c3fSmrg                                        output.address =
80301e04c3fSmrg                                                cl_address(rsc->bo,
80401e04c3fSmrg                                                           target->buffer_offset +
80501e04c3fSmrg                                                           offset);
80601e04c3fSmrg                                }
80701e04c3fSmrg                        };
80801e04c3fSmrg#endif /* V3D_VERSION < 40 */
80901e04c3fSmrg                        if (target) {
8107ec681f3Smrg                                v3d_job_add_tf_write_resource(v3d->job,
8117ec681f3Smrg                                                              target->buffer);
81201e04c3fSmrg                        }
81301e04c3fSmrg                        /* XXX: buffer_size? */
81401e04c3fSmrg                }
81501e04c3fSmrg        }
81601e04c3fSmrg
8177ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_OQ) {
81801e04c3fSmrg                cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter) {
81901e04c3fSmrg                        if (v3d->active_queries && v3d->current_oq) {
82001e04c3fSmrg                                counter.address = cl_address(v3d->current_oq, 0);
82101e04c3fSmrg                        }
82201e04c3fSmrg                }
82301e04c3fSmrg        }
82401e04c3fSmrg
82501e04c3fSmrg#if V3D_VERSION >= 40
8267ec681f3Smrg        if (v3d->dirty & V3D_DIRTY_SAMPLE_STATE) {
82701e04c3fSmrg                cl_emit(&job->bcl, SAMPLE_STATE, state) {
82801e04c3fSmrg                        /* Note: SampleCoverage was handled at the
8297ec681f3Smrg                         * frontend level by converting to sample_mask.
83001e04c3fSmrg                         */
83101e04c3fSmrg                        state.coverage = 1.0;
83201e04c3fSmrg                        state.mask = job->msaa ? v3d->sample_mask : 0xf;
83301e04c3fSmrg                }
83401e04c3fSmrg        }
83501e04c3fSmrg#endif
83601e04c3fSmrg}
837