genX_blorp_exec.c revision 16a9fcbbb688537ac2e8f952e683d63eb7c688e8
1/* 2 * Copyright © 2011 Intel Corporation 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 <assert.h> 25 26#include "intel_batchbuffer.h" 27#include "intel_mipmap_tree.h" 28 29#include "brw_context.h" 30#include "brw_state.h" 31 32#include "blorp_priv.h" 33 34#include "genxml/gen_macros.h" 35 36static void * 37blorp_emit_dwords(struct brw_context *brw, unsigned n) 38{ 39 intel_batchbuffer_begin(brw, n, RENDER_RING); 40 uint32_t *map = brw->batch.map_next; 41 brw->batch.map_next += n; 42 intel_batchbuffer_advance(brw); 43 return map; 44} 45 46struct blorp_address { 47 drm_intel_bo *buffer; 48 uint32_t read_domains; 49 uint32_t write_domain; 50 uint32_t offset; 51}; 52 53static uint64_t 54blorp_emit_reloc(struct brw_context *brw, void *location, 55 struct blorp_address address, uint32_t delta) 56{ 57 uint32_t offset = (char *)location - (char *)brw->batch.map; 58 if (brw->gen >= 8) { 59 return intel_batchbuffer_reloc64(brw, address.buffer, offset, 60 address.read_domains, 61 address.write_domain, 62 address.offset + delta); 63 } else { 64 return intel_batchbuffer_reloc(brw, address.buffer, offset, 65 address.read_domains, 66 address.write_domain, 67 address.offset + delta); 68 } 69} 70 71#define __gen_address_type struct blorp_address 72#define __gen_user_data struct brw_context 73 74static uint64_t 75__gen_combine_address(struct brw_context *brw, void *location, 76 struct blorp_address address, uint32_t delta) 77{ 78 if (address.buffer == NULL) { 79 return address.offset + delta; 80 } else { 81 return blorp_emit_reloc(brw, location, address, delta); 82 } 83} 84 85#include "genxml/genX_pack.h" 86 87#define _blorp_cmd_length(cmd) cmd ## _length 88#define _blorp_cmd_length_bias(cmd) cmd ## _length_bias 89#define _blorp_cmd_header(cmd) cmd ## _header 90#define _blorp_cmd_pack(cmd) cmd ## _pack 91 92#define blorp_emit(brw, cmd, name) \ 93 for (struct cmd name = { _blorp_cmd_header(cmd) }, \ 94 *_dst = blorp_emit_dwords(brw, _blorp_cmd_length(cmd)); \ 95 __builtin_expect(_dst != NULL, 1); \ 96 _blorp_cmd_pack(cmd)(brw, (void *)_dst, &name), \ 97 _dst = NULL) 98 99#define blorp_emitn(batch, cmd, n) ({ \ 100 uint32_t *_dw = blorp_emit_dwords(batch, n); \ 101 struct cmd template = { \ 102 _blorp_cmd_header(cmd), \ 103 .DWordLength = n - _blorp_cmd_length_bias(cmd), \ 104 }; \ 105 _blorp_cmd_pack(cmd)(batch, _dw, &template); \ 106 _dw + 1; /* Array starts at dw[1] */ \ 107 }) 108 109/* Once vertex fetcher has written full VUE entries with complete 110 * header the space requirement is as follows per vertex (in bytes): 111 * 112 * Header Position Program constants 113 * +--------+------------+-------------------+ 114 * | 16 | 16 | n x 16 | 115 * +--------+------------+-------------------+ 116 * 117 * where 'n' stands for number of varying inputs expressed as vec4s. 118 * 119 * The URB size is in turn expressed in 64 bytes (512 bits). 120 */ 121static inline unsigned 122gen7_blorp_get_vs_entry_size(const struct brw_blorp_params *params) 123{ 124 const unsigned num_varyings = 125 params->wm_prog_data ? params->wm_prog_data->num_varying_inputs : 0; 126 const unsigned total_needed = 16 + 16 + num_varyings * 16; 127 128 return DIV_ROUND_UP(total_needed, 64); 129} 130 131/* 3DSTATE_URB 132/* 3DSTATE_URB_VS 133 * 3DSTATE_URB_HS 134 * 3DSTATE_URB_DS 135 * 3DSTATE_URB_GS 136 * 137 * Assign the entire URB to the VS. Even though the VS disabled, URB space 138 * is still needed because the clipper loads the VUE's from the URB. From 139 * the Sandybridge PRM, Volume 2, Part 1, Section 3DSTATE, 140 * Dword 1.15:0 "VS Number of URB Entries": 141 * This field is always used (even if VS Function Enable is DISABLED). 142 * 143 * The warning below appears in the PRM (Section 3DSTATE_URB), but we can 144 * safely ignore it because this batch contains only one draw call. 145 * Because of URB corruption caused by allocating a previous GS unit 146 * URB entry to the VS unit, software is required to send a “GS NULL 147 * Fence” (Send URB fence with VS URB size == 1 and GS URB size == 0) 148 * plus a dummy DRAW call before any case where VS will be taking over 149 * GS URB space. 150 * 151 * If the 3DSTATE_URB_VS is emitted, than the others must be also. 152 * From the Ivybridge PRM, Volume 2 Part 1, section 1.7.1 3DSTATE_URB_VS: 153 * 154 * 3DSTATE_URB_HS, 3DSTATE_URB_DS, and 3DSTATE_URB_GS must also be 155 * programmed in order for the programming of this state to be 156 * valid. 157 */ 158static void 159emit_urb_config(struct brw_context *brw, 160 const struct brw_blorp_params *params) 161{ 162#if GEN_GEN >= 7 163 const unsigned vs_entry_size = gen7_blorp_get_vs_entry_size(params); 164 165 if (!(brw->ctx.NewDriverState & (BRW_NEW_CONTEXT | BRW_NEW_URB_SIZE)) && 166 brw->urb.vsize >= vs_entry_size) 167 return; 168 169 brw->ctx.NewDriverState |= BRW_NEW_URB_SIZE; 170 171 gen7_upload_urb(brw, vs_entry_size, false, false); 172#else 173 blorp_emit(brw, GENX(3DSTATE_URB), urb) { 174 urb.VSNumberofURBEntries = brw->urb.max_vs_entries; 175 } 176#endif 177} 178 179static void 180blorp_emit_vertex_data(struct brw_context *brw, 181 const struct brw_blorp_params *params, 182 struct blorp_address *addr, 183 uint32_t *size) 184{ 185 const float vertices[] = { 186 /* v0 */ (float)params->x0, (float)params->y1, 187 /* v1 */ (float)params->x1, (float)params->y1, 188 /* v2 */ (float)params->x0, (float)params->y0, 189 }; 190 191 uint32_t offset; 192 void *data = brw_state_batch(brw, AUB_TRACE_VERTEX_BUFFER, 193 sizeof(vertices), 32, &offset); 194 memcpy(data, vertices, sizeof(vertices)); 195 196 *addr = (struct blorp_address) { 197 .buffer = brw->batch.bo, 198 .read_domains = I915_GEM_DOMAIN_VERTEX, 199 .write_domain = 0, 200 .offset = offset, 201 }; 202 *size = sizeof(vertices); 203} 204 205static void 206blorp_emit_input_varying_data(struct brw_context *brw, 207 const struct brw_blorp_params *params, 208 struct blorp_address *addr, 209 uint32_t *size) 210{ 211 const unsigned vec4_size_in_bytes = 4 * sizeof(float); 212 const unsigned max_num_varyings = 213 DIV_ROUND_UP(sizeof(params->wm_inputs), vec4_size_in_bytes); 214 const unsigned num_varyings = params->wm_prog_data->num_varying_inputs; 215 216 *size = num_varyings * vec4_size_in_bytes; 217 218 const float *const inputs_src = (const float *)¶ms->wm_inputs; 219 uint32_t offset; 220 float *inputs = brw_state_batch(brw, AUB_TRACE_VERTEX_BUFFER, 221 *size, 32, &offset); 222 223 /* Walk over the attribute slots, determine if the attribute is used by 224 * the program and when necessary copy the values from the input storage to 225 * the vertex data buffer. 226 */ 227 for (unsigned i = 0; i < max_num_varyings; i++) { 228 const gl_varying_slot attr = VARYING_SLOT_VAR0 + i; 229 230 if (!(params->wm_prog_data->inputs_read & BITFIELD64_BIT(attr))) 231 continue; 232 233 memcpy(inputs, inputs_src + i * 4, vec4_size_in_bytes); 234 235 inputs += 4; 236 } 237 238 *addr = (struct blorp_address) { 239 .buffer = brw->batch.bo, 240 .read_domains = I915_GEM_DOMAIN_VERTEX, 241 .write_domain = 0, 242 .offset = offset, 243 }; 244} 245 246static void 247blorp_emit_vertex_buffers(struct brw_context *brw, 248 const struct brw_blorp_params *params) 249{ 250 struct GENX(VERTEX_BUFFER_STATE) vb[2]; 251 memset(vb, 0, sizeof(vb)); 252 253 unsigned num_buffers = 1; 254 255#if GEN_GEN == 9 256 uint32_t mocs = (2 << 1); /* SKL_MOCS_WB */ 257#elif GEN_GEN == 8 258 uint32_t mocs = 0x78; /* BDW_MOCS_WB */ 259#elif GEN_GEN == 7 260 uint32_t mocs = 1; /* GEN7_MOCS_L3 */ 261#else 262 uint32_t mocs = 0; 263#endif 264 265 uint32_t size; 266 blorp_emit_vertex_data(brw, params, &vb[0].BufferStartingAddress, &size); 267 vb[0].VertexBufferIndex = 0; 268 vb[0].BufferPitch = 2 * sizeof(float); 269 vb[0].VertexBufferMOCS = mocs; 270#if GEN_GEN >= 7 271 vb[0].AddressModifyEnable = true; 272#endif 273#if GEN_GEN >= 8 274 vb[0].BufferSize = size; 275#else 276 vb[0].BufferAccessType = VERTEXDATA; 277 vb[0].EndAddress = vb[0].BufferStartingAddress; 278 vb[0].EndAddress.offset += size - 1; 279#endif 280 281 if (params->wm_prog_data && params->wm_prog_data->num_varying_inputs) { 282 blorp_emit_input_varying_data(brw, params, 283 &vb[1].BufferStartingAddress, &size); 284 vb[1].VertexBufferIndex = 1; 285 vb[1].BufferPitch = 0; 286 vb[1].VertexBufferMOCS = mocs; 287#if GEN_GEN >= 7 288 vb[1].AddressModifyEnable = true; 289#endif 290#if GEN_GEN >= 8 291 vb[1].BufferSize = size; 292#else 293 vb[1].BufferAccessType = INSTANCEDATA; 294 vb[1].EndAddress = vb[1].BufferStartingAddress; 295 vb[1].EndAddress.offset += size - 1; 296#endif 297 num_buffers++; 298 } 299 300 const unsigned num_dwords = 301 1 + GENX(VERTEX_BUFFER_STATE_length) * num_buffers; 302 uint32_t *dw = blorp_emitn(brw, GENX(3DSTATE_VERTEX_BUFFERS), num_dwords); 303 304 for (unsigned i = 0; i < num_buffers; i++) { 305 GENX(VERTEX_BUFFER_STATE_pack)(brw, dw, &vb[i]); 306 dw += GENX(VERTEX_BUFFER_STATE_length); 307 } 308} 309 310static void 311blorp_emit_vertex_elements(struct brw_context *brw, 312 const struct brw_blorp_params *params) 313{ 314 const unsigned num_varyings = 315 params->wm_prog_data ? params->wm_prog_data->num_varying_inputs : 0; 316 const unsigned num_elements = 2 + num_varyings; 317 318 struct GENX(VERTEX_ELEMENT_STATE) ve[num_elements]; 319 memset(ve, 0, num_elements * sizeof(*ve)); 320 321 /* Setup VBO for the rectangle primitive.. 322 * 323 * A rectangle primitive (3DPRIM_RECTLIST) consists of only three 324 * vertices. The vertices reside in screen space with DirectX 325 * coordinates (that is, (0, 0) is the upper left corner). 326 * 327 * v2 ------ implied 328 * | | 329 * | | 330 * v0 ----- v1 331 * 332 * Since the VS is disabled, the clipper loads each VUE directly from 333 * the URB. This is controlled by the 3DSTATE_VERTEX_BUFFERS and 334 * 3DSTATE_VERTEX_ELEMENTS packets below. The VUE contents are as follows: 335 * dw0: Reserved, MBZ. 336 * dw1: Render Target Array Index. The HiZ op does not use indexed 337 * vertices, so set the dword to 0. 338 * dw2: Viewport Index. The HiZ op disables viewport mapping and 339 * scissoring, so set the dword to 0. 340 * dw3: Point Width: The HiZ op does not emit the POINTLIST primitive, 341 * so set the dword to 0. 342 * dw4: Vertex Position X. 343 * dw5: Vertex Position Y. 344 * dw6: Vertex Position Z. 345 * dw7: Vertex Position W. 346 * 347 * dw8: Flat vertex input 0 348 * dw9: Flat vertex input 1 349 * ... 350 * dwn: Flat vertex input n - 8 351 * 352 * For details, see the Sandybridge PRM, Volume 2, Part 1, Section 1.5.1 353 * "Vertex URB Entry (VUE) Formats". 354 * 355 * Only vertex position X and Y are going to be variable, Z is fixed to 356 * zero and W to one. Header words dw0-3 are all zero. There is no need to 357 * include the fixed values in the vertex buffer. Vertex fetcher can be 358 * instructed to fill vertex elements with constant values of one and zero 359 * instead of reading them from the buffer. 360 * Flat inputs are program constants that are not interpolated. Moreover 361 * their values will be the same between vertices. 362 * 363 * See the vertex element setup below. 364 */ 365 ve[0].VertexBufferIndex = 0; 366 ve[0].Valid = true; 367 ve[0].SourceElementFormat = ISL_FORMAT_R32G32B32A32_FLOAT; 368 ve[0].SourceElementOffset = 0; 369 ve[0].Component0Control = VFCOMP_STORE_0; 370 ve[0].Component1Control = VFCOMP_STORE_0; 371 ve[0].Component2Control = VFCOMP_STORE_0; 372 ve[0].Component3Control = VFCOMP_STORE_0; 373 374 ve[1].VertexBufferIndex = 0; 375 ve[1].Valid = true; 376 ve[1].SourceElementFormat = ISL_FORMAT_R32G32_FLOAT; 377 ve[1].SourceElementOffset = 0; 378 ve[1].Component0Control = VFCOMP_STORE_SRC; 379 ve[1].Component1Control = VFCOMP_STORE_SRC; 380 ve[1].Component2Control = VFCOMP_STORE_0; 381 ve[1].Component3Control = VFCOMP_STORE_1_FP; 382 383 for (unsigned i = 0; i < num_varyings; ++i) { 384 ve[i + 2].VertexBufferIndex = 1; 385 ve[i + 2].Valid = true; 386 ve[i + 2].SourceElementFormat = ISL_FORMAT_R32G32B32A32_FLOAT; 387 ve[i + 2].SourceElementOffset = i * 4 * sizeof(float); 388 ve[i + 2].Component0Control = VFCOMP_STORE_SRC; 389 ve[i + 2].Component1Control = VFCOMP_STORE_SRC; 390 ve[i + 2].Component2Control = VFCOMP_STORE_SRC; 391 ve[i + 2].Component3Control = VFCOMP_STORE_SRC; 392 } 393 394 const unsigned num_dwords = 395 1 + GENX(VERTEX_ELEMENT_STATE_length) * num_elements; 396 uint32_t *dw = blorp_emitn(brw, GENX(3DSTATE_VERTEX_ELEMENTS), num_dwords); 397 398 for (unsigned i = 0; i < num_elements; i++) { 399 GENX(VERTEX_ELEMENT_STATE_pack)(brw, dw, &ve[i]); 400 dw += GENX(VERTEX_ELEMENT_STATE_length); 401 } 402 403#if GEN_GEN >= 8 404 blorp_emit(brw, GENX(3DSTATE_VF_SGVS), sgvs); 405 406 for (unsigned i = 0; i < num_elements; i++) { 407 blorp_emit(brw, GENX(3DSTATE_VF_INSTANCING), vf) { 408 vf.VertexElementIndex = i; 409 vf.InstancingEnable = false; 410 } 411 } 412 413 blorp_emit(brw, GENX(3DSTATE_VF_TOPOLOGY), topo) { 414 topo.PrimitiveTopologyType = _3DPRIM_RECTLIST; 415 } 416#endif 417} 418 419static void 420blorp_emit_sf_config(struct brw_context *brw, 421 const struct brw_blorp_params *params) 422{ 423 const struct brw_blorp_prog_data *prog_data = params->wm_prog_data; 424 425 /* 3DSTATE_SF 426 * 427 * Disable ViewportTransformEnable (dw2.1) 428 * 429 * From the SandyBridge PRM, Volume 2, Part 1, Section 1.3, "3D 430 * Primitives Overview": 431 * RECTLIST: Viewport Mapping must be DISABLED (as is typical with the 432 * use of screen- space coordinates). 433 * 434 * A solid rectangle must be rendered, so set FrontFaceFillMode (dw2.4:3) 435 * and BackFaceFillMode (dw2.5:6) to SOLID(0). 436 * 437 * From the Sandy Bridge PRM, Volume 2, Part 1, Section 438 * 6.4.1.1 3DSTATE_SF, Field FrontFaceFillMode: 439 * SOLID: Any triangle or rectangle object found to be front-facing 440 * is rendered as a solid object. This setting is required when 441 * (rendering rectangle (RECTLIST) objects. 442 */ 443 444#if GEN_GEN >= 8 445 446 blorp_emit(brw, GENX(3DSTATE_SF), sf); 447 448 blorp_emit(brw, GENX(3DSTATE_RASTER), raster) { 449 raster.CullMode = CULLMODE_NONE; 450 } 451 452 blorp_emit(brw, GENX(3DSTATE_SBE), sbe) { 453 sbe.VertexURBEntryReadOffset = BRW_SF_URB_ENTRY_READ_OFFSET; 454 sbe.NumberofSFOutputAttributes = prog_data->num_varying_inputs; 455 sbe.VertexURBEntryReadLength = brw_blorp_get_urb_length(prog_data); 456 sbe.ForceVertexURBEntryReadLength = true; 457 sbe.ForceVertexURBEntryReadOffset = true; 458 sbe.ConstantInterpolationEnable = prog_data->flat_inputs; 459 460#if GEN_GEN >= 9 461 for (unsigned i = 0; i < 32; i++) 462 sbe.AttributeActiveComponentFormat[i] = ACF_XYZW; 463#endif 464 } 465 466#elif GEN_GEN >= 7 467 468 blorp_emit(brw, GENX(3DSTATE_SF), sf) { 469 sf.FrontFaceFillMode = FILL_MODE_SOLID; 470 sf.BackFaceFillMode = FILL_MODE_SOLID; 471 472 sf.MultisampleRasterizationMode = params->dst.surf.samples > 1 ? 473 MSRASTMODE_ON_PATTERN : MSRASTMODE_OFF_PIXEL; 474 475#if GEN_GEN == 7 476 sf.DepthBufferSurfaceFormat = params->depth_format; 477#endif 478 } 479 480 blorp_emit(brw, GENX(3DSTATE_SBE), sbe) { 481 sbe.VertexURBEntryReadOffset = BRW_SF_URB_ENTRY_READ_OFFSET; 482 if (prog_data) { 483 sbe.NumberofSFOutputAttributes = prog_data->num_varying_inputs; 484 sbe.VertexURBEntryReadLength = brw_blorp_get_urb_length(prog_data); 485 sbe.ConstantInterpolationEnable = prog_data->flat_inputs; 486 } else { 487 sbe.NumberofSFOutputAttributes = 0; 488 sbe.VertexURBEntryReadLength = 1; 489 } 490 } 491 492#else /* GEN_GEN <= 6 */ 493 494 blorp_emit(brw, GENX(3DSTATE_SF), sf) { 495 sf.FrontFaceFillMode = FILL_MODE_SOLID; 496 sf.BackFaceFillMode = FILL_MODE_SOLID; 497 498 sf.MultisampleRasterizationMode = params->dst.surf.samples > 1 ? 499 MSRASTMODE_ON_PATTERN : MSRASTMODE_OFF_PIXEL; 500 501 sf.VertexURBEntryReadOffset = BRW_SF_URB_ENTRY_READ_OFFSET; 502 if (prog_data) { 503 sf.NumberofSFOutputAttributes = prog_data->num_varying_inputs; 504 sf.VertexURBEntryReadLength = brw_blorp_get_urb_length(prog_data); 505 sf.ConstantInterpolationEnable = prog_data->flat_inputs; 506 } else { 507 sf.NumberofSFOutputAttributes = 0; 508 sf.VertexURBEntryReadLength = 1; 509 } 510 } 511 512#endif /* GEN_GEN */ 513} 514 515static void 516blorp_emit_ps_config(struct brw_context *brw, 517 const struct brw_blorp_params *params) 518{ 519 const struct brw_blorp_prog_data *prog_data = params->wm_prog_data; 520 521 /* Even when thread dispatch is disabled, max threads (dw5.25:31) must be 522 * nonzero to prevent the GPU from hanging. While the documentation doesn't 523 * mention this explicitly, it notes that the valid range for the field is 524 * [1,39] = [2,40] threads, which excludes zero. 525 * 526 * To be safe (and to minimize extraneous code) we go ahead and fully 527 * configure the WM state whether or not there is a WM program. 528 */ 529 530#if GEN_GEN >= 8 531 532 blorp_emit(brw, GENX(3DSTATE_WM), wm); 533 534 blorp_emit(brw, GENX(3DSTATE_PS), ps) { 535 if (params->src.bo) { 536 ps.SamplerCount = 1; /* Up to 4 samplers */ 537 ps.BindingTableEntryCount = 2; 538 } else { 539 ps.BindingTableEntryCount = 1; 540 } 541 542 ps.DispatchGRFStartRegisterForConstantSetupData0 = 543 prog_data->first_curbe_grf_0; 544 ps.DispatchGRFStartRegisterForConstantSetupData2 = 545 prog_data->first_curbe_grf_2; 546 547 ps._8PixelDispatchEnable = prog_data->dispatch_8; 548 ps._16PixelDispatchEnable = prog_data->dispatch_16; 549 550 ps.KernelStartPointer0 = params->wm_prog_kernel; 551 ps.KernelStartPointer2 = 552 params->wm_prog_kernel + prog_data->ksp_offset_2; 553 554 /* 3DSTATE_PS expects the number of threads per PSD, which is always 64; 555 * it implicitly scales for different GT levels (which have some # of 556 * PSDs). 557 * 558 * In Gen8 the format is U8-2 whereas in Gen9 it is U8-1. 559 */ 560 if (GEN_GEN >= 9) 561 ps.MaximumNumberofThreadsPerPSD = 64 - 1; 562 else 563 ps.MaximumNumberofThreadsPerPSD = 64 - 2; 564 565 switch (params->fast_clear_op) { 566#if GEN_GEN >= 9 567 case (1 << 6): /* GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE */ 568 ps.RenderTargetResolveType = RESOLVE_PARTIAL; 569 break; 570 case (3 << 6): /* GEN9_PS_RENDER_TARGET_RESOLVE_FULL */ 571 ps.RenderTargetResolveType = RESOLVE_FULL; 572 break; 573#else 574 case (1 << 6): /* GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE */ 575 ps.RenderTargetResolveEnable = true; 576 break; 577#endif 578 case (1 << 8): /* GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE */ 579 ps.RenderTargetFastClearEnable = true; 580 break; 581 } 582 } 583 584 blorp_emit(brw, GENX(3DSTATE_PS_EXTRA), psx) { 585 psx.PixelShaderValid = true; 586 587 if (params->src.bo) 588 psx.PixelShaderKillsPixel = true; 589 590 psx.AttributeEnable = prog_data->num_varying_inputs > 0; 591 592 if (prog_data && prog_data->persample_msaa_dispatch) 593 psx.PixelShaderIsPerSample = true; 594 } 595 596#elif GEN_GEN >= 7 597 598 blorp_emit(brw, GENX(3DSTATE_WM), wm) { 599 switch (params->hiz_op) { 600 case GEN6_HIZ_OP_DEPTH_CLEAR: 601 wm.DepthBufferClear = true; 602 break; 603 case GEN6_HIZ_OP_DEPTH_RESOLVE: 604 wm.DepthBufferResolveEnable = true; 605 break; 606 case GEN6_HIZ_OP_HIZ_RESOLVE: 607 wm.HierarchicalDepthBufferResolveEnable = true; 608 break; 609 case GEN6_HIZ_OP_NONE: 610 break; 611 default: 612 unreachable("not reached"); 613 } 614 615 if (prog_data) 616 wm.ThreadDispatchEnable = true; 617 618 if (params->src.bo) 619 wm.PixelShaderKillPixel = true; 620 621 if (params->dst.surf.samples > 1) { 622 wm.MultisampleRasterizationMode = MSRASTMODE_ON_PATTERN; 623 wm.MultisampleDispatchMode = 624 (prog_data && prog_data->persample_msaa_dispatch) ? 625 MSDISPMODE_PERSAMPLE : MSDISPMODE_PERPIXEL; 626 } else { 627 wm.MultisampleRasterizationMode = MSRASTMODE_OFF_PIXEL; 628 wm.MultisampleDispatchMode = MSDISPMODE_PERSAMPLE; 629 } 630 } 631 632 blorp_emit(brw, GENX(3DSTATE_PS), ps) { 633 ps.MaximumNumberofThreads = brw->max_wm_threads - 1; 634 635#if GEN_IS_HASWELL 636 ps.SampleMask = 1; 637#endif 638 639 if (prog_data) { 640 ps.DispatchGRFStartRegisterforConstantSetupData0 = 641 prog_data->first_curbe_grf_0; 642 ps.DispatchGRFStartRegisterforConstantSetupData2 = 643 prog_data->first_curbe_grf_2; 644 645 ps.KernelStartPointer0 = params->wm_prog_kernel; 646 ps.KernelStartPointer2 = 647 params->wm_prog_kernel + prog_data->ksp_offset_2; 648 649 ps._8PixelDispatchEnable = prog_data->dispatch_8; 650 ps._16PixelDispatchEnable = prog_data->dispatch_16; 651 652 ps.AttributeEnable = prog_data->num_varying_inputs > 0; 653 } else { 654 /* Gen7 hardware gets angry if we don't enable at least one dispatch 655 * mode, so just enable 16-pixel dispatch if we don't have a program. 656 */ 657 ps._16PixelDispatchEnable = true; 658 } 659 660 if (params->src.bo) 661 ps.SamplerCount = 1; /* Up to 4 samplers */ 662 663 switch (params->fast_clear_op) { 664 case (1 << 6): /* GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE */ 665 ps.RenderTargetResolveEnable = true; 666 break; 667 case (1 << 8): /* GEN7_PS_RENDER_TARGET_FAST_CLEAR_ENABLE */ 668 ps.RenderTargetFastClearEnable = true; 669 break; 670 } 671 } 672 673#else /* GEN_GEN <= 6 */ 674 675 blorp_emit(brw, GENX(3DSTATE_WM), wm) { 676 wm.MaximumNumberofThreads = brw->max_wm_threads - 1; 677 678 switch (params->hiz_op) { 679 case GEN6_HIZ_OP_DEPTH_CLEAR: 680 wm.DepthBufferClear = true; 681 break; 682 case GEN6_HIZ_OP_DEPTH_RESOLVE: 683 wm.DepthBufferResolveEnable = true; 684 break; 685 case GEN6_HIZ_OP_HIZ_RESOLVE: 686 wm.HierarchicalDepthBufferResolveEnable = true; 687 break; 688 case GEN6_HIZ_OP_NONE: 689 break; 690 default: 691 unreachable("not reached"); 692 } 693 694 if (prog_data) { 695 wm.ThreadDispatchEnable = true; 696 697 wm.DispatchGRFStartRegisterforConstantSetupData0 = 698 prog_data->first_curbe_grf_0; 699 wm.DispatchGRFStartRegisterforConstantSetupData2 = 700 prog_data->first_curbe_grf_2; 701 702 wm.KernelStartPointer0 = params->wm_prog_kernel; 703 wm.KernelStartPointer2 = 704 params->wm_prog_kernel + prog_data->ksp_offset_2; 705 706 wm._8PixelDispatchEnable = prog_data->dispatch_8; 707 wm._16PixelDispatchEnable = prog_data->dispatch_16; 708 709 wm.NumberofSFOutputAttributes = prog_data->num_varying_inputs; 710 } 711 712 if (params->src.bo) { 713 wm.SamplerCount = 1; /* Up to 4 samplers */ 714 wm.PixelShaderKillPixel = true; /* TODO: temporarily smash on */ 715 } 716 717 if (params->dst.surf.samples > 1) { 718 wm.MultisampleRasterizationMode = MSRASTMODE_ON_PATTERN; 719 wm.MultisampleDispatchMode = 720 (prog_data && prog_data->persample_msaa_dispatch) ? 721 MSDISPMODE_PERSAMPLE : MSDISPMODE_PERPIXEL; 722 } else { 723 wm.MultisampleRasterizationMode = MSRASTMODE_OFF_PIXEL; 724 wm.MultisampleDispatchMode = MSDISPMODE_PERSAMPLE; 725 } 726 } 727 728#endif /* GEN_GEN */ 729} 730 731 732static void 733blorp_emit_depth_stencil_config(struct brw_context *brw, 734 const struct brw_blorp_params *params) 735{ 736 brw_emit_depth_stall_flushes(brw); 737 738#if GEN_GEN >= 7 739 const uint32_t mocs = 1; /* GEN7_MOCS_L3 */ 740#else 741 const uint32_t mocs = 0; 742#endif 743 744 blorp_emit(brw, GENX(3DSTATE_DEPTH_BUFFER), db) { 745 switch (params->depth.surf.dim) { 746 case ISL_SURF_DIM_1D: 747 db.SurfaceType = SURFTYPE_1D; 748 break; 749 case ISL_SURF_DIM_2D: 750 db.SurfaceType = SURFTYPE_2D; 751 break; 752 case ISL_SURF_DIM_3D: 753 db.SurfaceType = SURFTYPE_3D; 754 break; 755 } 756 757 db.SurfaceFormat = params->depth_format; 758 759#if GEN_GEN >= 7 760 db.DepthWriteEnable = true; 761#endif 762 763#if GEN_GEN <= 6 764 db.TiledSurface = true; 765 db.TileWalk = TILEWALK_YMAJOR; 766 db.MIPMapLayoutMode = MIPLAYOUT_BELOW; 767 db.SeparateStencilBufferEnable = true; 768#endif 769 770 db.HierarchicalDepthBufferEnable = true; 771 772 db.Width = params->depth.surf.logical_level0_px.width - 1; 773 db.Height = params->depth.surf.logical_level0_px.height - 1; 774 db.RenderTargetViewExtent = db.Depth = 775 MAX2(params->depth.surf.logical_level0_px.depth, 776 params->depth.surf.logical_level0_px.array_len) - 1; 777 778 db.LOD = params->depth.view.base_level; 779 db.MinimumArrayElement = params->depth.view.base_array_layer; 780 781 db.SurfacePitch = params->depth.surf.row_pitch - 1; 782 db.SurfaceBaseAddress = (struct blorp_address) { 783 .buffer = params->depth.bo, 784 .read_domains = I915_GEM_DOMAIN_RENDER, 785 .write_domain = I915_GEM_DOMAIN_RENDER, 786 .offset = params->depth.offset, 787 }; 788 db.DepthBufferMOCS = mocs; 789 } 790 791 blorp_emit(brw, GENX(3DSTATE_HIER_DEPTH_BUFFER), hiz) { 792 hiz.SurfacePitch = params->depth.aux_surf.row_pitch - 1; 793 hiz.SurfaceBaseAddress = (struct blorp_address) { 794 .buffer = params->depth.aux_bo, 795 .read_domains = I915_GEM_DOMAIN_RENDER, 796 .write_domain = I915_GEM_DOMAIN_RENDER, 797 .offset = params->depth.aux_offset, 798 }; 799 hiz.HierarchicalDepthBufferMOCS = mocs; 800 } 801 802 blorp_emit(brw, GENX(3DSTATE_STENCIL_BUFFER), sb); 803} 804 805static uint32_t 806blorp_emit_blend_state(struct brw_context *brw, 807 const struct brw_blorp_params *params) 808{ 809 struct GENX(BLEND_STATE) blend; 810 memset(&blend, 0, sizeof(blend)); 811 812 for (unsigned i = 0; i < params->num_draw_buffers; ++i) { 813 blend.Entry[i].PreBlendColorClampEnable = true; 814 blend.Entry[i].PostBlendColorClampEnable = true; 815 blend.Entry[i].ColorClampRange = COLORCLAMP_RTFORMAT; 816 817 blend.Entry[i].WriteDisableRed = params->color_write_disable[0]; 818 blend.Entry[i].WriteDisableGreen = params->color_write_disable[1]; 819 blend.Entry[i].WriteDisableBlue = params->color_write_disable[2]; 820 blend.Entry[i].WriteDisableAlpha = params->color_write_disable[3]; 821 } 822 823 uint32_t offset; 824 void *state = brw_state_batch(brw, AUB_TRACE_BLEND_STATE, 825 GENX(BLEND_STATE_length) * 4, 64, &offset); 826 GENX(BLEND_STATE_pack)(NULL, state, &blend); 827 828#if GEN_GEN >= 7 829 blorp_emit(brw, GENX(3DSTATE_BLEND_STATE_POINTERS), sp) { 830 sp.BlendStatePointer = offset; 831#if GEN_GEN >= 8 832 sp.BlendStatePointerValid = true; 833#endif 834 } 835#endif 836 837#if GEN_GEN >= 8 838 blorp_emit(brw, GENX(3DSTATE_PS_BLEND), ps_blend) { 839 ps_blend.HasWriteableRT = true; 840 } 841#endif 842 843 return offset; 844} 845 846static uint32_t 847blorp_emit_color_calc_state(struct brw_context *brw, 848 const struct brw_blorp_params *params) 849{ 850 uint32_t offset; 851 void *state = brw_state_batch(brw, AUB_TRACE_CC_STATE, 852 GENX(COLOR_CALC_STATE_length) * 4, 64, &offset); 853 memset(state, 0, GENX(COLOR_CALC_STATE_length) * 4); 854 855#if GEN_GEN >= 7 856 blorp_emit(brw, GENX(3DSTATE_CC_STATE_POINTERS), sp) { 857 sp.ColorCalcStatePointer = offset; 858#if GEN_GEN >= 8 859 sp.ColorCalcStatePointerValid = true; 860#endif 861 } 862#endif 863 864 return offset; 865} 866 867static uint32_t 868blorp_emit_depth_stencil_state(struct brw_context *brw, 869 const struct brw_blorp_params *params) 870{ 871#if GEN_GEN >= 8 872 873 /* On gen8+, DEPTH_STENCIL state is simply an instruction */ 874 blorp_emit(brw, GENX(3DSTATE_WM_DEPTH_STENCIL), ds); 875 return 0; 876 877#else /* GEN_GEN <= 7 */ 878 879 /* See the following sections of the Sandy Bridge PRM, Volume 1, Part2: 880 * - 7.5.3.1 Depth Buffer Clear 881 * - 7.5.3.2 Depth Buffer Resolve 882 * - 7.5.3.3 Hierarchical Depth Buffer Resolve 883 */ 884 struct GENX(DEPTH_STENCIL_STATE) ds = { 885 .DepthBufferWriteEnable = true, 886 }; 887 888 if (params->hiz_op == GEN6_HIZ_OP_DEPTH_RESOLVE) { 889 ds.DepthTestEnable = true; 890 ds.DepthTestFunction = COMPAREFUNCTION_NEVER; 891 } 892 893 uint32_t offset; 894 void *state = brw_state_batch(brw, AUB_TRACE_DEPTH_STENCIL_STATE, 895 GENX(DEPTH_STENCIL_STATE_length) * 4, 64, 896 &offset); 897 GENX(DEPTH_STENCIL_STATE_pack)(NULL, state, &ds); 898 899#if GEN_GEN >= 7 900 blorp_emit(brw, GENX(3DSTATE_DEPTH_STENCIL_STATE_POINTERS), sp) { 901 sp.PointertoDEPTH_STENCIL_STATE = offset; 902 } 903#endif 904 905 return offset; 906 907#endif /* GEN_GEN */ 908} 909 910static void 911blorp_emit_surface_states(struct brw_context *brw, 912 const struct brw_blorp_params *params) 913{ 914 uint32_t bind_offset; 915 uint32_t *bind = 916 brw_state_batch(brw, AUB_TRACE_BINDING_TABLE, 917 sizeof(uint32_t) * BRW_BLORP_NUM_BINDING_TABLE_ENTRIES, 918 32, /* alignment */ &bind_offset); 919 920 bind[BRW_BLORP_RENDERBUFFER_BINDING_TABLE_INDEX] = 921 brw_blorp_emit_surface_state(brw, ¶ms->dst, 922 I915_GEM_DOMAIN_RENDER, 923 I915_GEM_DOMAIN_RENDER, true); 924 if (params->src.bo) { 925 bind[BRW_BLORP_TEXTURE_BINDING_TABLE_INDEX] = 926 brw_blorp_emit_surface_state(brw, ¶ms->src, 927 I915_GEM_DOMAIN_SAMPLER, 0, false); 928 } 929 930#if GEN_GEN >= 7 931 blorp_emit(brw, GENX(3DSTATE_BINDING_TABLE_POINTERS_PS), bt) { 932 bt.PointertoPSBindingTable = bind_offset; 933 } 934#else 935 blorp_emit(brw, GENX(3DSTATE_BINDING_TABLE_POINTERS), bt) { 936 bt.PSBindingTableChange = true; 937 bt.PointertoPSBindingTable = bind_offset; 938 } 939#endif 940} 941 942static void 943blorp_emit_sampler_state(struct brw_context *brw, 944 const struct brw_blorp_params *params) 945{ 946 struct GENX(SAMPLER_STATE) sampler = { 947 .MipModeFilter = MIPFILTER_NONE, 948 .MagModeFilter = MAPFILTER_LINEAR, 949 .MinModeFilter = MAPFILTER_LINEAR, 950 .MinLOD = 0, 951 .MaxLOD = 0, 952 .TCXAddressControlMode = TCM_CLAMP, 953 .TCYAddressControlMode = TCM_CLAMP, 954 .TCZAddressControlMode = TCM_CLAMP, 955 .MaximumAnisotropy = RATIO21, 956 .RAddressMinFilterRoundingEnable = true, 957 .RAddressMagFilterRoundingEnable = true, 958 .VAddressMinFilterRoundingEnable = true, 959 .VAddressMagFilterRoundingEnable = true, 960 .UAddressMinFilterRoundingEnable = true, 961 .UAddressMagFilterRoundingEnable = true, 962 .NonnormalizedCoordinateEnable = true, 963 }; 964 965 uint32_t offset; 966 void *state = brw_state_batch(brw, AUB_TRACE_SAMPLER_STATE, 967 GENX(SAMPLER_STATE_length) * 4, 32, &offset); 968 GENX(SAMPLER_STATE_pack)(NULL, state, &sampler); 969 970#if GEN_GEN >= 7 971 blorp_emit(brw, GENX(3DSTATE_SAMPLER_STATE_POINTERS_PS), ssp) { 972 ssp.PointertoPSSamplerState = offset; 973 } 974#else 975 blorp_emit(brw, GENX(3DSTATE_SAMPLER_STATE_POINTERS), ssp) { 976 ssp.VSSamplerStateChange = true; 977 ssp.GSSamplerStateChange = true; 978 ssp.PSSamplerStateChange = true; 979 ssp.PointertoPSSamplerState = offset; 980 } 981#endif 982} 983 984/* 3DSTATE_VIEWPORT_STATE_POINTERS */ 985static void 986blorp_emit_viewport_state(struct brw_context *brw, 987 const struct brw_blorp_params *params) 988{ 989 uint32_t cc_vp_offset; 990 991 void *state = brw_state_batch(brw, AUB_TRACE_CC_VP_STATE, 992 GENX(CC_VIEWPORT_length) * 4, 32, 993 &cc_vp_offset); 994 995 GENX(CC_VIEWPORT_pack)(brw, state, 996 &(struct GENX(CC_VIEWPORT)) { 997 .MinimumDepth = 0.0, 998 .MaximumDepth = 1.0, 999 }); 1000 1001#if GEN_GEN >= 7 1002 blorp_emit(brw, GENX(3DSTATE_VIEWPORT_STATE_POINTERS_CC), vsp) { 1003 vsp.CCViewportPointer = cc_vp_offset; 1004 } 1005#else 1006 blorp_emit(brw, GENX(3DSTATE_VIEWPORT_STATE_POINTERS), vsp) { 1007 vsp.CCViewportStateChange = true; 1008 vsp.PointertoCC_VIEWPORT = cc_vp_offset; 1009 } 1010#endif 1011} 1012 1013 1014/** 1015 * \brief Execute a blit or render pass operation. 1016 * 1017 * To execute the operation, this function manually constructs and emits a 1018 * batch to draw a rectangle primitive. The batchbuffer is flushed before 1019 * constructing and after emitting the batch. 1020 * 1021 * This function alters no GL state. 1022 */ 1023void 1024genX(blorp_exec)(struct brw_context *brw, 1025 const struct brw_blorp_params *params) 1026{ 1027 uint32_t blend_state_offset = 0; 1028 uint32_t color_calc_state_offset = 0; 1029 uint32_t depth_stencil_state_offset; 1030 1031#if GEN_GEN == 6 1032 /* Emit workaround flushes when we switch from drawing to blorping. */ 1033 brw_emit_post_sync_nonzero_flush(brw); 1034#endif 1035 1036 brw_upload_state_base_address(brw); 1037 1038#if GEN_GEN >= 8 1039 gen7_l3_state.emit(brw); 1040#endif 1041 1042 blorp_emit_vertex_buffers(brw, params); 1043 blorp_emit_vertex_elements(brw, params); 1044 1045 emit_urb_config(brw, params); 1046 1047 if (params->wm_prog_data) { 1048 blend_state_offset = blorp_emit_blend_state(brw, params); 1049 color_calc_state_offset = blorp_emit_color_calc_state(brw, params); 1050 } 1051 depth_stencil_state_offset = blorp_emit_depth_stencil_state(brw, params); 1052 1053#if GEN_GEN <= 6 1054 /* 3DSTATE_CC_STATE_POINTERS 1055 * 1056 * The pointer offsets are relative to 1057 * CMD_STATE_BASE_ADDRESS.DynamicStateBaseAddress. 1058 * 1059 * The HiZ op doesn't use BLEND_STATE or COLOR_CALC_STATE. 1060 * 1061 * The dynamic state emit helpers emit their own STATE_POINTERS packets on 1062 * gen7+. However, on gen6 and earlier, they're all lumpped together in 1063 * one CC_STATE_POINTERS packet so we have to emit that here. 1064 */ 1065 blorp_emit(brw, GENX(3DSTATE_CC_STATE_POINTERS), cc) { 1066 cc.BLEND_STATEChange = true; 1067 cc.COLOR_CALC_STATEChange = true; 1068 cc.DEPTH_STENCIL_STATEChange = true; 1069 cc.PointertoBLEND_STATE = blend_state_offset; 1070 cc.PointertoCOLOR_CALC_STATE = color_calc_state_offset; 1071 cc.PointertoDEPTH_STENCIL_STATE = depth_stencil_state_offset; 1072 } 1073#else 1074 (void)blend_state_offset; 1075 (void)color_calc_state_offset; 1076 (void)depth_stencil_state_offset; 1077#endif 1078 1079 blorp_emit(brw, GENX(3DSTATE_CONSTANT_VS), vs); 1080#if GEN_GEN >= 7 1081 blorp_emit(brw, GENX(3DSTATE_CONSTANT_HS), hs); 1082 blorp_emit(brw, GENX(3DSTATE_CONSTANT_DS), DS); 1083#endif 1084 blorp_emit(brw, GENX(3DSTATE_CONSTANT_GS), gs); 1085 blorp_emit(brw, GENX(3DSTATE_CONSTANT_PS), ps); 1086 1087 if (brw->use_resource_streamer) 1088 gen7_disable_hw_binding_tables(brw); 1089 1090 if (params->wm_prog_data) 1091 blorp_emit_surface_states(brw, params); 1092 1093 if (params->src.bo) 1094 blorp_emit_sampler_state(brw, params); 1095 1096#if GEN_GEN >= 8 1097 gen8_emit_3dstate_multisample(brw, params->dst.surf.samples); 1098#else 1099 gen6_emit_3dstate_multisample(brw, params->dst.surf.samples); 1100#endif 1101 1102 blorp_emit(brw, GENX(3DSTATE_SAMPLE_MASK), mask) { 1103 mask.SampleMask = (1 << params->dst.surf.samples) - 1; 1104 } 1105 1106 /* From the BSpec, 3D Pipeline > Geometry > Vertex Shader > State, 1107 * 3DSTATE_VS, Dword 5.0 "VS Function Enable": 1108 * 1109 * [DevSNB] A pipeline flush must be programmed prior to a 1110 * 3DSTATE_VS command that causes the VS Function Enable to 1111 * toggle. Pipeline flush can be executed by sending a PIPE_CONTROL 1112 * command with CS stall bit set and a post sync operation. 1113 * 1114 * We've already done one at the start of the BLORP operation. 1115 */ 1116 blorp_emit(brw, GENX(3DSTATE_VS), vs); 1117#if GEN_GEN >= 7 1118 blorp_emit(brw, GENX(3DSTATE_HS), hs); 1119 blorp_emit(brw, GENX(3DSTATE_TE), te); 1120 blorp_emit(brw, GENX(3DSTATE_DS), DS); 1121 blorp_emit(brw, GENX(3DSTATE_STREAMOUT), so); 1122#endif 1123 blorp_emit(brw, GENX(3DSTATE_GS), gs); 1124 1125 blorp_emit(brw, GENX(3DSTATE_CLIP), clip) { 1126 clip.PerspectiveDivideDisable = true; 1127 } 1128 1129 blorp_emit_sf_config(brw, params); 1130 blorp_emit_ps_config(brw, params); 1131 1132 blorp_emit_viewport_state(brw, params); 1133 1134 if (params->depth.bo) { 1135 blorp_emit_depth_stencil_config(brw, params); 1136 } else { 1137 brw_emit_depth_stall_flushes(brw); 1138 1139 blorp_emit(brw, GENX(3DSTATE_DEPTH_BUFFER), db) { 1140 db.SurfaceType = SURFTYPE_NULL; 1141 db.SurfaceFormat = D32_FLOAT; 1142 } 1143 blorp_emit(brw, GENX(3DSTATE_HIER_DEPTH_BUFFER), hiz); 1144 blorp_emit(brw, GENX(3DSTATE_STENCIL_BUFFER), sb); 1145 } 1146 1147 /* 3DSTATE_CLEAR_PARAMS 1148 * 1149 * From the Sandybridge PRM, Volume 2, Part 1, Section 3DSTATE_CLEAR_PARAMS: 1150 * [DevSNB] 3DSTATE_CLEAR_PARAMS packet must follow the DEPTH_BUFFER_STATE 1151 * packet when HiZ is enabled and the DEPTH_BUFFER_STATE changes. 1152 */ 1153 blorp_emit(brw, GENX(3DSTATE_CLEAR_PARAMS), clear) { 1154 clear.DepthClearValueValid = true; 1155 clear.DepthClearValue = params->depth.clear_color.u32[0]; 1156 } 1157 1158 blorp_emit(brw, GENX(3DSTATE_DRAWING_RECTANGLE), rect) { 1159 rect.ClippedDrawingRectangleXMax = MAX2(params->x1, params->x0) - 1; 1160 rect.ClippedDrawingRectangleYMax = MAX2(params->y1, params->y0) - 1; 1161 } 1162 1163 blorp_emit(brw, GENX(3DPRIMITIVE), prim) { 1164 prim.VertexAccessType = SEQUENTIAL; 1165 prim.PrimitiveTopologyType = _3DPRIM_RECTLIST; 1166 prim.VertexCountPerInstance = 3; 1167 prim.InstanceCount = params->num_layers; 1168 } 1169} 1170