1 /**********************************************************
2 * Copyright 2014 VMware, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 **********************************************************/
26 #include "util/u_memory.h"
27 #include "util/u_bitmask.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"
36 struct svga_stream_output_target
{
37 struct pipe_stream_output_target base
;
41 static inline struct svga_stream_output_target
*
42 svga_stream_output_target(struct pipe_stream_output_target
*s
)
44 return (struct svga_stream_output_target
*)s
;
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
)
52 struct svga_stream_output
*streamout
;
53 SVGA3dStreamOutputDeclarationEntry decls
[SVGA3D_MAX_STREAMOUT_DECLS
];
54 unsigned strides
[SVGA3D_DX_MAX_SOTARGETS
];
59 assert(info
->num_outputs
<= PIPE_MAX_SO_OUTPUTS
);
61 /* Gallium utility creates shaders with stream output.
62 * For non-DX10, just return NULL.
64 if (!svga_have_vgpu10(svga
))
67 assert(info
->num_outputs
<= SVGA3D_MAX_STREAMOUT_DECLS
);
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
) {
75 /* Allocate the streamout data structure */
76 streamout
= CALLOC_STRUCT(svga_stream_output
);
81 streamout
->info
= *info
;
83 streamout
->pos_out_index
= -1;
85 SVGA_DBG(DEBUG_STREAMOUT
, "%s, num_outputs=%d id=%d\n", __FUNCTION__
,
86 info
->num_outputs
, id
);
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
));
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
];
98 assert(buf_idx
<= PIPE_MAX_SO_BUFFERS
);
100 if (sem_name
== TGSI_SEMANTIC_POSITION
) {
102 * Check if streaming out POSITION. If so, replace the
103 * register index with the index for NON_ADJUSTED POSITION.
105 decls
[i
].registerIndex
= shader
->info
.num_outputs
;
107 /* Save this output index, so we can tell later if this stream output
108 * includes an output of a vertex position
110 streamout
->pos_out_index
= i
;
112 else if (sem_name
== TGSI_SEMANTIC_CLIPDIST
) {
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
119 decls
[i
].registerIndex
= shader
->info
.num_outputs
+ 1 +
120 shader
->info
.output_semantic_index
[reg_idx
];
123 decls
[i
].registerIndex
= reg_idx
;
126 decls
[i
].outputSlot
= buf_idx
;
127 decls
[i
].registerMask
=
128 ((1 << info
->output
[i
].num_components
) - 1)
129 << info
->output
[i
].start_component
;
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
);
135 strides
[buf_idx
] = info
->stride
[buf_idx
] * sizeof(float);
138 ret
= SVGA3D_vgpu10_DefineStreamOutput(svga
->swc
, id
,
142 if (ret
!= PIPE_OK
) {
143 svga_context_flush(svga
, NULL
);
144 ret
= SVGA3D_vgpu10_DefineStreamOutput(svga
->swc
, id
,
148 if (ret
!= PIPE_OK
) {
149 util_bitmask_clear(svga
->stream_output_id_bm
, id
);
158 svga_set_stream_output(struct svga_context
*svga
,
159 struct svga_stream_output
*streamout
)
161 unsigned id
= streamout
? streamout
->id
: SVGA3D_INVALID_ID
;
163 if (!svga_have_vgpu10(svga
)) {
167 SVGA_DBG(DEBUG_STREAMOUT
, "%s streamout=0x%x id=%d\n", __FUNCTION__
,
170 if (svga
->current_so
!= streamout
) {
171 enum pipe_error ret
= SVGA3D_vgpu10_SetStreamOutput(svga
->swc
, id
);
172 if (ret
!= PIPE_OK
) {
176 svga
->current_so
= streamout
;
183 svga_delete_stream_output(struct svga_context
*svga
,
184 struct svga_stream_output
*streamout
)
188 SVGA_DBG(DEBUG_STREAMOUT
, "%s streamout=0x%x\n", __FUNCTION__
, streamout
);
190 assert(svga_have_vgpu10(svga
));
191 assert(streamout
!= NULL
);
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
);
200 util_bitmask_clear(svga
->stream_output_id_bm
, streamout
->id
);
202 /* Free streamout structure */
206 static struct pipe_stream_output_target
*
207 svga_create_stream_output_target(struct pipe_context
*pipe
,
208 struct pipe_resource
*buffer
,
209 unsigned buffer_offset
,
210 unsigned buffer_size
)
212 struct svga_context
*svga
= svga_context(pipe
);
213 struct svga_stream_output_target
*sot
;
215 SVGA_DBG(DEBUG_STREAMOUT
, "%s offset=%d size=%d\n", __FUNCTION__
,
216 buffer_offset
, buffer_size
);
218 assert(svga_have_vgpu10(svga
));
221 sot
= CALLOC_STRUCT(svga_stream_output_target
);
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
;
236 svga_destroy_stream_output_target(struct pipe_context
*pipe
,
237 struct pipe_stream_output_target
*target
)
239 struct svga_stream_output_target
*sot
= svga_stream_output_target(target
);
241 SVGA_DBG(DEBUG_STREAMOUT
, "%s\n", __FUNCTION__
);
243 pipe_resource_reference(&sot
->base
.buffer
, NULL
);
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
)
253 struct svga_context
*svga
= svga_context(pipe
);
254 struct SVGA3dSoTarget soBindings
[SVGA3D_DX_MAX_SOTARGETS
];
257 unsigned num_so_targets
;
259 SVGA_DBG(DEBUG_STREAMOUT
, "%s num_targets=%d\n", __FUNCTION__
,
262 assert(svga_have_vgpu10(svga
));
264 /* Mark the streamout buffers as dirty so that we'll issue readbacks
267 for (i
= 0; i
< svga
->num_so_targets
; i
++) {
268 struct svga_buffer
*sbuf
= svga_buffer(svga
->so_targets
[i
]->buffer
);
272 assert(num_targets
<= SVGA3D_DX_MAX_SOTARGETS
);
274 for (i
= 0; i
< num_targets
; i
++) {
275 struct svga_stream_output_target
*sot
276 = svga_stream_output_target(targets
[i
]);
279 svga
->so_surfaces
[i
] = svga_buffer_handle(svga
, sot
->base
.buffer
,
280 PIPE_BIND_STREAM_OUTPUT
);
282 assert(svga_buffer(sot
->base
.buffer
)->key
.flags
283 & SVGA3D_SURFACE_BIND_STREAM_OUTPUT
);
285 svga
->so_targets
[i
] = &sot
->base
;
286 soBindings
[i
].offset
= sot
->base
.buffer_offset
;
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
);
292 soBindings
[i
].sizeInBytes
= size
;
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
;
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
);
310 svga
->num_so_targets
= num_targets
;
314 * Rebind stream output target surfaces
317 svga_rebind_stream_output_targets(struct svga_context
*svga
)
319 struct svga_winsys_context
*swc
= svga
->swc
;
323 for (i
= 0; i
< svga
->num_so_targets
; i
++) {
324 ret
= swc
->resource_rebind(swc
, svga
->so_surfaces
[i
], NULL
, SVGA_RELOC_WRITE
);
333 svga_init_stream_output_functions(struct svga_context
*svga
)
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
;