1 /**********************************************************
2 * Copyright 2014 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26 #include "util/u_memory.h"
27 #include "util/u_bitmask.h"
28
29 #include "svga_cmd.h"
30 #include "svga_context.h"
31 #include "svga_resource_buffer.h"
32 #include "svga_shader.h"
33 #include "svga_debug.h"
34 #include "svga_streamout.h"
35
36 struct svga_stream_output_target {
37 struct pipe_stream_output_target base;
38 };
39
40 /** cast wrapper */
41 static inline struct svga_stream_output_target *
svga_stream_output_target(struct pipe_stream_output_target * s)42 svga_stream_output_target(struct pipe_stream_output_target *s)
43 {
44 return (struct svga_stream_output_target *)s;
45 }
46
47
48 /**
49 * A helper function to send different version of the DefineStreamOutput command
50 * depending on if device is SM5 capable or not.
51 */
52 static enum pipe_error
svga_define_stream_output(struct svga_context * svga,SVGA3dStreamOutputId soid,uint32 numOutputStreamEntries,uint32 numOutputStreamStrides,uint32 streamStrides[SVGA3D_DX_MAX_SOTARGETS],const SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS],uint32 rasterizedStream,struct svga_stream_output * streamout)53 svga_define_stream_output(struct svga_context *svga,
54 SVGA3dStreamOutputId soid,
55 uint32 numOutputStreamEntries,
56 uint32 numOutputStreamStrides,
57 uint32 streamStrides[SVGA3D_DX_MAX_SOTARGETS],
58 const SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS],
59 uint32 rasterizedStream,
60 struct svga_stream_output *streamout)
61 {
62 unsigned i;
63
64 SVGA_DBG(DEBUG_STREAMOUT, "%s: id=%d\n", __FUNCTION__, soid);
65 SVGA_DBG(DEBUG_STREAMOUT,
66 "numOutputStreamEntires=%d\n", numOutputStreamEntries);
67
68 for (i = 0; i < numOutputStreamEntries; i++) {
69 SVGA_DBG(DEBUG_STREAMOUT,
70 " %d: slot=%d regIdx=%d regMask=0x%x stream=%d\n",
71 i, decls[i].outputSlot, decls[i].registerIndex,
72 decls[i].registerMask, decls[i].stream);
73 }
74
75 SVGA_DBG(DEBUG_STREAMOUT,
76 "numOutputStreamStrides=%d\n", numOutputStreamStrides);
77 for (i = 0; i < numOutputStreamStrides; i++) {
78 SVGA_DBG(DEBUG_STREAMOUT, " %d ", streamStrides[i]);
79 }
80 SVGA_DBG(DEBUG_STREAMOUT, "\n");
81
82 if (svga_have_sm5(svga) &&
83 (numOutputStreamEntries > SVGA3D_MAX_DX10_STREAMOUT_DECLS ||
84 numOutputStreamStrides > 1)) {
85 unsigned bufSize = sizeof(SVGA3dStreamOutputDeclarationEntry)
86 * numOutputStreamEntries;
87 struct svga_winsys_buffer *declBuf;
88 struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
89 void *map;
90
91 declBuf = svga_winsys_buffer_create(svga, 1, SVGA_BUFFER_USAGE_PINNED,
92 bufSize);
93 if (!declBuf)
94 return PIPE_ERROR;
95 map = sws->buffer_map(sws, declBuf, PIPE_MAP_WRITE);
96 if (!map) {
97 sws->buffer_destroy(sws, declBuf);
98 return PIPE_ERROR;
99 }
100
101 /* copy decls to buffer */
102 memcpy(map, decls, bufSize);
103
104 /* unmap buffer */
105 sws->buffer_unmap(sws, declBuf);
106 streamout->declBuf = declBuf;
107
108 SVGA_RETRY(svga, SVGA3D_sm5_DefineAndBindStreamOutput
109 (svga->swc, soid,
110 numOutputStreamEntries,
111 numOutputStreamStrides,
112 streamStrides,
113 streamout->declBuf,
114 rasterizedStream,
115 bufSize));
116 } else {
117 SVGA_RETRY(svga, SVGA3D_vgpu10_DefineStreamOutput(svga->swc, soid,
118 numOutputStreamEntries,
119 streamStrides,
120 decls));
121 }
122
123 return PIPE_OK;
124 }
125
126
127 /**
128 * Creates stream output from the stream output info.
129 */
130 struct svga_stream_output *
svga_create_stream_output(struct svga_context * svga,struct svga_shader * shader,const struct pipe_stream_output_info * info)131 svga_create_stream_output(struct svga_context *svga,
132 struct svga_shader *shader,
133 const struct pipe_stream_output_info *info)
134 {
135 struct svga_stream_output *streamout;
136 SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS];
137 unsigned strides[SVGA3D_DX_MAX_SOTARGETS];
138 unsigned dstOffset[SVGA3D_DX_MAX_SOTARGETS];
139 unsigned numStreamStrides = 0;
140 unsigned numDecls;
141 unsigned i;
142 enum pipe_error ret;
143 unsigned id;
144 ASSERTED unsigned maxDecls = 0;
145
146 assert(info->num_outputs <= PIPE_MAX_SO_OUTPUTS);
147
148 /* Gallium utility creates shaders with stream output.
149 * For non-DX10, just return NULL.
150 */
151 if (!svga_have_vgpu10(svga))
152 return NULL;
153
154 if (svga_have_sm5(svga))
155 maxDecls = SVGA3D_MAX_STREAMOUT_DECLS;
156 else if (svga_have_vgpu10(svga))
157 maxDecls = SVGA3D_MAX_DX10_STREAMOUT_DECLS;
158
159 assert(info->num_outputs <= maxDecls);
160
161 /* Allocate an integer ID for the stream output */
162 id = util_bitmask_add(svga->stream_output_id_bm);
163 if (id == UTIL_BITMASK_INVALID_INDEX) {
164 return NULL;
165 }
166
167 /* Allocate the streamout data structure */
168 streamout = CALLOC_STRUCT(svga_stream_output);
169
170 if (!streamout)
171 return NULL;
172
173 streamout->info = *info;
174 streamout->id = id;
175 streamout->pos_out_index = -1;
176 streamout->streammask = 0;
177
178 /* Init whole decls and stride arrays to zero to avoid garbage values */
179 memset(decls, 0, sizeof(decls));
180 memset(strides, 0, sizeof(strides));
181 memset(dstOffset, 0, sizeof(dstOffset));
182
183 SVGA_DBG(DEBUG_STREAMOUT, "%s: num_outputs=%d\n",
184 __FUNCTION__, info->num_outputs);
185
186 for (i = 0, numDecls = 0; i < info->num_outputs; i++, numDecls++) {
187 unsigned reg_idx = info->output[i].register_index;
188 unsigned buf_idx = info->output[i].output_buffer;
189 const enum tgsi_semantic sem_name =
190 shader->tgsi_info.output_semantic_name[reg_idx];
191
192 assert(buf_idx <= PIPE_MAX_SO_BUFFERS);
193
194 numStreamStrides = MAX2(numStreamStrides, buf_idx);
195
196 SVGA_DBG(DEBUG_STREAMOUT,
197 " %d: register_index=%d output_buffer=%d stream=%d\n",
198 i, reg_idx, buf_idx, info->output[i].stream);
199
200 SVGA_DBG(DEBUG_STREAMOUT,
201 " dst_offset=%d start_component=%d num_components=%d\n",
202 info->output[i].dst_offset,
203 info->output[i].start_component,
204 info->output[i].num_components);
205
206 streamout->buffer_stream |= info->output[i].stream << (buf_idx * 4);
207
208 /**
209 * Check if the destination offset of the current output
210 * is at the expected offset. If it is greater, then that means
211 * there is a gap in the stream output. We need to insert
212 * extra declaration entries with an invalid register index
213 * to specify a gap.
214 */
215 while (info->output[i].dst_offset > dstOffset[buf_idx]) {
216
217 unsigned numComponents = info->output[i].dst_offset -
218 dstOffset[buf_idx];;
219
220 assert(svga_have_sm5(svga));
221
222 /* We can only specify at most 4 components to skip in each
223 * declaration entry.
224 */
225 numComponents = numComponents > 4 ? 4 : numComponents;
226
227 decls[numDecls].outputSlot = buf_idx,
228 decls[numDecls].stream = info->output[i].stream;
229 decls[numDecls].registerIndex = SVGA3D_INVALID_ID;
230 decls[numDecls].registerMask = (1 << numComponents) - 1;
231
232 dstOffset[buf_idx] += numComponents;
233 numDecls++;
234 }
235
236 if (sem_name == TGSI_SEMANTIC_POSITION) {
237 /**
238 * Check if streaming out POSITION. If so, replace the
239 * register index with the index for NON_ADJUSTED POSITION.
240 */
241 decls[numDecls].registerIndex = shader->tgsi_info.num_outputs;
242
243 /* Save this output index, so we can tell later if this stream output
244 * includes an output of a vertex position
245 */
246 streamout->pos_out_index = numDecls;
247 }
248 else if (sem_name == TGSI_SEMANTIC_CLIPDIST) {
249 /**
250 * Use the shadow copy for clip distance because
251 * CLIPDIST instruction is only emitted for enabled clip planes.
252 * It's valid to write to ClipDistance variable for non-enabled
253 * clip planes.
254 */
255 decls[numDecls].registerIndex =
256 shader->tgsi_info.num_outputs + 1 +
257 shader->tgsi_info.output_semantic_index[reg_idx];
258 }
259 else {
260 decls[numDecls].registerIndex = reg_idx;
261 }
262
263 decls[numDecls].outputSlot = buf_idx;
264 decls[numDecls].registerMask =
265 ((1 << info->output[i].num_components) - 1)
266 << info->output[i].start_component;
267
268 decls[numDecls].stream = info->output[i].stream;
269 assert(decls[numDecls].stream == 0 || svga_have_sm5(svga));
270
271 /* Set the bit in streammask for the enabled stream */
272 streamout->streammask |= 1 << info->output[i].stream;
273
274 /* Update the expected offset for the next output */
275 dstOffset[buf_idx] += info->output[i].num_components;
276
277 strides[buf_idx] = info->stride[buf_idx] * sizeof(float);
278 }
279
280 assert(numDecls <= maxDecls);
281
282 /* Send the DefineStreamOutput command.
283 * Note, rasterizedStream is always 0.
284 */
285 ret = svga_define_stream_output(svga, id,
286 numDecls, numStreamStrides+1,
287 strides, decls, 0, streamout);
288
289 if (ret != PIPE_OK) {
290 util_bitmask_clear(svga->stream_output_id_bm, id);
291 FREE(streamout);
292 streamout = NULL;
293 }
294 return streamout;
295 }
296
297
298 enum pipe_error
svga_set_stream_output(struct svga_context * svga,struct svga_stream_output * streamout)299 svga_set_stream_output(struct svga_context *svga,
300 struct svga_stream_output *streamout)
301 {
302 unsigned id = streamout ? streamout->id : SVGA3D_INVALID_ID;
303
304 if (!svga_have_vgpu10(svga)) {
305 return PIPE_OK;
306 }
307
308 SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x id=%d\n", __FUNCTION__,
309 streamout, id);
310
311 if (svga->current_so != streamout) {
312
313 /* Before unbinding the current stream output, stop the stream output
314 * statistics queries for the active streams.
315 */
316 if (svga_have_sm5(svga) && svga->current_so) {
317 svga->vcount_buffer_stream = svga->current_so->buffer_stream;
318 svga_end_stream_output_queries(svga, svga->current_so->streammask);
319 }
320
321 enum pipe_error ret = SVGA3D_vgpu10_SetStreamOutput(svga->swc, id);
322 if (ret != PIPE_OK) {
323 return ret;
324 }
325
326 svga->current_so = streamout;
327
328 /* After binding the new stream output, start the stream output
329 * statistics queries for the active streams.
330 */
331 if (svga_have_sm5(svga) && svga->current_so) {
332 svga_begin_stream_output_queries(svga, svga->current_so->streammask);
333 }
334 }
335
336 return PIPE_OK;
337 }
338
339 void
svga_delete_stream_output(struct svga_context * svga,struct svga_stream_output * streamout)340 svga_delete_stream_output(struct svga_context *svga,
341 struct svga_stream_output *streamout)
342 {
343 struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
344
345 SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x\n", __FUNCTION__, streamout);
346
347 assert(svga_have_vgpu10(svga));
348 assert(streamout != NULL);
349
350 SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyStreamOutput(svga->swc,
351 streamout->id));
352
353 if (svga_have_sm5(svga) && streamout->declBuf) {
354 sws->buffer_destroy(sws, streamout->declBuf);
355 }
356
357 /* Before deleting the current streamout, make sure to stop any pending
358 * SO queries.
359 */
360 if (svga->current_so == streamout) {
361 if (svga->in_streamout)
362 svga_end_stream_output_queries(svga, svga->current_so->streammask);
363 svga->current_so = NULL;
364 }
365
366 /* Release the ID */
367 util_bitmask_clear(svga->stream_output_id_bm, streamout->id);
368
369 /* Free streamout structure */
370 FREE(streamout);
371 }
372
373
374 static struct pipe_stream_output_target *
svga_create_stream_output_target(struct pipe_context * pipe,struct pipe_resource * buffer,unsigned buffer_offset,unsigned buffer_size)375 svga_create_stream_output_target(struct pipe_context *pipe,
376 struct pipe_resource *buffer,
377 unsigned buffer_offset,
378 unsigned buffer_size)
379 {
380 struct svga_context *svga = svga_context(pipe);
381 struct svga_stream_output_target *sot;
382
383 SVGA_DBG(DEBUG_STREAMOUT, "%s offset=%d size=%d\n", __FUNCTION__,
384 buffer_offset, buffer_size);
385
386 assert(svga_have_vgpu10(svga));
387 (void) svga;
388
389 sot = CALLOC_STRUCT(svga_stream_output_target);
390 if (!sot)
391 return NULL;
392
393 pipe_reference_init(&sot->base.reference, 1);
394 pipe_resource_reference(&sot->base.buffer, buffer);
395 sot->base.context = pipe;
396 sot->base.buffer = buffer;
397 sot->base.buffer_offset = buffer_offset;
398 sot->base.buffer_size = buffer_size;
399
400 return &sot->base;
401 }
402
403 static void
svga_destroy_stream_output_target(struct pipe_context * pipe,struct pipe_stream_output_target * target)404 svga_destroy_stream_output_target(struct pipe_context *pipe,
405 struct pipe_stream_output_target *target)
406 {
407 struct svga_stream_output_target *sot = svga_stream_output_target(target);
408
409 SVGA_DBG(DEBUG_STREAMOUT, "%s\n", __FUNCTION__);
410
411 pipe_resource_reference(&sot->base.buffer, NULL);
412 FREE(sot);
413 }
414
415 static void
svga_set_stream_output_targets(struct pipe_context * pipe,unsigned num_targets,struct pipe_stream_output_target ** targets,const unsigned * offsets)416 svga_set_stream_output_targets(struct pipe_context *pipe,
417 unsigned num_targets,
418 struct pipe_stream_output_target **targets,
419 const unsigned *offsets)
420 {
421 struct svga_context *svga = svga_context(pipe);
422 struct SVGA3dSoTarget soBindings[SVGA3D_DX_MAX_SOTARGETS];
423 unsigned i;
424 unsigned num_so_targets;
425 boolean begin_so_queries = num_targets > 0;
426
427 SVGA_DBG(DEBUG_STREAMOUT, "%s num_targets=%d\n", __FUNCTION__,
428 num_targets);
429
430 assert(svga_have_vgpu10(svga));
431
432 /* Mark the streamout buffers as dirty so that we'll issue readbacks
433 * before mapping.
434 */
435 for (i = 0; i < svga->num_so_targets; i++) {
436 struct svga_buffer *sbuf = svga_buffer(svga->so_targets[i]->buffer);
437 sbuf->dirty = TRUE;
438 }
439
440 /* Before the currently bound streamout targets are unbound,
441 * save them in case they need to be referenced to retrieve the
442 * number of vertices being streamed out.
443 */
444 for (i = 0; i < ARRAY_SIZE(svga->so_targets); i++) {
445 svga->vcount_so_targets[i] = svga->so_targets[i];
446 }
447
448 assert(num_targets <= SVGA3D_DX_MAX_SOTARGETS);
449
450 for (i = 0; i < num_targets; i++) {
451 struct svga_stream_output_target *sot
452 = svga_stream_output_target(targets[i]);
453 struct svga_buffer *sbuf = svga_buffer(sot->base.buffer);
454 unsigned size;
455
456 svga->so_surfaces[i] = svga_buffer_handle(svga, sot->base.buffer,
457 PIPE_BIND_STREAM_OUTPUT);
458
459 assert(svga_buffer(sot->base.buffer)->key.flags
460 & SVGA3D_SURFACE_BIND_STREAM_OUTPUT);
461
462 /* Mark the buffer surface as RENDERED */
463 assert(sbuf->bufsurf);
464 sbuf->bufsurf->surface_state = SVGA_SURFACE_STATE_RENDERED;
465
466 svga->so_targets[i] = &sot->base;
467 if (offsets[i] == -1) {
468 soBindings[i].offset = -1;
469
470 /* The streamout is being resumed. There is no need to restart streamout statistics
471 * queries for the draw-auto fallback since those queries are still active.
472 */
473 begin_so_queries = FALSE;
474 }
475 else
476 soBindings[i].offset = sot->base.buffer_offset + offsets[i];
477
478 /* The size cannot extend beyond the end of the buffer. Clamp it. */
479 size = MIN2(sot->base.buffer_size,
480 sot->base.buffer->width0 - sot->base.buffer_offset);
481
482 soBindings[i].sizeInBytes = size;
483 }
484
485 /* unbind any previously bound stream output buffers */
486 for (; i < svga->num_so_targets; i++) {
487 svga->so_surfaces[i] = NULL;
488 svga->so_targets[i] = NULL;
489 }
490
491 num_so_targets = MAX2(svga->num_so_targets, num_targets);
492 SVGA_RETRY(svga, SVGA3D_vgpu10_SetSOTargets(svga->swc, num_so_targets,
493 soBindings, svga->so_surfaces));
494 svga->num_so_targets = num_targets;
495
496 if (svga_have_sm5(svga) && svga->current_so && begin_so_queries) {
497
498 /* If there are already active queries and we need to start a new streamout,
499 * we need to stop the current active queries first.
500 */
501 if (svga->in_streamout) {
502 svga_end_stream_output_queries(svga, svga->current_so->streammask);
503 }
504
505 /* Start stream out statistics queries for the new streamout */
506 svga_begin_stream_output_queries(svga, svga->current_so->streammask);
507 }
508 }
509
510 /**
511 * Rebind stream output target surfaces
512 */
513 enum pipe_error
svga_rebind_stream_output_targets(struct svga_context * svga)514 svga_rebind_stream_output_targets(struct svga_context *svga)
515 {
516 struct svga_winsys_context *swc = svga->swc;
517 enum pipe_error ret;
518 unsigned i;
519
520 for (i = 0; i < svga->num_so_targets; i++) {
521 ret = swc->resource_rebind(swc, svga->so_surfaces[i], NULL, SVGA_RELOC_WRITE);
522 if (ret != PIPE_OK)
523 return ret;
524 }
525
526 return PIPE_OK;
527 }
528
529
530 void
svga_init_stream_output_functions(struct svga_context * svga)531 svga_init_stream_output_functions(struct svga_context *svga)
532 {
533 svga->pipe.create_stream_output_target = svga_create_stream_output_target;
534 svga->pipe.stream_output_target_destroy = svga_destroy_stream_output_target;
535 svga->pipe.set_stream_output_targets = svga_set_stream_output_targets;
536 }
537
538
539 /**
540 * A helper function to create stream output statistics queries for each stream.
541 * These queries are created as a workaround for DrawTransformFeedbackInstanced or
542 * DrawTransformFeedbackStreamInstanced when auto draw doesn't support
543 * instancing or non-0 stream. In this case, the vertex count will
544 * be retrieved from the stream output statistics query.
545 */
546 void
svga_create_stream_output_queries(struct svga_context * svga)547 svga_create_stream_output_queries(struct svga_context *svga)
548 {
549 unsigned i;
550
551 if (!svga_have_sm5(svga))
552 return;
553
554 for (i = 0; i < ARRAY_SIZE(svga->so_queries); i++) {
555 svga->so_queries[i] = svga->pipe.create_query(&svga->pipe,
556 PIPE_QUERY_SO_STATISTICS, i);
557 assert(svga->so_queries[i] != NULL);
558 }
559 }
560
561
562 /**
563 * Destroy the stream output statistics queries for the draw-auto workaround.
564 */
565 void
svga_destroy_stream_output_queries(struct svga_context * svga)566 svga_destroy_stream_output_queries(struct svga_context *svga)
567 {
568 unsigned i;
569
570 if (!svga_have_sm5(svga))
571 return;
572
573 for (i = 0; i < ARRAY_SIZE(svga->so_queries); i++) {
574 svga->pipe.destroy_query(&svga->pipe, svga->so_queries[i]);
575 }
576 }
577
578
579 /**
580 * Start stream output statistics queries for the active streams.
581 */
582 void
svga_begin_stream_output_queries(struct svga_context * svga,unsigned streammask)583 svga_begin_stream_output_queries(struct svga_context *svga,
584 unsigned streammask)
585 {
586 assert(svga_have_sm5(svga));
587 assert(!svga->in_streamout);
588
589 for (unsigned i = 0; i < ARRAY_SIZE(svga->so_queries); i++) {
590 bool ret;
591 if (streammask & (1 << i)) {
592 ret = svga->pipe.begin_query(&svga->pipe, svga->so_queries[i]);
593 }
594 (void) ret;
595 }
596 svga->in_streamout = TRUE;
597
598 return;
599 }
600
601
602 /**
603 * Stop stream output statistics queries for the active streams.
604 */
605 void
svga_end_stream_output_queries(struct svga_context * svga,unsigned streammask)606 svga_end_stream_output_queries(struct svga_context *svga,
607 unsigned streammask)
608 {
609 assert(svga_have_sm5(svga));
610
611 if (!svga->in_streamout)
612 return;
613
614 for (unsigned i = 0; i < ARRAY_SIZE(svga->so_queries); i++) {
615 bool ret;
616 if (streammask & (1 << i)) {
617 ret = svga->pipe.end_query(&svga->pipe, svga->so_queries[i]);
618 }
619 (void) ret;
620 }
621 svga->in_streamout = FALSE;
622
623 return;
624 }
625
626
627 /**
628 * Return the primitive count returned from the stream output statistics query
629 * for the specified stream.
630 */
631 unsigned
svga_get_primcount_from_stream_output(struct svga_context * svga,unsigned stream)632 svga_get_primcount_from_stream_output(struct svga_context *svga,
633 unsigned stream)
634 {
635 unsigned primcount = 0;
636 union pipe_query_result result;
637 bool ret;
638
639 if (svga->current_so) {
640 svga_end_stream_output_queries(svga, svga->current_so->streammask);
641 }
642
643 ret = svga->pipe.get_query_result(&svga->pipe,
644 svga->so_queries[stream],
645 TRUE, &result);
646 if (ret)
647 primcount = result.so_statistics.num_primitives_written;
648
649 return primcount;
650 }
651