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 36struct svga_stream_output_target { 37 struct pipe_stream_output_target base; 38}; 39 40/** cast wrapper */ 41static inline struct svga_stream_output_target * 42svga_stream_output_target(struct pipe_stream_output_target *s) 43{ 44 return (struct svga_stream_output_target *)s; 45} 46 47struct svga_stream_output * 48svga_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 156enum pipe_error 157svga_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 184void 185svga_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 208static struct pipe_stream_output_target * 209svga_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 237static void 238svga_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 249static void 250svga_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 */ 317enum pipe_error 318svga_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 333void 334svga_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