1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3bf215546Sopenharmony_ci * Copyright 2015 Patrick Rudolph <siro@das-labor.org> 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 9bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 10bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "buffer9.h" 25bf215546Sopenharmony_ci#include "device9.h" 26bf215546Sopenharmony_ci#include "indexbuffer9.h" 27bf215546Sopenharmony_ci#include "nine_buffer_upload.h" 28bf215546Sopenharmony_ci#include "nine_helpers.h" 29bf215546Sopenharmony_ci#include "nine_pipe.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "pipe/p_screen.h" 32bf215546Sopenharmony_ci#include "pipe/p_context.h" 33bf215546Sopenharmony_ci#include "pipe/p_state.h" 34bf215546Sopenharmony_ci#include "pipe/p_defines.h" 35bf215546Sopenharmony_ci#include "pipe/p_format.h" 36bf215546Sopenharmony_ci#include "util/u_box.h" 37bf215546Sopenharmony_ci#include "util/u_inlines.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER) 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ciHRESULT 42bf215546Sopenharmony_ciNineBuffer9_ctor( struct NineBuffer9 *This, 43bf215546Sopenharmony_ci struct NineUnknownParams *pParams, 44bf215546Sopenharmony_ci D3DRESOURCETYPE Type, 45bf215546Sopenharmony_ci DWORD Usage, 46bf215546Sopenharmony_ci UINT Size, 47bf215546Sopenharmony_ci D3DPOOL Pool ) 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_ci struct pipe_resource *info = &This->base.info; 50bf215546Sopenharmony_ci HRESULT hr; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci DBG("This=%p Size=0x%x Usage=%x Pool=%u\n", This, Size, Usage, Pool); 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci user_assert(Pool != D3DPOOL_SCRATCH, D3DERR_INVALIDCALL); 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci This->maps = MALLOC(sizeof(struct NineTransfer)); 57bf215546Sopenharmony_ci if (!This->maps) 58bf215546Sopenharmony_ci return E_OUTOFMEMORY; 59bf215546Sopenharmony_ci This->nlocks = 0; 60bf215546Sopenharmony_ci This->nmaps = 0; 61bf215546Sopenharmony_ci This->maxmaps = 1; 62bf215546Sopenharmony_ci This->size = Size; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci info->screen = pParams->device->screen; 65bf215546Sopenharmony_ci info->target = PIPE_BUFFER; 66bf215546Sopenharmony_ci info->format = PIPE_FORMAT_R8_UNORM; 67bf215546Sopenharmony_ci info->width0 = Size; 68bf215546Sopenharmony_ci info->flags = 0; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci /* Note: WRITEONLY is just tip for resource placement, the resource 71bf215546Sopenharmony_ci * can still be read (but slower). */ 72bf215546Sopenharmony_ci info->bind = (Type == D3DRTYPE_INDEXBUFFER) ? PIPE_BIND_INDEX_BUFFER : PIPE_BIND_VERTEX_BUFFER; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci /* Software vertex processing: 75bf215546Sopenharmony_ci * If the device is full software vertex processing, 76bf215546Sopenharmony_ci * then the buffer is supposed to be used only for sw processing. 77bf215546Sopenharmony_ci * For mixed vertex processing, buffers with D3DUSAGE_SOFTWAREPROCESSING 78bf215546Sopenharmony_ci * can be used for both sw and hw processing. 79bf215546Sopenharmony_ci * These buffers are expected to be stored in RAM. 80bf215546Sopenharmony_ci * Apps expect locking the full buffer with no flags, then 81bf215546Sopenharmony_ci * render a a few primitive, then locking again, etc 82bf215546Sopenharmony_ci * to be a fast pattern. Only the SYSTEMMEM DYNAMIC path 83bf215546Sopenharmony_ci * will give that pattern ok performance in our case. 84bf215546Sopenharmony_ci * An alternative would be when sw processing is detected to 85bf215546Sopenharmony_ci * convert Draw* calls to Draw*Up calls. */ 86bf215546Sopenharmony_ci if (Usage & D3DUSAGE_SOFTWAREPROCESSING || 87bf215546Sopenharmony_ci pParams->device->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) { 88bf215546Sopenharmony_ci Pool = D3DPOOL_SYSTEMMEM; 89bf215546Sopenharmony_ci Usage |= D3DUSAGE_DYNAMIC; 90bf215546Sopenharmony_ci /* Note: the application cannot retrieve Pool and Usage */ 91bf215546Sopenharmony_ci } 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci /* Always use the DYNAMIC path for SYSTEMMEM. 94bf215546Sopenharmony_ci * If the app uses the vertex buffer is a dynamic fashion, 95bf215546Sopenharmony_ci * this is going to be very significantly faster that way. 96bf215546Sopenharmony_ci * If the app uses the vertex buffer in a static fashion, 97bf215546Sopenharmony_ci * instead of being filled all at once, the buffer will be filled 98bf215546Sopenharmony_ci * little per little, until it is fully filled, thus the perf hit 99bf215546Sopenharmony_ci * will be very small. */ 100bf215546Sopenharmony_ci if (Pool == D3DPOOL_SYSTEMMEM) 101bf215546Sopenharmony_ci Usage |= D3DUSAGE_DYNAMIC; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci /* It is hard to find clear information on where to place the buffer in 104bf215546Sopenharmony_ci * memory depending on the flag. 105bf215546Sopenharmony_ci * MSDN: resources are static, except for those with DYNAMIC, thus why you 106bf215546Sopenharmony_ci * can only use DISCARD on them. 107bf215546Sopenharmony_ci * ATI doc: The driver has the liberty it wants for having things static 108bf215546Sopenharmony_ci * or not. 109bf215546Sopenharmony_ci * MANAGED: Ram + uploads to Vram copy at unlock (msdn and nvidia doc say 110bf215546Sopenharmony_ci * at first draw call using the buffer) 111bf215546Sopenharmony_ci * DEFAULT + Usage = 0 => System memory backing for easy read access 112bf215546Sopenharmony_ci * (That doc is very unclear on the details, like whether some copies to 113bf215546Sopenharmony_ci * vram copy are involved or not). 114bf215546Sopenharmony_ci * DEFAULT + WRITEONLY => Vram 115bf215546Sopenharmony_ci * DEFAULT + WRITEONLY + DYNAMIC => Either Vram buffer or GTT_WC, depending on what the driver wants. 116bf215546Sopenharmony_ci * SYSTEMMEM: Same as MANAGED, but handled by the driver instead of the runtime (which means 117bf215546Sopenharmony_ci * some small behavior differences between vendors). Implementing exactly as MANAGED should 118bf215546Sopenharmony_ci * be fine. 119bf215546Sopenharmony_ci */ 120bf215546Sopenharmony_ci if (Pool == D3DPOOL_SYSTEMMEM && Usage & D3DUSAGE_DYNAMIC) 121bf215546Sopenharmony_ci info->usage = PIPE_USAGE_STREAM; 122bf215546Sopenharmony_ci else if (Pool != D3DPOOL_DEFAULT) 123bf215546Sopenharmony_ci info->usage = PIPE_USAGE_DEFAULT; 124bf215546Sopenharmony_ci else if (Usage & D3DUSAGE_DYNAMIC && Usage & D3DUSAGE_WRITEONLY) 125bf215546Sopenharmony_ci info->usage = PIPE_USAGE_STREAM; 126bf215546Sopenharmony_ci else if (Usage & D3DUSAGE_WRITEONLY) 127bf215546Sopenharmony_ci info->usage = PIPE_USAGE_DEFAULT; 128bf215546Sopenharmony_ci /* For the remaining two, PIPE_USAGE_STAGING would probably be 129bf215546Sopenharmony_ci * a good fit according to the doc. However it seems rather a mistake 130bf215546Sopenharmony_ci * from apps to use these (mistakes that do really happen). Try 131bf215546Sopenharmony_ci * to put the flags that are the best compromise between the real 132bf215546Sopenharmony_ci * behaviour and what buggy apps should get for better performance. */ 133bf215546Sopenharmony_ci else if (Usage & D3DUSAGE_DYNAMIC) 134bf215546Sopenharmony_ci info->usage = PIPE_USAGE_STREAM; 135bf215546Sopenharmony_ci else 136bf215546Sopenharmony_ci info->usage = PIPE_USAGE_DYNAMIC; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci /* When Writeonly is not set, we don't want to enable the 139bf215546Sopenharmony_ci * optimizations */ 140bf215546Sopenharmony_ci This->discard_nooverwrite_only = !!(Usage & D3DUSAGE_WRITEONLY) && 141bf215546Sopenharmony_ci pParams->device->buffer_upload; 142bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_DONOTCLIP) { } */ 143bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_NONSECURE) { } */ 144bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_NPATCHES) { } */ 145bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_POINTS) { } */ 146bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_RTPATCHES) { } */ 147bf215546Sopenharmony_ci /* if (pDesc->Usage & D3DUSAGE_TEXTAPI) { } */ 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci info->height0 = 1; 150bf215546Sopenharmony_ci info->depth0 = 1; 151bf215546Sopenharmony_ci info->array_size = 1; 152bf215546Sopenharmony_ci info->last_level = 0; 153bf215546Sopenharmony_ci info->nr_samples = 0; 154bf215546Sopenharmony_ci info->nr_storage_samples = 0; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci hr = NineResource9_ctor(&This->base, pParams, NULL, TRUE, 157bf215546Sopenharmony_ci Type, Pool, Usage); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci if (FAILED(hr)) 160bf215546Sopenharmony_ci return hr; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci if (Pool != D3DPOOL_DEFAULT) { 163bf215546Sopenharmony_ci This->managed.data = align_calloc( 164bf215546Sopenharmony_ci nine_format_get_level_alloc_size(This->base.info.format, 165bf215546Sopenharmony_ci Size, 1, 0), 32); 166bf215546Sopenharmony_ci if (!This->managed.data) 167bf215546Sopenharmony_ci return E_OUTOFMEMORY; 168bf215546Sopenharmony_ci This->managed.dirty = TRUE; 169bf215546Sopenharmony_ci u_box_1d(0, Size, &This->managed.dirty_box); 170bf215546Sopenharmony_ci u_box_1d(0, 0, &This->managed.valid_region); 171bf215546Sopenharmony_ci u_box_1d(0, 0, &This->managed.required_valid_region); 172bf215546Sopenharmony_ci u_box_1d(0, 0, &This->managed.filled_region); 173bf215546Sopenharmony_ci This->managed.can_unsynchronized = true; 174bf215546Sopenharmony_ci This->managed.num_worker_thread_syncs = 0; 175bf215546Sopenharmony_ci list_inithead(&This->managed.list); 176bf215546Sopenharmony_ci list_inithead(&This->managed.list2); 177bf215546Sopenharmony_ci list_add(&This->managed.list2, &pParams->device->managed_buffers); 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci return D3D_OK; 181bf215546Sopenharmony_ci} 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_civoid 184bf215546Sopenharmony_ciNineBuffer9_dtor( struct NineBuffer9 *This ) 185bf215546Sopenharmony_ci{ 186bf215546Sopenharmony_ci DBG("This=%p\n", This); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (This->maps) { 189bf215546Sopenharmony_ci while (This->nlocks) { 190bf215546Sopenharmony_ci NineBuffer9_Unlock(This); 191bf215546Sopenharmony_ci } 192bf215546Sopenharmony_ci assert(!This->nmaps); 193bf215546Sopenharmony_ci FREE(This->maps); 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (This->base.pool != D3DPOOL_DEFAULT) { 197bf215546Sopenharmony_ci if (This->managed.data) 198bf215546Sopenharmony_ci align_free(This->managed.data); 199bf215546Sopenharmony_ci if (list_is_linked(&This->managed.list)) 200bf215546Sopenharmony_ci list_del(&This->managed.list); 201bf215546Sopenharmony_ci if (list_is_linked(&This->managed.list2)) 202bf215546Sopenharmony_ci list_del(&This->managed.list2); 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (This->buf) 206bf215546Sopenharmony_ci nine_upload_release_buffer(This->base.base.device->buffer_upload, This->buf); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci NineResource9_dtor(&This->base); 209bf215546Sopenharmony_ci} 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_cistruct pipe_resource * 212bf215546Sopenharmony_ciNineBuffer9_GetResource( struct NineBuffer9 *This, unsigned *offset ) 213bf215546Sopenharmony_ci{ 214bf215546Sopenharmony_ci if (This->buf) 215bf215546Sopenharmony_ci return nine_upload_buffer_resource_and_offset(This->buf, offset); 216bf215546Sopenharmony_ci *offset = 0; 217bf215546Sopenharmony_ci return NineResource9_GetResource(&This->base); 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_cistatic void 221bf215546Sopenharmony_ciNineBuffer9_RebindIfRequired( struct NineBuffer9 *This, 222bf215546Sopenharmony_ci struct NineDevice9 *device, 223bf215546Sopenharmony_ci struct pipe_resource *resource, 224bf215546Sopenharmony_ci unsigned offset ) 225bf215546Sopenharmony_ci{ 226bf215546Sopenharmony_ci int i; 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci if (!This->bind_count) 229bf215546Sopenharmony_ci return; 230bf215546Sopenharmony_ci for (i = 0; i < device->caps.MaxStreams; i++) { 231bf215546Sopenharmony_ci if (device->state.stream[i] == (struct NineVertexBuffer9 *)This) 232bf215546Sopenharmony_ci nine_context_set_stream_source_apply(device, i, 233bf215546Sopenharmony_ci resource, 234bf215546Sopenharmony_ci device->state.vtxbuf[i].buffer_offset + offset, 235bf215546Sopenharmony_ci device->state.vtxbuf[i].stride); 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci if (device->state.idxbuf == (struct NineIndexBuffer9 *)This) 238bf215546Sopenharmony_ci nine_context_set_indices_apply(device, resource, 239bf215546Sopenharmony_ci ((struct NineIndexBuffer9 *)This)->index_size, 240bf215546Sopenharmony_ci offset); 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ciHRESULT NINE_WINAPI 244bf215546Sopenharmony_ciNineBuffer9_Lock( struct NineBuffer9 *This, 245bf215546Sopenharmony_ci UINT OffsetToLock, 246bf215546Sopenharmony_ci UINT SizeToLock, 247bf215546Sopenharmony_ci void **ppbData, 248bf215546Sopenharmony_ci DWORD Flags ) 249bf215546Sopenharmony_ci{ 250bf215546Sopenharmony_ci struct NineDevice9 *device = This->base.base.device; 251bf215546Sopenharmony_ci struct pipe_box box; 252bf215546Sopenharmony_ci struct pipe_context *pipe; 253bf215546Sopenharmony_ci void *data; 254bf215546Sopenharmony_ci unsigned usage; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci DBG("This=%p(pipe=%p) OffsetToLock=0x%x, SizeToLock=0x%x, Flags=0x%x\n", 257bf215546Sopenharmony_ci This, This->base.resource, 258bf215546Sopenharmony_ci OffsetToLock, SizeToLock, Flags); 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci user_assert(ppbData, E_POINTER); 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci if (SizeToLock == 0) { 263bf215546Sopenharmony_ci SizeToLock = This->size - OffsetToLock; 264bf215546Sopenharmony_ci user_warn(OffsetToLock != 0); 265bf215546Sopenharmony_ci } 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci /* Write out of bound seems to have to be taken into account for these. 268bf215546Sopenharmony_ci * TODO: Do more tests (is it only at buffer first lock ? etc). 269bf215546Sopenharmony_ci * Since these buffers are supposed to be locked once and never 270bf215546Sopenharmony_ci * writen again (MANAGED or DYNAMIC is used for the other uses cases), 271bf215546Sopenharmony_ci * performance should be unaffected. */ 272bf215546Sopenharmony_ci if (!(This->base.usage & D3DUSAGE_DYNAMIC) && This->base.pool == D3DPOOL_DEFAULT) 273bf215546Sopenharmony_ci SizeToLock = This->size - OffsetToLock; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci SizeToLock = MIN2(SizeToLock, This->size - OffsetToLock); /* Do not read or track out of the buffer */ 276bf215546Sopenharmony_ci u_box_1d(OffsetToLock, SizeToLock, &box); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci if (This->base.pool != D3DPOOL_DEFAULT) { 279bf215546Sopenharmony_ci /* MANAGED: READONLY doesn't dirty the buffer, nor 280bf215546Sopenharmony_ci * wait the upload in the worker thread 281bf215546Sopenharmony_ci * SYSTEMMEM: AMD/NVidia: All locks dirty the full buffer. Not on Intel 282bf215546Sopenharmony_ci * For Nvidia, SYSTEMMEM behaves are if there is no worker thread. 283bf215546Sopenharmony_ci * On AMD, READONLY and NOOVERWRITE do dirty the buffer, but do not sync the previous uploads 284bf215546Sopenharmony_ci * in the worker thread. On Intel only NOOVERWRITE has that effect. 285bf215546Sopenharmony_ci * We implement the AMD behaviour. */ 286bf215546Sopenharmony_ci if (This->base.pool == D3DPOOL_MANAGED) { 287bf215546Sopenharmony_ci if (!(Flags & D3DLOCK_READONLY)) { 288bf215546Sopenharmony_ci if (!This->managed.dirty) { 289bf215546Sopenharmony_ci assert(list_is_empty(&This->managed.list)); 290bf215546Sopenharmony_ci This->managed.dirty = TRUE; 291bf215546Sopenharmony_ci This->managed.dirty_box = box; 292bf215546Sopenharmony_ci /* Flush if regions pending to be uploaded would be dirtied */ 293bf215546Sopenharmony_ci if (p_atomic_read(&This->managed.pending_upload)) { 294bf215546Sopenharmony_ci u_box_intersect_1d(&box, &box, &This->managed.upload_pending_regions); 295bf215546Sopenharmony_ci if (box.width != 0) 296bf215546Sopenharmony_ci nine_csmt_process(This->base.base.device); 297bf215546Sopenharmony_ci } 298bf215546Sopenharmony_ci } else 299bf215546Sopenharmony_ci u_box_union_1d(&This->managed.dirty_box, &This->managed.dirty_box, &box); 300bf215546Sopenharmony_ci /* Tests trying to draw while the buffer is locked show that 301bf215546Sopenharmony_ci * SYSTEMMEM/MANAGED buffers are made dirty at Lock time */ 302bf215546Sopenharmony_ci BASEBUF_REGISTER_UPDATE(This); 303bf215546Sopenharmony_ci } 304bf215546Sopenharmony_ci } else { 305bf215546Sopenharmony_ci if (!(Flags & (D3DLOCK_READONLY|D3DLOCK_NOOVERWRITE)) && 306bf215546Sopenharmony_ci p_atomic_read(&This->managed.pending_upload)) { 307bf215546Sopenharmony_ci This->managed.num_worker_thread_syncs++; 308bf215546Sopenharmony_ci /* If we sync too often, pick the vertex_uploader path */ 309bf215546Sopenharmony_ci if (This->managed.num_worker_thread_syncs >= 3) 310bf215546Sopenharmony_ci This->managed.can_unsynchronized = false; 311bf215546Sopenharmony_ci nine_csmt_process(This->base.base.device); 312bf215546Sopenharmony_ci /* Note: AS DISCARD is not relevant for SYSTEMMEM, 313bf215546Sopenharmony_ci * NOOVERWRITE might have a similar meaning as what is 314bf215546Sopenharmony_ci * in D3D7 doc. Basically that data from previous draws 315bf215546Sopenharmony_ci * OF THIS FRAME are unaffected. As we flush csmt in Present(), 316bf215546Sopenharmony_ci * we should be correct. In some parts of the doc, the notion 317bf215546Sopenharmony_ci * of frame is implied to be related to Begin/EndScene(), 318bf215546Sopenharmony_ci * but tests show NOOVERWRITE after EndScene() doesn't flush 319bf215546Sopenharmony_ci * the csmt thread. */ 320bf215546Sopenharmony_ci } 321bf215546Sopenharmony_ci This->managed.dirty = true; 322bf215546Sopenharmony_ci u_box_1d(0, This->size, &This->managed.dirty_box); /* systemmem non-dynamic */ 323bf215546Sopenharmony_ci u_box_1d(0, 0, &This->managed.valid_region); /* systemmem dynamic */ 324bf215546Sopenharmony_ci BASEBUF_REGISTER_UPDATE(This); 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci *ppbData = (int8_t *)This->managed.data + OffsetToLock; 328bf215546Sopenharmony_ci DBG("returning pointer %p\n", *ppbData); 329bf215546Sopenharmony_ci This->nlocks++; 330bf215546Sopenharmony_ci return D3D_OK; 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci /* Driver ddi doc: READONLY is never passed to the device. So it can only 334bf215546Sopenharmony_ci * have effect on things handled by the driver (MANAGED pool for example). 335bf215546Sopenharmony_ci * Msdn doc: DISCARD and NOOVERWRITE are only for DYNAMIC. 336bf215546Sopenharmony_ci * ATI doc: You can use DISCARD and NOOVERWRITE without DYNAMIC. 337bf215546Sopenharmony_ci * Msdn doc: D3DLOCK_DONOTWAIT is not among the valid flags for buffers. 338bf215546Sopenharmony_ci * Our tests: On win 7 nvidia, D3DLOCK_DONOTWAIT does return 339bf215546Sopenharmony_ci * D3DERR_WASSTILLDRAWING if the resource is in use, except for DYNAMIC. 340bf215546Sopenharmony_ci * Our tests: some apps do use both DISCARD and NOOVERWRITE at the same 341bf215546Sopenharmony_ci * time. On windows it seems to return different pointer in some conditions, 342bf215546Sopenharmony_ci * creation flags and drivers. However these tests indicate having 343bf215546Sopenharmony_ci * NOOVERWRITE win is a valid behaviour (NVidia). 344bf215546Sopenharmony_ci */ 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci /* Have NOOVERWRITE win over DISCARD. This is allowed (see above) and 347bf215546Sopenharmony_ci * it prevents overconsuming buffers if apps do use both at the same time. */ 348bf215546Sopenharmony_ci if ((Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) 349bf215546Sopenharmony_ci Flags &= ~D3DLOCK_DISCARD; 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci if (Flags & D3DLOCK_DISCARD) 352bf215546Sopenharmony_ci usage = PIPE_MAP_WRITE | PIPE_MAP_DISCARD_WHOLE_RESOURCE; 353bf215546Sopenharmony_ci else if (Flags & D3DLOCK_NOOVERWRITE) 354bf215546Sopenharmony_ci usage = PIPE_MAP_WRITE | PIPE_MAP_UNSYNCHRONIZED; 355bf215546Sopenharmony_ci else 356bf215546Sopenharmony_ci /* Do not ask for READ if writeonly and default pool (should be safe enough, 357bf215546Sopenharmony_ci * as the doc says app shouldn't expect reading to work with writeonly). */ 358bf215546Sopenharmony_ci usage = (This->base.usage & D3DUSAGE_WRITEONLY) ? 359bf215546Sopenharmony_ci PIPE_MAP_WRITE : 360bf215546Sopenharmony_ci PIPE_MAP_READ_WRITE; 361bf215546Sopenharmony_ci if (Flags & D3DLOCK_DONOTWAIT && !(This->base.usage & D3DUSAGE_DYNAMIC)) 362bf215546Sopenharmony_ci usage |= PIPE_MAP_DONTBLOCK; 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci This->discard_nooverwrite_only &= !!(Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)); 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci if (This->nmaps == This->maxmaps) { 367bf215546Sopenharmony_ci struct NineTransfer *newmaps = 368bf215546Sopenharmony_ci REALLOC(This->maps, sizeof(struct NineTransfer)*This->maxmaps, 369bf215546Sopenharmony_ci sizeof(struct NineTransfer)*(This->maxmaps << 1)); 370bf215546Sopenharmony_ci if (newmaps == NULL) 371bf215546Sopenharmony_ci return E_OUTOFMEMORY; 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci This->maxmaps <<= 1; 374bf215546Sopenharmony_ci This->maps = newmaps; 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci if (This->buf && !This->discard_nooverwrite_only) { 378bf215546Sopenharmony_ci struct pipe_box src_box; 379bf215546Sopenharmony_ci unsigned offset; 380bf215546Sopenharmony_ci struct pipe_resource *src_res; 381bf215546Sopenharmony_ci DBG("Disabling nine_subbuffer for a buffer having" 382bf215546Sopenharmony_ci "used a nine_subbuffer buffer\n"); 383bf215546Sopenharmony_ci /* Copy buffer content to the buffer resource, which 384bf215546Sopenharmony_ci * we will now use. 385bf215546Sopenharmony_ci * Note: The behaviour may be different from what is expected 386bf215546Sopenharmony_ci * with double lock. However applications can't really make expectations 387bf215546Sopenharmony_ci * about double locks, and don't really use them, so that's ok. */ 388bf215546Sopenharmony_ci src_res = nine_upload_buffer_resource_and_offset(This->buf, &offset); 389bf215546Sopenharmony_ci u_box_1d(offset, This->size, &src_box); 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci pipe = NineDevice9_GetPipe(device); 392bf215546Sopenharmony_ci pipe->resource_copy_region(pipe, This->base.resource, 0, 0, 0, 0, 393bf215546Sopenharmony_ci src_res, 0, &src_box); 394bf215546Sopenharmony_ci /* Release previous resource */ 395bf215546Sopenharmony_ci if (This->nmaps >= 1) 396bf215546Sopenharmony_ci This->maps[This->nmaps-1].should_destroy_buf = true; 397bf215546Sopenharmony_ci else 398bf215546Sopenharmony_ci nine_upload_release_buffer(device->buffer_upload, This->buf); 399bf215546Sopenharmony_ci This->buf = NULL; 400bf215546Sopenharmony_ci /* Rebind buffer */ 401bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci This->maps[This->nmaps].transfer = NULL; 405bf215546Sopenharmony_ci This->maps[This->nmaps].is_pipe_secondary = false; 406bf215546Sopenharmony_ci This->maps[This->nmaps].buf = NULL; 407bf215546Sopenharmony_ci This->maps[This->nmaps].should_destroy_buf = false; 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci if (This->discard_nooverwrite_only) { 410bf215546Sopenharmony_ci if (This->buf && (Flags & D3DLOCK_DISCARD)) { 411bf215546Sopenharmony_ci /* Release previous buffer */ 412bf215546Sopenharmony_ci if (This->nmaps >= 1) 413bf215546Sopenharmony_ci This->maps[This->nmaps-1].should_destroy_buf = true; 414bf215546Sopenharmony_ci else 415bf215546Sopenharmony_ci nine_upload_release_buffer(device->buffer_upload, This->buf); 416bf215546Sopenharmony_ci This->buf = NULL; 417bf215546Sopenharmony_ci } 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci if (!This->buf) { 420bf215546Sopenharmony_ci unsigned offset; 421bf215546Sopenharmony_ci struct pipe_resource *res; 422bf215546Sopenharmony_ci This->buf = nine_upload_create_buffer(device->buffer_upload, This->base.info.width0); 423bf215546Sopenharmony_ci res = nine_upload_buffer_resource_and_offset(This->buf, &offset); 424bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, res, offset); 425bf215546Sopenharmony_ci } 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci if (This->buf) { 428bf215546Sopenharmony_ci This->maps[This->nmaps].buf = This->buf; 429bf215546Sopenharmony_ci This->nmaps++; 430bf215546Sopenharmony_ci This->nlocks++; 431bf215546Sopenharmony_ci DBG("Returning %p\n", nine_upload_buffer_get_map(This->buf) + OffsetToLock); 432bf215546Sopenharmony_ci *ppbData = nine_upload_buffer_get_map(This->buf) + OffsetToLock; 433bf215546Sopenharmony_ci return D3D_OK; 434bf215546Sopenharmony_ci } else { 435bf215546Sopenharmony_ci /* Fallback to normal path, and don't try again */ 436bf215546Sopenharmony_ci This->discard_nooverwrite_only = false; 437bf215546Sopenharmony_ci } 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci /* Previous mappings may need pending commands to write to the 441bf215546Sopenharmony_ci * buffer (staging buffer for example). Before a NOOVERWRITE, 442bf215546Sopenharmony_ci * we thus need a finish, to guarantee any upload is finished. 443bf215546Sopenharmony_ci * Note for discard_nooverwrite_only we don't need to do this 444bf215546Sopenharmony_ci * check as neither discard nor nooverwrite have issues there */ 445bf215546Sopenharmony_ci if (This->need_sync_if_nooverwrite && !(Flags & D3DLOCK_DISCARD) && 446bf215546Sopenharmony_ci (Flags & D3DLOCK_NOOVERWRITE)) { 447bf215546Sopenharmony_ci struct pipe_screen *screen = NineDevice9_GetScreen(device); 448bf215546Sopenharmony_ci struct pipe_fence_handle *fence = NULL; 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci pipe = NineDevice9_GetPipe(device); 451bf215546Sopenharmony_ci pipe->flush(pipe, &fence, 0); 452bf215546Sopenharmony_ci (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 453bf215546Sopenharmony_ci screen->fence_reference(screen, &fence, NULL); 454bf215546Sopenharmony_ci } 455bf215546Sopenharmony_ci This->need_sync_if_nooverwrite = !(Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)); 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci /* When csmt is active, we want to avoid stalls as much as possible, 458bf215546Sopenharmony_ci * and thus we want to create a new resource on discard and map it 459bf215546Sopenharmony_ci * with the secondary pipe, instead of waiting on the main pipe. */ 460bf215546Sopenharmony_ci if (Flags & D3DLOCK_DISCARD && device->csmt_active) { 461bf215546Sopenharmony_ci struct pipe_screen *screen = NineDevice9_GetScreen(device); 462bf215546Sopenharmony_ci struct pipe_resource *new_res = nine_resource_create_with_retry(device, screen, &This->base.info); 463bf215546Sopenharmony_ci if (new_res) { 464bf215546Sopenharmony_ci /* Use the new resource */ 465bf215546Sopenharmony_ci pipe_resource_reference(&This->base.resource, new_res); 466bf215546Sopenharmony_ci pipe_resource_reference(&new_res, NULL); 467bf215546Sopenharmony_ci usage = PIPE_MAP_WRITE | PIPE_MAP_UNSYNCHRONIZED; 468bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); 469bf215546Sopenharmony_ci This->maps[This->nmaps].is_pipe_secondary = TRUE; 470bf215546Sopenharmony_ci } 471bf215546Sopenharmony_ci } else if (Flags & D3DLOCK_NOOVERWRITE && device->csmt_active) 472bf215546Sopenharmony_ci This->maps[This->nmaps].is_pipe_secondary = TRUE; 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_ci if (This->maps[This->nmaps].is_pipe_secondary) 475bf215546Sopenharmony_ci pipe = device->pipe_secondary; 476bf215546Sopenharmony_ci else 477bf215546Sopenharmony_ci pipe = NineDevice9_GetPipe(device); 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci data = pipe->buffer_map(pipe, This->base.resource, 0, 480bf215546Sopenharmony_ci usage, &box, &This->maps[This->nmaps].transfer); 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci if (!data) { 483bf215546Sopenharmony_ci DBG("pipe::buffer_map failed\n" 484bf215546Sopenharmony_ci " usage = %x\n" 485bf215546Sopenharmony_ci " box.x = %u\n" 486bf215546Sopenharmony_ci " box.width = %u\n", 487bf215546Sopenharmony_ci usage, box.x, box.width); 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci if (Flags & D3DLOCK_DONOTWAIT) 490bf215546Sopenharmony_ci return D3DERR_WASSTILLDRAWING; 491bf215546Sopenharmony_ci return D3DERR_INVALIDCALL; 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci DBG("returning pointer %p\n", data); 495bf215546Sopenharmony_ci This->nmaps++; 496bf215546Sopenharmony_ci This->nlocks++; 497bf215546Sopenharmony_ci *ppbData = data; 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci return D3D_OK; 500bf215546Sopenharmony_ci} 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_ciHRESULT NINE_WINAPI 503bf215546Sopenharmony_ciNineBuffer9_Unlock( struct NineBuffer9 *This ) 504bf215546Sopenharmony_ci{ 505bf215546Sopenharmony_ci struct NineDevice9 *device = This->base.base.device; 506bf215546Sopenharmony_ci struct pipe_context *pipe; 507bf215546Sopenharmony_ci int i; 508bf215546Sopenharmony_ci DBG("This=%p\n", This); 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci user_assert(This->nlocks > 0, D3DERR_INVALIDCALL); 511bf215546Sopenharmony_ci This->nlocks--; 512bf215546Sopenharmony_ci if (This->nlocks > 0) 513bf215546Sopenharmony_ci return D3D_OK; /* Pending unlocks. Wait all unlocks before unmapping */ 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci if (This->base.pool == D3DPOOL_DEFAULT) { 516bf215546Sopenharmony_ci for (i = 0; i < This->nmaps; i++) { 517bf215546Sopenharmony_ci if (!This->maps[i].buf) { 518bf215546Sopenharmony_ci pipe = This->maps[i].is_pipe_secondary ? 519bf215546Sopenharmony_ci device->pipe_secondary : 520bf215546Sopenharmony_ci nine_context_get_pipe_acquire(device); 521bf215546Sopenharmony_ci pipe->buffer_unmap(pipe, This->maps[i].transfer); 522bf215546Sopenharmony_ci /* We need to flush in case the driver does implicit copies */ 523bf215546Sopenharmony_ci if (This->maps[i].is_pipe_secondary) 524bf215546Sopenharmony_ci pipe->flush(pipe, NULL, 0); 525bf215546Sopenharmony_ci else 526bf215546Sopenharmony_ci nine_context_get_pipe_release(device); 527bf215546Sopenharmony_ci } else if (This->maps[i].should_destroy_buf) 528bf215546Sopenharmony_ci nine_upload_release_buffer(device->buffer_upload, This->maps[i].buf); 529bf215546Sopenharmony_ci } 530bf215546Sopenharmony_ci This->nmaps = 0; 531bf215546Sopenharmony_ci } 532bf215546Sopenharmony_ci return D3D_OK; 533bf215546Sopenharmony_ci} 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_civoid 536bf215546Sopenharmony_ciNineBuffer9_SetDirty( struct NineBuffer9 *This ) 537bf215546Sopenharmony_ci{ 538bf215546Sopenharmony_ci assert(This->base.pool != D3DPOOL_DEFAULT); 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci This->managed.dirty = TRUE; 541bf215546Sopenharmony_ci u_box_1d(0, This->size, &This->managed.dirty_box); 542bf215546Sopenharmony_ci BASEBUF_REGISTER_UPDATE(This); 543bf215546Sopenharmony_ci} 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci/* Try to remove b from a, supposed to include b */ 546bf215546Sopenharmony_cistatic void u_box_try_remove_region_1d(struct pipe_box *dst, 547bf215546Sopenharmony_ci const struct pipe_box *a, 548bf215546Sopenharmony_ci const struct pipe_box *b) 549bf215546Sopenharmony_ci{ 550bf215546Sopenharmony_ci int x, width; 551bf215546Sopenharmony_ci if (a->x == b->x) { 552bf215546Sopenharmony_ci x = a->x + b->width; 553bf215546Sopenharmony_ci width = a->width - b->width; 554bf215546Sopenharmony_ci } else if ((a->x + a->width) == (b->x + b->width)) { 555bf215546Sopenharmony_ci x = a->x; 556bf215546Sopenharmony_ci width = a->width - b->width; 557bf215546Sopenharmony_ci } else { 558bf215546Sopenharmony_ci x = a->x; 559bf215546Sopenharmony_ci width = a->width; 560bf215546Sopenharmony_ci } 561bf215546Sopenharmony_ci dst->x = x; 562bf215546Sopenharmony_ci dst->width = width; 563bf215546Sopenharmony_ci} 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_civoid 566bf215546Sopenharmony_ciNineBuffer9_Upload( struct NineBuffer9 *This ) 567bf215546Sopenharmony_ci{ 568bf215546Sopenharmony_ci struct NineDevice9 *device = This->base.base.device; 569bf215546Sopenharmony_ci unsigned upload_flags = 0; 570bf215546Sopenharmony_ci struct pipe_box box_upload; 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci assert(This->base.pool != D3DPOOL_DEFAULT && This->managed.dirty); 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci if (This->base.pool == D3DPOOL_SYSTEMMEM && This->base.usage & D3DUSAGE_DYNAMIC) { 575bf215546Sopenharmony_ci struct pipe_box region_already_valid; 576bf215546Sopenharmony_ci struct pipe_box conflicting_region; 577bf215546Sopenharmony_ci struct pipe_box *valid_region = &This->managed.valid_region; 578bf215546Sopenharmony_ci struct pipe_box *required_valid_region = &This->managed.required_valid_region; 579bf215546Sopenharmony_ci struct pipe_box *filled_region = &This->managed.filled_region; 580bf215546Sopenharmony_ci /* Try to upload SYSTEMMEM DYNAMIC in an efficient fashion. 581bf215546Sopenharmony_ci * Unlike non-dynamic for which we upload the whole dirty region, try to 582bf215546Sopenharmony_ci * only upload the data needed for the draw. The draw call preparation 583bf215546Sopenharmony_ci * fills This->managed.required_valid_region for that */ 584bf215546Sopenharmony_ci u_box_intersect_1d(®ion_already_valid, 585bf215546Sopenharmony_ci valid_region, 586bf215546Sopenharmony_ci required_valid_region); 587bf215546Sopenharmony_ci /* If the required valid region is already valid, nothing to do */ 588bf215546Sopenharmony_ci if (region_already_valid.x == required_valid_region->x && 589bf215546Sopenharmony_ci region_already_valid.width == required_valid_region->width) { 590bf215546Sopenharmony_ci /* Rebind if the region happens to be valid in the original buffer 591bf215546Sopenharmony_ci * but we have since used vertex_uploader */ 592bf215546Sopenharmony_ci if (!This->managed.can_unsynchronized) 593bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); 594bf215546Sopenharmony_ci u_box_1d(0, 0, required_valid_region); 595bf215546Sopenharmony_ci return; 596bf215546Sopenharmony_ci } 597bf215546Sopenharmony_ci /* (Try to) Remove valid areas from the region to upload */ 598bf215546Sopenharmony_ci u_box_try_remove_region_1d(&box_upload, 599bf215546Sopenharmony_ci required_valid_region, 600bf215546Sopenharmony_ci ®ion_already_valid); 601bf215546Sopenharmony_ci assert(box_upload.width > 0); 602bf215546Sopenharmony_ci /* To maintain correctly the valid region, as we will do union later with 603bf215546Sopenharmony_ci * box_upload, we must ensure box_upload is consecutive with valid_region */ 604bf215546Sopenharmony_ci if (box_upload.x > valid_region->x + valid_region->width && valid_region->width > 0) { 605bf215546Sopenharmony_ci box_upload.width = box_upload.x + box_upload.width - (valid_region->x + valid_region->width); 606bf215546Sopenharmony_ci box_upload.x = valid_region->x + valid_region->width; 607bf215546Sopenharmony_ci } else if (box_upload.x + box_upload.width < valid_region->x && valid_region->width > 0) { 608bf215546Sopenharmony_ci box_upload.width = valid_region->x - box_upload.x; 609bf215546Sopenharmony_ci } 610bf215546Sopenharmony_ci /* There is conflict if some areas, that are not valid but are filled for previous draw calls, 611bf215546Sopenharmony_ci * intersect with the region we plan to upload. Note by construction valid_region IS 612bf215546Sopenharmony_ci * included in filled_region, thus so is region_already_valid. */ 613bf215546Sopenharmony_ci u_box_intersect_1d(&conflicting_region, &box_upload, filled_region); 614bf215546Sopenharmony_ci /* As box_upload could still contain region_already_valid, check the intersection 615bf215546Sopenharmony_ci * doesn't happen to be exactly region_already_valid (it cannot be smaller, see above) */ 616bf215546Sopenharmony_ci if (This->managed.can_unsynchronized && (conflicting_region.width == 0 || 617bf215546Sopenharmony_ci (conflicting_region.x == region_already_valid.x && 618bf215546Sopenharmony_ci conflicting_region.width == region_already_valid.width))) { 619bf215546Sopenharmony_ci /* No conflicts. */ 620bf215546Sopenharmony_ci upload_flags |= PIPE_MAP_UNSYNCHRONIZED; 621bf215546Sopenharmony_ci } else { 622bf215546Sopenharmony_ci /* We cannot use PIPE_MAP_UNSYNCHRONIZED. We must choose between no flag and DISCARD. 623bf215546Sopenharmony_ci * Criterias to discard: 624bf215546Sopenharmony_ci * . Most of the resource was filled (but some apps do allocate a big buffer 625bf215546Sopenharmony_ci * to only use a small part in a round fashion) 626bf215546Sopenharmony_ci * . The region to upload is very small compared to the filled region and 627bf215546Sopenharmony_ci * at the start of the buffer (hints at round usage starting again) 628bf215546Sopenharmony_ci * . The region to upload is very big compared to the required region 629bf215546Sopenharmony_ci * . We have not discarded yet this frame 630bf215546Sopenharmony_ci * If the buffer use pattern seems to sync the worker thread too often, 631bf215546Sopenharmony_ci * revert to the vertex_uploader */ 632bf215546Sopenharmony_ci if (This->managed.num_worker_thread_syncs < 3 && 633bf215546Sopenharmony_ci (filled_region->width > (This->size / 2) || 634bf215546Sopenharmony_ci (10 * box_upload.width < filled_region->width && 635bf215546Sopenharmony_ci box_upload.x < (filled_region->x + filled_region->width)/2) || 636bf215546Sopenharmony_ci box_upload.width > 2 * required_valid_region->width || 637bf215546Sopenharmony_ci This->managed.frame_count_last_discard != device->frame_count)) { 638bf215546Sopenharmony_ci /* Avoid DISCARDING too much by discarding only if most of the buffer 639bf215546Sopenharmony_ci * has been used */ 640bf215546Sopenharmony_ci DBG_FLAG(DBG_INDEXBUFFER|DBG_VERTEXBUFFER, 641bf215546Sopenharmony_ci "Uploading %p DISCARD: valid %d %d, filled %d %d, required %d %d, box_upload %d %d, required already_valid %d %d, conficting %d %d\n", 642bf215546Sopenharmony_ci This, valid_region->x, valid_region->width, filled_region->x, filled_region->width, 643bf215546Sopenharmony_ci required_valid_region->x, required_valid_region->width, box_upload.x, box_upload.width, 644bf215546Sopenharmony_ci region_already_valid.x, region_already_valid.width, conflicting_region.x, conflicting_region.width 645bf215546Sopenharmony_ci ); 646bf215546Sopenharmony_ci upload_flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 647bf215546Sopenharmony_ci u_box_1d(0, 0, filled_region); 648bf215546Sopenharmony_ci u_box_1d(0, 0, valid_region); 649bf215546Sopenharmony_ci box_upload = This->managed.required_valid_region; 650bf215546Sopenharmony_ci /* Rebind the buffer if we used intermediate alternative buffer */ 651bf215546Sopenharmony_ci if (!This->managed.can_unsynchronized) 652bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, This->base.resource, 0); 653bf215546Sopenharmony_ci This->managed.can_unsynchronized = true; 654bf215546Sopenharmony_ci This->managed.frame_count_last_discard = device->frame_count; 655bf215546Sopenharmony_ci } else { 656bf215546Sopenharmony_ci /* Once we use without UNSYNCHRONIZED, we cannot use it anymore. 657bf215546Sopenharmony_ci * Use a different buffer. */ 658bf215546Sopenharmony_ci unsigned buffer_offset = 0; 659bf215546Sopenharmony_ci struct pipe_resource *resource = NULL; 660bf215546Sopenharmony_ci This->managed.can_unsynchronized = false; 661bf215546Sopenharmony_ci u_upload_data(device->vertex_uploader, 662bf215546Sopenharmony_ci required_valid_region->x, 663bf215546Sopenharmony_ci required_valid_region->width, 664bf215546Sopenharmony_ci 64, 665bf215546Sopenharmony_ci This->managed.data + required_valid_region->x, 666bf215546Sopenharmony_ci &buffer_offset, 667bf215546Sopenharmony_ci &resource); 668bf215546Sopenharmony_ci buffer_offset -= required_valid_region->x; 669bf215546Sopenharmony_ci u_upload_unmap(device->vertex_uploader); 670bf215546Sopenharmony_ci if (resource) { 671bf215546Sopenharmony_ci NineBuffer9_RebindIfRequired(This, device, resource, buffer_offset); 672bf215546Sopenharmony_ci /* Note: This only works because for these types of buffers this function 673bf215546Sopenharmony_ci * is called before every draw call. Else it wouldn't work when the app 674bf215546Sopenharmony_ci * rebinds buffers. In addition it needs this function to be called only 675bf215546Sopenharmony_ci * once per buffers even if bound several times, which we do. */ 676bf215546Sopenharmony_ci u_box_1d(0, 0, required_valid_region); 677bf215546Sopenharmony_ci pipe_resource_reference(&resource, NULL); 678bf215546Sopenharmony_ci return; 679bf215546Sopenharmony_ci } 680bf215546Sopenharmony_ci } 681bf215546Sopenharmony_ci } 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_ci u_box_union_1d(filled_region, 684bf215546Sopenharmony_ci filled_region, 685bf215546Sopenharmony_ci &box_upload); 686bf215546Sopenharmony_ci u_box_union_1d(valid_region, 687bf215546Sopenharmony_ci valid_region, 688bf215546Sopenharmony_ci &box_upload); 689bf215546Sopenharmony_ci u_box_1d(0, 0, required_valid_region); 690bf215546Sopenharmony_ci } else 691bf215546Sopenharmony_ci box_upload = This->managed.dirty_box; 692bf215546Sopenharmony_ci 693bf215546Sopenharmony_ci if (box_upload.x == 0 && box_upload.width == This->size) { 694bf215546Sopenharmony_ci upload_flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 695bf215546Sopenharmony_ci } 696bf215546Sopenharmony_ci 697bf215546Sopenharmony_ci if (This->managed.pending_upload) { 698bf215546Sopenharmony_ci u_box_union_1d(&This->managed.upload_pending_regions, 699bf215546Sopenharmony_ci &This->managed.upload_pending_regions, 700bf215546Sopenharmony_ci &box_upload); 701bf215546Sopenharmony_ci } else { 702bf215546Sopenharmony_ci This->managed.upload_pending_regions = box_upload; 703bf215546Sopenharmony_ci } 704bf215546Sopenharmony_ci 705bf215546Sopenharmony_ci DBG_FLAG(DBG_INDEXBUFFER|DBG_VERTEXBUFFER, 706bf215546Sopenharmony_ci "Uploading %p, offset=%d, size=%d, Flags=0x%x\n", 707bf215546Sopenharmony_ci This, box_upload.x, box_upload.width, upload_flags); 708bf215546Sopenharmony_ci nine_context_range_upload(device, &This->managed.pending_upload, 709bf215546Sopenharmony_ci (struct NineUnknown *)This, 710bf215546Sopenharmony_ci This->base.resource, 711bf215546Sopenharmony_ci box_upload.x, 712bf215546Sopenharmony_ci box_upload.width, 713bf215546Sopenharmony_ci upload_flags, 714bf215546Sopenharmony_ci (int8_t *)This->managed.data + box_upload.x); 715bf215546Sopenharmony_ci This->managed.dirty = FALSE; 716bf215546Sopenharmony_ci} 717