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