1 /********************************************************** 2 * Copyright 2008-2009 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 "svga_cmd.h" 27 28 #include "pipe/p_state.h" 29 #include "pipe/p_defines.h" 30 #include "util/u_inlines.h" 31 #include "os/os_thread.h" 32 #include "util/u_math.h" 33 #include "util/u_memory.h" 34 #include "util/u_resource.h" 35 36 #include "svga_context.h" 37 #include "svga_screen.h" 38 #include "svga_resource_buffer.h" 39 #include "svga_resource_buffer_upload.h" 40 #include "svga_winsys.h" 41 #include "svga_debug.h" 42 43 44 /** 45 * Vertex and index buffers need hardware backing. Constant buffers 46 * do not. No other types of buffers currently supported. 47 */ 48 static inline boolean 49 svga_buffer_needs_hw_storage(unsigned usage) 50 { 51 return (usage & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER | 52 PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT)) != 0; 53 } 54 55 56 /** 57 * Create a buffer transfer. 58 * 59 * Unlike texture DMAs (which are written immediately to the command buffer and 60 * therefore inherently serialized with other context operations), for buffers 61 * we try to coalesce multiple range mappings (i.e, multiple calls to this 62 * function) into a single DMA command, for better efficiency in command 63 * processing. This means we need to exercise extra care here to ensure that 64 * the end result is exactly the same as if one DMA was used for every mapped 65 * range. 66 */ 67 static void * 68 svga_buffer_transfer_map(struct pipe_context *pipe, 69 struct pipe_resource *resource, 70 unsigned level, 71 unsigned usage, 72 const struct pipe_box *box, 73 struct pipe_transfer **ptransfer) 74 { 75 struct svga_context *svga = svga_context(pipe); 76 struct svga_screen *ss = svga_screen(pipe->screen); 77 struct svga_buffer *sbuf = svga_buffer(resource); 78 struct pipe_transfer *transfer; 79 uint8_t *map = NULL; 80 int64_t begin = svga_get_time(svga); 81 82 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERMAP); 83 84 assert(box->y == 0); 85 assert(box->z == 0); 86 assert(box->height == 1); 87 assert(box->depth == 1); 88 89 transfer = MALLOC_STRUCT(pipe_transfer); 90 if (!transfer) { 91 goto done; 92 } 93 94 transfer->resource = resource; 95 transfer->level = level; 96 transfer->usage = usage; 97 transfer->box = *box; 98 transfer->stride = 0; 99 transfer->layer_stride = 0; 100 101 if (usage & PIPE_TRANSFER_WRITE) { 102 /* If we write to the buffer for any reason, free any saved translated 103 * vertices. 104 */ 105 pipe_resource_reference(&sbuf->translated_indices.buffer, NULL); 106 } 107 108 if ((usage & PIPE_TRANSFER_READ) && sbuf->dirty) { 109 enum pipe_error ret; 110 111 /* Host-side buffers can only be dirtied with vgpu10 features 112 * (streamout and buffer copy). 113 */ 114 assert(svga_have_vgpu10(svga)); 115 116 if (!sbuf->user) { 117 (void) svga_buffer_handle(svga, resource, sbuf->bind_flags); 118 } 119 120 if (sbuf->dma.pending > 0) { 121 svga_buffer_upload_flush(svga, sbuf); 122 svga_context_finish(svga); 123 } 124 125 assert(sbuf->handle); 126 127 ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0); 128 if (ret != PIPE_OK) { 129 svga_context_flush(svga, NULL); 130 ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0); 131 assert(ret == PIPE_OK); 132 } 133 134 svga->hud.num_readbacks++; 135 136 svga_context_finish(svga); 137 138 sbuf->dirty = FALSE; 139 } 140 141 if (usage & PIPE_TRANSFER_WRITE) { 142 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 143 /* 144 * Flush any pending primitives, finish writing any pending DMA 145 * commands, and tell the host to discard the buffer contents on 146 * the next DMA operation. 147 */ 148 149 svga_hwtnl_flush_buffer(svga, resource); 150 151 if (sbuf->dma.pending) { 152 svga_buffer_upload_flush(svga, sbuf); 153 154 /* 155 * Instead of flushing the context command buffer, simply discard 156 * the current hwbuf, and start a new one. 157 * With GB objects, the map operation takes care of this 158 * if passed the PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE flag, 159 * and the old backing store is busy. 160 */ 161 162 if (!svga_have_gb_objects(svga)) 163 svga_buffer_destroy_hw_storage(ss, sbuf); 164 } 165 166 sbuf->map.num_ranges = 0; 167 sbuf->dma.flags.discard = TRUE; 168 } 169 170 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) { 171 if (!sbuf->map.num_ranges) { 172 /* 173 * No pending ranges to upload so far, so we can tell the host to 174 * not synchronize on the next DMA command. 175 */ 176 177 sbuf->dma.flags.unsynchronized = TRUE; 178 } 179 } else { 180 /* 181 * Synchronizing, so flush any pending primitives, finish writing any 182 * pending DMA command, and ensure the next DMA will be done in order. 183 */ 184 185 svga_hwtnl_flush_buffer(svga, resource); 186 187 if (sbuf->dma.pending) { 188 svga_buffer_upload_flush(svga, sbuf); 189 190 if (svga_buffer_has_hw_storage(sbuf)) { 191 /* 192 * We have a pending DMA upload from a hardware buffer, therefore 193 * we need to ensure that the host finishes processing that DMA 194 * command before the state tracker can start overwriting the 195 * hardware buffer. 196 * 197 * XXX: This could be avoided by tying the hardware buffer to 198 * the transfer (just as done with textures), which would allow 199 * overlapping DMAs commands to be queued on the same context 200 * buffer. However, due to the likelihood of software vertex 201 * processing, it is more convenient to hold on to the hardware 202 * buffer, allowing to quickly access the contents from the CPU 203 * without having to do a DMA download from the host. 204 */ 205 206 if (usage & PIPE_TRANSFER_DONTBLOCK) { 207 /* 208 * Flushing the command buffer here will most likely cause 209 * the map of the hwbuf below to block, so preemptively 210 * return NULL here if DONTBLOCK is set to prevent unnecessary 211 * command buffer flushes. 212 */ 213 214 FREE(transfer); 215 goto done; 216 } 217 218 svga_context_flush(svga, NULL); 219 } 220 } 221 222 sbuf->dma.flags.unsynchronized = FALSE; 223 } 224 } 225 226 if (!sbuf->swbuf && !svga_buffer_has_hw_storage(sbuf)) { 227 if (svga_buffer_create_hw_storage(ss, sbuf, sbuf->bind_flags) != PIPE_OK) { 228 /* 229 * We can't create a hardware buffer big enough, so create a malloc 230 * buffer instead. 231 */ 232 if (0) { 233 debug_printf("%s: failed to allocate %u KB of DMA, " 234 "splitting DMA transfers\n", 235 __FUNCTION__, 236 (sbuf->b.b.width0 + 1023)/1024); 237 } 238 239 sbuf->swbuf = align_malloc(sbuf->b.b.width0, 16); 240 if (!sbuf->swbuf) { 241 FREE(transfer); 242 goto done; 243 } 244 } 245 } 246 247 if (sbuf->swbuf) { 248 /* User/malloc buffer */ 249 map = sbuf->swbuf; 250 } 251 else if (svga_buffer_has_hw_storage(sbuf)) { 252 boolean retry; 253 254 map = svga_buffer_hw_storage_map(svga, sbuf, transfer->usage, &retry); 255 if (map == NULL && retry) { 256 /* 257 * At this point, svga_buffer_get_transfer() has already 258 * hit the DISCARD_WHOLE_RESOURCE path and flushed HWTNL 259 * for this buffer. 260 */ 261 svga_context_flush(svga, NULL); 262 map = svga_buffer_hw_storage_map(svga, sbuf, transfer->usage, &retry); 263 } 264 } 265 else { 266 map = NULL; 267 } 268 269 if (map) { 270 ++sbuf->map.count; 271 map += transfer->box.x; 272 *ptransfer = transfer; 273 } else { 274 FREE(transfer); 275 } 276 277 svga->hud.map_buffer_time += (svga_get_time(svga) - begin); 278 279 done: 280 SVGA_STATS_TIME_POP(svga_sws(svga)); 281 return map; 282 } 283 284 285 static void 286 svga_buffer_transfer_flush_region( struct pipe_context *pipe, 287 struct pipe_transfer *transfer, 288 const struct pipe_box *box) 289 { 290 struct svga_screen *ss = svga_screen(pipe->screen); 291 struct svga_buffer *sbuf = svga_buffer(transfer->resource); 292 293 unsigned offset = transfer->box.x + box->x; 294 unsigned length = box->width; 295 296 assert(transfer->usage & PIPE_TRANSFER_WRITE); 297 assert(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT); 298 299 mtx_lock(&ss->swc_mutex); 300 svga_buffer_add_range(sbuf, offset, offset + length); 301 mtx_unlock(&ss->swc_mutex); 302 } 303 304 305 static void 306 svga_buffer_transfer_unmap( struct pipe_context *pipe, 307 struct pipe_transfer *transfer ) 308 { 309 struct svga_screen *ss = svga_screen(pipe->screen); 310 struct svga_context *svga = svga_context(pipe); 311 struct svga_buffer *sbuf = svga_buffer(transfer->resource); 312 313 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERUNMAP); 314 315 mtx_lock(&ss->swc_mutex); 316 317 assert(sbuf->map.count); 318 if (sbuf->map.count) { 319 --sbuf->map.count; 320 } 321 322 if (svga_buffer_has_hw_storage(sbuf)) { 323 /* Note: we may wind up flushing here and unmapping other buffers 324 * which leads to recursively locking ss->swc_mutex. 325 */ 326 svga_buffer_hw_storage_unmap(svga, sbuf); 327 } 328 329 if (transfer->usage & PIPE_TRANSFER_WRITE) { 330 if (!(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) { 331 /* 332 * Mapped range not flushed explicitly, so flush the whole buffer, 333 * and tell the host to discard the contents when processing the DMA 334 * command. 335 */ 336 337 SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n"); 338 339 sbuf->dma.flags.discard = TRUE; 340 341 svga_buffer_add_range(sbuf, 0, sbuf->b.b.width0); 342 } 343 } 344 345 mtx_unlock(&ss->swc_mutex); 346 FREE(transfer); 347 SVGA_STATS_TIME_POP(svga_sws(svga)); 348 } 349 350 351 static void 352 svga_buffer_destroy( struct pipe_screen *screen, 353 struct pipe_resource *buf ) 354 { 355 struct svga_screen *ss = svga_screen(screen); 356 struct svga_buffer *sbuf = svga_buffer( buf ); 357 358 assert(!p_atomic_read(&buf->reference.count)); 359 360 assert(!sbuf->dma.pending); 361 362 if (sbuf->handle) 363 svga_buffer_destroy_host_surface(ss, sbuf); 364 365 if (sbuf->uploaded.buffer) 366 pipe_resource_reference(&sbuf->uploaded.buffer, NULL); 367 368 if (sbuf->hwbuf) 369 svga_buffer_destroy_hw_storage(ss, sbuf); 370 371 if (sbuf->swbuf && !sbuf->user) 372 align_free(sbuf->swbuf); 373 374 pipe_resource_reference(&sbuf->translated_indices.buffer, NULL); 375 376 ss->hud.total_resource_bytes -= sbuf->size; 377 assert(ss->hud.num_resources > 0); 378 if (ss->hud.num_resources > 0) 379 ss->hud.num_resources--; 380 381 FREE(sbuf); 382 } 383 384 385 struct u_resource_vtbl svga_buffer_vtbl = 386 { 387 u_default_resource_get_handle, /* get_handle */ 388 svga_buffer_destroy, /* resource_destroy */ 389 svga_buffer_transfer_map, /* transfer_map */ 390 svga_buffer_transfer_flush_region, /* transfer_flush_region */ 391 svga_buffer_transfer_unmap, /* transfer_unmap */ 392 }; 393 394 395 396 struct pipe_resource * 397 svga_buffer_create(struct pipe_screen *screen, 398 const struct pipe_resource *template) 399 { 400 struct svga_screen *ss = svga_screen(screen); 401 struct svga_buffer *sbuf; 402 unsigned bind_flags; 403 404 SVGA_STATS_TIME_PUSH(ss->sws, SVGA_STATS_TIME_CREATEBUFFER); 405 406 sbuf = CALLOC_STRUCT(svga_buffer); 407 if (!sbuf) 408 goto error1; 409 410 sbuf->b.b = *template; 411 sbuf->b.vtbl = &svga_buffer_vtbl; 412 pipe_reference_init(&sbuf->b.b.reference, 1); 413 sbuf->b.b.screen = screen; 414 bind_flags = template->bind; 415 416 LIST_INITHEAD(&sbuf->surfaces); 417 418 if (bind_flags & PIPE_BIND_CONSTANT_BUFFER) { 419 /* Constant buffers can only have the PIPE_BIND_CONSTANT_BUFFER 420 * flag set. 421 */ 422 if (ss->sws->have_vgpu10) { 423 bind_flags = PIPE_BIND_CONSTANT_BUFFER; 424 } 425 } 426 427 /* Although svga device only requires constant buffer size to be 428 * in multiples of 16, in order to allow bind_flags promotion, 429 * we are mandating all buffer size to be in multiples of 16. 430 */ 431 sbuf->b.b.width0 = align(sbuf->b.b.width0, 16); 432 433 if (svga_buffer_needs_hw_storage(bind_flags)) { 434 435 /* If the buffer is not used for constant buffer, set 436 * the vertex/index bind flags as well so that the buffer will be 437 * accepted for those uses. 438 * Note that the PIPE_BIND_ flags we get from the state tracker are 439 * just a hint about how the buffer may be used. And OpenGL buffer 440 * object may be used for many different things. 441 * Also note that we do not unconditionally set the streamout 442 * bind flag since streamout buffer is an output buffer and 443 * might have performance implication. 444 */ 445 if (!(template->bind & PIPE_BIND_CONSTANT_BUFFER)) { 446 /* Not a constant buffer. The buffer may be used for vertex data 447 * or indexes. 448 */ 449 bind_flags |= (PIPE_BIND_VERTEX_BUFFER | 450 PIPE_BIND_INDEX_BUFFER); 451 } 452 453 if (svga_buffer_create_host_surface(ss, sbuf, bind_flags) != PIPE_OK) 454 goto error2; 455 } 456 else { 457 sbuf->swbuf = align_malloc(sbuf->b.b.width0, 64); 458 if (!sbuf->swbuf) 459 goto error2; 460 } 461 462 debug_reference(&sbuf->b.b.reference, 463 (debug_reference_descriptor)debug_describe_resource, 0); 464 465 sbuf->bind_flags = bind_flags; 466 sbuf->size = util_resource_size(&sbuf->b.b); 467 ss->hud.total_resource_bytes += sbuf->size; 468 469 ss->hud.num_resources++; 470 SVGA_STATS_TIME_POP(ss->sws); 471 472 return &sbuf->b.b; 473 474 error2: 475 FREE(sbuf); 476 error1: 477 SVGA_STATS_TIME_POP(ss->sws); 478 return NULL; 479 } 480 481 482 struct pipe_resource * 483 svga_user_buffer_create(struct pipe_screen *screen, 484 void *ptr, 485 unsigned bytes, 486 unsigned bind) 487 { 488 struct svga_buffer *sbuf; 489 struct svga_screen *ss = svga_screen(screen); 490 491 sbuf = CALLOC_STRUCT(svga_buffer); 492 if (!sbuf) 493 goto no_sbuf; 494 495 pipe_reference_init(&sbuf->b.b.reference, 1); 496 sbuf->b.vtbl = &svga_buffer_vtbl; 497 sbuf->b.b.screen = screen; 498 sbuf->b.b.format = PIPE_FORMAT_R8_UNORM; /* ?? */ 499 sbuf->b.b.usage = PIPE_USAGE_IMMUTABLE; 500 sbuf->b.b.bind = bind; 501 sbuf->b.b.width0 = bytes; 502 sbuf->b.b.height0 = 1; 503 sbuf->b.b.depth0 = 1; 504 sbuf->b.b.array_size = 1; 505 506 sbuf->bind_flags = bind; 507 sbuf->swbuf = ptr; 508 sbuf->user = TRUE; 509 510 debug_reference(&sbuf->b.b.reference, 511 (debug_reference_descriptor)debug_describe_resource, 0); 512 513 ss->hud.num_resources++; 514 515 return &sbuf->b.b; 516 517 no_sbuf: 518 return NULL; 519 } 520 521 522 523