svga: rebind stream output targets
[mesa.git] / src / gallium / drivers / svga / svga_pipe_streamout.c
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 *
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 *
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
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
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 *
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
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
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
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
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 }