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