1/*
2 * Copyright © 2014-2017 Broadcom
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "util/format/u_format.h"
25#include "util/half_float.h"
26#include "v3d_context.h"
27#include "broadcom/common/v3d_macros.h"
28#include "broadcom/cle/v3dx_pack.h"
29#include "broadcom/compiler/v3d_compiler.h"
30
31static uint8_t
32v3d_factor(enum pipe_blendfactor factor, bool dst_alpha_one)
33{
34        /* We may get a bad blendfactor when blending is disabled. */
35        if (factor == 0)
36                return V3D_BLEND_FACTOR_ZERO;
37
38        switch (factor) {
39        case PIPE_BLENDFACTOR_ZERO:
40                return V3D_BLEND_FACTOR_ZERO;
41        case PIPE_BLENDFACTOR_ONE:
42                return V3D_BLEND_FACTOR_ONE;
43        case PIPE_BLENDFACTOR_SRC_COLOR:
44                return V3D_BLEND_FACTOR_SRC_COLOR;
45        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
46                return V3D_BLEND_FACTOR_INV_SRC_COLOR;
47        case PIPE_BLENDFACTOR_DST_COLOR:
48                return V3D_BLEND_FACTOR_DST_COLOR;
49        case PIPE_BLENDFACTOR_INV_DST_COLOR:
50                return V3D_BLEND_FACTOR_INV_DST_COLOR;
51        case PIPE_BLENDFACTOR_SRC_ALPHA:
52                return V3D_BLEND_FACTOR_SRC_ALPHA;
53        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
54                return V3D_BLEND_FACTOR_INV_SRC_ALPHA;
55        case PIPE_BLENDFACTOR_DST_ALPHA:
56                return (dst_alpha_one ?
57                        V3D_BLEND_FACTOR_ONE :
58                        V3D_BLEND_FACTOR_DST_ALPHA);
59        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
60                return (dst_alpha_one ?
61                        V3D_BLEND_FACTOR_ZERO :
62                        V3D_BLEND_FACTOR_INV_DST_ALPHA);
63        case PIPE_BLENDFACTOR_CONST_COLOR:
64                return V3D_BLEND_FACTOR_CONST_COLOR;
65        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
66                return V3D_BLEND_FACTOR_INV_CONST_COLOR;
67        case PIPE_BLENDFACTOR_CONST_ALPHA:
68                return V3D_BLEND_FACTOR_CONST_ALPHA;
69        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
70                return V3D_BLEND_FACTOR_INV_CONST_ALPHA;
71        case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
72                return (dst_alpha_one ?
73                        V3D_BLEND_FACTOR_ZERO :
74                        V3D_BLEND_FACTOR_SRC_ALPHA_SATURATE);
75        default:
76                unreachable("Bad blend factor");
77        }
78}
79
80static inline uint16_t
81swizzled_border_color(const struct v3d_device_info *devinfo,
82                      struct pipe_sampler_state *sampler,
83                      struct v3d_sampler_view *sview,
84                      int chan)
85{
86        const struct util_format_description *desc =
87                util_format_description(sview->base.format);
88        uint8_t swiz = chan;
89
90        /* If we're doing swizzling in the sampler, then only rearrange the
91         * border color for the mismatch between the V3D texture format and
92         * the PIPE_FORMAT, since GL_ARB_texture_swizzle will be handled by
93         * the sampler's swizzle.
94         *
95         * For swizzling in the shader, we don't do any pre-swizzling of the
96         * border color.
97         */
98        if (v3d_get_tex_return_size(devinfo, sview->base.format,
99                                    sampler->compare_mode) != 32)
100                swiz = desc->swizzle[swiz];
101
102        switch (swiz) {
103        case PIPE_SWIZZLE_0:
104                return _mesa_float_to_half(0.0);
105        case PIPE_SWIZZLE_1:
106                return _mesa_float_to_half(1.0);
107        default:
108                return _mesa_float_to_half(sampler->border_color.f[swiz]);
109        }
110}
111
112#if V3D_VERSION < 40
113static uint32_t
114translate_swizzle(unsigned char pipe_swizzle)
115{
116        switch (pipe_swizzle) {
117        case PIPE_SWIZZLE_0:
118                return 0;
119        case PIPE_SWIZZLE_1:
120                return 1;
121        case PIPE_SWIZZLE_X:
122        case PIPE_SWIZZLE_Y:
123        case PIPE_SWIZZLE_Z:
124        case PIPE_SWIZZLE_W:
125                return 2 + pipe_swizzle;
126        default:
127                unreachable("unknown swizzle");
128        }
129}
130
131static void
132emit_one_texture(struct v3d_context *v3d, struct v3d_texture_stateobj *stage_tex,
133                 int i)
134{
135        struct v3d_job *job = v3d->job;
136        struct pipe_sampler_state *psampler = stage_tex->samplers[i];
137        struct v3d_sampler_state *sampler = v3d_sampler_state(psampler);
138        struct pipe_sampler_view *psview = stage_tex->textures[i];
139        struct v3d_sampler_view *sview = v3d_sampler_view(psview);
140        struct pipe_resource *prsc = psview->texture;
141        struct v3d_resource *rsc = v3d_resource(prsc);
142        const struct v3d_device_info *devinfo = &v3d->screen->devinfo;
143
144        stage_tex->texture_state[i].offset =
145                v3d_cl_ensure_space(&job->indirect,
146                                    cl_packet_length(TEXTURE_SHADER_STATE),
147                                    32);
148        v3d_bo_set_reference(&stage_tex->texture_state[i].bo,
149                             job->indirect.bo);
150
151        uint32_t return_size = v3d_get_tex_return_size(devinfo, psview->format,
152                                                       psampler->compare_mode);
153
154        struct V3D33_TEXTURE_SHADER_STATE unpacked = {
155                /* XXX */
156                .border_color_red = swizzled_border_color(devinfo, psampler,
157                                                          sview, 0),
158                .border_color_green = swizzled_border_color(devinfo, psampler,
159                                                            sview, 1),
160                .border_color_blue = swizzled_border_color(devinfo, psampler,
161                                                           sview, 2),
162                .border_color_alpha = swizzled_border_color(devinfo, psampler,
163                                                            sview, 3),
164
165                /* In the normal texturing path, the LOD gets clamped between
166                 * min/max, and the base_level field (set in the sampler view
167                 * from first_level) only decides where the min/mag switch
168                 * happens, so we need to use the LOD clamps to keep us
169                 * between min and max.
170                 *
171                 * For txf, the LOD clamp is still used, despite GL not
172                 * wanting that.  We will need to have a separate
173                 * TEXTURE_SHADER_STATE that ignores psview->min/max_lod to
174                 * support txf properly.
175                 */
176                .min_level_of_detail = MIN2(psview->u.tex.first_level +
177                                            MAX2(psampler->min_lod, 0),
178                                            psview->u.tex.last_level),
179                .max_level_of_detail = MIN2(psview->u.tex.first_level +
180                                            MAX2(psampler->max_lod,
181                                                 psampler->min_lod),
182                                            psview->u.tex.last_level),
183
184                .texture_base_pointer = cl_address(rsc->bo,
185                                                   rsc->slices[0].offset),
186
187                .output_32_bit = return_size == 32,
188        };
189
190        /* Set up the sampler swizzle if we're doing 16-bit sampling.  For
191         * 32-bit, we leave swizzling up to the shader compiler.
192         *
193         * Note: Contrary to the docs, the swizzle still applies even if the
194         * return size is 32.  It's just that you probably want to swizzle in
195         * the shader, because you need the Y/Z/W channels to be defined.
196         */
197        if (return_size == 32) {
198                unpacked.swizzle_r = translate_swizzle(PIPE_SWIZZLE_X);
199                unpacked.swizzle_g = translate_swizzle(PIPE_SWIZZLE_Y);
200                unpacked.swizzle_b = translate_swizzle(PIPE_SWIZZLE_Z);
201                unpacked.swizzle_a = translate_swizzle(PIPE_SWIZZLE_W);
202        } else {
203                unpacked.swizzle_r = translate_swizzle(sview->swizzle[0]);
204                unpacked.swizzle_g = translate_swizzle(sview->swizzle[1]);
205                unpacked.swizzle_b = translate_swizzle(sview->swizzle[2]);
206                unpacked.swizzle_a = translate_swizzle(sview->swizzle[3]);
207        }
208
209        int min_img_filter = psampler->min_img_filter;
210        int min_mip_filter = psampler->min_mip_filter;
211        int mag_img_filter = psampler->mag_img_filter;
212
213        if (return_size == 32) {
214                min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
215                min_img_filter = PIPE_TEX_FILTER_NEAREST;
216                mag_img_filter = PIPE_TEX_FILTER_NEAREST;
217        }
218
219        bool min_nearest = min_img_filter == PIPE_TEX_FILTER_NEAREST;
220        switch (min_mip_filter) {
221        case PIPE_TEX_MIPFILTER_NONE:
222                unpacked.filter += min_nearest ? 2 : 0;
223                break;
224        case PIPE_TEX_MIPFILTER_NEAREST:
225                unpacked.filter += min_nearest ? 4 : 8;
226                break;
227        case PIPE_TEX_MIPFILTER_LINEAR:
228                unpacked.filter += min_nearest ? 4 : 8;
229                unpacked.filter += 2;
230                break;
231        }
232
233        if (mag_img_filter == PIPE_TEX_FILTER_NEAREST)
234                unpacked.filter++;
235
236        if (psampler->max_anisotropy > 8)
237                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_16_1;
238        else if (psampler->max_anisotropy > 4)
239                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_8_1;
240        else if (psampler->max_anisotropy > 2)
241                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_4_1;
242        else if (psampler->max_anisotropy)
243                unpacked.filter = V3D_TMU_FILTER_ANISOTROPIC_2_1;
244
245        uint8_t packed[cl_packet_length(TEXTURE_SHADER_STATE)];
246        cl_packet_pack(TEXTURE_SHADER_STATE)(&job->indirect, packed, &unpacked);
247
248        for (int i = 0; i < ARRAY_SIZE(packed); i++)
249                packed[i] |= sview->texture_shader_state[i] | sampler->texture_shader_state[i];
250
251        /* TMU indirect structs need to be 32b aligned. */
252        v3d_cl_ensure_space(&job->indirect, ARRAY_SIZE(packed), 32);
253        cl_emit_prepacked(&job->indirect, &packed);
254}
255
256static void
257emit_textures(struct v3d_context *v3d, struct v3d_texture_stateobj *stage_tex)
258{
259        for (int i = 0; i < stage_tex->num_textures; i++) {
260                if (stage_tex->textures[i])
261                        emit_one_texture(v3d, stage_tex, i);
262        }
263}
264#endif /* V3D_VERSION < 40 */
265
266static uint32_t
267translate_colormask(struct v3d_context *v3d, uint32_t colormask, int rt)
268{
269        if (v3d->swap_color_rb & (1 << rt)) {
270                colormask = ((colormask & (2 | 8)) |
271                             ((colormask & 1) << 2) |
272                             ((colormask & 4) >> 2));
273        }
274
275        return (~colormask) & 0xf;
276}
277
278static void
279emit_rt_blend(struct v3d_context *v3d, struct v3d_job *job,
280              struct pipe_blend_state *blend, int rt)
281{
282        struct pipe_rt_blend_state *rtblend = &blend->rt[rt];
283
284#if V3D_VERSION >= 40
285        /* We don't need to emit blend state for disabled RTs. */
286        if (!rtblend->blend_enable)
287                return;
288#endif
289
290        cl_emit(&job->bcl, BLEND_CFG, config) {
291#if V3D_VERSION >= 40
292                if (blend->independent_blend_enable)
293                        config.render_target_mask = 1 << rt;
294                else
295                        config.render_target_mask = (1 << V3D_MAX_DRAW_BUFFERS) - 1;
296#else
297                assert(rt == 0);
298#endif
299
300                config.color_blend_mode = rtblend->rgb_func;
301                config.color_blend_dst_factor =
302                        v3d_factor(rtblend->rgb_dst_factor,
303                                   v3d->blend_dst_alpha_one);
304                config.color_blend_src_factor =
305                        v3d_factor(rtblend->rgb_src_factor,
306                                   v3d->blend_dst_alpha_one);
307
308                config.alpha_blend_mode = rtblend->alpha_func;
309                config.alpha_blend_dst_factor =
310                        v3d_factor(rtblend->alpha_dst_factor,
311                                   v3d->blend_dst_alpha_one);
312                config.alpha_blend_src_factor =
313                        v3d_factor(rtblend->alpha_src_factor,
314                                   v3d->blend_dst_alpha_one);
315        }
316}
317
318static void
319emit_flat_shade_flags(struct v3d_job *job,
320                      int varying_offset,
321                      uint32_t varyings,
322                      enum V3DX(Varying_Flags_Action) lower,
323                      enum V3DX(Varying_Flags_Action) higher)
324{
325        cl_emit(&job->bcl, FLAT_SHADE_FLAGS, flags) {
326                flags.varying_offset_v0 = varying_offset;
327                flags.flat_shade_flags_for_varyings_v024 = varyings;
328                flags.action_for_flat_shade_flags_of_lower_numbered_varyings =
329                        lower;
330                flags.action_for_flat_shade_flags_of_higher_numbered_varyings =
331                        higher;
332        }
333}
334
335#if V3D_VERSION >= 40
336static void
337emit_noperspective_flags(struct v3d_job *job,
338                         int varying_offset,
339                         uint32_t varyings,
340                         enum V3DX(Varying_Flags_Action) lower,
341                         enum V3DX(Varying_Flags_Action) higher)
342{
343        cl_emit(&job->bcl, NON_PERSPECTIVE_FLAGS, flags) {
344                flags.varying_offset_v0 = varying_offset;
345                flags.non_perspective_flags_for_varyings_v024 = varyings;
346                flags.action_for_non_perspective_flags_of_lower_numbered_varyings =
347                        lower;
348                flags.action_for_non_perspective_flags_of_higher_numbered_varyings =
349                        higher;
350        }
351}
352
353static void
354emit_centroid_flags(struct v3d_job *job,
355                    int varying_offset,
356                    uint32_t varyings,
357                    enum V3DX(Varying_Flags_Action) lower,
358                    enum V3DX(Varying_Flags_Action) higher)
359{
360        cl_emit(&job->bcl, CENTROID_FLAGS, flags) {
361                flags.varying_offset_v0 = varying_offset;
362                flags.centroid_flags_for_varyings_v024 = varyings;
363                flags.action_for_centroid_flags_of_lower_numbered_varyings =
364                        lower;
365                flags.action_for_centroid_flags_of_higher_numbered_varyings =
366                        higher;
367        }
368}
369#endif /* V3D_VERSION >= 40 */
370
371static bool
372emit_varying_flags(struct v3d_job *job, uint32_t *flags,
373                   void (*flag_emit_callback)(struct v3d_job *job,
374                                              int varying_offset,
375                                              uint32_t flags,
376                                              enum V3DX(Varying_Flags_Action) lower,
377                                              enum V3DX(Varying_Flags_Action) higher))
378{
379        struct v3d_context *v3d = job->v3d;
380        bool emitted_any = false;
381
382        for (int i = 0; i < ARRAY_SIZE(v3d->prog.fs->prog_data.fs->flat_shade_flags); i++) {
383                if (!flags[i])
384                        continue;
385
386                if (emitted_any) {
387                        flag_emit_callback(job, i, flags[i],
388                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED,
389                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED);
390                } else if (i == 0) {
391                        flag_emit_callback(job, i, flags[i],
392                                           V3D_VARYING_FLAGS_ACTION_UNCHANGED,
393                                           V3D_VARYING_FLAGS_ACTION_ZEROED);
394                } else {
395                        flag_emit_callback(job, i, flags[i],
396                                           V3D_VARYING_FLAGS_ACTION_ZEROED,
397                                           V3D_VARYING_FLAGS_ACTION_ZEROED);
398                }
399                emitted_any = true;
400        }
401
402        return emitted_any;
403}
404
405static inline struct v3d_uncompiled_shader *
406get_tf_shader(struct v3d_context *v3d)
407{
408        if (v3d->prog.bind_gs)
409                return v3d->prog.bind_gs;
410        else
411                return v3d->prog.bind_vs;
412}
413
414void
415v3dX(emit_state)(struct pipe_context *pctx)
416{
417        struct v3d_context *v3d = v3d_context(pctx);
418        struct v3d_job *job = v3d->job;
419        bool rasterizer_discard = v3d->rasterizer->base.rasterizer_discard;
420
421        if (v3d->dirty & (V3D_DIRTY_SCISSOR | V3D_DIRTY_VIEWPORT |
422                          V3D_DIRTY_RASTERIZER)) {
423                float *vpscale = v3d->viewport.scale;
424                float *vptranslate = v3d->viewport.translate;
425                float vp_minx = -fabsf(vpscale[0]) + vptranslate[0];
426                float vp_maxx = fabsf(vpscale[0]) + vptranslate[0];
427                float vp_miny = -fabsf(vpscale[1]) + vptranslate[1];
428                float vp_maxy = fabsf(vpscale[1]) + vptranslate[1];
429
430                /* Clip to the scissor if it's enabled, but still clip to the
431                 * drawable regardless since that controls where the binner
432                 * tries to put things.
433                 *
434                 * Additionally, always clip the rendering to the viewport,
435                 * since the hardware does guardband clipping, meaning
436                 * primitives would rasterize outside of the view volume.
437                 */
438                uint32_t minx, miny, maxx, maxy;
439                if (!v3d->rasterizer->base.scissor) {
440                        minx = MAX2(vp_minx, 0);
441                        miny = MAX2(vp_miny, 0);
442                        maxx = MIN2(vp_maxx, job->draw_width);
443                        maxy = MIN2(vp_maxy, job->draw_height);
444                } else {
445                        minx = MAX2(vp_minx, v3d->scissor.minx);
446                        miny = MAX2(vp_miny, v3d->scissor.miny);
447                        maxx = MIN2(vp_maxx, v3d->scissor.maxx);
448                        maxy = MIN2(vp_maxy, v3d->scissor.maxy);
449                }
450
451                cl_emit(&job->bcl, CLIP_WINDOW, clip) {
452                        clip.clip_window_left_pixel_coordinate = minx;
453                        clip.clip_window_bottom_pixel_coordinate = miny;
454                        if (maxx > minx && maxy > miny) {
455                                clip.clip_window_width_in_pixels = maxx - minx;
456                                clip.clip_window_height_in_pixels = maxy - miny;
457                        } else if (V3D_VERSION < 41) {
458                                /* The HW won't entirely clip out when scissor
459                                 * w/h is 0.  Just treat it the same as
460                                 * rasterizer discard.
461                                 */
462                                rasterizer_discard = true;
463                                clip.clip_window_width_in_pixels = 1;
464                                clip.clip_window_height_in_pixels = 1;
465                        }
466                }
467
468                job->draw_min_x = MIN2(job->draw_min_x, minx);
469                job->draw_min_y = MIN2(job->draw_min_y, miny);
470                job->draw_max_x = MAX2(job->draw_max_x, maxx);
471                job->draw_max_y = MAX2(job->draw_max_y, maxy);
472
473                if (!v3d->rasterizer->base.scissor) {
474                    job->scissor.disabled = true;
475                } else if (!job->scissor.disabled &&
476                           (v3d->dirty & V3D_DIRTY_SCISSOR)) {
477                        if (job->scissor.count < MAX_JOB_SCISSORS) {
478                                job->scissor.rects[job->scissor.count].min_x =
479                                        v3d->scissor.minx;
480                                job->scissor.rects[job->scissor.count].min_y =
481                                        v3d->scissor.miny;
482                                job->scissor.rects[job->scissor.count].max_x =
483                                        v3d->scissor.maxx - 1;
484                                job->scissor.rects[job->scissor.count].max_y =
485                                        v3d->scissor.maxy - 1;
486                                job->scissor.count++;
487                        } else {
488                                job->scissor.disabled = true;
489                                perf_debug("Too many scissor rects.");
490                        }
491                }
492        }
493
494        if (v3d->dirty & (V3D_DIRTY_RASTERIZER |
495                          V3D_DIRTY_ZSA |
496                          V3D_DIRTY_BLEND |
497                          V3D_DIRTY_COMPILED_FS)) {
498                cl_emit(&job->bcl, CFG_BITS, config) {
499                        config.enable_forward_facing_primitive =
500                                !rasterizer_discard &&
501                                !(v3d->rasterizer->base.cull_face &
502                                  PIPE_FACE_FRONT);
503                        config.enable_reverse_facing_primitive =
504                                !rasterizer_discard &&
505                                !(v3d->rasterizer->base.cull_face &
506                                  PIPE_FACE_BACK);
507                        /* This seems backwards, but it's what gets the
508                         * clipflat test to pass.
509                         */
510                        config.clockwise_primitives =
511                                v3d->rasterizer->base.front_ccw;
512
513                        config.enable_depth_offset =
514                                v3d->rasterizer->base.offset_tri;
515
516                        /* V3D follows GL behavior where the sample mask only
517                         * applies when MSAA is enabled.  Gallium has sample
518                         * mask apply anyway, and the MSAA blit shaders will
519                         * set sample mask without explicitly setting
520                         * rasterizer oversample.  Just force it on here,
521                         * since the blit shaders are the only way to have
522                         * !multisample && samplemask != 0xf.
523                         */
524                        config.rasterizer_oversample_mode =
525                                v3d->rasterizer->base.multisample ||
526                                v3d->sample_mask != 0xf;
527
528                        config.direct3d_provoking_vertex =
529                                v3d->rasterizer->base.flatshade_first;
530
531                        config.blend_enable = v3d->blend->blend_enables;
532
533                        /* Note: EZ state may update based on the compiled FS,
534                         * along with ZSA
535                         */
536                        config.early_z_updates_enable =
537                                (job->ez_state != V3D_EZ_DISABLED);
538                        if (v3d->zsa->base.depth_enabled) {
539                                config.z_updates_enable =
540                                        v3d->zsa->base.depth_writemask;
541                                config.early_z_enable =
542                                        config.early_z_updates_enable;
543                                config.depth_test_function =
544                                        v3d->zsa->base.depth_func;
545                        } else {
546                                config.depth_test_function = PIPE_FUNC_ALWAYS;
547                        }
548
549                        config.stencil_enable =
550                                v3d->zsa->base.stencil[0].enabled;
551
552                        /* Use nicer line caps when line smoothing is
553                         * enabled
554                         */
555                        config.line_rasterization =
556                                v3d_line_smoothing_enabled(v3d) ? 1 : 0;
557                }
558
559        }
560
561        if (v3d->dirty & V3D_DIRTY_RASTERIZER &&
562            v3d->rasterizer->base.offset_tri) {
563                if (job->zsbuf &&
564                    job->zsbuf->format == PIPE_FORMAT_Z16_UNORM) {
565                        cl_emit_prepacked_sized(&job->bcl,
566                                                v3d->rasterizer->depth_offset_z16,
567                                                cl_packet_length(DEPTH_OFFSET));
568                } else {
569                        cl_emit_prepacked_sized(&job->bcl,
570                                                v3d->rasterizer->depth_offset,
571                                                cl_packet_length(DEPTH_OFFSET));
572                }
573        }
574
575        if (v3d->dirty & V3D_DIRTY_RASTERIZER) {
576                cl_emit(&job->bcl, POINT_SIZE, point_size) {
577                        point_size.point_size = v3d->rasterizer->point_size;
578                }
579
580                cl_emit(&job->bcl, LINE_WIDTH, line_width) {
581                        line_width.line_width = v3d_get_real_line_width(v3d);
582                }
583        }
584
585        if (v3d->dirty & V3D_DIRTY_VIEWPORT) {
586                cl_emit(&job->bcl, CLIPPER_XY_SCALING, clip) {
587                        clip.viewport_half_width_in_1_256th_of_pixel =
588                                v3d->viewport.scale[0] * 256.0f;
589                        clip.viewport_half_height_in_1_256th_of_pixel =
590                                v3d->viewport.scale[1] * 256.0f;
591                }
592
593                cl_emit(&job->bcl, CLIPPER_Z_SCALE_AND_OFFSET, clip) {
594                        clip.viewport_z_offset_zc_to_zs =
595                                v3d->viewport.translate[2];
596                        clip.viewport_z_scale_zc_to_zs =
597                                v3d->viewport.scale[2];
598                }
599                cl_emit(&job->bcl, CLIPPER_Z_MIN_MAX_CLIPPING_PLANES, clip) {
600                        float z1 = (v3d->viewport.translate[2] -
601                                    v3d->viewport.scale[2]);
602                        float z2 = (v3d->viewport.translate[2] +
603                                    v3d->viewport.scale[2]);
604                        clip.minimum_zw = MIN2(z1, z2);
605                        clip.maximum_zw = MAX2(z1, z2);
606                }
607
608                cl_emit(&job->bcl, VIEWPORT_OFFSET, vp) {
609                        vp.viewport_centre_x_coordinate =
610                                v3d->viewport.translate[0];
611                        vp.viewport_centre_y_coordinate =
612                                v3d->viewport.translate[1];
613                }
614        }
615
616        if (v3d->dirty & V3D_DIRTY_BLEND) {
617                struct v3d_blend_state *blend = v3d->blend;
618
619                if (blend->blend_enables) {
620#if V3D_VERSION >= 40
621                        cl_emit(&job->bcl, BLEND_ENABLES, enables) {
622                                enables.mask = blend->blend_enables;
623                        }
624#endif
625
626                        if (blend->base.independent_blend_enable) {
627                                for (int i = 0; i < V3D_MAX_DRAW_BUFFERS; i++)
628                                        emit_rt_blend(v3d, job, &blend->base, i);
629                        } else {
630                                emit_rt_blend(v3d, job, &blend->base, 0);
631                        }
632                }
633        }
634
635        if (v3d->dirty & V3D_DIRTY_BLEND) {
636                struct pipe_blend_state *blend = &v3d->blend->base;
637
638                cl_emit(&job->bcl, COLOR_WRITE_MASKS, mask) {
639                        for (int i = 0; i < 4; i++) {
640                                int rt = blend->independent_blend_enable ? i : 0;
641                                int rt_mask = blend->rt[rt].colormask;
642
643                                mask.mask |= translate_colormask(v3d, rt_mask,
644                                                                 i) << (4 * i);
645                        }
646                }
647        }
648
649        /* GFXH-1431: On V3D 3.x, writing BLEND_CONFIG resets the constant
650         * color.
651         */
652        if (v3d->dirty & V3D_DIRTY_BLEND_COLOR ||
653            (V3D_VERSION < 41 && (v3d->dirty & V3D_DIRTY_BLEND))) {
654                cl_emit(&job->bcl, BLEND_CONSTANT_COLOR, color) {
655                        color.red_f16 = (v3d->swap_color_rb ?
656                                          v3d->blend_color.hf[2] :
657                                          v3d->blend_color.hf[0]);
658                        color.green_f16 = v3d->blend_color.hf[1];
659                        color.blue_f16 = (v3d->swap_color_rb ?
660                                           v3d->blend_color.hf[0] :
661                                           v3d->blend_color.hf[2]);
662                        color.alpha_f16 = v3d->blend_color.hf[3];
663                }
664        }
665
666        if (v3d->dirty & (V3D_DIRTY_ZSA | V3D_DIRTY_STENCIL_REF)) {
667                struct pipe_stencil_state *front = &v3d->zsa->base.stencil[0];
668                struct pipe_stencil_state *back = &v3d->zsa->base.stencil[1];
669
670                if (front->enabled) {
671                        cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
672                                               v3d->zsa->stencil_front, config) {
673                                config.stencil_ref_value =
674                                        v3d->stencil_ref.ref_value[0];
675                        }
676                }
677
678                if (back->enabled) {
679                        cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
680                                               v3d->zsa->stencil_back, config) {
681                                config.stencil_ref_value =
682                                        v3d->stencil_ref.ref_value[1];
683                        }
684                }
685        }
686
687#if V3D_VERSION < 40
688        /* Pre-4.x, we have texture state that depends on both the sampler and
689         * the view, so we merge them together at draw time.
690         */
691        if (v3d->dirty & V3D_DIRTY_FRAGTEX)
692                emit_textures(v3d, &v3d->tex[PIPE_SHADER_FRAGMENT]);
693
694        if (v3d->dirty & V3D_DIRTY_GEOMTEX)
695                emit_textures(v3d, &v3d->tex[PIPE_SHADER_GEOMETRY]);
696
697        if (v3d->dirty & V3D_DIRTY_VERTTEX)
698                emit_textures(v3d, &v3d->tex[PIPE_SHADER_VERTEX]);
699#endif
700
701        if (v3d->dirty & V3D_DIRTY_FLAT_SHADE_FLAGS) {
702                if (!emit_varying_flags(job,
703                                        v3d->prog.fs->prog_data.fs->flat_shade_flags,
704                                        emit_flat_shade_flags)) {
705                        cl_emit(&job->bcl, ZERO_ALL_FLAT_SHADE_FLAGS, flags);
706                }
707        }
708
709#if V3D_VERSION >= 40
710        if (v3d->dirty & V3D_DIRTY_NOPERSPECTIVE_FLAGS) {
711                if (!emit_varying_flags(job,
712                                        v3d->prog.fs->prog_data.fs->noperspective_flags,
713                                        emit_noperspective_flags)) {
714                        cl_emit(&job->bcl, ZERO_ALL_NON_PERSPECTIVE_FLAGS, flags);
715                }
716        }
717
718        if (v3d->dirty & V3D_DIRTY_CENTROID_FLAGS) {
719                if (!emit_varying_flags(job,
720                                        v3d->prog.fs->prog_data.fs->centroid_flags,
721                                        emit_centroid_flags)) {
722                        cl_emit(&job->bcl, ZERO_ALL_CENTROID_FLAGS, flags);
723                }
724        }
725#endif
726
727        /* Set up the transform feedback data specs (which VPM entries to
728         * output to which buffers).
729         */
730        if (v3d->dirty & (V3D_DIRTY_STREAMOUT |
731                          V3D_DIRTY_RASTERIZER |
732                          V3D_DIRTY_PRIM_MODE)) {
733                struct v3d_streamout_stateobj *so = &v3d->streamout;
734                if (so->num_targets) {
735                        bool psiz_per_vertex = (v3d->prim_mode == PIPE_PRIM_POINTS &&
736                                                v3d->rasterizer->base.point_size_per_vertex);
737                        struct v3d_uncompiled_shader *tf_shader =
738                                get_tf_shader(v3d);
739                        uint16_t *tf_specs = (psiz_per_vertex ?
740                                              tf_shader->tf_specs_psiz :
741                                              tf_shader->tf_specs);
742
743#if V3D_VERSION >= 40
744                        bool tf_enabled = v3d_transform_feedback_enabled(v3d);
745                        job->tf_enabled |= tf_enabled;
746
747                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
748                                tfe.number_of_16_bit_output_data_specs_following =
749                                        tf_shader->num_tf_specs;
750                                tfe.enable = tf_enabled;
751                        };
752#else /* V3D_VERSION < 40 */
753                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_ENABLE, tfe) {
754                                tfe.number_of_32_bit_output_buffer_address_following =
755                                        so->num_targets;
756                                tfe.number_of_16_bit_output_data_specs_following =
757                                        tf_shader->num_tf_specs;
758                        };
759#endif /* V3D_VERSION < 40 */
760                        for (int i = 0; i < tf_shader->num_tf_specs; i++) {
761                                cl_emit_prepacked(&job->bcl, &tf_specs[i]);
762                        }
763                } else {
764#if V3D_VERSION >= 40
765                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
766                                tfe.enable = false;
767                        };
768#endif /* V3D_VERSION >= 40 */
769                }
770        }
771
772        /* Set up the transform feedback buffers. */
773        if (v3d->dirty & V3D_DIRTY_STREAMOUT) {
774                struct v3d_uncompiled_shader *tf_shader = get_tf_shader(v3d);
775                struct v3d_streamout_stateobj *so = &v3d->streamout;
776                for (int i = 0; i < so->num_targets; i++) {
777                        const struct pipe_stream_output_target *target =
778                                so->targets[i];
779                        struct v3d_resource *rsc = target ?
780                                v3d_resource(target->buffer) : NULL;
781                        struct pipe_shader_state *ss = &tf_shader->base;
782                        struct pipe_stream_output_info *info = &ss->stream_output;
783                        uint32_t offset = (v3d->streamout.offsets[i] *
784                                           info->stride[i] * 4);
785
786#if V3D_VERSION >= 40
787                        if (!target)
788                                continue;
789
790                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_BUFFER, output) {
791                                output.buffer_address =
792                                        cl_address(rsc->bo,
793                                                   target->buffer_offset +
794                                                   offset);
795                                output.buffer_size_in_32_bit_words =
796                                        (target->buffer_size - offset) >> 2;
797                                output.buffer_number = i;
798                        }
799#else /* V3D_VERSION < 40 */
800                        cl_emit(&job->bcl, TRANSFORM_FEEDBACK_OUTPUT_ADDRESS, output) {
801                                if (target) {
802                                        output.address =
803                                                cl_address(rsc->bo,
804                                                           target->buffer_offset +
805                                                           offset);
806                                }
807                        };
808#endif /* V3D_VERSION < 40 */
809                        if (target) {
810                                v3d_job_add_tf_write_resource(v3d->job,
811                                                              target->buffer);
812                        }
813                        /* XXX: buffer_size? */
814                }
815        }
816
817        if (v3d->dirty & V3D_DIRTY_OQ) {
818                cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter) {
819                        if (v3d->active_queries && v3d->current_oq) {
820                                counter.address = cl_address(v3d->current_oq, 0);
821                        }
822                }
823        }
824
825#if V3D_VERSION >= 40
826        if (v3d->dirty & V3D_DIRTY_SAMPLE_STATE) {
827                cl_emit(&job->bcl, SAMPLE_STATE, state) {
828                        /* Note: SampleCoverage was handled at the
829                         * frontend level by converting to sample_mask.
830                         */
831                        state.coverage = 1.0;
832                        state.mask = job->msaa ? v3d->sample_mask : 0xf;
833                }
834        }
835#endif
836}
837