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