1bf215546Sopenharmony_ci/********************************************************** 2bf215546Sopenharmony_ci * Copyright 2014 VMware, Inc. All rights reserved. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person 5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation 6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without 7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy, 8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies 9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is 10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be 13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci **********************************************************/ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "util/u_memory.h" 27bf215546Sopenharmony_ci#include "util/u_bitmask.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "svga_cmd.h" 30bf215546Sopenharmony_ci#include "svga_context.h" 31bf215546Sopenharmony_ci#include "svga_resource_buffer.h" 32bf215546Sopenharmony_ci#include "svga_shader.h" 33bf215546Sopenharmony_ci#include "svga_debug.h" 34bf215546Sopenharmony_ci#include "svga_streamout.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cistruct svga_stream_output_target { 37bf215546Sopenharmony_ci struct pipe_stream_output_target base; 38bf215546Sopenharmony_ci}; 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci/** cast wrapper */ 41bf215546Sopenharmony_cistatic inline struct svga_stream_output_target * 42bf215546Sopenharmony_cisvga_stream_output_target(struct pipe_stream_output_target *s) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci return (struct svga_stream_output_target *)s; 45bf215546Sopenharmony_ci} 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci/** 49bf215546Sopenharmony_ci * A helper function to send different version of the DefineStreamOutput command 50bf215546Sopenharmony_ci * depending on if device is SM5 capable or not. 51bf215546Sopenharmony_ci */ 52bf215546Sopenharmony_cistatic enum pipe_error 53bf215546Sopenharmony_cisvga_define_stream_output(struct svga_context *svga, 54bf215546Sopenharmony_ci SVGA3dStreamOutputId soid, 55bf215546Sopenharmony_ci uint32 numOutputStreamEntries, 56bf215546Sopenharmony_ci uint32 numOutputStreamStrides, 57bf215546Sopenharmony_ci uint32 streamStrides[SVGA3D_DX_MAX_SOTARGETS], 58bf215546Sopenharmony_ci const SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS], 59bf215546Sopenharmony_ci uint32 rasterizedStream, 60bf215546Sopenharmony_ci struct svga_stream_output *streamout) 61bf215546Sopenharmony_ci{ 62bf215546Sopenharmony_ci unsigned i; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s: id=%d\n", __FUNCTION__, soid); 65bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, 66bf215546Sopenharmony_ci "numOutputStreamEntires=%d\n", numOutputStreamEntries); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci for (i = 0; i < numOutputStreamEntries; i++) { 69bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, 70bf215546Sopenharmony_ci " %d: slot=%d regIdx=%d regMask=0x%x stream=%d\n", 71bf215546Sopenharmony_ci i, decls[i].outputSlot, decls[i].registerIndex, 72bf215546Sopenharmony_ci decls[i].registerMask, decls[i].stream); 73bf215546Sopenharmony_ci } 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, 76bf215546Sopenharmony_ci "numOutputStreamStrides=%d\n", numOutputStreamStrides); 77bf215546Sopenharmony_ci for (i = 0; i < numOutputStreamStrides; i++) { 78bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, " %d ", streamStrides[i]); 79bf215546Sopenharmony_ci } 80bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "\n"); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci if (svga_have_sm5(svga) && 83bf215546Sopenharmony_ci (numOutputStreamEntries > SVGA3D_MAX_DX10_STREAMOUT_DECLS || 84bf215546Sopenharmony_ci numOutputStreamStrides > 1)) { 85bf215546Sopenharmony_ci unsigned bufSize = sizeof(SVGA3dStreamOutputDeclarationEntry) 86bf215546Sopenharmony_ci * numOutputStreamEntries; 87bf215546Sopenharmony_ci struct svga_winsys_buffer *declBuf; 88bf215546Sopenharmony_ci struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; 89bf215546Sopenharmony_ci void *map; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci declBuf = svga_winsys_buffer_create(svga, 1, SVGA_BUFFER_USAGE_PINNED, 92bf215546Sopenharmony_ci bufSize); 93bf215546Sopenharmony_ci if (!declBuf) 94bf215546Sopenharmony_ci return PIPE_ERROR; 95bf215546Sopenharmony_ci map = sws->buffer_map(sws, declBuf, PIPE_MAP_WRITE); 96bf215546Sopenharmony_ci if (!map) { 97bf215546Sopenharmony_ci sws->buffer_destroy(sws, declBuf); 98bf215546Sopenharmony_ci return PIPE_ERROR; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci /* copy decls to buffer */ 102bf215546Sopenharmony_ci memcpy(map, decls, bufSize); 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci /* unmap buffer */ 105bf215546Sopenharmony_ci sws->buffer_unmap(sws, declBuf); 106bf215546Sopenharmony_ci streamout->declBuf = declBuf; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci SVGA_RETRY(svga, SVGA3D_sm5_DefineAndBindStreamOutput 109bf215546Sopenharmony_ci (svga->swc, soid, 110bf215546Sopenharmony_ci numOutputStreamEntries, 111bf215546Sopenharmony_ci numOutputStreamStrides, 112bf215546Sopenharmony_ci streamStrides, 113bf215546Sopenharmony_ci streamout->declBuf, 114bf215546Sopenharmony_ci rasterizedStream, 115bf215546Sopenharmony_ci bufSize)); 116bf215546Sopenharmony_ci } else { 117bf215546Sopenharmony_ci SVGA_RETRY(svga, SVGA3D_vgpu10_DefineStreamOutput(svga->swc, soid, 118bf215546Sopenharmony_ci numOutputStreamEntries, 119bf215546Sopenharmony_ci streamStrides, 120bf215546Sopenharmony_ci decls)); 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci return PIPE_OK; 124bf215546Sopenharmony_ci} 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci/** 128bf215546Sopenharmony_ci * Creates stream output from the stream output info. 129bf215546Sopenharmony_ci */ 130bf215546Sopenharmony_cistruct svga_stream_output * 131bf215546Sopenharmony_cisvga_create_stream_output(struct svga_context *svga, 132bf215546Sopenharmony_ci struct svga_shader *shader, 133bf215546Sopenharmony_ci const struct pipe_stream_output_info *info) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci struct svga_stream_output *streamout; 136bf215546Sopenharmony_ci SVGA3dStreamOutputDeclarationEntry decls[SVGA3D_MAX_STREAMOUT_DECLS]; 137bf215546Sopenharmony_ci unsigned strides[SVGA3D_DX_MAX_SOTARGETS]; 138bf215546Sopenharmony_ci unsigned dstOffset[SVGA3D_DX_MAX_SOTARGETS]; 139bf215546Sopenharmony_ci unsigned numStreamStrides = 0; 140bf215546Sopenharmony_ci unsigned numDecls; 141bf215546Sopenharmony_ci unsigned i; 142bf215546Sopenharmony_ci enum pipe_error ret; 143bf215546Sopenharmony_ci unsigned id; 144bf215546Sopenharmony_ci ASSERTED unsigned maxDecls = 0; 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci assert(info->num_outputs <= PIPE_MAX_SO_OUTPUTS); 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci /* Gallium utility creates shaders with stream output. 149bf215546Sopenharmony_ci * For non-DX10, just return NULL. 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_ci if (!svga_have_vgpu10(svga)) 152bf215546Sopenharmony_ci return NULL; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (svga_have_sm5(svga)) 155bf215546Sopenharmony_ci maxDecls = SVGA3D_MAX_STREAMOUT_DECLS; 156bf215546Sopenharmony_ci else if (svga_have_vgpu10(svga)) 157bf215546Sopenharmony_ci maxDecls = SVGA3D_MAX_DX10_STREAMOUT_DECLS; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci assert(info->num_outputs <= maxDecls); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci /* Allocate an integer ID for the stream output */ 162bf215546Sopenharmony_ci id = util_bitmask_add(svga->stream_output_id_bm); 163bf215546Sopenharmony_ci if (id == UTIL_BITMASK_INVALID_INDEX) { 164bf215546Sopenharmony_ci return NULL; 165bf215546Sopenharmony_ci } 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci /* Allocate the streamout data structure */ 168bf215546Sopenharmony_ci streamout = CALLOC_STRUCT(svga_stream_output); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci if (!streamout) 171bf215546Sopenharmony_ci return NULL; 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci streamout->info = *info; 174bf215546Sopenharmony_ci streamout->id = id; 175bf215546Sopenharmony_ci streamout->pos_out_index = -1; 176bf215546Sopenharmony_ci streamout->streammask = 0; 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci /* Init whole decls and stride arrays to zero to avoid garbage values */ 179bf215546Sopenharmony_ci memset(decls, 0, sizeof(decls)); 180bf215546Sopenharmony_ci memset(strides, 0, sizeof(strides)); 181bf215546Sopenharmony_ci memset(dstOffset, 0, sizeof(dstOffset)); 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s: num_outputs=%d\n", 184bf215546Sopenharmony_ci __FUNCTION__, info->num_outputs); 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci for (i = 0, numDecls = 0; i < info->num_outputs; i++, numDecls++) { 187bf215546Sopenharmony_ci unsigned reg_idx = info->output[i].register_index; 188bf215546Sopenharmony_ci unsigned buf_idx = info->output[i].output_buffer; 189bf215546Sopenharmony_ci const enum tgsi_semantic sem_name = 190bf215546Sopenharmony_ci shader->tgsi_info.output_semantic_name[reg_idx]; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci assert(buf_idx <= PIPE_MAX_SO_BUFFERS); 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci numStreamStrides = MAX2(numStreamStrides, buf_idx); 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, 197bf215546Sopenharmony_ci " %d: register_index=%d output_buffer=%d stream=%d\n", 198bf215546Sopenharmony_ci i, reg_idx, buf_idx, info->output[i].stream); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, 201bf215546Sopenharmony_ci " dst_offset=%d start_component=%d num_components=%d\n", 202bf215546Sopenharmony_ci info->output[i].dst_offset, 203bf215546Sopenharmony_ci info->output[i].start_component, 204bf215546Sopenharmony_ci info->output[i].num_components); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci streamout->buffer_stream |= info->output[i].stream << (buf_idx * 4); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci /** 209bf215546Sopenharmony_ci * Check if the destination offset of the current output 210bf215546Sopenharmony_ci * is at the expected offset. If it is greater, then that means 211bf215546Sopenharmony_ci * there is a gap in the stream output. We need to insert 212bf215546Sopenharmony_ci * extra declaration entries with an invalid register index 213bf215546Sopenharmony_ci * to specify a gap. 214bf215546Sopenharmony_ci */ 215bf215546Sopenharmony_ci while (info->output[i].dst_offset > dstOffset[buf_idx]) { 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci unsigned numComponents = info->output[i].dst_offset - 218bf215546Sopenharmony_ci dstOffset[buf_idx];; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci assert(svga_have_sm5(svga)); 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci /* We can only specify at most 4 components to skip in each 223bf215546Sopenharmony_ci * declaration entry. 224bf215546Sopenharmony_ci */ 225bf215546Sopenharmony_ci numComponents = numComponents > 4 ? 4 : numComponents; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci decls[numDecls].outputSlot = buf_idx, 228bf215546Sopenharmony_ci decls[numDecls].stream = info->output[i].stream; 229bf215546Sopenharmony_ci decls[numDecls].registerIndex = SVGA3D_INVALID_ID; 230bf215546Sopenharmony_ci decls[numDecls].registerMask = (1 << numComponents) - 1; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci dstOffset[buf_idx] += numComponents; 233bf215546Sopenharmony_ci numDecls++; 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci if (sem_name == TGSI_SEMANTIC_POSITION) { 237bf215546Sopenharmony_ci /** 238bf215546Sopenharmony_ci * Check if streaming out POSITION. If so, replace the 239bf215546Sopenharmony_ci * register index with the index for NON_ADJUSTED POSITION. 240bf215546Sopenharmony_ci */ 241bf215546Sopenharmony_ci decls[numDecls].registerIndex = shader->tgsi_info.num_outputs; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci /* Save this output index, so we can tell later if this stream output 244bf215546Sopenharmony_ci * includes an output of a vertex position 245bf215546Sopenharmony_ci */ 246bf215546Sopenharmony_ci streamout->pos_out_index = numDecls; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci else if (sem_name == TGSI_SEMANTIC_CLIPDIST) { 249bf215546Sopenharmony_ci /** 250bf215546Sopenharmony_ci * Use the shadow copy for clip distance because 251bf215546Sopenharmony_ci * CLIPDIST instruction is only emitted for enabled clip planes. 252bf215546Sopenharmony_ci * It's valid to write to ClipDistance variable for non-enabled 253bf215546Sopenharmony_ci * clip planes. 254bf215546Sopenharmony_ci */ 255bf215546Sopenharmony_ci decls[numDecls].registerIndex = 256bf215546Sopenharmony_ci shader->tgsi_info.num_outputs + 1 + 257bf215546Sopenharmony_ci shader->tgsi_info.output_semantic_index[reg_idx]; 258bf215546Sopenharmony_ci } 259bf215546Sopenharmony_ci else { 260bf215546Sopenharmony_ci decls[numDecls].registerIndex = reg_idx; 261bf215546Sopenharmony_ci } 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci decls[numDecls].outputSlot = buf_idx; 264bf215546Sopenharmony_ci decls[numDecls].registerMask = 265bf215546Sopenharmony_ci ((1 << info->output[i].num_components) - 1) 266bf215546Sopenharmony_ci << info->output[i].start_component; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci decls[numDecls].stream = info->output[i].stream; 269bf215546Sopenharmony_ci assert(decls[numDecls].stream == 0 || svga_have_sm5(svga)); 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci /* Set the bit in streammask for the enabled stream */ 272bf215546Sopenharmony_ci streamout->streammask |= 1 << info->output[i].stream; 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci /* Update the expected offset for the next output */ 275bf215546Sopenharmony_ci dstOffset[buf_idx] += info->output[i].num_components; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci strides[buf_idx] = info->stride[buf_idx] * sizeof(float); 278bf215546Sopenharmony_ci } 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci assert(numDecls <= maxDecls); 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci /* Send the DefineStreamOutput command. 283bf215546Sopenharmony_ci * Note, rasterizedStream is always 0. 284bf215546Sopenharmony_ci */ 285bf215546Sopenharmony_ci ret = svga_define_stream_output(svga, id, 286bf215546Sopenharmony_ci numDecls, numStreamStrides+1, 287bf215546Sopenharmony_ci strides, decls, 0, streamout); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci if (ret != PIPE_OK) { 290bf215546Sopenharmony_ci util_bitmask_clear(svga->stream_output_id_bm, id); 291bf215546Sopenharmony_ci FREE(streamout); 292bf215546Sopenharmony_ci streamout = NULL; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci return streamout; 295bf215546Sopenharmony_ci} 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_cienum pipe_error 299bf215546Sopenharmony_cisvga_set_stream_output(struct svga_context *svga, 300bf215546Sopenharmony_ci struct svga_stream_output *streamout) 301bf215546Sopenharmony_ci{ 302bf215546Sopenharmony_ci unsigned id = streamout ? streamout->id : SVGA3D_INVALID_ID; 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci if (!svga_have_vgpu10(svga)) { 305bf215546Sopenharmony_ci return PIPE_OK; 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x id=%d\n", __FUNCTION__, 309bf215546Sopenharmony_ci streamout, id); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci if (svga->current_so != streamout) { 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci /* Before unbinding the current stream output, stop the stream output 314bf215546Sopenharmony_ci * statistics queries for the active streams. 315bf215546Sopenharmony_ci */ 316bf215546Sopenharmony_ci if (svga_have_sm5(svga) && svga->current_so) { 317bf215546Sopenharmony_ci svga->vcount_buffer_stream = svga->current_so->buffer_stream; 318bf215546Sopenharmony_ci svga_end_stream_output_queries(svga, svga->current_so->streammask); 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci enum pipe_error ret = SVGA3D_vgpu10_SetStreamOutput(svga->swc, id); 322bf215546Sopenharmony_ci if (ret != PIPE_OK) { 323bf215546Sopenharmony_ci return ret; 324bf215546Sopenharmony_ci } 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci svga->current_so = streamout; 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci /* After binding the new stream output, start the stream output 329bf215546Sopenharmony_ci * statistics queries for the active streams. 330bf215546Sopenharmony_ci */ 331bf215546Sopenharmony_ci if (svga_have_sm5(svga) && svga->current_so) { 332bf215546Sopenharmony_ci svga_begin_stream_output_queries(svga, svga->current_so->streammask); 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci return PIPE_OK; 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_civoid 340bf215546Sopenharmony_cisvga_delete_stream_output(struct svga_context *svga, 341bf215546Sopenharmony_ci struct svga_stream_output *streamout) 342bf215546Sopenharmony_ci{ 343bf215546Sopenharmony_ci struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s streamout=0x%x\n", __FUNCTION__, streamout); 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci assert(svga_have_vgpu10(svga)); 348bf215546Sopenharmony_ci assert(streamout != NULL); 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyStreamOutput(svga->swc, 351bf215546Sopenharmony_ci streamout->id)); 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci if (svga_have_sm5(svga) && streamout->declBuf) { 354bf215546Sopenharmony_ci sws->buffer_destroy(sws, streamout->declBuf); 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci /* Before deleting the current streamout, make sure to stop any pending 358bf215546Sopenharmony_ci * SO queries. 359bf215546Sopenharmony_ci */ 360bf215546Sopenharmony_ci if (svga->current_so == streamout) { 361bf215546Sopenharmony_ci if (svga->in_streamout) 362bf215546Sopenharmony_ci svga_end_stream_output_queries(svga, svga->current_so->streammask); 363bf215546Sopenharmony_ci svga->current_so = NULL; 364bf215546Sopenharmony_ci } 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci /* Release the ID */ 367bf215546Sopenharmony_ci util_bitmask_clear(svga->stream_output_id_bm, streamout->id); 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci /* Free streamout structure */ 370bf215546Sopenharmony_ci FREE(streamout); 371bf215546Sopenharmony_ci} 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_cistatic struct pipe_stream_output_target * 375bf215546Sopenharmony_cisvga_create_stream_output_target(struct pipe_context *pipe, 376bf215546Sopenharmony_ci struct pipe_resource *buffer, 377bf215546Sopenharmony_ci unsigned buffer_offset, 378bf215546Sopenharmony_ci unsigned buffer_size) 379bf215546Sopenharmony_ci{ 380bf215546Sopenharmony_ci struct svga_context *svga = svga_context(pipe); 381bf215546Sopenharmony_ci struct svga_stream_output_target *sot; 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s offset=%d size=%d\n", __FUNCTION__, 384bf215546Sopenharmony_ci buffer_offset, buffer_size); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci assert(svga_have_vgpu10(svga)); 387bf215546Sopenharmony_ci (void) svga; 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci sot = CALLOC_STRUCT(svga_stream_output_target); 390bf215546Sopenharmony_ci if (!sot) 391bf215546Sopenharmony_ci return NULL; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci pipe_reference_init(&sot->base.reference, 1); 394bf215546Sopenharmony_ci pipe_resource_reference(&sot->base.buffer, buffer); 395bf215546Sopenharmony_ci sot->base.context = pipe; 396bf215546Sopenharmony_ci sot->base.buffer = buffer; 397bf215546Sopenharmony_ci sot->base.buffer_offset = buffer_offset; 398bf215546Sopenharmony_ci sot->base.buffer_size = buffer_size; 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci return &sot->base; 401bf215546Sopenharmony_ci} 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_cistatic void 404bf215546Sopenharmony_cisvga_destroy_stream_output_target(struct pipe_context *pipe, 405bf215546Sopenharmony_ci struct pipe_stream_output_target *target) 406bf215546Sopenharmony_ci{ 407bf215546Sopenharmony_ci struct svga_stream_output_target *sot = svga_stream_output_target(target); 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s\n", __FUNCTION__); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci pipe_resource_reference(&sot->base.buffer, NULL); 412bf215546Sopenharmony_ci FREE(sot); 413bf215546Sopenharmony_ci} 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_cistatic void 416bf215546Sopenharmony_cisvga_set_stream_output_targets(struct pipe_context *pipe, 417bf215546Sopenharmony_ci unsigned num_targets, 418bf215546Sopenharmony_ci struct pipe_stream_output_target **targets, 419bf215546Sopenharmony_ci const unsigned *offsets) 420bf215546Sopenharmony_ci{ 421bf215546Sopenharmony_ci struct svga_context *svga = svga_context(pipe); 422bf215546Sopenharmony_ci struct SVGA3dSoTarget soBindings[SVGA3D_DX_MAX_SOTARGETS]; 423bf215546Sopenharmony_ci unsigned i; 424bf215546Sopenharmony_ci unsigned num_so_targets; 425bf215546Sopenharmony_ci boolean begin_so_queries = num_targets > 0; 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci SVGA_DBG(DEBUG_STREAMOUT, "%s num_targets=%d\n", __FUNCTION__, 428bf215546Sopenharmony_ci num_targets); 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci assert(svga_have_vgpu10(svga)); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci /* Mark the streamout buffers as dirty so that we'll issue readbacks 433bf215546Sopenharmony_ci * before mapping. 434bf215546Sopenharmony_ci */ 435bf215546Sopenharmony_ci for (i = 0; i < svga->num_so_targets; i++) { 436bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(svga->so_targets[i]->buffer); 437bf215546Sopenharmony_ci sbuf->dirty = TRUE; 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci /* Before the currently bound streamout targets are unbound, 441bf215546Sopenharmony_ci * save them in case they need to be referenced to retrieve the 442bf215546Sopenharmony_ci * number of vertices being streamed out. 443bf215546Sopenharmony_ci */ 444bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(svga->so_targets); i++) { 445bf215546Sopenharmony_ci svga->vcount_so_targets[i] = svga->so_targets[i]; 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci assert(num_targets <= SVGA3D_DX_MAX_SOTARGETS); 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci for (i = 0; i < num_targets; i++) { 451bf215546Sopenharmony_ci struct svga_stream_output_target *sot 452bf215546Sopenharmony_ci = svga_stream_output_target(targets[i]); 453bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(sot->base.buffer); 454bf215546Sopenharmony_ci unsigned size; 455bf215546Sopenharmony_ci 456bf215546Sopenharmony_ci svga->so_surfaces[i] = svga_buffer_handle(svga, sot->base.buffer, 457bf215546Sopenharmony_ci PIPE_BIND_STREAM_OUTPUT); 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci assert(svga_buffer(sot->base.buffer)->key.flags 460bf215546Sopenharmony_ci & SVGA3D_SURFACE_BIND_STREAM_OUTPUT); 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci /* Mark the buffer surface as RENDERED */ 463bf215546Sopenharmony_ci assert(sbuf->bufsurf); 464bf215546Sopenharmony_ci sbuf->bufsurf->surface_state = SVGA_SURFACE_STATE_RENDERED; 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci svga->so_targets[i] = &sot->base; 467bf215546Sopenharmony_ci if (offsets[i] == -1) { 468bf215546Sopenharmony_ci soBindings[i].offset = -1; 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci /* The streamout is being resumed. There is no need to restart streamout statistics 471bf215546Sopenharmony_ci * queries for the draw-auto fallback since those queries are still active. 472bf215546Sopenharmony_ci */ 473bf215546Sopenharmony_ci begin_so_queries = FALSE; 474bf215546Sopenharmony_ci } 475bf215546Sopenharmony_ci else 476bf215546Sopenharmony_ci soBindings[i].offset = sot->base.buffer_offset + offsets[i]; 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci /* The size cannot extend beyond the end of the buffer. Clamp it. */ 479bf215546Sopenharmony_ci size = MIN2(sot->base.buffer_size, 480bf215546Sopenharmony_ci sot->base.buffer->width0 - sot->base.buffer_offset); 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci soBindings[i].sizeInBytes = size; 483bf215546Sopenharmony_ci } 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_ci /* unbind any previously bound stream output buffers */ 486bf215546Sopenharmony_ci for (; i < svga->num_so_targets; i++) { 487bf215546Sopenharmony_ci svga->so_surfaces[i] = NULL; 488bf215546Sopenharmony_ci svga->so_targets[i] = NULL; 489bf215546Sopenharmony_ci } 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci num_so_targets = MAX2(svga->num_so_targets, num_targets); 492bf215546Sopenharmony_ci SVGA_RETRY(svga, SVGA3D_vgpu10_SetSOTargets(svga->swc, num_so_targets, 493bf215546Sopenharmony_ci soBindings, svga->so_surfaces)); 494bf215546Sopenharmony_ci svga->num_so_targets = num_targets; 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci if (svga_have_sm5(svga) && svga->current_so && begin_so_queries) { 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci /* If there are already active queries and we need to start a new streamout, 499bf215546Sopenharmony_ci * we need to stop the current active queries first. 500bf215546Sopenharmony_ci */ 501bf215546Sopenharmony_ci if (svga->in_streamout) { 502bf215546Sopenharmony_ci svga_end_stream_output_queries(svga, svga->current_so->streammask); 503bf215546Sopenharmony_ci } 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci /* Start stream out statistics queries for the new streamout */ 506bf215546Sopenharmony_ci svga_begin_stream_output_queries(svga, svga->current_so->streammask); 507bf215546Sopenharmony_ci } 508bf215546Sopenharmony_ci} 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci/** 511bf215546Sopenharmony_ci * Rebind stream output target surfaces 512bf215546Sopenharmony_ci */ 513bf215546Sopenharmony_cienum pipe_error 514bf215546Sopenharmony_cisvga_rebind_stream_output_targets(struct svga_context *svga) 515bf215546Sopenharmony_ci{ 516bf215546Sopenharmony_ci struct svga_winsys_context *swc = svga->swc; 517bf215546Sopenharmony_ci enum pipe_error ret; 518bf215546Sopenharmony_ci unsigned i; 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci for (i = 0; i < svga->num_so_targets; i++) { 521bf215546Sopenharmony_ci ret = swc->resource_rebind(swc, svga->so_surfaces[i], NULL, SVGA_RELOC_WRITE); 522bf215546Sopenharmony_ci if (ret != PIPE_OK) 523bf215546Sopenharmony_ci return ret; 524bf215546Sopenharmony_ci } 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci return PIPE_OK; 527bf215546Sopenharmony_ci} 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_civoid 531bf215546Sopenharmony_cisvga_init_stream_output_functions(struct svga_context *svga) 532bf215546Sopenharmony_ci{ 533bf215546Sopenharmony_ci svga->pipe.create_stream_output_target = svga_create_stream_output_target; 534bf215546Sopenharmony_ci svga->pipe.stream_output_target_destroy = svga_destroy_stream_output_target; 535bf215546Sopenharmony_ci svga->pipe.set_stream_output_targets = svga_set_stream_output_targets; 536bf215546Sopenharmony_ci} 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci/** 540bf215546Sopenharmony_ci * A helper function to create stream output statistics queries for each stream. 541bf215546Sopenharmony_ci * These queries are created as a workaround for DrawTransformFeedbackInstanced or 542bf215546Sopenharmony_ci * DrawTransformFeedbackStreamInstanced when auto draw doesn't support 543bf215546Sopenharmony_ci * instancing or non-0 stream. In this case, the vertex count will 544bf215546Sopenharmony_ci * be retrieved from the stream output statistics query. 545bf215546Sopenharmony_ci */ 546bf215546Sopenharmony_civoid 547bf215546Sopenharmony_cisvga_create_stream_output_queries(struct svga_context *svga) 548bf215546Sopenharmony_ci{ 549bf215546Sopenharmony_ci unsigned i; 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci if (!svga_have_sm5(svga)) 552bf215546Sopenharmony_ci return; 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(svga->so_queries); i++) { 555bf215546Sopenharmony_ci svga->so_queries[i] = svga->pipe.create_query(&svga->pipe, 556bf215546Sopenharmony_ci PIPE_QUERY_SO_STATISTICS, i); 557bf215546Sopenharmony_ci assert(svga->so_queries[i] != NULL); 558bf215546Sopenharmony_ci } 559bf215546Sopenharmony_ci} 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci/** 563bf215546Sopenharmony_ci * Destroy the stream output statistics queries for the draw-auto workaround. 564bf215546Sopenharmony_ci */ 565bf215546Sopenharmony_civoid 566bf215546Sopenharmony_cisvga_destroy_stream_output_queries(struct svga_context *svga) 567bf215546Sopenharmony_ci{ 568bf215546Sopenharmony_ci unsigned i; 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci if (!svga_have_sm5(svga)) 571bf215546Sopenharmony_ci return; 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(svga->so_queries); i++) { 574bf215546Sopenharmony_ci svga->pipe.destroy_query(&svga->pipe, svga->so_queries[i]); 575bf215546Sopenharmony_ci } 576bf215546Sopenharmony_ci} 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci 579bf215546Sopenharmony_ci/** 580bf215546Sopenharmony_ci * Start stream output statistics queries for the active streams. 581bf215546Sopenharmony_ci */ 582bf215546Sopenharmony_civoid 583bf215546Sopenharmony_cisvga_begin_stream_output_queries(struct svga_context *svga, 584bf215546Sopenharmony_ci unsigned streammask) 585bf215546Sopenharmony_ci{ 586bf215546Sopenharmony_ci assert(svga_have_sm5(svga)); 587bf215546Sopenharmony_ci assert(!svga->in_streamout); 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(svga->so_queries); i++) { 590bf215546Sopenharmony_ci bool ret; 591bf215546Sopenharmony_ci if (streammask & (1 << i)) { 592bf215546Sopenharmony_ci ret = svga->pipe.begin_query(&svga->pipe, svga->so_queries[i]); 593bf215546Sopenharmony_ci } 594bf215546Sopenharmony_ci (void) ret; 595bf215546Sopenharmony_ci } 596bf215546Sopenharmony_ci svga->in_streamout = TRUE; 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci return; 599bf215546Sopenharmony_ci} 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci 602bf215546Sopenharmony_ci/** 603bf215546Sopenharmony_ci * Stop stream output statistics queries for the active streams. 604bf215546Sopenharmony_ci */ 605bf215546Sopenharmony_civoid 606bf215546Sopenharmony_cisvga_end_stream_output_queries(struct svga_context *svga, 607bf215546Sopenharmony_ci unsigned streammask) 608bf215546Sopenharmony_ci{ 609bf215546Sopenharmony_ci assert(svga_have_sm5(svga)); 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci if (!svga->in_streamout) 612bf215546Sopenharmony_ci return; 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(svga->so_queries); i++) { 615bf215546Sopenharmony_ci bool ret; 616bf215546Sopenharmony_ci if (streammask & (1 << i)) { 617bf215546Sopenharmony_ci ret = svga->pipe.end_query(&svga->pipe, svga->so_queries[i]); 618bf215546Sopenharmony_ci } 619bf215546Sopenharmony_ci (void) ret; 620bf215546Sopenharmony_ci } 621bf215546Sopenharmony_ci svga->in_streamout = FALSE; 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_ci return; 624bf215546Sopenharmony_ci} 625bf215546Sopenharmony_ci 626bf215546Sopenharmony_ci 627bf215546Sopenharmony_ci/** 628bf215546Sopenharmony_ci * Return the primitive count returned from the stream output statistics query 629bf215546Sopenharmony_ci * for the specified stream. 630bf215546Sopenharmony_ci */ 631bf215546Sopenharmony_ciunsigned 632bf215546Sopenharmony_cisvga_get_primcount_from_stream_output(struct svga_context *svga, 633bf215546Sopenharmony_ci unsigned stream) 634bf215546Sopenharmony_ci{ 635bf215546Sopenharmony_ci unsigned primcount = 0; 636bf215546Sopenharmony_ci union pipe_query_result result; 637bf215546Sopenharmony_ci bool ret; 638bf215546Sopenharmony_ci 639bf215546Sopenharmony_ci if (svga->current_so) { 640bf215546Sopenharmony_ci svga_end_stream_output_queries(svga, svga->current_so->streammask); 641bf215546Sopenharmony_ci } 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_ci ret = svga->pipe.get_query_result(&svga->pipe, 644bf215546Sopenharmony_ci svga->so_queries[stream], 645bf215546Sopenharmony_ci TRUE, &result); 646bf215546Sopenharmony_ci if (ret) 647bf215546Sopenharmony_ci primcount = result.so_statistics.num_primitives_written; 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci return primcount; 650bf215546Sopenharmony_ci} 651