• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 struct svga_stream_output *
svga_create_stream_output(struct svga_context * svga,struct svga_shader * shader,const struct pipe_stream_output_info * info)48 svga_create_stream_output(struct svga_context *svga,
49                           struct svga_shader *shader,
50                           const struct pipe_stream_output_info *info)
51 {
52    struct svga_stream_output *streamout;
53    SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS];
54    unsigned strides[SVGA3D_DX_MAX_SOTARGETS];
55    unsigned i;
56    enum pipe_error ret;
57    unsigned id;
58 
59    assert(info->num_outputs <= PIPE_MAX_SO_OUTPUTS);
60 
61    /* Gallium utility creates shaders with stream output.
62     * For non-DX10, just return NULL.
63     */
64    if (!svga_have_vgpu10(svga))
65       return NULL;
66 
67    assert(info->num_outputs <= SVGA3D_MAX_STREAMOUT_DECLS);
68 
69    /* Allocate an integer ID for the stream output */
70    id = util_bitmask_add(svga->stream_output_id_bm);
71    if (id == UTIL_BITMASK_INVALID_INDEX) {
72       return NULL;
73    }
74 
75    /* Allocate the streamout data structure */
76    streamout = CALLOC_STRUCT(svga_stream_output);
77 
78    if (!streamout)
79       return NULL;
80 
81    streamout->info = *info;
82    streamout->id = id;
83    streamout->pos_out_index = -1;
84 
85    SVGA_DBG(DEBUG_STREAMOUT, "%s, num_outputs=%d id=%d\n", __FUNCTION__,
86             info->num_outputs, id);
87 
88    /* init whole decls and stride arrays to zero to avoid garbage values */
89    memset(decls, 0, sizeof(decls));
90    memset(strides, 0, sizeof(strides));
91 
92    for (i = 0; i < info->num_outputs; i++) {
93       unsigned reg_idx = info->output[i].register_index;
94       unsigned buf_idx = info->output[i].output_buffer;
95       const unsigned sem_name = shader->info.output_semantic_name[reg_idx];
96 
97       assert(buf_idx <= PIPE_MAX_SO_BUFFERS);
98 
99       if (sem_name == TGSI_SEMANTIC_POSITION) {
100          /**
101           * Check if streaming out POSITION. If so, replace the
102           * register index with the index for NON_ADJUSTED POSITION.
103           */
104          decls[i].registerIndex = shader->info.num_outputs;
105 
106          /* Save this output index, so we can tell later if this stream output
107           * includes an output of a vertex position
108           */
109          streamout->pos_out_index = i;
110       }
111       else if (sem_name == TGSI_SEMANTIC_CLIPDIST) {
112          /**
113           * Use the shadow copy for clip distance because
114           * CLIPDIST instruction is only emitted for enabled clip planes.
115           * It's valid to write to ClipDistance variable for non-enabled
116           * clip planes.
117           */
118          decls[i].registerIndex = shader->info.num_outputs + 1 +
119                                   shader->info.output_semantic_index[reg_idx];
120       }
121       else {
122          decls[i].registerIndex = reg_idx;
123       }
124 
125       decls[i].outputSlot = buf_idx;
126       decls[i].registerMask =
127          ((1 << info->output[i].num_components) - 1)
128             << info->output[i].start_component;
129 
130       SVGA_DBG(DEBUG_STREAMOUT, "%d slot=%d regIdx=%d regMask=0x%x\n",
131                i, decls[i].outputSlot, decls[i].registerIndex,
132                decls[i].registerMask);
133 
134       strides[buf_idx] = info->stride[buf_idx] * sizeof(float);
135    }
136 
137    ret = SVGA3D_vgpu10_DefineStreamOutput(svga->swc, id,
138                                           info->num_outputs,
139                                           strides,
140                                           decls);
141    if (ret != PIPE_OK) {
142       svga_context_flush(svga, NULL);
143       ret = SVGA3D_vgpu10_DefineStreamOutput(svga->swc, id,
144                                              info->num_outputs,
145                                              strides,
146                                              decls);
147       if (ret != PIPE_OK) {
148          util_bitmask_clear(svga->stream_output_id_bm, id);
149          FREE(streamout);
150          streamout = NULL;
151       }
152    }
153    return streamout;
154 }
155 
156 enum pipe_error
svga_set_stream_output(struct svga_context * svga,struct svga_stream_output * streamout)157 svga_set_stream_output(struct svga_context *svga,
158                        struct svga_stream_output *streamout)
159 {
160    enum pipe_error ret = PIPE_OK;
161    unsigned id = streamout ? streamout->id : SVGA3D_INVALID_ID;
162 
163    if (!svga_have_vgpu10(svga)) {
164       return PIPE_OK;
165    }
166 
167    SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x id=%d\n", __FUNCTION__,
168             streamout, id);
169 
170    if (svga->current_so != streamout) {
171       /* Save current SO state */
172       svga->current_so = streamout;
173 
174       ret = SVGA3D_vgpu10_SetStreamOutput(svga->swc, id);
175       if (ret != PIPE_OK) {
176          svga_context_flush(svga, NULL);
177          ret = SVGA3D_vgpu10_SetStreamOutput(svga->swc, id);
178       }
179    }
180 
181    return ret;
182 }
183 
184 void
svga_delete_stream_output(struct svga_context * svga,struct svga_stream_output * streamout)185 svga_delete_stream_output(struct svga_context *svga,
186                           struct svga_stream_output *streamout)
187 {
188    enum pipe_error ret;
189 
190    SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x\n", __FUNCTION__, streamout);
191 
192    assert(svga_have_vgpu10(svga));
193    assert(streamout != NULL);
194 
195    ret = SVGA3D_vgpu10_DestroyStreamOutput(svga->swc, streamout->id);
196    if (ret != PIPE_OK) {
197       svga_context_flush(svga, NULL);
198       ret = SVGA3D_vgpu10_DestroyStreamOutput(svga->swc, streamout->id);
199    }
200 
201    /* Release the ID */
202    util_bitmask_clear(svga->stream_output_id_bm, streamout->id);
203 
204    /* Free streamout structure */
205    FREE(streamout);
206 }
207 
208 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)209 svga_create_stream_output_target(struct pipe_context *pipe,
210                                  struct pipe_resource *buffer,
211                                  unsigned buffer_offset,
212                                  unsigned buffer_size)
213 {
214    struct svga_context *svga = svga_context(pipe);
215    struct svga_stream_output_target *sot;
216 
217    SVGA_DBG(DEBUG_STREAMOUT, "%s offset=%d size=%d\n", __FUNCTION__,
218             buffer_offset, buffer_size);
219 
220    assert(svga_have_vgpu10(svga));
221    (void) svga;
222 
223    sot = CALLOC_STRUCT(svga_stream_output_target);
224    if (!sot)
225       return NULL;
226 
227    pipe_reference_init(&sot->base.reference, 1);
228    pipe_resource_reference(&sot->base.buffer, buffer);
229    sot->base.context = pipe;
230    sot->base.buffer = buffer;
231    sot->base.buffer_offset = buffer_offset;
232    sot->base.buffer_size = buffer_size;
233 
234    return &sot->base;
235 }
236 
237 static void
svga_destroy_stream_output_target(struct pipe_context * pipe,struct pipe_stream_output_target * target)238 svga_destroy_stream_output_target(struct pipe_context *pipe,
239                                   struct pipe_stream_output_target *target)
240 {
241    struct svga_stream_output_target *sot = svga_stream_output_target(target);
242 
243    SVGA_DBG(DEBUG_STREAMOUT, "%s\n", __FUNCTION__);
244 
245    pipe_resource_reference(&sot->base.buffer, NULL);
246    FREE(sot);
247 }
248 
249 static void
svga_set_stream_output_targets(struct pipe_context * pipe,unsigned num_targets,struct pipe_stream_output_target ** targets,const unsigned * offsets)250 svga_set_stream_output_targets(struct pipe_context *pipe,
251                                unsigned num_targets,
252                                struct pipe_stream_output_target **targets,
253                                const unsigned *offsets)
254 {
255    struct svga_context *svga = svga_context(pipe);
256    struct SVGA3dSoTarget soBindings[SVGA3D_DX_MAX_SOTARGETS];
257    enum pipe_error ret;
258    unsigned i;
259    unsigned num_so_targets;
260 
261    SVGA_DBG(DEBUG_STREAMOUT, "%s num_targets=%d\n", __FUNCTION__,
262             num_targets);
263 
264    assert(svga_have_vgpu10(svga));
265 
266    /* Mark the streamout buffers as dirty so that we'll issue readbacks
267     * before mapping.
268     */
269    for (i = 0; i < svga->num_so_targets; i++) {
270       struct svga_buffer *sbuf = svga_buffer(svga->so_targets[i]->buffer);
271       sbuf->dirty = TRUE;
272    }
273 
274    assert(num_targets <= SVGA3D_DX_MAX_SOTARGETS);
275 
276    for (i = 0; i < num_targets; i++) {
277       struct svga_stream_output_target *sot
278          = svga_stream_output_target(targets[i]);
279       struct svga_buffer *sbuf = svga_buffer(sot->base.buffer);
280       unsigned size;
281 
282       assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT);
283       (void) sbuf;
284 
285       svga->so_surfaces[i] = svga_buffer_handle(svga, sot->base.buffer);
286       svga->so_targets[i] = &sot->base;
287       soBindings[i].offset = sot->base.buffer_offset;
288 
289       /* The size cannot extend beyond the end of the buffer.  Clamp it. */
290       size = MIN2(sot->base.buffer_size,
291                   sot->base.buffer->width0 - sot->base.buffer_offset);
292 
293       soBindings[i].sizeInBytes = size;
294    }
295 
296    /* unbind any previously bound stream output buffers */
297    for (; i < svga->num_so_targets; i++) {
298       svga->so_surfaces[i] = NULL;
299       svga->so_targets[i] = NULL;
300    }
301 
302    num_so_targets = MAX2(svga->num_so_targets, num_targets);
303    ret = SVGA3D_vgpu10_SetSOTargets(svga->swc, num_so_targets,
304                                     soBindings, svga->so_surfaces);
305    if (ret != PIPE_OK) {
306       svga_context_flush(svga, NULL);
307       ret = SVGA3D_vgpu10_SetSOTargets(svga->swc, num_so_targets,
308                                        soBindings, svga->so_surfaces);
309    }
310 
311    svga->num_so_targets = num_targets;
312 }
313 
314 /**
315  * Rebind stream output target surfaces
316  */
317 enum pipe_error
svga_rebind_stream_output_targets(struct svga_context * svga)318 svga_rebind_stream_output_targets(struct svga_context *svga)
319 {
320    struct svga_winsys_context *swc = svga->swc;
321    enum pipe_error ret;
322    unsigned i;
323 
324    for (i = 0; i < svga->num_so_targets; i++) {
325       ret = swc->resource_rebind(swc, svga->so_surfaces[i], NULL, SVGA_RELOC_WRITE);
326       if (ret != PIPE_OK)
327          return ret;
328    }
329 
330    return PIPE_OK;
331 }
332 
333 void
svga_init_stream_output_functions(struct svga_context * svga)334 svga_init_stream_output_functions(struct svga_context *svga)
335 {
336    svga->pipe.create_stream_output_target = svga_create_stream_output_target;
337    svga->pipe.stream_output_target_destroy = svga_destroy_stream_output_target;
338    svga->pipe.set_stream_output_targets = svga_set_stream_output_targets;
339 }
340