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(®ion_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 ®ion_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