1 /*
2 * Copyright © 2014 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 * This code is based on original work by Ilia Mirkin.
24 */
25
26 /**
27 * \file gfx6_gs_visitor.cpp
28 *
29 * Gfx6 geometry shader implementation
30 */
31
32 #include "gfx6_gs_visitor.h"
33 #include "brw_eu.h"
34
35 namespace brw {
36
37 void
emit_prolog()38 gfx6_gs_visitor::emit_prolog()
39 {
40 vec4_gs_visitor::emit_prolog();
41
42 /* Gfx6 geometry shaders require to allocate an initial VUE handle via
43 * FF_SYNC message, however the documentation remarks that only one thread
44 * can write to the URB simultaneously and the FF_SYNC message provides the
45 * synchronization mechanism for this, so using this message effectively
46 * stalls the thread until it is its turn to write to the URB. Because of
47 * this, the best way to implement geometry shader algorithms in gfx6 is to
48 * execute the algorithm before the FF_SYNC message to maximize parallelism.
49 *
50 * To achieve this we buffer the geometry shader outputs for each emitted
51 * vertex in vertex_output during operation. Then, when we have processed
52 * the last vertex (that is, at thread end time), we send the FF_SYNC
53 * message to allocate the initial VUE handle and write all buffered vertex
54 * data to the URB in one go.
55 *
56 * For each emitted vertex, vertex_output will hold vue_map.num_slots
57 * data items plus one additional item to hold required flags
58 * (PrimType, PrimStart, PrimEnd, as expected by the URB_WRITE message)
59 * which come right after the data items for that vertex. Vertex data and
60 * flags for the next vertex come right after the data items and flags for
61 * the previous vertex.
62 */
63 this->current_annotation = "gfx6 prolog";
64 this->vertex_output = src_reg(this,
65 glsl_type::uint_type,
66 (prog_data->vue_map.num_slots + 1) *
67 nir->info.gs.vertices_out);
68 this->vertex_output_offset = src_reg(this, glsl_type::uint_type);
69 emit(MOV(dst_reg(this->vertex_output_offset), brw_imm_ud(0u)));
70
71 /* MRF 1 will be the header for all messages (FF_SYNC and URB_WRITES),
72 * so initialize it once to R0.
73 */
74 vec4_instruction *inst = emit(MOV(dst_reg(MRF, 1),
75 retype(brw_vec8_grf(0, 0),
76 BRW_REGISTER_TYPE_UD)));
77 inst->force_writemask_all = true;
78
79 /* This will be used as a temporary to store writeback data of FF_SYNC
80 * and URB_WRITE messages.
81 */
82 this->temp = src_reg(this, glsl_type::uint_type);
83
84 /* This will be used to know when we are processing the first vertex of
85 * a primitive. We will set this to URB_WRITE_PRIM_START only when we know
86 * that we are processing the first vertex in the primitive and to zero
87 * otherwise. This way we can use its value directly in the URB write
88 * headers.
89 */
90 this->first_vertex = src_reg(this, glsl_type::uint_type);
91 emit(MOV(dst_reg(this->first_vertex), brw_imm_ud(URB_WRITE_PRIM_START)));
92
93 /* The FF_SYNC message requires to know the number of primitives generated,
94 * so keep a counter for this.
95 */
96 this->prim_count = src_reg(this, glsl_type::uint_type);
97 emit(MOV(dst_reg(this->prim_count), brw_imm_ud(0u)));
98
99 if (gs_prog_data->num_transform_feedback_bindings) {
100 /* Create a virtual register to hold destination indices in SOL */
101 this->destination_indices = src_reg(this, glsl_type::uvec4_type);
102 /* Create a virtual register to hold number of written primitives */
103 this->sol_prim_written = src_reg(this, glsl_type::uint_type);
104 /* Create a virtual register to hold Streamed Vertex Buffer Indices */
105 this->svbi = src_reg(this, glsl_type::uvec4_type);
106 /* Create a virtual register to hold max values of SVBI */
107 this->max_svbi = src_reg(this, glsl_type::uvec4_type);
108 emit(MOV(dst_reg(this->max_svbi),
109 src_reg(retype(brw_vec1_grf(1, 4), BRW_REGISTER_TYPE_UD))));
110 }
111
112 /* PrimitveID is delivered in r0.1 of the thread payload. If the program
113 * needs it we have to move it to a separate register where we can map
114 * the atttribute.
115 *
116 * Notice that we cannot use a virtual register for this, because we need to
117 * map all input attributes to hardware registers in setup_payload(),
118 * which happens before virtual registers are mapped to hardware registers.
119 * We could work around that issue if we were able to compute the first
120 * non-payload register here and move the PrimitiveID information to that
121 * register, but we can't because at this point we don't know the final
122 * number uniforms that will be included in the payload.
123 *
124 * So, what we do is to place PrimitiveID information in r1, which is always
125 * delivered as part of the payload, but its only populated with data
126 * relevant for transform feedback when we set GFX6_GS_SVBI_PAYLOAD_ENABLE
127 * in the 3DSTATE_GS state packet. That information can be obtained by other
128 * means though, so we can safely use r1 for this purpose.
129 */
130 if (gs_prog_data->include_primitive_id) {
131 this->primitive_id =
132 src_reg(retype(brw_vec8_grf(1, 0), BRW_REGISTER_TYPE_UD));
133 emit(GS_OPCODE_SET_PRIMITIVE_ID, dst_reg(this->primitive_id));
134 }
135 }
136
137 void
gs_emit_vertex(int stream_id)138 gfx6_gs_visitor::gs_emit_vertex(int stream_id)
139 {
140 this->current_annotation = "gfx6 emit vertex";
141
142 /* Buffer all output slots for this vertex in vertex_output */
143 for (int slot = 0; slot < prog_data->vue_map.num_slots; ++slot) {
144 int varying = prog_data->vue_map.slot_to_varying[slot];
145 if (varying != VARYING_SLOT_PSIZ) {
146 dst_reg dst(this->vertex_output);
147 dst.reladdr = ralloc(mem_ctx, src_reg);
148 memcpy(dst.reladdr, &this->vertex_output_offset, sizeof(src_reg));
149 emit_urb_slot(dst, varying);
150 } else {
151 /* The PSIZ slot can pack multiple varyings in different channels
152 * and emit_urb_slot() will produce a MOV instruction for each of
153 * them. Since we are writing to an array, that will translate to
154 * possibly multiple MOV instructions with an array destination and
155 * each will generate a scratch write with the same offset into
156 * scratch space (thus, each one overwriting the previous). This is
157 * not what we want. What we will do instead is emit PSIZ to a
158 * a regular temporary register, then move that resgister into the
159 * array. This way we only have one instruction with an array
160 * destination and we only produce a single scratch write.
161 */
162 dst_reg tmp = dst_reg(src_reg(this, glsl_type::uvec4_type));
163 emit_urb_slot(tmp, varying);
164 dst_reg dst(this->vertex_output);
165 dst.reladdr = ralloc(mem_ctx, src_reg);
166 memcpy(dst.reladdr, &this->vertex_output_offset, sizeof(src_reg));
167 vec4_instruction *inst = emit(MOV(dst, src_reg(tmp)));
168 inst->force_writemask_all = true;
169 }
170
171 emit(ADD(dst_reg(this->vertex_output_offset),
172 this->vertex_output_offset, brw_imm_ud(1u)));
173 }
174
175 /* Now buffer flags for this vertex */
176 dst_reg dst(this->vertex_output);
177 dst.reladdr = ralloc(mem_ctx, src_reg);
178 memcpy(dst.reladdr, &this->vertex_output_offset, sizeof(src_reg));
179 if (nir->info.gs.output_primitive == GL_POINTS) {
180 /* If we are outputting points, then every vertex has PrimStart and
181 * PrimEnd set.
182 */
183 emit(MOV(dst, brw_imm_d((_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT) |
184 URB_WRITE_PRIM_START | URB_WRITE_PRIM_END)));
185 emit(ADD(dst_reg(this->prim_count), this->prim_count, brw_imm_ud(1u)));
186 } else {
187 /* Otherwise, we can only set the PrimStart flag, which we have stored
188 * in the first_vertex register. We will have to wait until we execute
189 * EndPrimitive() or we end the thread to set the PrimEnd flag on a
190 * vertex.
191 */
192 emit(OR(dst, this->first_vertex,
193 brw_imm_ud(gs_prog_data->output_topology <<
194 URB_WRITE_PRIM_TYPE_SHIFT)));
195 emit(MOV(dst_reg(this->first_vertex), brw_imm_ud(0u)));
196 }
197 emit(ADD(dst_reg(this->vertex_output_offset),
198 this->vertex_output_offset, brw_imm_ud(1u)));
199 }
200
201 void
gs_end_primitive()202 gfx6_gs_visitor::gs_end_primitive()
203 {
204 this->current_annotation = "gfx6 end primitive";
205 /* Calling EndPrimitive() is optional for point output. In this case we set
206 * the PrimEnd flag when we process EmitVertex().
207 */
208 if (nir->info.gs.output_primitive == GL_POINTS)
209 return;
210
211 /* Otherwise we know that the last vertex we have processed was the last
212 * vertex in the primitive and we need to set its PrimEnd flag, so do this
213 * unless we haven't emitted that vertex at all (vertex_count != 0).
214 *
215 * Notice that we have already incremented vertex_count when we processed
216 * the last emit_vertex, so we need to take that into account in the
217 * comparison below (hence the num_output_vertices + 1 in the comparison
218 * below).
219 */
220 unsigned num_output_vertices = nir->info.gs.vertices_out;
221 emit(CMP(dst_null_ud(), this->vertex_count,
222 brw_imm_ud(num_output_vertices + 1), BRW_CONDITIONAL_L));
223 vec4_instruction *inst = emit(CMP(dst_null_ud(),
224 this->vertex_count, brw_imm_ud(0u),
225 BRW_CONDITIONAL_NEQ));
226 inst->predicate = BRW_PREDICATE_NORMAL;
227 emit(IF(BRW_PREDICATE_NORMAL));
228 {
229 /* vertex_output_offset is already pointing at the first entry of the
230 * next vertex. So subtract 1 to modify the flags for the previous
231 * vertex.
232 */
233 src_reg offset(this, glsl_type::uint_type);
234 emit(ADD(dst_reg(offset), this->vertex_output_offset, brw_imm_d(-1)));
235
236 src_reg dst(this->vertex_output);
237 dst.reladdr = ralloc(mem_ctx, src_reg);
238 memcpy(dst.reladdr, &offset, sizeof(src_reg));
239
240 emit(OR(dst_reg(dst), dst, brw_imm_d(URB_WRITE_PRIM_END)));
241 emit(ADD(dst_reg(this->prim_count), this->prim_count, brw_imm_ud(1u)));
242
243 /* Set the first vertex flag to indicate that the next vertex will start
244 * a primitive.
245 */
246 emit(MOV(dst_reg(this->first_vertex), brw_imm_d(URB_WRITE_PRIM_START)));
247 }
248 emit(BRW_OPCODE_ENDIF);
249 }
250
251 void
emit_urb_write_header(int mrf)252 gfx6_gs_visitor::emit_urb_write_header(int mrf)
253 {
254 this->current_annotation = "gfx6 urb header";
255 /* Compute offset of the flags for the current vertex in vertex_output and
256 * write them in dw2 of the message header.
257 *
258 * Notice that by the time that emit_thread_end() calls here
259 * vertex_output_offset should point to the first data item of the current
260 * vertex in vertex_output, thus we only need to add the number of output
261 * slots per vertex to that offset to obtain the flags data offset.
262 */
263 src_reg flags_offset(this, glsl_type::uint_type);
264 emit(ADD(dst_reg(flags_offset),
265 this->vertex_output_offset,
266 brw_imm_d(prog_data->vue_map.num_slots)));
267
268 src_reg flags_data(this->vertex_output);
269 flags_data.reladdr = ralloc(mem_ctx, src_reg);
270 memcpy(flags_data.reladdr, &flags_offset, sizeof(src_reg));
271
272 emit(GS_OPCODE_SET_DWORD_2, dst_reg(MRF, mrf), flags_data);
273 }
274
275 static unsigned
align_interleaved_urb_mlen(unsigned mlen)276 align_interleaved_urb_mlen(unsigned mlen)
277 {
278 /* URB data written (does not include the message header reg) must
279 * be a multiple of 256 bits, or 2 VS registers. See vol5c.5,
280 * section 5.4.3.2.2: URB_INTERLEAVED.
281 */
282 if ((mlen % 2) != 1)
283 mlen++;
284 return mlen;
285 }
286
287 void
emit_snb_gs_urb_write_opcode(bool complete,int base_mrf,int last_mrf,int urb_offset)288 gfx6_gs_visitor::emit_snb_gs_urb_write_opcode(bool complete, int base_mrf,
289 int last_mrf, int urb_offset)
290 {
291 vec4_instruction *inst = NULL;
292
293 if (!complete) {
294 /* If the vertex is not complete we don't have to do anything special */
295 inst = emit(GS_OPCODE_URB_WRITE);
296 inst->urb_write_flags = BRW_URB_WRITE_NO_FLAGS;
297 } else {
298 /* Otherwise we always request to allocate a new VUE handle. If this is
299 * the last write before the EOT message and the new handle never gets
300 * used it will be dereferenced when we send the EOT message. This is
301 * necessary to avoid different setups for the EOT message (one for the
302 * case when there is no output and another for the case when there is)
303 * which would require to end the program with an IF/ELSE/ENDIF block,
304 * something we do not want.
305 */
306 inst = emit(GS_OPCODE_URB_WRITE_ALLOCATE);
307 inst->urb_write_flags = BRW_URB_WRITE_COMPLETE;
308 inst->dst = dst_reg(MRF, base_mrf);
309 inst->src[0] = this->temp;
310 }
311
312 inst->base_mrf = base_mrf;
313 inst->mlen = align_interleaved_urb_mlen(last_mrf - base_mrf);
314 inst->offset = urb_offset;
315 }
316
317 void
emit_thread_end()318 gfx6_gs_visitor::emit_thread_end()
319 {
320 /* Make sure the current primitive is ended: we know it is not ended when
321 * first_vertex is not zero. This is only relevant for outputs other than
322 * points because in the point case we set PrimEnd on all vertices.
323 */
324 if (nir->info.gs.output_primitive != GL_POINTS) {
325 emit(CMP(dst_null_ud(), this->first_vertex, brw_imm_ud(0u), BRW_CONDITIONAL_Z));
326 emit(IF(BRW_PREDICATE_NORMAL));
327 gs_end_primitive();
328 emit(BRW_OPCODE_ENDIF);
329 }
330
331 /* Here we have to:
332 * 1) Emit an FF_SYNC messsage to obtain an initial VUE handle.
333 * 2) Loop over all buffered vertex data and write it to corresponding
334 * URB entries.
335 * 3) Allocate new VUE handles for all vertices other than the first.
336 * 4) Send a final EOT message.
337 */
338
339 /* MRF 0 is reserved for the debugger, so start with message header
340 * in MRF 1.
341 */
342 int base_mrf = 1;
343
344 /* In the process of generating our URB write message contents, we
345 * may need to unspill a register or load from an array. Those
346 * reads would use MRFs 21..23
347 */
348 int max_usable_mrf = FIRST_SPILL_MRF(devinfo->ver);
349
350 /* Issue the FF_SYNC message and obtain the initial VUE handle. */
351 this->current_annotation = "gfx6 thread end: ff_sync";
352
353 vec4_instruction *inst = NULL;
354 if (gs_prog_data->num_transform_feedback_bindings) {
355 src_reg sol_temp(this, glsl_type::uvec4_type);
356 emit(GS_OPCODE_FF_SYNC_SET_PRIMITIVES,
357 dst_reg(this->svbi),
358 this->vertex_count,
359 this->prim_count,
360 sol_temp);
361 inst = emit(GS_OPCODE_FF_SYNC,
362 dst_reg(this->temp), this->prim_count, this->svbi);
363 } else {
364 inst = emit(GS_OPCODE_FF_SYNC,
365 dst_reg(this->temp), this->prim_count, brw_imm_ud(0u));
366 }
367 inst->base_mrf = base_mrf;
368
369 emit(CMP(dst_null_ud(), this->vertex_count, brw_imm_ud(0u), BRW_CONDITIONAL_G));
370 emit(IF(BRW_PREDICATE_NORMAL));
371 {
372 /* Loop over all buffered vertices and emit URB write messages */
373 this->current_annotation = "gfx6 thread end: urb writes init";
374 src_reg vertex(this, glsl_type::uint_type);
375 emit(MOV(dst_reg(vertex), brw_imm_ud(0u)));
376 emit(MOV(dst_reg(this->vertex_output_offset), brw_imm_ud(0u)));
377
378 this->current_annotation = "gfx6 thread end: urb writes";
379 emit(BRW_OPCODE_DO);
380 {
381 emit(CMP(dst_null_d(), vertex, this->vertex_count, BRW_CONDITIONAL_GE));
382 inst = emit(BRW_OPCODE_BREAK);
383 inst->predicate = BRW_PREDICATE_NORMAL;
384
385 /* First we prepare the message header */
386 emit_urb_write_header(base_mrf);
387
388 /* Then add vertex data to the message in interleaved fashion */
389 int slot = 0;
390 bool complete = false;
391 do {
392 int mrf = base_mrf + 1;
393
394 /* URB offset is in URB row increments, and each of our MRFs is half
395 * of one of those, since we're doing interleaved writes.
396 */
397 int urb_offset = slot / 2;
398
399 for (; slot < prog_data->vue_map.num_slots; ++slot) {
400 int varying = prog_data->vue_map.slot_to_varying[slot];
401 current_annotation = output_reg_annotation[varying];
402
403 /* Compute offset of this slot for the current vertex
404 * in vertex_output
405 */
406 src_reg data(this->vertex_output);
407 data.reladdr = ralloc(mem_ctx, src_reg);
408 memcpy(data.reladdr, &this->vertex_output_offset,
409 sizeof(src_reg));
410
411 /* Copy this slot to the appropriate message register */
412 dst_reg reg = dst_reg(MRF, mrf);
413 reg.type = output_reg[varying][0].type;
414 data.type = reg.type;
415 inst = emit(MOV(reg, data));
416 inst->force_writemask_all = true;
417
418 mrf++;
419 emit(ADD(dst_reg(this->vertex_output_offset),
420 this->vertex_output_offset, brw_imm_ud(1u)));
421
422 /* If this was max_usable_mrf, we can't fit anything more into
423 * this URB WRITE. Same if we reached the max. message length.
424 */
425 if (mrf > max_usable_mrf ||
426 align_interleaved_urb_mlen(mrf - base_mrf + 1) > BRW_MAX_MSG_LENGTH) {
427 slot++;
428 break;
429 }
430 }
431
432 complete = slot >= prog_data->vue_map.num_slots;
433 emit_snb_gs_urb_write_opcode(complete, base_mrf, mrf, urb_offset);
434 } while (!complete);
435
436 /* Skip over the flags data item so that vertex_output_offset points
437 * to the first data item of the next vertex, so that we can start
438 * writing the next vertex.
439 */
440 emit(ADD(dst_reg(this->vertex_output_offset),
441 this->vertex_output_offset, brw_imm_ud(1u)));
442
443 emit(ADD(dst_reg(vertex), vertex, brw_imm_ud(1u)));
444 }
445 emit(BRW_OPCODE_WHILE);
446
447 if (gs_prog_data->num_transform_feedback_bindings)
448 xfb_write();
449 }
450 emit(BRW_OPCODE_ENDIF);
451
452 /* Finally, emit EOT message.
453 *
454 * In gfx6 we need to end the thread differently depending on whether we have
455 * emitted at least one vertex or not. In case we did, the EOT message must
456 * always include the COMPLETE flag or else the GPU hangs. If we have not
457 * produced any output we can't use the COMPLETE flag.
458 *
459 * However, this would lead us to end the program with an ENDIF opcode,
460 * which we want to avoid, so what we do is that we always request a new
461 * VUE handle every time, even if GS produces no output.
462 * With this we make sure that whether we have emitted at least one vertex
463 * or none at all, we have to finish the thread without writing to the URB,
464 * which works for both cases by setting the COMPLETE and UNUSED flags in
465 * the EOT message.
466 */
467 this->current_annotation = "gfx6 thread end: EOT";
468
469 if (gs_prog_data->num_transform_feedback_bindings) {
470 /* When emitting EOT, set SONumPrimsWritten Increment Value. */
471 src_reg data(this, glsl_type::uint_type);
472 emit(AND(dst_reg(data), this->sol_prim_written, brw_imm_ud(0xffffu)));
473 emit(SHL(dst_reg(data), data, brw_imm_ud(16u)));
474 emit(GS_OPCODE_SET_DWORD_2, dst_reg(MRF, base_mrf), data);
475 }
476
477 inst = emit(GS_OPCODE_THREAD_END);
478 inst->urb_write_flags = BRW_URB_WRITE_COMPLETE | BRW_URB_WRITE_UNUSED;
479 inst->base_mrf = base_mrf;
480 inst->mlen = 1;
481 }
482
483 void
setup_payload()484 gfx6_gs_visitor::setup_payload()
485 {
486 int attribute_map[BRW_VARYING_SLOT_COUNT * MAX_GS_INPUT_VERTICES];
487
488 /* Attributes are going to be interleaved, so one register contains two
489 * attribute slots.
490 */
491 int attributes_per_reg = 2;
492
493 /* If a geometry shader tries to read from an input that wasn't written by
494 * the vertex shader, that produces undefined results, but it shouldn't
495 * crash anything. So initialize attribute_map to zeros--that ensures that
496 * these undefined results are read from r0.
497 */
498 memset(attribute_map, 0, sizeof(attribute_map));
499
500 int reg = 0;
501
502 /* The payload always contains important data in r0. */
503 reg++;
504
505 /* r1 is always part of the payload and it holds information relevant
506 * for transform feedback when we set the GFX6_GS_SVBI_PAYLOAD_ENABLE bit in
507 * the 3DSTATE_GS packet. We will overwrite it with the PrimitiveID
508 * information (and move the original value to a virtual register if
509 * necessary).
510 */
511 if (gs_prog_data->include_primitive_id)
512 attribute_map[VARYING_SLOT_PRIMITIVE_ID] = attributes_per_reg * reg;
513 reg++;
514
515 reg = setup_uniforms(reg);
516
517 reg = setup_varying_inputs(reg, attributes_per_reg);
518
519 this->first_non_payload_grf = reg;
520 }
521
522 void
xfb_write()523 gfx6_gs_visitor::xfb_write()
524 {
525 unsigned num_verts;
526
527 switch (gs_prog_data->output_topology) {
528 case _3DPRIM_POINTLIST:
529 num_verts = 1;
530 break;
531 case _3DPRIM_LINELIST:
532 case _3DPRIM_LINESTRIP:
533 case _3DPRIM_LINELOOP:
534 num_verts = 2;
535 break;
536 case _3DPRIM_TRILIST:
537 case _3DPRIM_TRIFAN:
538 case _3DPRIM_TRISTRIP:
539 case _3DPRIM_RECTLIST:
540 num_verts = 3;
541 break;
542 case _3DPRIM_QUADLIST:
543 case _3DPRIM_QUADSTRIP:
544 case _3DPRIM_POLYGON:
545 num_verts = 3;
546 break;
547 default:
548 unreachable("Unexpected primitive type in Gfx6 SOL program.");
549 }
550
551 this->current_annotation = "gfx6 thread end: svb writes init";
552
553 emit(MOV(dst_reg(this->vertex_output_offset), brw_imm_ud(0u)));
554 emit(MOV(dst_reg(this->sol_prim_written), brw_imm_ud(0u)));
555
556 /* Check that at least one primitive can be written
557 *
558 * Note: since we use the binding table to keep track of buffer offsets
559 * and stride, the GS doesn't need to keep track of a separate pointer
560 * into each buffer; it uses a single pointer which increments by 1 for
561 * each vertex. So we use SVBI0 for this pointer, regardless of whether
562 * transform feedback is in interleaved or separate attribs mode.
563 */
564 src_reg sol_temp(this, glsl_type::uvec4_type);
565 emit(ADD(dst_reg(sol_temp), this->svbi, brw_imm_ud(num_verts)));
566
567 /* Compare SVBI calculated number with the maximum value, which is
568 * in R1.4 (previously saved in this->max_svbi) for gfx6.
569 */
570 emit(CMP(dst_null_d(), sol_temp, this->max_svbi, BRW_CONDITIONAL_LE));
571 emit(IF(BRW_PREDICATE_NORMAL));
572 {
573 vec4_instruction *inst = emit(MOV(dst_reg(destination_indices),
574 brw_imm_vf4(brw_float_to_vf(0.0),
575 brw_float_to_vf(1.0),
576 brw_float_to_vf(2.0),
577 brw_float_to_vf(0.0))));
578 inst->force_writemask_all = true;
579
580 emit(ADD(dst_reg(this->destination_indices),
581 this->destination_indices,
582 this->svbi));
583 }
584 emit(BRW_OPCODE_ENDIF);
585
586 /* Write transform feedback data for all processed vertices. */
587 for (int i = 0; i < (int)nir->info.gs.vertices_out; i++) {
588 emit(MOV(dst_reg(sol_temp), brw_imm_d(i)));
589 emit(CMP(dst_null_d(), sol_temp, this->vertex_count,
590 BRW_CONDITIONAL_L));
591 emit(IF(BRW_PREDICATE_NORMAL));
592 {
593 xfb_program(i, num_verts);
594 }
595 emit(BRW_OPCODE_ENDIF);
596 }
597 }
598
599 void
xfb_program(unsigned vertex,unsigned num_verts)600 gfx6_gs_visitor::xfb_program(unsigned vertex, unsigned num_verts)
601 {
602 unsigned binding;
603 unsigned num_bindings = gs_prog_data->num_transform_feedback_bindings;
604 src_reg sol_temp(this, glsl_type::uvec4_type);
605
606 /* Check for buffer overflow: we need room to write the complete primitive
607 * (all vertices). Otherwise, avoid writing any vertices for it
608 */
609 emit(ADD(dst_reg(sol_temp), this->sol_prim_written, brw_imm_ud(1u)));
610 emit(MUL(dst_reg(sol_temp), sol_temp, brw_imm_ud(num_verts)));
611 emit(ADD(dst_reg(sol_temp), sol_temp, this->svbi));
612 emit(CMP(dst_null_d(), sol_temp, this->max_svbi, BRW_CONDITIONAL_LE));
613 emit(IF(BRW_PREDICATE_NORMAL));
614 {
615 /* Avoid overwriting MRF 1 as it is used as URB write message header */
616 dst_reg mrf_reg(MRF, 2);
617
618 this->current_annotation = "gfx6: emit SOL vertex data";
619 /* For each vertex, generate code to output each varying using the
620 * appropriate binding table entry.
621 */
622 for (binding = 0; binding < num_bindings; ++binding) {
623 unsigned char varying =
624 gs_prog_data->transform_feedback_bindings[binding];
625
626 /* Set up the correct destination index for this vertex */
627 vec4_instruction *inst = emit(GS_OPCODE_SVB_SET_DST_INDEX,
628 mrf_reg,
629 this->destination_indices);
630 inst->sol_vertex = vertex % num_verts;
631
632 /* From the Sandybridge PRM, Volume 2, Part 1, Section 4.5.1:
633 *
634 * "Prior to End of Thread with a URB_WRITE, the kernel must
635 * ensure that all writes are complete by sending the final
636 * write as a committed write."
637 */
638 bool final_write = binding == (unsigned) num_bindings - 1 &&
639 inst->sol_vertex == num_verts - 1;
640
641 /* Compute offset of this varying for the current vertex
642 * in vertex_output
643 */
644 this->current_annotation = output_reg_annotation[varying];
645 src_reg data(this->vertex_output);
646 data.reladdr = ralloc(mem_ctx, src_reg);
647 int offset = get_vertex_output_offset_for_varying(vertex, varying);
648 emit(MOV(dst_reg(this->vertex_output_offset), brw_imm_d(offset)));
649 memcpy(data.reladdr, &this->vertex_output_offset, sizeof(src_reg));
650 data.type = output_reg[varying][0].type;
651 data.swizzle = gs_prog_data->transform_feedback_swizzles[binding];
652
653 /* Write data */
654 inst = emit(GS_OPCODE_SVB_WRITE, mrf_reg, data, sol_temp);
655 inst->sol_binding = binding;
656 inst->sol_final_write = final_write;
657
658 if (final_write) {
659 /* This is the last vertex of the primitive, then increment
660 * SO num primitive counter and destination indices.
661 */
662 emit(ADD(dst_reg(this->destination_indices),
663 this->destination_indices,
664 brw_imm_ud(num_verts)));
665 emit(ADD(dst_reg(this->sol_prim_written),
666 this->sol_prim_written, brw_imm_ud(1u)));
667 }
668
669 }
670 this->current_annotation = NULL;
671 }
672 emit(BRW_OPCODE_ENDIF);
673 }
674
675 int
get_vertex_output_offset_for_varying(int vertex,int varying)676 gfx6_gs_visitor::get_vertex_output_offset_for_varying(int vertex, int varying)
677 {
678 /* Find the output slot assigned to this varying.
679 *
680 * VARYING_SLOT_LAYER and VARYING_SLOT_VIEWPORT are packed in the same slot
681 * as VARYING_SLOT_PSIZ.
682 */
683 if (varying == VARYING_SLOT_LAYER || varying == VARYING_SLOT_VIEWPORT)
684 varying = VARYING_SLOT_PSIZ;
685 int slot = prog_data->vue_map.varying_to_slot[varying];
686
687 if (slot < 0) {
688 /* This varying does not exist in the VUE so we are not writing to it
689 * and its value is undefined. We still want to return a valid offset
690 * into vertex_output though, to prevent any out-of-bound accesses into
691 * the vertex_output array. Since the value for this varying is undefined
692 * we don't really care for the value we assign to it, so any offset
693 * within the limits of vertex_output will do.
694 */
695 slot = 0;
696 }
697
698 return vertex * (prog_data->vue_map.num_slots + 1) + slot;
699 }
700
701 } /* namespace brw */
702