Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / drivers / svga / svga_resource_buffer_upload.c
1 /**********************************************************
2  * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  **********************************************************/
25
26 #include "svga_cmd.h"
27
28 #include "pipe/p_state.h"
29 #include "pipe/p_defines.h"
30 #include "util/u_inlines.h"
31 #include "os/os_thread.h"
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
34
35 #include "svga_context.h"
36 #include "svga_screen.h"
37 #include "svga_resource_buffer.h"
38 #include "svga_resource_buffer_upload.h"
39 #include "svga_winsys.h"
40 #include "svga_debug.h"
41
42
43 /* Allocate a winsys_buffer (ie. DMA, aka GMR memory).
44  */
45 struct svga_winsys_buffer *
46 svga_winsys_buffer_create( struct svga_screen *ss,
47                            unsigned alignment, 
48                            unsigned usage,
49                            unsigned size )
50 {
51    struct svga_winsys_screen *sws = ss->sws;
52    struct svga_winsys_buffer *buf;
53    
54    /* Just try */
55    buf = sws->buffer_create(sws, alignment, usage, size);
56    if(!buf) {
57
58       SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "flushing screen to find %d bytes GMR\n", 
59                size); 
60       
61       /* Try flushing all pending DMAs */
62       svga_screen_flush(ss, NULL);
63       buf = sws->buffer_create(sws, alignment, usage, size);
64
65    }
66    
67    return buf;
68 }
69
70
71 void
72 svga_buffer_destroy_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf)
73 {
74    struct svga_winsys_screen *sws = ss->sws;
75
76    assert(!sbuf->map.count);
77    assert(sbuf->hwbuf);
78    if(sbuf->hwbuf) {
79       sws->buffer_destroy(sws, sbuf->hwbuf);
80       sbuf->hwbuf = NULL;
81    }
82 }
83
84
85
86 /**
87  * Allocate DMA'ble storage for the buffer. 
88  * 
89  * Called before mapping a buffer.
90  */
91 enum pipe_error
92 svga_buffer_create_hw_storage(struct svga_screen *ss,
93                               struct svga_buffer *sbuf)
94 {
95    assert(!sbuf->user);
96
97    if(!sbuf->hwbuf) {
98       unsigned alignment = 16;
99       unsigned usage = 0;
100       unsigned size = sbuf->b.b.width0;
101       
102       sbuf->hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
103       if(!sbuf->hwbuf)
104          return PIPE_ERROR_OUT_OF_MEMORY;
105       
106       assert(!sbuf->dma.pending);
107    }
108    
109    return PIPE_OK;
110 }
111
112
113
114 enum pipe_error
115 svga_buffer_create_host_surface(struct svga_screen *ss,
116                                 struct svga_buffer *sbuf)
117 {
118    if(!sbuf->handle) {
119       sbuf->key.flags = 0;
120       
121       sbuf->key.format = SVGA3D_BUFFER;
122       if(sbuf->b.b.bind & PIPE_BIND_VERTEX_BUFFER)
123          sbuf->key.flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER;
124       if(sbuf->b.b.bind & PIPE_BIND_INDEX_BUFFER)
125          sbuf->key.flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER;
126       
127       sbuf->key.size.width = sbuf->b.b.width0;
128       sbuf->key.size.height = 1;
129       sbuf->key.size.depth = 1;
130       
131       sbuf->key.numFaces = 1;
132       sbuf->key.numMipLevels = 1;
133       sbuf->key.cachable = 1;
134       
135       SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n", sbuf->b.b.width0);
136
137       sbuf->handle = svga_screen_surface_create(ss, &sbuf->key);
138       if(!sbuf->handle)
139          return PIPE_ERROR_OUT_OF_MEMORY;
140    
141       /* Always set the discard flag on the first time the buffer is written
142        * as svga_screen_surface_create might have passed a recycled host
143        * buffer.
144        */
145       sbuf->dma.flags.discard = TRUE;
146
147       SVGA_DBG(DEBUG_DMA, "   --> got sid %p sz %d (buffer)\n", sbuf->handle, sbuf->b.b.width0);
148    }
149    
150    return PIPE_OK;
151 }   
152
153
154 void
155 svga_buffer_destroy_host_surface(struct svga_screen *ss,
156                                  struct svga_buffer *sbuf)
157 {
158    if(sbuf->handle) {
159       SVGA_DBG(DEBUG_DMA, " ungrab sid %p sz %d\n", sbuf->handle, sbuf->b.b.width0);
160       svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle);
161    }
162 }   
163
164
165 /**
166  * Variant of SVGA3D_BufferDMA which leaves the copy box temporarily in blank.
167  */
168 static enum pipe_error
169 svga_buffer_upload_command(struct svga_context *svga,
170                            struct svga_buffer *sbuf)
171 {
172    struct svga_winsys_context *swc = svga->swc;
173    struct svga_winsys_buffer *guest = sbuf->hwbuf;
174    struct svga_winsys_surface *host = sbuf->handle;
175    SVGA3dTransferType transfer = SVGA3D_WRITE_HOST_VRAM;
176    SVGA3dCmdSurfaceDMA *cmd;
177    uint32 numBoxes = sbuf->map.num_ranges;
178    SVGA3dCopyBox *boxes;
179    SVGA3dCmdSurfaceDMASuffix *pSuffix;
180    unsigned region_flags;
181    unsigned surface_flags;
182    struct pipe_resource *dummy;
183
184    if(transfer == SVGA3D_WRITE_HOST_VRAM) {
185       region_flags = SVGA_RELOC_READ;
186       surface_flags = SVGA_RELOC_WRITE;
187    }
188    else if(transfer == SVGA3D_READ_HOST_VRAM) {
189       region_flags = SVGA_RELOC_WRITE;
190       surface_flags = SVGA_RELOC_READ;
191    }
192    else {
193       assert(0);
194       return PIPE_ERROR_BAD_INPUT;
195    }
196
197    assert(numBoxes);
198
199    cmd = SVGA3D_FIFOReserve(swc,
200                             SVGA_3D_CMD_SURFACE_DMA,
201                             sizeof *cmd + numBoxes * sizeof *boxes + sizeof *pSuffix,
202                             2);
203    if(!cmd)
204       return PIPE_ERROR_OUT_OF_MEMORY;
205
206    swc->region_relocation(swc, &cmd->guest.ptr, guest, 0, region_flags);
207    cmd->guest.pitch = 0;
208
209    swc->surface_relocation(swc, &cmd->host.sid, host, surface_flags);
210    cmd->host.face = 0;
211    cmd->host.mipmap = 0;
212
213    cmd->transfer = transfer;
214
215    sbuf->dma.boxes = (SVGA3dCopyBox *)&cmd[1];
216    sbuf->dma.svga = svga;
217
218    /* Increment reference count */
219    dummy = NULL;
220    pipe_resource_reference(&dummy, &sbuf->b.b);
221
222    pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + numBoxes * sizeof *boxes);
223    pSuffix->suffixSize = sizeof *pSuffix;
224    pSuffix->maximumOffset = sbuf->b.b.width0;
225    pSuffix->flags = sbuf->dma.flags;
226
227    SVGA_FIFOCommitAll(swc);
228
229    sbuf->dma.flags.discard = FALSE;
230
231    return PIPE_OK;
232 }
233
234
235 /**
236  * Patch up the upload DMA command reserved by svga_buffer_upload_command
237  * with the final ranges.
238  */
239 static void
240 svga_buffer_upload_flush(struct svga_context *svga,
241                          struct svga_buffer *sbuf)
242 {
243    SVGA3dCopyBox *boxes;
244    unsigned i;
245
246    assert(sbuf->handle); 
247    assert(sbuf->hwbuf);
248    assert(sbuf->map.num_ranges);
249    assert(sbuf->dma.svga == svga);
250    assert(sbuf->dma.boxes);
251    
252    /*
253     * Patch the DMA command with the final copy box.
254     */
255
256    SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
257
258    boxes = sbuf->dma.boxes;
259    for(i = 0; i < sbuf->map.num_ranges; ++i) {
260       SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
261                sbuf->map.ranges[i].start, sbuf->map.ranges[i].end);
262
263       boxes[i].x = sbuf->map.ranges[i].start;
264       boxes[i].y = 0;
265       boxes[i].z = 0;
266       boxes[i].w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start;
267       boxes[i].h = 1;
268       boxes[i].d = 1;
269       boxes[i].srcx = sbuf->map.ranges[i].start;
270       boxes[i].srcy = 0;
271       boxes[i].srcz = 0;
272    }
273
274    sbuf->map.num_ranges = 0;
275
276    assert(sbuf->head.prev && sbuf->head.next);
277    LIST_DEL(&sbuf->head);
278 #ifdef DEBUG
279    sbuf->head.next = sbuf->head.prev = NULL; 
280 #endif
281    sbuf->dma.pending = FALSE;
282
283    sbuf->dma.svga = NULL;
284    sbuf->dma.boxes = NULL;
285
286    /* Decrement reference count */
287    pipe_reference(&(sbuf->b.b.reference), NULL);
288    sbuf = NULL;
289 }
290
291
292
293 /**
294  * Note a dirty range.
295  *
296  * This function only notes the range down. It doesn't actually emit a DMA
297  * upload command. That only happens when a context tries to refer to this
298  * buffer, and the DMA upload command is added to that context's command buffer.
299  * 
300  * We try to lump as many contiguous DMA transfers together as possible.
301  */
302 void
303 svga_buffer_add_range(struct svga_buffer *sbuf,
304                       unsigned start,
305                       unsigned end)
306 {
307    unsigned i;
308    unsigned nearest_range;
309    unsigned nearest_dist;
310
311    assert(end > start);
312    
313    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
314       nearest_range = sbuf->map.num_ranges;
315       nearest_dist = ~0;
316    } else {
317       nearest_range = SVGA_BUFFER_MAX_RANGES - 1;
318       nearest_dist = 0;
319    }
320
321    /*
322     * Try to grow one of the ranges.
323     *
324     * Note that it is not this function task to care about overlapping ranges,
325     * as the GMR was already given so it is too late to do anything. Situations
326     * where overlapping ranges may pose a problem should be detected via
327     * pipe_context::is_resource_referenced and the context that refers to the
328     * buffer should be flushed.
329     */
330
331    for(i = 0; i < sbuf->map.num_ranges; ++i) {
332       int left_dist;
333       int right_dist;
334       int dist;
335
336       left_dist = start - sbuf->map.ranges[i].end;
337       right_dist = sbuf->map.ranges[i].start - end;
338       dist = MAX2(left_dist, right_dist);
339
340       if (dist <= 0) {
341          /*
342           * Ranges are contiguous or overlapping -- extend this one and return.
343           */
344
345          sbuf->map.ranges[i].start = MIN2(sbuf->map.ranges[i].start, start);
346          sbuf->map.ranges[i].end   = MAX2(sbuf->map.ranges[i].end,   end);
347          return;
348       }
349       else {
350          /*
351           * Discontiguous ranges -- keep track of the nearest range.
352           */
353
354          if (dist < nearest_dist) {
355             nearest_range = i;
356             nearest_dist = dist;
357          }
358       }
359    }
360
361    /*
362     * We cannot add a new range to an existing DMA command, so patch-up the
363     * pending DMA upload and start clean.
364     */
365
366    if(sbuf->dma.pending)
367       svga_buffer_upload_flush(sbuf->dma.svga, sbuf);
368
369    assert(!sbuf->dma.pending);
370    assert(!sbuf->dma.svga);
371    assert(!sbuf->dma.boxes);
372
373    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
374       /*
375        * Add a new range.
376        */
377
378       sbuf->map.ranges[sbuf->map.num_ranges].start = start;
379       sbuf->map.ranges[sbuf->map.num_ranges].end = end;
380       ++sbuf->map.num_ranges;
381    } else {
382       /*
383        * Everything else failed, so just extend the nearest range.
384        *
385        * It is OK to do this because we always keep a local copy of the
386        * host buffer data, for SW TNL, and the host never modifies the buffer.
387        */
388
389       assert(nearest_range < SVGA_BUFFER_MAX_RANGES);
390       assert(nearest_range < sbuf->map.num_ranges);
391       sbuf->map.ranges[nearest_range].start = MIN2(sbuf->map.ranges[nearest_range].start, start);
392       sbuf->map.ranges[nearest_range].end   = MAX2(sbuf->map.ranges[nearest_range].end,   end);
393    }
394 }
395
396
397
398 /**
399  * Copy the contents of the malloc buffer to a hardware buffer.
400  */
401 static INLINE enum pipe_error
402 svga_buffer_update_hw(struct svga_screen *ss, struct svga_buffer *sbuf)
403 {
404    assert(!sbuf->user);
405    if(!sbuf->hwbuf) {
406       enum pipe_error ret;
407       void *map;
408       
409       assert(sbuf->swbuf);
410       if(!sbuf->swbuf)
411          return PIPE_ERROR;
412       
413       ret = svga_buffer_create_hw_storage(ss, sbuf);
414       if(ret != PIPE_OK)
415          return ret;
416
417       pipe_mutex_lock(ss->swc_mutex);
418       map = ss->sws->buffer_map(ss->sws, sbuf->hwbuf, PIPE_TRANSFER_WRITE);
419       assert(map);
420       if(!map) {
421          pipe_mutex_unlock(ss->swc_mutex);
422          svga_buffer_destroy_hw_storage(ss, sbuf);
423          return PIPE_ERROR;
424       }
425
426       memcpy(map, sbuf->swbuf, sbuf->b.b.width0);
427       ss->sws->buffer_unmap(ss->sws, sbuf->hwbuf);
428
429       /* This user/malloc buffer is now indistinguishable from a gpu buffer */
430       assert(!sbuf->map.count);
431       if(!sbuf->map.count) {
432          if(sbuf->user)
433             sbuf->user = FALSE;
434          else
435             align_free(sbuf->swbuf);
436          sbuf->swbuf = NULL;
437       }
438       
439       pipe_mutex_unlock(ss->swc_mutex);
440    }
441    
442    return PIPE_OK;
443 }
444
445
446 /**
447  * Upload the buffer to the host in a piecewise fashion.
448  *
449  * Used when the buffer is too big to fit in the GMR aperture.
450  */
451 static INLINE enum pipe_error
452 svga_buffer_upload_piecewise(struct svga_screen *ss,
453                              struct svga_context *svga,
454                              struct svga_buffer *sbuf)
455 {
456    struct svga_winsys_screen *sws = ss->sws;
457    const unsigned alignment = sizeof(void *);
458    const unsigned usage = 0;
459    unsigned i;
460
461    assert(sbuf->map.num_ranges);
462    assert(!sbuf->dma.pending);
463
464    SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
465
466    for (i = 0; i < sbuf->map.num_ranges; ++i) {
467       struct svga_buffer_range *range = &sbuf->map.ranges[i];
468       unsigned offset = range->start;
469       unsigned size = range->end - range->start;
470
471       while (offset < range->end) {
472          struct svga_winsys_buffer *hwbuf;
473          uint8_t *map;
474          enum pipe_error ret;
475
476          if (offset + size > range->end)
477             size = range->end - offset;
478
479          hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
480          while (!hwbuf) {
481             size /= 2;
482             if (!size)
483                return PIPE_ERROR_OUT_OF_MEMORY;
484             hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
485          }
486
487          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
488                   offset, offset + size);
489
490          map = sws->buffer_map(sws, hwbuf,
491                                PIPE_TRANSFER_WRITE |
492                                PIPE_TRANSFER_DISCARD);
493          assert(map);
494          if (map) {
495             memcpy(map, sbuf->swbuf, size);
496             sws->buffer_unmap(sws, hwbuf);
497          }
498
499          ret = SVGA3D_BufferDMA(svga->swc,
500                                 hwbuf, sbuf->handle,
501                                 SVGA3D_WRITE_HOST_VRAM,
502                                 size, 0, offset, sbuf->dma.flags);
503          if(ret != PIPE_OK) {
504             svga_context_flush(svga, NULL);
505             ret =  SVGA3D_BufferDMA(svga->swc,
506                                     hwbuf, sbuf->handle,
507                                     SVGA3D_WRITE_HOST_VRAM,
508                                     size, 0, offset, sbuf->dma.flags);
509             assert(ret == PIPE_OK);
510          }
511
512          sbuf->dma.flags.discard = FALSE;
513
514          sws->buffer_destroy(sws, hwbuf);
515
516          offset += size;
517       }
518    }
519
520    sbuf->map.num_ranges = 0;
521
522    return PIPE_OK;
523 }
524
525
526
527
528 /* Get (or create/upload) the winsys surface handle so that we can
529  * refer to this buffer in fifo commands.
530  */
531 struct svga_winsys_surface *
532 svga_buffer_handle(struct svga_context *svga,
533                    struct pipe_resource *buf)
534 {
535    struct pipe_screen *screen = svga->pipe.screen;
536    struct svga_screen *ss = svga_screen(screen);
537    struct svga_buffer *sbuf;
538    enum pipe_error ret;
539
540    if(!buf)
541       return NULL;
542
543    sbuf = svga_buffer(buf);
544    
545    assert(!sbuf->map.count);
546    assert(!sbuf->user);
547    
548    if(!sbuf->handle) {
549       ret = svga_buffer_create_host_surface(ss, sbuf);
550       if(ret != PIPE_OK)
551          return NULL;
552    }
553
554    assert(sbuf->handle);
555
556    if (sbuf->map.num_ranges) {
557       if (!sbuf->dma.pending) {
558          /*
559           * No pending DMA upload yet, so insert a DMA upload command now.
560           */
561
562          /*
563           * Migrate the data from swbuf -> hwbuf if necessary.
564           */
565          ret = svga_buffer_update_hw(ss, sbuf);
566          if (ret == PIPE_OK) {
567             /*
568              * Queue a dma command.
569              */
570
571             ret = svga_buffer_upload_command(svga, sbuf);
572             if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
573                svga_context_flush(svga, NULL);
574                ret = svga_buffer_upload_command(svga, sbuf);
575                assert(ret == PIPE_OK);
576             }
577             if (ret == PIPE_OK) {
578                sbuf->dma.pending = TRUE;
579                assert(!sbuf->head.prev && !sbuf->head.next);
580                LIST_ADDTAIL(&sbuf->head, &svga->dirty_buffers);
581             }
582          }
583          else if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
584             /*
585              * The buffer is too big to fit in the GMR aperture, so break it in
586              * smaller pieces.
587              */
588             ret = svga_buffer_upload_piecewise(ss, svga, sbuf);
589          }
590
591          if (ret != PIPE_OK) {
592             /*
593              * Something unexpected happened above. There is very little that
594              * we can do other than proceeding while ignoring the dirty ranges.
595              */
596             assert(0);
597             sbuf->map.num_ranges = 0;
598          }
599       }
600       else {
601          /*
602           * There a pending dma already. Make sure it is from this context.
603           */
604          assert(sbuf->dma.svga == svga);
605       }
606    }
607
608    assert(!sbuf->map.num_ranges || sbuf->dma.pending);
609
610    return sbuf->handle;
611 }
612
613
614
615 void
616 svga_context_flush_buffers(struct svga_context *svga)
617 {
618    struct list_head *curr, *next;
619    struct svga_buffer *sbuf;
620
621    curr = svga->dirty_buffers.next;
622    next = curr->next;
623    while(curr != &svga->dirty_buffers) {
624       sbuf = LIST_ENTRY(struct svga_buffer, curr, head);
625
626       assert(p_atomic_read(&sbuf->b.b.reference.count) != 0);
627       assert(sbuf->dma.pending);
628       
629       svga_buffer_upload_flush(svga, sbuf);
630
631       curr = next; 
632       next = curr->next;
633    }
634 }