• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/common/v3d_util.h"
30 #include "broadcom/compiler/v3d_compiler.h"
31 
32 static uint8_t
v3d_factor(enum pipe_blendfactor factor,bool dst_alpha_one)33 v3d_factor(enum pipe_blendfactor factor, bool dst_alpha_one)
34 {
35         /* We may get a bad blendfactor when blending is disabled. */
36         if (factor == 0)
37                 return V3D_BLEND_FACTOR_ZERO;
38 
39         switch (factor) {
40         case PIPE_BLENDFACTOR_ZERO:
41                 return V3D_BLEND_FACTOR_ZERO;
42         case PIPE_BLENDFACTOR_ONE:
43                 return V3D_BLEND_FACTOR_ONE;
44         case PIPE_BLENDFACTOR_SRC_COLOR:
45                 return V3D_BLEND_FACTOR_SRC_COLOR;
46         case PIPE_BLENDFACTOR_INV_SRC_COLOR:
47                 return V3D_BLEND_FACTOR_INV_SRC_COLOR;
48         case PIPE_BLENDFACTOR_DST_COLOR:
49                 return V3D_BLEND_FACTOR_DST_COLOR;
50         case PIPE_BLENDFACTOR_INV_DST_COLOR:
51                 return V3D_BLEND_FACTOR_INV_DST_COLOR;
52         case PIPE_BLENDFACTOR_SRC_ALPHA:
53                 return V3D_BLEND_FACTOR_SRC_ALPHA;
54         case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
55                 return V3D_BLEND_FACTOR_INV_SRC_ALPHA;
56         case PIPE_BLENDFACTOR_DST_ALPHA:
57                 return (dst_alpha_one ?
58                         V3D_BLEND_FACTOR_ONE :
59                         V3D_BLEND_FACTOR_DST_ALPHA);
60         case PIPE_BLENDFACTOR_INV_DST_ALPHA:
61                 return (dst_alpha_one ?
62                         V3D_BLEND_FACTOR_ZERO :
63                         V3D_BLEND_FACTOR_INV_DST_ALPHA);
64         case PIPE_BLENDFACTOR_CONST_COLOR:
65                 return V3D_BLEND_FACTOR_CONST_COLOR;
66         case PIPE_BLENDFACTOR_INV_CONST_COLOR:
67                 return V3D_BLEND_FACTOR_INV_CONST_COLOR;
68         case PIPE_BLENDFACTOR_CONST_ALPHA:
69                 return V3D_BLEND_FACTOR_CONST_ALPHA;
70         case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
71                 return V3D_BLEND_FACTOR_INV_CONST_ALPHA;
72         case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
73                 return (dst_alpha_one ?
74                         V3D_BLEND_FACTOR_ZERO :
75                         V3D_BLEND_FACTOR_SRC_ALPHA_SATURATE);
76         default:
77                 unreachable("Bad blend factor");
78         }
79 }
80 
81 static uint32_t
translate_colormask(struct v3d_context * v3d,uint32_t colormask,int rt)82 translate_colormask(struct v3d_context *v3d, uint32_t colormask, int rt)
83 {
84         if (v3d->swap_color_rb & (1 << rt)) {
85                 colormask = ((colormask & (2 | 8)) |
86                              ((colormask & 1) << 2) |
87                              ((colormask & 4) >> 2));
88         }
89 
90         return (~colormask) & 0xf;
91 }
92 
93 static void
emit_rt_blend(struct v3d_context * v3d,struct v3d_job * job,struct pipe_blend_state * blend,int rt,uint8_t rt_mask,bool blend_dst_alpha_one)94 emit_rt_blend(struct v3d_context *v3d, struct v3d_job *job,
95               struct pipe_blend_state *blend, int rt, uint8_t rt_mask,
96               bool blend_dst_alpha_one)
97 {
98         struct pipe_rt_blend_state *rtblend = &blend->rt[rt];
99 
100         /* We don't need to emit blend state for disabled RTs. */
101         if (!rtblend->blend_enable)
102                 return;
103 
104         cl_emit(&job->bcl, BLEND_CFG, config) {
105                 config.render_target_mask = rt_mask;
106 
107                 config.color_blend_mode = rtblend->rgb_func;
108                 config.color_blend_dst_factor =
109                         v3d_factor(rtblend->rgb_dst_factor,
110                                    blend_dst_alpha_one);
111                 config.color_blend_src_factor =
112                         v3d_factor(rtblend->rgb_src_factor,
113                                    blend_dst_alpha_one);
114 
115                 config.alpha_blend_mode = rtblend->alpha_func;
116                 config.alpha_blend_dst_factor =
117                         v3d_factor(rtblend->alpha_dst_factor,
118                                    blend_dst_alpha_one);
119                 config.alpha_blend_src_factor =
120                         v3d_factor(rtblend->alpha_src_factor,
121                                    blend_dst_alpha_one);
122         }
123 }
124 
125 static void
emit_flat_shade_flags(struct v3d_job * job,int varying_offset,uint32_t varyings,enum V3DX (Varying_Flags_Action)lower,enum V3DX (Varying_Flags_Action)higher)126 emit_flat_shade_flags(struct v3d_job *job,
127                       int varying_offset,
128                       uint32_t varyings,
129                       enum V3DX(Varying_Flags_Action) lower,
130                       enum V3DX(Varying_Flags_Action) higher)
131 {
132         cl_emit(&job->bcl, FLAT_SHADE_FLAGS, flags) {
133                 flags.varying_offset_v0 = varying_offset;
134                 flags.flat_shade_flags_for_varyings_v024 = varyings;
135                 flags.action_for_flat_shade_flags_of_lower_numbered_varyings =
136                         lower;
137                 flags.action_for_flat_shade_flags_of_higher_numbered_varyings =
138                         higher;
139         }
140 }
141 
142 static void
emit_noperspective_flags(struct v3d_job * job,int varying_offset,uint32_t varyings,enum V3DX (Varying_Flags_Action)lower,enum V3DX (Varying_Flags_Action)higher)143 emit_noperspective_flags(struct v3d_job *job,
144                          int varying_offset,
145                          uint32_t varyings,
146                          enum V3DX(Varying_Flags_Action) lower,
147                          enum V3DX(Varying_Flags_Action) higher)
148 {
149         cl_emit(&job->bcl, NON_PERSPECTIVE_FLAGS, flags) {
150                 flags.varying_offset_v0 = varying_offset;
151                 flags.non_perspective_flags_for_varyings_v024 = varyings;
152                 flags.action_for_non_perspective_flags_of_lower_numbered_varyings =
153                         lower;
154                 flags.action_for_non_perspective_flags_of_higher_numbered_varyings =
155                         higher;
156         }
157 }
158 
159 static void
emit_centroid_flags(struct v3d_job * job,int varying_offset,uint32_t varyings,enum V3DX (Varying_Flags_Action)lower,enum V3DX (Varying_Flags_Action)higher)160 emit_centroid_flags(struct v3d_job *job,
161                     int varying_offset,
162                     uint32_t varyings,
163                     enum V3DX(Varying_Flags_Action) lower,
164                     enum V3DX(Varying_Flags_Action) higher)
165 {
166         cl_emit(&job->bcl, CENTROID_FLAGS, flags) {
167                 flags.varying_offset_v0 = varying_offset;
168                 flags.centroid_flags_for_varyings_v024 = varyings;
169                 flags.action_for_centroid_flags_of_lower_numbered_varyings =
170                         lower;
171                 flags.action_for_centroid_flags_of_higher_numbered_varyings =
172                         higher;
173         }
174 }
175 
176 static bool
emit_varying_flags(struct v3d_job * job,uint32_t * flags,void (* flag_emit_callback)(struct v3d_job * job,int varying_offset,uint32_t flags,enum V3DX (Varying_Flags_Action)lower,enum V3DX (Varying_Flags_Action)higher))177 emit_varying_flags(struct v3d_job *job, uint32_t *flags,
178                    void (*flag_emit_callback)(struct v3d_job *job,
179                                               int varying_offset,
180                                               uint32_t flags,
181                                               enum V3DX(Varying_Flags_Action) lower,
182                                               enum V3DX(Varying_Flags_Action) higher))
183 {
184         bool emitted_any = false;
185 
186         for (int i = 0; i < ARRAY_SIZE(job->v3d->prog.fs->prog_data.fs->flat_shade_flags); i++) {
187                 if (!flags[i])
188                         continue;
189 
190                 if (emitted_any) {
191                         flag_emit_callback(job, i, flags[i],
192                                            V3D_VARYING_FLAGS_ACTION_UNCHANGED,
193                                            V3D_VARYING_FLAGS_ACTION_UNCHANGED);
194                 } else if (i == 0) {
195                         flag_emit_callback(job, i, flags[i],
196                                            V3D_VARYING_FLAGS_ACTION_UNCHANGED,
197                                            V3D_VARYING_FLAGS_ACTION_ZEROED);
198                 } else {
199                         flag_emit_callback(job, i, flags[i],
200                                            V3D_VARYING_FLAGS_ACTION_ZEROED,
201                                            V3D_VARYING_FLAGS_ACTION_ZEROED);
202                 }
203                 emitted_any = true;
204         }
205 
206         return emitted_any;
207 }
208 
209 static inline struct v3d_uncompiled_shader *
get_tf_shader(struct v3d_context * v3d)210 get_tf_shader(struct v3d_context *v3d)
211 {
212         if (v3d->prog.bind_gs)
213                 return v3d->prog.bind_gs;
214         else
215                 return v3d->prog.bind_vs;
216 }
217 
218 void
v3dX(emit_state)219 v3dX(emit_state)(struct pipe_context *pctx)
220 {
221         struct v3d_context *v3d = v3d_context(pctx);
222         struct v3d_job *job = v3d->job;
223         bool rasterizer_discard = v3d->rasterizer->base.rasterizer_discard;
224 
225         if (v3d->dirty & (V3D_DIRTY_SCISSOR | V3D_DIRTY_VIEWPORT |
226                           V3D_DIRTY_RASTERIZER)) {
227                 float *vpscale = v3d->viewport.scale;
228                 float *vptranslate = v3d->viewport.translate;
229                 float vp_minx = -fabsf(vpscale[0]) + vptranslate[0];
230                 float vp_maxx = fabsf(vpscale[0]) + vptranslate[0];
231                 float vp_miny = -fabsf(vpscale[1]) + vptranslate[1];
232                 float vp_maxy = fabsf(vpscale[1]) + vptranslate[1];
233 
234                 /* Clip to the scissor if it's enabled, but still clip to the
235                  * drawable regardless since that controls where the binner
236                  * tries to put things.
237                  *
238                  * Additionally, always clip the rendering to the viewport,
239                  * since the hardware does guardband clipping, meaning
240                  * primitives would rasterize outside of the view volume.
241                  */
242                 uint32_t minx, miny, maxx, maxy;
243                 if (!v3d->rasterizer->base.scissor) {
244                         minx = MAX2(vp_minx, 0);
245                         miny = MAX2(vp_miny, 0);
246                         maxx = MIN2(vp_maxx, job->draw_width);
247                         maxy = MIN2(vp_maxy, job->draw_height);
248                 } else {
249                         minx = MAX2(vp_minx, v3d->scissor.minx);
250                         miny = MAX2(vp_miny, v3d->scissor.miny);
251                         maxx = MIN2(vp_maxx, v3d->scissor.maxx);
252                         maxy = MIN2(vp_maxy, v3d->scissor.maxy);
253                 }
254 
255                 cl_emit(&job->bcl, CLIP_WINDOW, clip) {
256                         clip.clip_window_left_pixel_coordinate = minx;
257                         clip.clip_window_bottom_pixel_coordinate = miny;
258                         if (maxx > minx && maxy > miny) {
259                                 clip.clip_window_width_in_pixels = maxx - minx;
260                                 clip.clip_window_height_in_pixels = maxy - miny;
261                         }
262                 }
263 
264                 job->draw_min_x = MIN2(job->draw_min_x, minx);
265                 job->draw_min_y = MIN2(job->draw_min_y, miny);
266                 job->draw_max_x = MAX2(job->draw_max_x, maxx);
267                 job->draw_max_y = MAX2(job->draw_max_y, maxy);
268 
269                 if (!v3d->rasterizer->base.scissor) {
270                     job->scissor.disabled = true;
271                 } else if (!job->scissor.disabled &&
272                            (v3d->dirty & V3D_DIRTY_SCISSOR)) {
273                         if (job->scissor.count < MAX_JOB_SCISSORS) {
274                                 job->scissor.rects[job->scissor.count].min_x =
275                                         v3d->scissor.minx;
276                                 job->scissor.rects[job->scissor.count].min_y =
277                                         v3d->scissor.miny;
278                                 job->scissor.rects[job->scissor.count].max_x =
279                                         v3d->scissor.maxx - 1;
280                                 job->scissor.rects[job->scissor.count].max_y =
281                                         v3d->scissor.maxy - 1;
282                                 job->scissor.count++;
283                         } else {
284                                 job->scissor.disabled = true;
285                                 perf_debug("Too many scissor rects.");
286                         }
287                 }
288         }
289 
290         if (v3d->dirty & (V3D_DIRTY_RASTERIZER |
291                           V3D_DIRTY_ZSA |
292                           V3D_DIRTY_BLEND |
293                           V3D_DIRTY_COMPILED_FS)) {
294                 cl_emit(&job->bcl, CFG_BITS, config) {
295                         config.enable_forward_facing_primitive =
296                                 !rasterizer_discard &&
297                                 !(v3d->rasterizer->base.cull_face &
298                                   PIPE_FACE_FRONT);
299                         config.enable_reverse_facing_primitive =
300                                 !rasterizer_discard &&
301                                 !(v3d->rasterizer->base.cull_face &
302                                   PIPE_FACE_BACK);
303                         /* This seems backwards, but it's what gets the
304                          * clipflat test to pass.
305                          */
306                         config.clockwise_primitives =
307                                 v3d->rasterizer->base.front_ccw;
308 
309                         config.enable_depth_offset =
310                                 v3d->rasterizer->base.offset_tri;
311 
312                         /* V3D follows GL behavior where the sample mask only
313                          * applies when MSAA is enabled.  Gallium has sample
314                          * mask apply anyway, and the MSAA blit shaders will
315                          * set sample mask without explicitly setting
316                          * rasterizer oversample.  Just force it on here,
317                          * since the blit shaders are the only way to have
318                          * !multisample && samplemask != 0xf.
319                          */
320                         config.rasterizer_oversample_mode =
321                                 v3d->rasterizer->base.multisample ||
322                                 v3d->sample_mask != 0xf;
323 
324                         config.direct3d_provoking_vertex =
325                                 v3d->rasterizer->base.flatshade_first;
326 
327                         config.blend_enable = v3d->blend->blend_enables;
328 
329                         /* Note: EZ state may update based on the compiled FS,
330                          * along with ZSA
331                          */
332 #if V3D_VERSION == 42
333                         config.early_z_updates_enable =
334                                 (job->ez_state != V3D_EZ_DISABLED);
335 #endif
336                         if (v3d->zsa->base.depth_enabled) {
337                                 config.z_updates_enable =
338                                         v3d->zsa->base.depth_writemask;
339 #if V3D_VERSION == 42
340                                 config.early_z_enable =
341                                         config.early_z_updates_enable;
342 #endif
343                                 config.depth_test_function =
344                                         v3d->zsa->base.depth_func;
345                         } else {
346                                 config.depth_test_function = PIPE_FUNC_ALWAYS;
347                         }
348 
349                         config.stencil_enable =
350                                 v3d->zsa->base.stencil[0].enabled;
351 
352                         /* Use nicer line caps when line smoothing is
353                          * enabled
354                          */
355                         config.line_rasterization =
356                                 v3d_line_smoothing_enabled(v3d) ?
357                                 V3D_LINE_RASTERIZATION_PERP_END_CAPS :
358                                 V3D_LINE_RASTERIZATION_DIAMOND_EXIT;
359 
360                         if (config.enable_forward_facing_primitive &&
361                             config.enable_reverse_facing_primitive &&
362                             v3d->rasterizer->base.fill_front != v3d->rasterizer->base.fill_back) {
363                                 mesa_logw_once("Setting a different polygon mode for "
364                                                "front and back faces is not supported");
365                         }
366 
367                         if (config.enable_forward_facing_primitive) {
368                                 if (v3d->rasterizer->base.fill_front != PIPE_POLYGON_MODE_FILL) {
369                                         config.direct3d_wireframe_triangles_mode = true;
370                                         config.direct3d_point_fill_mode =
371                                                 v3d->rasterizer->base.fill_front == PIPE_POLYGON_MODE_POINT;
372                                 }
373                         } else {
374                                 if (v3d->rasterizer->base.fill_back != PIPE_POLYGON_MODE_FILL) {
375                                         config.direct3d_wireframe_triangles_mode = true;
376                                         config.direct3d_point_fill_mode =
377                                                 v3d->rasterizer->base.fill_back == PIPE_POLYGON_MODE_POINT;
378                                 }
379                         }
380 
381 #if V3D_VERSION >= 71
382                         config.z_clipping_mode = v3d->rasterizer->base.depth_clip_near ||
383                            v3d->rasterizer->base.depth_clip_far ?
384                            V3D_Z_CLIP_MODE_MIN_ONE_TO_ONE : V3D_Z_CLIP_MODE_NONE;
385 
386                         config.z_clamp_mode = v3d->rasterizer->base.depth_clamp;
387 #endif
388                 }
389         }
390 
391         if (v3d->dirty & V3D_DIRTY_RASTERIZER &&
392             v3d->rasterizer->base.offset_tri) {
393                 if (v3d->screen->devinfo.ver == 42 &&
394                     job->zsbuf &&
395                     job->zsbuf->format == PIPE_FORMAT_Z16_UNORM) {
396                         cl_emit_prepacked_sized(&job->bcl,
397                                                 v3d->rasterizer->depth_offset_z16,
398                                                 cl_packet_length(DEPTH_OFFSET));
399                 } else {
400                         cl_emit_prepacked_sized(&job->bcl,
401                                                 v3d->rasterizer->depth_offset,
402                                                 cl_packet_length(DEPTH_OFFSET));
403                 }
404         }
405 
406         if (v3d->dirty & V3D_DIRTY_RASTERIZER) {
407                 cl_emit(&job->bcl, POINT_SIZE, point_size) {
408                         point_size.point_size = v3d->rasterizer->point_size;
409                 }
410 
411                 cl_emit(&job->bcl, LINE_WIDTH, line_width) {
412                         line_width.line_width = v3d_get_real_line_width(v3d);
413                 }
414         }
415 
416         if (v3d->dirty & V3D_DIRTY_VIEWPORT) {
417 #if V3D_VERSION == 42
418                 cl_emit(&job->bcl, CLIPPER_XY_SCALING, clip) {
419                         clip.viewport_half_width_in_1_256th_of_pixel =
420                                 v3d->viewport.scale[0] * 256.0f;
421                         clip.viewport_half_height_in_1_256th_of_pixel =
422                                 v3d->viewport.scale[1] * 256.0f;
423                 }
424 #endif
425 #if V3D_VERSION >= 71
426                 cl_emit(&job->bcl, CLIPPER_XY_SCALING, clip) {
427                         clip.viewport_half_width_in_1_64th_of_pixel =
428                                 v3d->viewport.scale[0] * 64.0f;
429                         clip.viewport_half_height_in_1_64th_of_pixel =
430                                 v3d->viewport.scale[1] * 64.0f;
431                 }
432 #endif
433 
434 
435                 cl_emit(&job->bcl, CLIPPER_Z_SCALE_AND_OFFSET, clip) {
436                         clip.viewport_z_offset_zc_to_zs =
437                                 v3d->viewport.translate[2];
438                         clip.viewport_z_scale_zc_to_zs =
439                                 v3d->viewport.scale[2];
440                 }
441                 cl_emit(&job->bcl, CLIPPER_Z_MIN_MAX_CLIPPING_PLANES, clip) {
442                         float z1 = (v3d->viewport.translate[2] -
443                                     v3d->viewport.scale[2]);
444                         float z2 = (v3d->viewport.translate[2] +
445                                     v3d->viewport.scale[2]);
446                         clip.minimum_zw = MIN2(z1, z2);
447                         clip.maximum_zw = MAX2(z1, z2);
448                 }
449 
450                 cl_emit(&job->bcl, VIEWPORT_OFFSET, vp) {
451                         float vp_fine_x = v3d->viewport.translate[0];
452                         float vp_fine_y = v3d->viewport.translate[1];
453                         int32_t vp_coarse_x = 0;
454                         int32_t vp_coarse_y = 0;
455 
456                         /* The fine coordinates must be unsigned, but coarse
457                          * can be signed.
458                          */
459                         if (unlikely(vp_fine_x < 0)) {
460                                 int32_t blocks_64 =
461                                         DIV_ROUND_UP(fabsf(vp_fine_x), 64);
462                                 vp_fine_x += 64.0f * blocks_64;
463                                 vp_coarse_x -= blocks_64;
464                         }
465 
466                         if (unlikely(vp_fine_y < 0)) {
467                                 int32_t blocks_64 =
468                                         DIV_ROUND_UP(fabsf(vp_fine_y), 64);
469                                 vp_fine_y += 64.0f * blocks_64;
470                                 vp_coarse_y -= blocks_64;
471                         }
472 
473                         vp.fine_x = vp_fine_x;
474                         vp.fine_y = vp_fine_y;
475                         vp.coarse_x = vp_coarse_x;
476                         vp.coarse_y = vp_coarse_y;
477                 }
478         }
479 
480         if (v3d->dirty & V3D_DIRTY_BLEND) {
481                 struct v3d_blend_state *blend = v3d->blend;
482 
483                 if (blend->blend_enables) {
484                         cl_emit(&job->bcl, BLEND_ENABLES, enables) {
485                                 enables.mask = blend->blend_enables;
486                         }
487 
488                         const uint32_t max_rts =
489                                 V3D_MAX_RENDER_TARGETS(v3d->screen->devinfo.ver);
490                         if (blend->base.independent_blend_enable) {
491                                 for (int i = 0; i < max_rts; i++)
492                                         emit_rt_blend(v3d, job, &blend->base, i,
493                                                       (1 << i),
494                                                       v3d->blend_dst_alpha_one & (1 << i));
495                         } else if (v3d->blend_dst_alpha_one &&
496                                    util_bitcount(v3d->blend_dst_alpha_one) < job->nr_cbufs) {
497                                 /* Even if we don't have independent per-RT
498                                  * blending, we may have a combination of RT
499                                  * formats were some RTs have an alpha channel
500                                  * and others don't. Since this affects how
501                                  * blending is performed, we also need to emit
502                                  * independent blend configurations in this
503                                  * case: one for RTs with alpha and one for
504                                  * RTs without.
505                                  */
506                                 emit_rt_blend(v3d, job, &blend->base, 0,
507                                               ((1 << max_rts) - 1) &
508                                                    v3d->blend_dst_alpha_one,
509                                               true);
510                                 emit_rt_blend(v3d, job, &blend->base, 0,
511                                               ((1 << max_rts) - 1) &
512                                                    ~v3d->blend_dst_alpha_one,
513                                               false);
514                         } else {
515                                 emit_rt_blend(v3d, job, &blend->base, 0,
516                                               (1 << max_rts) - 1,
517                                               v3d->blend_dst_alpha_one);
518                         }
519                 }
520         }
521 
522         if (v3d->dirty & V3D_DIRTY_BLEND) {
523                 struct pipe_blend_state *blend = &v3d->blend->base;
524 
525                 const uint32_t max_rts =
526                         V3D_MAX_RENDER_TARGETS(v3d->screen->devinfo.ver);
527                 cl_emit(&job->bcl, COLOR_WRITE_MASKS, mask) {
528                         for (int i = 0; i < max_rts; i++) {
529                                 int rt = blend->independent_blend_enable ? i : 0;
530                                 int rt_mask = blend->rt[rt].colormask;
531 
532                                 mask.mask |= translate_colormask(v3d, rt_mask,
533                                                                  i) << (4 * i);
534                         }
535                 }
536         }
537 
538         /* GFXH-1431: On V3D 3.x, writing BLEND_CONFIG resets the constant
539          * color.
540          */
541         if (v3d->dirty & V3D_DIRTY_BLEND_COLOR) {
542                 cl_emit(&job->bcl, BLEND_CONSTANT_COLOR, color) {
543                         color.red_f16 = (v3d->swap_color_rb ?
544                                           v3d->blend_color.hf[2] :
545                                           v3d->blend_color.hf[0]);
546                         color.green_f16 = v3d->blend_color.hf[1];
547                         color.blue_f16 = (v3d->swap_color_rb ?
548                                            v3d->blend_color.hf[0] :
549                                            v3d->blend_color.hf[2]);
550                         color.alpha_f16 = v3d->blend_color.hf[3];
551                 }
552         }
553 
554         if (v3d->dirty & (V3D_DIRTY_ZSA | V3D_DIRTY_STENCIL_REF)) {
555                 struct pipe_stencil_state *front = &v3d->zsa->base.stencil[0];
556                 struct pipe_stencil_state *back = &v3d->zsa->base.stencil[1];
557 
558                 if (front->enabled) {
559                         cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
560                                                v3d->zsa->stencil_front, config) {
561                                 config.stencil_ref_value =
562                                         v3d->stencil_ref.ref_value[0];
563                         }
564                 }
565 
566                 if (back->enabled) {
567                         cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
568                                                v3d->zsa->stencil_back, config) {
569                                 config.stencil_ref_value =
570                                         v3d->stencil_ref.ref_value[1];
571                         }
572                 }
573         }
574 
575         if (v3d->dirty & V3D_DIRTY_FLAT_SHADE_FLAGS) {
576                 if (!emit_varying_flags(job,
577                                         v3d->prog.fs->prog_data.fs->flat_shade_flags,
578                                         emit_flat_shade_flags)) {
579                         cl_emit(&job->bcl, ZERO_ALL_FLAT_SHADE_FLAGS, flags);
580                 }
581         }
582 
583         if (v3d->dirty & V3D_DIRTY_NOPERSPECTIVE_FLAGS) {
584                 if (!emit_varying_flags(job,
585                                         v3d->prog.fs->prog_data.fs->noperspective_flags,
586                                         emit_noperspective_flags)) {
587                         cl_emit(&job->bcl, ZERO_ALL_NON_PERSPECTIVE_FLAGS, flags);
588                 }
589         }
590 
591         if (v3d->dirty & V3D_DIRTY_CENTROID_FLAGS) {
592                 if (!emit_varying_flags(job,
593                                         v3d->prog.fs->prog_data.fs->centroid_flags,
594                                         emit_centroid_flags)) {
595                         cl_emit(&job->bcl, ZERO_ALL_CENTROID_FLAGS, flags);
596                 }
597         }
598 
599         /* Set up the transform feedback data specs (which VPM entries to
600          * output to which buffers).
601          */
602         if (v3d->dirty & (V3D_DIRTY_STREAMOUT |
603                           V3D_DIRTY_RASTERIZER |
604                           V3D_DIRTY_PRIM_MODE)) {
605                 struct v3d_streamout_stateobj *so = &v3d->streamout;
606                 if (so->num_targets) {
607                         bool psiz_per_vertex = (v3d->prim_mode == MESA_PRIM_POINTS &&
608                                                 v3d->rasterizer->base.point_size_per_vertex);
609                         struct v3d_uncompiled_shader *tf_shader =
610                                 get_tf_shader(v3d);
611                         uint16_t *tf_specs = (psiz_per_vertex ?
612                                               tf_shader->tf_specs_psiz :
613                                               tf_shader->tf_specs);
614 
615                         bool tf_enabled = v3d_transform_feedback_enabled(v3d);
616                         job->tf_enabled |= tf_enabled;
617 
618                         cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
619                                 tfe.number_of_16_bit_output_data_specs_following =
620                                         tf_shader->num_tf_specs;
621                                 tfe.enable = tf_enabled;
622                         };
623                         for (int i = 0; i < tf_shader->num_tf_specs; i++) {
624                                 cl_emit_prepacked(&job->bcl, &tf_specs[i]);
625                         }
626                 } else {
627                         cl_emit(&job->bcl, TRANSFORM_FEEDBACK_SPECS, tfe) {
628                                 tfe.enable = false;
629                         };
630                 }
631         }
632 
633         /* Set up the transform feedback buffers. */
634         if (v3d->dirty & V3D_DIRTY_STREAMOUT) {
635                 struct v3d_uncompiled_shader *tf_shader = get_tf_shader(v3d);
636                 struct v3d_streamout_stateobj *so = &v3d->streamout;
637                 for (int i = 0; i < so->num_targets; i++) {
638                         struct pipe_stream_output_target *target =
639                                 so->targets[i];
640                         struct v3d_resource *rsc = target ?
641                                 v3d_resource(target->buffer) : NULL;
642                         struct pipe_shader_state *ss = &tf_shader->base;
643                         struct pipe_stream_output_info *info = &ss->stream_output;
644                         uint32_t offset = target ?
645                                 v3d_stream_output_target(target)->offset * info->stride[i] * 4 : 0;
646 
647                         if (!target)
648                                 continue;
649 
650                         cl_emit(&job->bcl, TRANSFORM_FEEDBACK_BUFFER, output) {
651                                 output.buffer_address =
652                                         cl_address(rsc->bo,
653                                                    target->buffer_offset +
654                                                    offset);
655                                 output.buffer_size_in_32_bit_words =
656                                         (target->buffer_size - offset) >> 2;
657                                 output.buffer_number = i;
658                         }
659                         if (target) {
660                                 v3d_job_add_tf_write_resource(v3d->job,
661                                                               target->buffer);
662                         }
663                         /* XXX: buffer_size? */
664                 }
665         }
666 
667         if (v3d->dirty & V3D_DIRTY_OQ) {
668                 cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter) {
669                         if (v3d->active_queries && v3d->current_oq) {
670                                 counter.address = cl_address(v3d->current_oq, 0);
671                         }
672                 }
673         }
674 
675         if (v3d->dirty & V3D_DIRTY_SAMPLE_STATE) {
676                 cl_emit(&job->bcl, SAMPLE_STATE, state) {
677                         /* Note: SampleCoverage was handled at the
678                          * frontend level by converting to sample_mask.
679                          */
680                         state.coverage = 1.0;
681                         state.mask = job->msaa ? v3d->sample_mask : 0xf;
682                 }
683         }
684 }
685