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