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