1bf215546Sopenharmony_ci/********************************************************** 2bf215546Sopenharmony_ci * Copyright 2008-2009 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 "svga_cmd.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "pipe/p_state.h" 29bf215546Sopenharmony_ci#include "pipe/p_defines.h" 30bf215546Sopenharmony_ci#include "util/u_inlines.h" 31bf215546Sopenharmony_ci#include "os/os_thread.h" 32bf215546Sopenharmony_ci#include "util/u_math.h" 33bf215546Sopenharmony_ci#include "util/u_memory.h" 34bf215546Sopenharmony_ci#include "util/u_resource.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "svga_context.h" 37bf215546Sopenharmony_ci#include "svga_screen.h" 38bf215546Sopenharmony_ci#include "svga_resource_buffer.h" 39bf215546Sopenharmony_ci#include "svga_resource_buffer_upload.h" 40bf215546Sopenharmony_ci#include "svga_resource_texture.h" 41bf215546Sopenharmony_ci#include "svga_sampler_view.h" 42bf215546Sopenharmony_ci#include "svga_winsys.h" 43bf215546Sopenharmony_ci#include "svga_debug.h" 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci/** 47bf215546Sopenharmony_ci * Determine what buffers eventually need hardware backing. 48bf215546Sopenharmony_ci * 49bf215546Sopenharmony_ci * Vertex- and index buffers need hardware backing. Constant buffers 50bf215546Sopenharmony_ci * do on vgpu10. Staging texture-upload buffers do when they are 51bf215546Sopenharmony_ci * supported. 52bf215546Sopenharmony_ci */ 53bf215546Sopenharmony_cistatic inline boolean 54bf215546Sopenharmony_cisvga_buffer_needs_hw_storage(const struct svga_screen *ss, 55bf215546Sopenharmony_ci const struct pipe_resource *template) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci unsigned bind_mask = (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER | 58bf215546Sopenharmony_ci PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT | 59bf215546Sopenharmony_ci PIPE_BIND_SHADER_BUFFER | PIPE_BIND_COMMAND_ARGS_BUFFER); 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci if (ss->sws->have_vgpu10) { 62bf215546Sopenharmony_ci /* 63bf215546Sopenharmony_ci * Driver-created upload const0- and staging texture upload buffers 64bf215546Sopenharmony_ci * tagged with PIPE_BIND_CUSTOM 65bf215546Sopenharmony_ci */ 66bf215546Sopenharmony_ci bind_mask |= PIPE_BIND_CUSTOM; 67bf215546Sopenharmony_ci /** 68bf215546Sopenharmony_ci * Uniform buffer objects. 69bf215546Sopenharmony_ci * Don't create hardware storage for state-tracker constant buffers, 70bf215546Sopenharmony_ci * because we frequently map them for reading and writing, and 71bf215546Sopenharmony_ci * the length of those buffers are always small, so it is better 72bf215546Sopenharmony_ci * to just use system memory. 73bf215546Sopenharmony_ci */ 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci if (template->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) 77bf215546Sopenharmony_ci return TRUE; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci return !!(template->bind & bind_mask); 80bf215546Sopenharmony_ci} 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_cistatic inline boolean 84bf215546Sopenharmony_cineed_buf_readback(struct svga_context *svga, 85bf215546Sopenharmony_ci struct pipe_transfer *st) 86bf215546Sopenharmony_ci{ 87bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(st->resource); 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci if (st->usage != PIPE_MAP_READ) 90bf215546Sopenharmony_ci return FALSE; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci /* No buffer surface has been created */ 93bf215546Sopenharmony_ci if (!sbuf->bufsurf) 94bf215546Sopenharmony_ci return FALSE; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci return ((sbuf->dirty || 97bf215546Sopenharmony_ci sbuf->bufsurf->surface_state == SVGA_SURFACE_STATE_RENDERED) && 98bf215546Sopenharmony_ci !sbuf->key.coherent && !svga->swc->force_coherent); 99bf215546Sopenharmony_ci} 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci/** 103bf215546Sopenharmony_ci * Create a buffer transfer. 104bf215546Sopenharmony_ci * 105bf215546Sopenharmony_ci * Unlike texture DMAs (which are written immediately to the command buffer and 106bf215546Sopenharmony_ci * therefore inherently serialized with other context operations), for buffers 107bf215546Sopenharmony_ci * we try to coalesce multiple range mappings (i.e, multiple calls to this 108bf215546Sopenharmony_ci * function) into a single DMA command, for better efficiency in command 109bf215546Sopenharmony_ci * processing. This means we need to exercise extra care here to ensure that 110bf215546Sopenharmony_ci * the end result is exactly the same as if one DMA was used for every mapped 111bf215546Sopenharmony_ci * range. 112bf215546Sopenharmony_ci */ 113bf215546Sopenharmony_civoid * 114bf215546Sopenharmony_cisvga_buffer_transfer_map(struct pipe_context *pipe, 115bf215546Sopenharmony_ci struct pipe_resource *resource, 116bf215546Sopenharmony_ci unsigned level, 117bf215546Sopenharmony_ci unsigned usage, 118bf215546Sopenharmony_ci const struct pipe_box *box, 119bf215546Sopenharmony_ci struct pipe_transfer **ptransfer) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci struct svga_context *svga = svga_context(pipe); 122bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(pipe->screen); 123bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(resource); 124bf215546Sopenharmony_ci struct pipe_transfer *transfer; 125bf215546Sopenharmony_ci uint8_t *map = NULL; 126bf215546Sopenharmony_ci int64_t begin = svga_get_time(svga); 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERMAP); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci assert(box->y == 0); 131bf215546Sopenharmony_ci assert(box->z == 0); 132bf215546Sopenharmony_ci assert(box->height == 1); 133bf215546Sopenharmony_ci assert(box->depth == 1); 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci transfer = MALLOC_STRUCT(pipe_transfer); 136bf215546Sopenharmony_ci if (!transfer) { 137bf215546Sopenharmony_ci goto done; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci transfer->resource = resource; 141bf215546Sopenharmony_ci transfer->level = level; 142bf215546Sopenharmony_ci transfer->usage = usage; 143bf215546Sopenharmony_ci transfer->box = *box; 144bf215546Sopenharmony_ci transfer->stride = 0; 145bf215546Sopenharmony_ci transfer->layer_stride = 0; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) { 148bf215546Sopenharmony_ci /* If we write to the buffer for any reason, free any saved translated 149bf215546Sopenharmony_ci * vertices. 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_ci pipe_resource_reference(&sbuf->translated_indices.buffer, NULL); 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci /* If it is a read transfer and the buffer is dirty or the buffer is bound 155bf215546Sopenharmony_ci * to a uav, we will need to read the subresource content from the device. 156bf215546Sopenharmony_ci */ 157bf215546Sopenharmony_ci if (need_buf_readback(svga, transfer)) { 158bf215546Sopenharmony_ci /* Host-side buffers can be dirtied with vgpu10 features 159bf215546Sopenharmony_ci * (streamout and buffer copy) and sm5 feature via uav. 160bf215546Sopenharmony_ci */ 161bf215546Sopenharmony_ci assert(svga_have_vgpu10(svga)); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci if (!sbuf->user) { 164bf215546Sopenharmony_ci (void) svga_buffer_handle(svga, resource, sbuf->bind_flags); 165bf215546Sopenharmony_ci } 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci if (sbuf->dma.pending) { 168bf215546Sopenharmony_ci svga_buffer_upload_flush(svga, sbuf); 169bf215546Sopenharmony_ci svga_context_finish(svga); 170bf215546Sopenharmony_ci } 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci assert(sbuf->handle); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci SVGA_RETRY(svga, SVGA3D_ReadbackGBSurface(svga->swc, sbuf->handle)); 175bf215546Sopenharmony_ci svga->hud.num_readbacks++; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci svga_context_finish(svga); 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci sbuf->dirty = FALSE; 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci /* Mark the buffer surface state as UPDATED */ 182bf215546Sopenharmony_ci assert(sbuf->bufsurf); 183bf215546Sopenharmony_ci sbuf->bufsurf->surface_state = SVGA_SURFACE_STATE_UPDATED; 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) { 187bf215546Sopenharmony_ci if ((usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) && 188bf215546Sopenharmony_ci !(resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)) { 189bf215546Sopenharmony_ci /* 190bf215546Sopenharmony_ci * Flush any pending primitives, finish writing any pending DMA 191bf215546Sopenharmony_ci * commands, and tell the host to discard the buffer contents on 192bf215546Sopenharmony_ci * the next DMA operation. 193bf215546Sopenharmony_ci */ 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci svga_hwtnl_flush_buffer(svga, resource); 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci if (sbuf->dma.pending) { 198bf215546Sopenharmony_ci svga_buffer_upload_flush(svga, sbuf); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci /* 201bf215546Sopenharmony_ci * Instead of flushing the context command buffer, simply discard 202bf215546Sopenharmony_ci * the current hwbuf, and start a new one. 203bf215546Sopenharmony_ci * With GB objects, the map operation takes care of this 204bf215546Sopenharmony_ci * if passed the PIPE_MAP_DISCARD_WHOLE_RESOURCE flag, 205bf215546Sopenharmony_ci * and the old backing store is busy. 206bf215546Sopenharmony_ci */ 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci if (!svga_have_gb_objects(svga)) 209bf215546Sopenharmony_ci svga_buffer_destroy_hw_storage(ss, sbuf); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci sbuf->map.num_ranges = 0; 213bf215546Sopenharmony_ci sbuf->dma.flags.discard = TRUE; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci if (usage & PIPE_MAP_UNSYNCHRONIZED) { 217bf215546Sopenharmony_ci if (!sbuf->map.num_ranges) { 218bf215546Sopenharmony_ci /* 219bf215546Sopenharmony_ci * No pending ranges to upload so far, so we can tell the host to 220bf215546Sopenharmony_ci * not synchronize on the next DMA command. 221bf215546Sopenharmony_ci */ 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci sbuf->dma.flags.unsynchronized = TRUE; 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci } else { 226bf215546Sopenharmony_ci /* 227bf215546Sopenharmony_ci * Synchronizing, so flush any pending primitives, finish writing any 228bf215546Sopenharmony_ci * pending DMA command, and ensure the next DMA will be done in order. 229bf215546Sopenharmony_ci */ 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci svga_hwtnl_flush_buffer(svga, resource); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci if (sbuf->dma.pending) { 234bf215546Sopenharmony_ci svga_buffer_upload_flush(svga, sbuf); 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci if (svga_buffer_has_hw_storage(sbuf)) { 237bf215546Sopenharmony_ci /* 238bf215546Sopenharmony_ci * We have a pending DMA upload from a hardware buffer, therefore 239bf215546Sopenharmony_ci * we need to ensure that the host finishes processing that DMA 240bf215546Sopenharmony_ci * command before the gallium frontend can start overwriting the 241bf215546Sopenharmony_ci * hardware buffer. 242bf215546Sopenharmony_ci * 243bf215546Sopenharmony_ci * XXX: This could be avoided by tying the hardware buffer to 244bf215546Sopenharmony_ci * the transfer (just as done with textures), which would allow 245bf215546Sopenharmony_ci * overlapping DMAs commands to be queued on the same context 246bf215546Sopenharmony_ci * buffer. However, due to the likelihood of software vertex 247bf215546Sopenharmony_ci * processing, it is more convenient to hold on to the hardware 248bf215546Sopenharmony_ci * buffer, allowing to quickly access the contents from the CPU 249bf215546Sopenharmony_ci * without having to do a DMA download from the host. 250bf215546Sopenharmony_ci */ 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci if (usage & PIPE_MAP_DONTBLOCK) { 253bf215546Sopenharmony_ci /* 254bf215546Sopenharmony_ci * Flushing the command buffer here will most likely cause 255bf215546Sopenharmony_ci * the map of the hwbuf below to block, so preemptively 256bf215546Sopenharmony_ci * return NULL here if DONTBLOCK is set to prevent unnecessary 257bf215546Sopenharmony_ci * command buffer flushes. 258bf215546Sopenharmony_ci */ 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci FREE(transfer); 261bf215546Sopenharmony_ci goto done; 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci svga_context_flush(svga, NULL); 265bf215546Sopenharmony_ci } 266bf215546Sopenharmony_ci } 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci sbuf->dma.flags.unsynchronized = FALSE; 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (!sbuf->swbuf && !svga_buffer_has_hw_storage(sbuf)) { 273bf215546Sopenharmony_ci if (svga_buffer_create_hw_storage(ss, sbuf, sbuf->bind_flags) != PIPE_OK) { 274bf215546Sopenharmony_ci /* 275bf215546Sopenharmony_ci * We can't create a hardware buffer big enough, so create a malloc 276bf215546Sopenharmony_ci * buffer instead. 277bf215546Sopenharmony_ci */ 278bf215546Sopenharmony_ci if (0) { 279bf215546Sopenharmony_ci debug_printf("%s: failed to allocate %u KB of DMA, " 280bf215546Sopenharmony_ci "splitting DMA transfers\n", 281bf215546Sopenharmony_ci __FUNCTION__, 282bf215546Sopenharmony_ci (sbuf->b.width0 + 1023)/1024); 283bf215546Sopenharmony_ci } 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci sbuf->swbuf = align_malloc(sbuf->b.width0, 16); 286bf215546Sopenharmony_ci if (!sbuf->swbuf) { 287bf215546Sopenharmony_ci FREE(transfer); 288bf215546Sopenharmony_ci goto done; 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci } 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci if (sbuf->swbuf) { 294bf215546Sopenharmony_ci /* User/malloc buffer */ 295bf215546Sopenharmony_ci map = sbuf->swbuf; 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci else if (svga_buffer_has_hw_storage(sbuf)) { 298bf215546Sopenharmony_ci boolean retry; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci map = SVGA_TRY_MAP(svga_buffer_hw_storage_map 301bf215546Sopenharmony_ci (svga, sbuf, transfer->usage, &retry), retry); 302bf215546Sopenharmony_ci if (map == NULL && retry) { 303bf215546Sopenharmony_ci /* 304bf215546Sopenharmony_ci * At this point, svga_buffer_get_transfer() has already 305bf215546Sopenharmony_ci * hit the DISCARD_WHOLE_RESOURCE path and flushed HWTNL 306bf215546Sopenharmony_ci * for this buffer. 307bf215546Sopenharmony_ci */ 308bf215546Sopenharmony_ci svga_retry_enter(svga); 309bf215546Sopenharmony_ci svga_context_flush(svga, NULL); 310bf215546Sopenharmony_ci map = svga_buffer_hw_storage_map(svga, sbuf, transfer->usage, &retry); 311bf215546Sopenharmony_ci svga_retry_exit(svga); 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci else { 315bf215546Sopenharmony_ci map = NULL; 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci if (map) { 319bf215546Sopenharmony_ci ++sbuf->map.count; 320bf215546Sopenharmony_ci map += transfer->box.x; 321bf215546Sopenharmony_ci *ptransfer = transfer; 322bf215546Sopenharmony_ci } else { 323bf215546Sopenharmony_ci FREE(transfer); 324bf215546Sopenharmony_ci } 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci svga->hud.map_buffer_time += (svga_get_time(svga) - begin); 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_cidone: 329bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(svga_sws(svga)); 330bf215546Sopenharmony_ci return map; 331bf215546Sopenharmony_ci} 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_civoid 335bf215546Sopenharmony_cisvga_buffer_transfer_flush_region(struct pipe_context *pipe, 336bf215546Sopenharmony_ci struct pipe_transfer *transfer, 337bf215546Sopenharmony_ci const struct pipe_box *box) 338bf215546Sopenharmony_ci{ 339bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(pipe->screen); 340bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(transfer->resource); 341bf215546Sopenharmony_ci struct svga_context *svga = svga_context(pipe); 342bf215546Sopenharmony_ci unsigned offset = transfer->box.x + box->x; 343bf215546Sopenharmony_ci unsigned length = box->width; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci assert(transfer->usage & PIPE_MAP_WRITE); 346bf215546Sopenharmony_ci assert(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT); 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci if (!(svga->swc->force_coherent || sbuf->key.coherent) || sbuf->swbuf) { 349bf215546Sopenharmony_ci mtx_lock(&ss->swc_mutex); 350bf215546Sopenharmony_ci svga_buffer_add_range(sbuf, offset, offset + length); 351bf215546Sopenharmony_ci mtx_unlock(&ss->swc_mutex); 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci} 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_civoid 357bf215546Sopenharmony_cisvga_buffer_transfer_unmap(struct pipe_context *pipe, 358bf215546Sopenharmony_ci struct pipe_transfer *transfer) 359bf215546Sopenharmony_ci{ 360bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(pipe->screen); 361bf215546Sopenharmony_ci struct svga_context *svga = svga_context(pipe); 362bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(transfer->resource); 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERUNMAP); 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci mtx_lock(&ss->swc_mutex); 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci assert(sbuf->map.count); 369bf215546Sopenharmony_ci if (sbuf->map.count) { 370bf215546Sopenharmony_ci --sbuf->map.count; 371bf215546Sopenharmony_ci } 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci if (svga_buffer_has_hw_storage(sbuf)) { 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci /* Note: we may wind up flushing here and unmapping other buffers 376bf215546Sopenharmony_ci * which leads to recursively locking ss->swc_mutex. 377bf215546Sopenharmony_ci */ 378bf215546Sopenharmony_ci svga_buffer_hw_storage_unmap(svga, sbuf); 379bf215546Sopenharmony_ci } 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE) { 382bf215546Sopenharmony_ci if (!(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT)) { 383bf215546Sopenharmony_ci /* 384bf215546Sopenharmony_ci * Mapped range not flushed explicitly, so flush the whole buffer, 385bf215546Sopenharmony_ci * and tell the host to discard the contents when processing the DMA 386bf215546Sopenharmony_ci * command. 387bf215546Sopenharmony_ci */ 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n"); 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci sbuf->dma.flags.discard = TRUE; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci if (!(svga->swc->force_coherent || sbuf->key.coherent) || sbuf->swbuf) 394bf215546Sopenharmony_ci svga_buffer_add_range(sbuf, 0, sbuf->b.width0); 395bf215546Sopenharmony_ci } 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci if (sbuf->swbuf && 398bf215546Sopenharmony_ci (!sbuf->bind_flags || (sbuf->bind_flags & PIPE_BIND_CONSTANT_BUFFER))) { 399bf215546Sopenharmony_ci /* 400bf215546Sopenharmony_ci * Since the constant buffer is in system buffer, we need 401bf215546Sopenharmony_ci * to set the constant buffer dirty bits, so that the context 402bf215546Sopenharmony_ci * can update the changes in the device. 403bf215546Sopenharmony_ci * According to the GL spec, buffer bound to other contexts will 404bf215546Sopenharmony_ci * have to be explicitly rebound by the user to have the changes take 405bf215546Sopenharmony_ci * into effect. 406bf215546Sopenharmony_ci */ 407bf215546Sopenharmony_ci svga->dirty |= SVGA_NEW_CONST_BUFFER; 408bf215546Sopenharmony_ci } 409bf215546Sopenharmony_ci } 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci mtx_unlock(&ss->swc_mutex); 412bf215546Sopenharmony_ci FREE(transfer); 413bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(svga_sws(svga)); 414bf215546Sopenharmony_ci} 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_civoid 418bf215546Sopenharmony_cisvga_resource_destroy(struct pipe_screen *screen, 419bf215546Sopenharmony_ci struct pipe_resource *buf) 420bf215546Sopenharmony_ci{ 421bf215546Sopenharmony_ci if (buf->target == PIPE_BUFFER) { 422bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(screen); 423bf215546Sopenharmony_ci struct svga_buffer *sbuf = svga_buffer(buf); 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci assert(!p_atomic_read(&buf->reference.count)); 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci assert(!sbuf->dma.pending); 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci if (sbuf->handle) 430bf215546Sopenharmony_ci svga_buffer_destroy_host_surface(ss, sbuf); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci if (sbuf->uploaded.buffer) 433bf215546Sopenharmony_ci pipe_resource_reference(&sbuf->uploaded.buffer, NULL); 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci if (sbuf->hwbuf) 436bf215546Sopenharmony_ci svga_buffer_destroy_hw_storage(ss, sbuf); 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci if (sbuf->swbuf && !sbuf->user) 439bf215546Sopenharmony_ci align_free(sbuf->swbuf); 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci pipe_resource_reference(&sbuf->translated_indices.buffer, NULL); 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci ss->hud.total_resource_bytes -= sbuf->size; 444bf215546Sopenharmony_ci assert(ss->hud.num_resources > 0); 445bf215546Sopenharmony_ci if (ss->hud.num_resources > 0) 446bf215546Sopenharmony_ci ss->hud.num_resources--; 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci FREE(sbuf); 449bf215546Sopenharmony_ci } else { 450bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(screen); 451bf215546Sopenharmony_ci struct svga_texture *tex = svga_texture(buf); 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci ss->texture_timestamp++; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci svga_sampler_view_reference(&tex->cached_view, NULL); 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci /* 458bf215546Sopenharmony_ci DBG("%s deleting %p\n", __FUNCTION__, (void *) tex); 459bf215546Sopenharmony_ci */ 460bf215546Sopenharmony_ci SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle); 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci boolean to_invalidate = svga_was_texture_rendered_to(tex); 463bf215546Sopenharmony_ci svga_screen_surface_destroy(ss, &tex->key, to_invalidate, &tex->handle); 464bf215546Sopenharmony_ci 465bf215546Sopenharmony_ci /* Destroy the backed surface handle if exists */ 466bf215546Sopenharmony_ci if (tex->backed_handle) 467bf215546Sopenharmony_ci svga_screen_surface_destroy(ss, &tex->backed_key, to_invalidate, &tex->backed_handle); 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci ss->hud.total_resource_bytes -= tex->size; 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci FREE(tex->defined); 472bf215546Sopenharmony_ci FREE(tex->rendered_to); 473bf215546Sopenharmony_ci FREE(tex->dirty); 474bf215546Sopenharmony_ci FREE(tex); 475bf215546Sopenharmony_ci 476bf215546Sopenharmony_ci assert(ss->hud.num_resources > 0); 477bf215546Sopenharmony_ci if (ss->hud.num_resources > 0) 478bf215546Sopenharmony_ci ss->hud.num_resources--; 479bf215546Sopenharmony_ci } 480bf215546Sopenharmony_ci} 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_cistruct pipe_resource * 483bf215546Sopenharmony_cisvga_buffer_create(struct pipe_screen *screen, 484bf215546Sopenharmony_ci const struct pipe_resource *template) 485bf215546Sopenharmony_ci{ 486bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(screen); 487bf215546Sopenharmony_ci struct svga_buffer *sbuf; 488bf215546Sopenharmony_ci unsigned bind_flags; 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(ss->sws, SVGA_STATS_TIME_CREATEBUFFER); 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci sbuf = CALLOC_STRUCT(svga_buffer); 493bf215546Sopenharmony_ci if (!sbuf) 494bf215546Sopenharmony_ci goto error1; 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci sbuf->b = *template; 497bf215546Sopenharmony_ci pipe_reference_init(&sbuf->b.reference, 1); 498bf215546Sopenharmony_ci sbuf->b.screen = screen; 499bf215546Sopenharmony_ci bind_flags = template->bind & ~PIPE_BIND_CUSTOM; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci list_inithead(&sbuf->surfaces); 502bf215546Sopenharmony_ci 503bf215546Sopenharmony_ci if (bind_flags & PIPE_BIND_CONSTANT_BUFFER) { 504bf215546Sopenharmony_ci /* Constant buffers can only have the PIPE_BIND_CONSTANT_BUFFER 505bf215546Sopenharmony_ci * flag set. 506bf215546Sopenharmony_ci */ 507bf215546Sopenharmony_ci if (ss->sws->have_vgpu10) { 508bf215546Sopenharmony_ci bind_flags = PIPE_BIND_CONSTANT_BUFFER; 509bf215546Sopenharmony_ci } 510bf215546Sopenharmony_ci } 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci /* Although svga device only requires constant buffer size to be 513bf215546Sopenharmony_ci * in multiples of 16, in order to allow bind_flags promotion, 514bf215546Sopenharmony_ci * we are mandating all buffer size to be in multiples of 16. 515bf215546Sopenharmony_ci */ 516bf215546Sopenharmony_ci sbuf->b.width0 = align(sbuf->b.width0, 16); 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_ci if (svga_buffer_needs_hw_storage(ss, template)) { 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci /* If the buffer is not used for constant buffer, set 521bf215546Sopenharmony_ci * the vertex/index bind flags as well so that the buffer will be 522bf215546Sopenharmony_ci * accepted for those uses. 523bf215546Sopenharmony_ci * Note that the PIPE_BIND_ flags we get from the gallium frontend are 524bf215546Sopenharmony_ci * just a hint about how the buffer may be used. And OpenGL buffer 525bf215546Sopenharmony_ci * object may be used for many different things. 526bf215546Sopenharmony_ci * Also note that we do not unconditionally set the streamout 527bf215546Sopenharmony_ci * bind flag since streamout buffer is an output buffer and 528bf215546Sopenharmony_ci * might have performance implication. 529bf215546Sopenharmony_ci */ 530bf215546Sopenharmony_ci if (!(template->bind & PIPE_BIND_CONSTANT_BUFFER) && 531bf215546Sopenharmony_ci !(template->bind & PIPE_BIND_CUSTOM)) { 532bf215546Sopenharmony_ci /* Not a constant- or staging buffer. 533bf215546Sopenharmony_ci * The buffer may be used for vertex data or indexes. 534bf215546Sopenharmony_ci */ 535bf215546Sopenharmony_ci bind_flags |= (PIPE_BIND_VERTEX_BUFFER | 536bf215546Sopenharmony_ci PIPE_BIND_INDEX_BUFFER); 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci /* It may be used for shader resource as well. */ 539bf215546Sopenharmony_ci bind_flags |= PIPE_BIND_SAMPLER_VIEW; 540bf215546Sopenharmony_ci } 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci if (svga_buffer_create_host_surface(ss, sbuf, bind_flags) != PIPE_OK) 543bf215546Sopenharmony_ci goto error2; 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci else { 546bf215546Sopenharmony_ci sbuf->swbuf = align_malloc(sbuf->b.width0, 64); 547bf215546Sopenharmony_ci if (!sbuf->swbuf) 548bf215546Sopenharmony_ci goto error2; 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci /* Since constant buffer is usually small, it is much cheaper to 551bf215546Sopenharmony_ci * use system memory for the data just as it is being done for 552bf215546Sopenharmony_ci * the default constant buffer. 553bf215546Sopenharmony_ci */ 554bf215546Sopenharmony_ci if ((bind_flags & PIPE_BIND_CONSTANT_BUFFER) || !bind_flags) 555bf215546Sopenharmony_ci sbuf->use_swbuf = TRUE; 556bf215546Sopenharmony_ci } 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci debug_reference(&sbuf->b.reference, 559bf215546Sopenharmony_ci (debug_reference_descriptor)debug_describe_resource, 0); 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci sbuf->bind_flags = bind_flags; 562bf215546Sopenharmony_ci sbuf->size = util_resource_size(&sbuf->b); 563bf215546Sopenharmony_ci ss->hud.total_resource_bytes += sbuf->size; 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci ss->hud.num_resources++; 566bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(ss->sws); 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci return &sbuf->b; 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_cierror2: 571bf215546Sopenharmony_ci FREE(sbuf); 572bf215546Sopenharmony_cierror1: 573bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(ss->sws); 574bf215546Sopenharmony_ci return NULL; 575bf215546Sopenharmony_ci} 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_cistruct pipe_resource * 579bf215546Sopenharmony_cisvga_user_buffer_create(struct pipe_screen *screen, 580bf215546Sopenharmony_ci void *ptr, 581bf215546Sopenharmony_ci unsigned bytes, 582bf215546Sopenharmony_ci unsigned bind) 583bf215546Sopenharmony_ci{ 584bf215546Sopenharmony_ci struct svga_buffer *sbuf; 585bf215546Sopenharmony_ci struct svga_screen *ss = svga_screen(screen); 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci sbuf = CALLOC_STRUCT(svga_buffer); 588bf215546Sopenharmony_ci if (!sbuf) 589bf215546Sopenharmony_ci goto no_sbuf; 590bf215546Sopenharmony_ci 591bf215546Sopenharmony_ci pipe_reference_init(&sbuf->b.reference, 1); 592bf215546Sopenharmony_ci sbuf->b.screen = screen; 593bf215546Sopenharmony_ci sbuf->b.format = PIPE_FORMAT_R8_UNORM; /* ?? */ 594bf215546Sopenharmony_ci sbuf->b.usage = PIPE_USAGE_IMMUTABLE; 595bf215546Sopenharmony_ci sbuf->b.bind = bind; 596bf215546Sopenharmony_ci sbuf->b.width0 = bytes; 597bf215546Sopenharmony_ci sbuf->b.height0 = 1; 598bf215546Sopenharmony_ci sbuf->b.depth0 = 1; 599bf215546Sopenharmony_ci sbuf->b.array_size = 1; 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci sbuf->bind_flags = bind; 602bf215546Sopenharmony_ci sbuf->swbuf = ptr; 603bf215546Sopenharmony_ci sbuf->user = TRUE; 604bf215546Sopenharmony_ci 605bf215546Sopenharmony_ci debug_reference(&sbuf->b.reference, 606bf215546Sopenharmony_ci (debug_reference_descriptor)debug_describe_resource, 0); 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci ss->hud.num_resources++; 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci return &sbuf->b; 611bf215546Sopenharmony_ci 612bf215546Sopenharmony_cino_sbuf: 613bf215546Sopenharmony_ci return NULL; 614bf215546Sopenharmony_ci} 615