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 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 157enum pipe_error 158svga_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 182void 183svga_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 206static struct pipe_stream_output_target * 207svga_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 235static void 236svga_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 247static void 248svga_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 */ 316enum pipe_error 317svga_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 332void 333svga_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