X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fsvga%2Fsvga_screen_buffer.c;h=1ff6a3a5b317172dce122055b466ea8e52ce5eb8;hb=2657325c4a73a2bfa94888a936d06466000e7fbf;hp=1f8a88967238e9f3430a7fa15c7ca1f98a3ce6a7;hpb=06d3732a9094030fc33120f16f162e0d405f132c;p=mesa.git diff --git a/src/gallium/drivers/svga/svga_screen_buffer.c b/src/gallium/drivers/svga/svga_screen_buffer.c index 1f8a8896723..1ff6a3a5b31 100644 --- a/src/gallium/drivers/svga/svga_screen_buffer.c +++ b/src/gallium/drivers/svga/svga_screen_buffer.c @@ -27,8 +27,8 @@ #include "pipe/p_state.h" #include "pipe/p_defines.h" -#include "pipe/p_inlines.h" -#include "pipe/p_thread.h" +#include "util/u_inlines.h" +#include "os/os_thread.h" #include "util/u_math.h" #include "util/u_memory.h" @@ -83,7 +83,7 @@ svga_buffer_create_host_surface(struct svga_screen *ss, * as svga_screen_surface_create might have passed a recycled host * buffer. */ - sbuf->hw.flags.discard = TRUE; + sbuf->dma.flags.discard = TRUE; SVGA_DBG(DEBUG_DMA, " --> got sid %p sz %d (buffer)\n", sbuf->handle, sbuf->base.size); } @@ -109,72 +109,13 @@ svga_buffer_destroy_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf) struct svga_winsys_screen *sws = ss->sws; assert(!sbuf->map.count); - assert(sbuf->hw.buf); - if(sbuf->hw.buf) { - sws->buffer_destroy(sws, sbuf->hw.buf); - sbuf->hw.buf = NULL; - assert(sbuf->head.prev && sbuf->head.next); - LIST_DEL(&sbuf->head); -#ifdef DEBUG - sbuf->head.next = sbuf->head.prev = NULL; -#endif + assert(sbuf->hwbuf); + if(sbuf->hwbuf) { + sws->buffer_destroy(sws, sbuf->hwbuf); + sbuf->hwbuf = NULL; } } -static INLINE enum pipe_error -svga_buffer_backup(struct svga_screen *ss, struct svga_buffer *sbuf) -{ - if (sbuf->hw.buf && sbuf->hw.num_ranges) { - void *src; - - if (!sbuf->swbuf) - sbuf->swbuf = align_malloc(sbuf->base.size, sbuf->base.alignment); - if (!sbuf->swbuf) - return PIPE_ERROR_OUT_OF_MEMORY; - - src = ss->sws->buffer_map(ss->sws, sbuf->hw.buf, - PIPE_BUFFER_USAGE_CPU_READ); - if (!src) - return PIPE_ERROR; - - memcpy(sbuf->swbuf, src, sbuf->base.size); - ss->sws->buffer_unmap(ss->sws, sbuf->hw.buf); - } - - return PIPE_OK; -} - -/** - * Try to make GMR space available by freeing the hardware storage of - * unmapped - */ -boolean -svga_buffer_free_cached_hw_storage(struct svga_screen *ss) -{ - struct list_head *curr; - struct svga_buffer *sbuf; - enum pipe_error ret = PIPE_OK; - - curr = ss->cached_buffers.prev; - - /* free the least recently used buffer's hw storage which is not mapped */ - do { - if(curr == &ss->cached_buffers) - return FALSE; - - sbuf = LIST_ENTRY(struct svga_buffer, curr, head); - - curr = curr->prev; - if (sbuf->map.count == 0) - ret = svga_buffer_backup(ss, sbuf); - - } while(sbuf->map.count != 0 || ret != PIPE_OK); - - svga_buffer_destroy_hw_storage(ss, sbuf); - - return TRUE; -} - struct svga_winsys_buffer * svga_winsys_buffer_create( struct svga_screen *ss, unsigned alignment, @@ -195,12 +136,6 @@ svga_winsys_buffer_create( struct svga_screen *ss, svga_screen_flush(ss, NULL); buf = sws->buffer_create(sws, alignment, usage, size); - SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "evicting buffers to find %d bytes GMR\n", - size); - - /* Try evicing all buffer storage */ - while(!buf && svga_buffer_free_cached_hw_storage(ss)) - buf = sws->buffer_create(sws, alignment, usage, size); } return buf; @@ -216,18 +151,18 @@ static INLINE enum pipe_error svga_buffer_create_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf) { - if(!sbuf->hw.buf) { + assert(!sbuf->user); + + if(!sbuf->hwbuf) { unsigned alignment = sbuf->base.alignment; unsigned usage = 0; unsigned size = sbuf->base.size; - sbuf->hw.buf = svga_winsys_buffer_create(ss, alignment, usage, size); - if(!sbuf->hw.buf) + sbuf->hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size); + if(!sbuf->hwbuf) return PIPE_ERROR_OUT_OF_MEMORY; - assert(!sbuf->needs_flush); - assert(!sbuf->head.prev && !sbuf->head.next); - LIST_ADD(&sbuf->head, &ss->cached_buffers); + assert(!sbuf->dma.pending); } return PIPE_OK; @@ -242,12 +177,11 @@ svga_buffer_upload_command(struct svga_context *svga, struct svga_buffer *sbuf) { struct svga_winsys_context *swc = svga->swc; - struct svga_winsys_buffer *guest = sbuf->hw.buf; + struct svga_winsys_buffer *guest = sbuf->hwbuf; struct svga_winsys_surface *host = sbuf->handle; SVGA3dTransferType transfer = SVGA3D_WRITE_HOST_VRAM; - SVGA3dSurfaceDMAFlags flags = sbuf->hw.flags; SVGA3dCmdSurfaceDMA *cmd; - uint32 numBoxes = sbuf->hw.num_ranges; + uint32 numBoxes = sbuf->map.num_ranges; SVGA3dCopyBox *boxes; SVGA3dCmdSurfaceDMASuffix *pSuffix; unsigned region_flags; @@ -285,8 +219,8 @@ svga_buffer_upload_command(struct svga_context *svga, cmd->transfer = transfer; - sbuf->hw.boxes = (SVGA3dCopyBox *)&cmd[1]; - sbuf->hw.svga = svga; + sbuf->dma.boxes = (SVGA3dCopyBox *)&cmd[1]; + sbuf->dma.svga = svga; /* Increment reference count */ dummy = NULL; @@ -295,9 +229,11 @@ svga_buffer_upload_command(struct svga_context *svga, pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + numBoxes * sizeof *boxes); pSuffix->suffixSize = sizeof *pSuffix; pSuffix->maximumOffset = sbuf->base.size; - pSuffix->flags = flags; + pSuffix->flags = sbuf->dma.flags; + + SVGA_FIFOCommitAll(swc); - swc->commit(swc); + sbuf->dma.flags.discard = FALSE; return PIPE_OK; } @@ -311,15 +247,14 @@ static void svga_buffer_upload_flush(struct svga_context *svga, struct svga_buffer *sbuf) { - struct svga_screen *ss = svga_screen(svga->pipe.screen); SVGA3dCopyBox *boxes; unsigned i; assert(sbuf->handle); - assert(sbuf->hw.buf); - assert(sbuf->hw.num_ranges); - assert(sbuf->hw.svga == svga); - assert(sbuf->hw.boxes); + assert(sbuf->hwbuf); + assert(sbuf->map.num_ranges); + assert(sbuf->dma.svga == svga); + assert(sbuf->dma.boxes); /* * Patch the DMA command with the final copy box. @@ -327,41 +262,42 @@ svga_buffer_upload_flush(struct svga_context *svga, SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle); - boxes = sbuf->hw.boxes; - for(i = 0; i < sbuf->hw.num_ranges; ++i) { + boxes = sbuf->dma.boxes; + for(i = 0; i < sbuf->map.num_ranges; ++i) { SVGA_DBG(DEBUG_DMA, " bytes %u - %u\n", - sbuf->hw.ranges[i].start, sbuf->hw.ranges[i].end); + sbuf->map.ranges[i].start, sbuf->map.ranges[i].end); - boxes[i].x = sbuf->hw.ranges[i].start; + boxes[i].x = sbuf->map.ranges[i].start; boxes[i].y = 0; boxes[i].z = 0; - boxes[i].w = sbuf->hw.ranges[i].end - sbuf->hw.ranges[i].start; + boxes[i].w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start; boxes[i].h = 1; boxes[i].d = 1; - boxes[i].srcx = sbuf->hw.ranges[i].start; + boxes[i].srcx = sbuf->map.ranges[i].start; boxes[i].srcy = 0; boxes[i].srcz = 0; } - sbuf->hw.num_ranges = 0; - memset(&sbuf->hw.flags, 0, sizeof sbuf->hw.flags); + sbuf->map.num_ranges = 0; assert(sbuf->head.prev && sbuf->head.next); LIST_DEL(&sbuf->head); - sbuf->needs_flush = FALSE; - /* XXX: do we care about cached_buffers any more ?*/ - LIST_ADD(&sbuf->head, &ss->cached_buffers); +#ifdef DEBUG + sbuf->head.next = sbuf->head.prev = NULL; +#endif + sbuf->dma.pending = FALSE; - sbuf->hw.svga = NULL; - sbuf->hw.boxes = NULL; + sbuf->dma.svga = NULL; + sbuf->dma.boxes = NULL; /* Decrement reference count */ - pipe_buffer_reference((struct pipe_buffer **)&sbuf, NULL); + pipe_reference(&(sbuf->base.reference), NULL); + sbuf = NULL; } /** - * Queue a DMA upload of a range of this buffer to the host. + * Note a dirty range. * * This function only notes the range down. It doesn't actually emit a DMA * upload command. That only happens when a context tries to refer to this @@ -370,15 +306,24 @@ svga_buffer_upload_flush(struct svga_context *svga, * We try to lump as many contiguous DMA transfers together as possible. */ static void -svga_buffer_upload_queue(struct svga_buffer *sbuf, - unsigned start, - unsigned end) +svga_buffer_add_range(struct svga_buffer *sbuf, + unsigned start, + unsigned end) { unsigned i; + unsigned nearest_range; + unsigned nearest_dist; - assert(sbuf->hw.buf); assert(end > start); + if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) { + nearest_range = sbuf->map.num_ranges; + nearest_dist = ~0; + } else { + nearest_range = SVGA_BUFFER_MAX_RANGES - 1; + nearest_dist = 0; + } + /* * Try to grow one of the ranges. * @@ -389,12 +334,34 @@ svga_buffer_upload_queue(struct svga_buffer *sbuf, * buffer should be flushed. */ - for(i = 0; i < sbuf->hw.num_ranges; ++i) { - if(start <= sbuf->hw.ranges[i].end && sbuf->hw.ranges[i].start <= end) { - sbuf->hw.ranges[i].start = MIN2(sbuf->hw.ranges[i].start, start); - sbuf->hw.ranges[i].end = MAX2(sbuf->hw.ranges[i].end, end); + for(i = 0; i < sbuf->map.num_ranges; ++i) { + int left_dist; + int right_dist; + int dist; + + left_dist = start - sbuf->map.ranges[i].end; + right_dist = sbuf->map.ranges[i].start - end; + dist = MAX2(left_dist, right_dist); + + if (dist <= 0) { + /* + * Ranges are contiguous or overlapping -- extend this one and return. + */ + + sbuf->map.ranges[i].start = MIN2(sbuf->map.ranges[i].start, start); + sbuf->map.ranges[i].end = MAX2(sbuf->map.ranges[i].end, end); return; } + else { + /* + * Discontiguous ranges -- keep track of the nearest range. + */ + + if (dist < nearest_dist) { + nearest_range = i; + nearest_dist = dist; + } + } } /* @@ -402,20 +369,34 @@ svga_buffer_upload_queue(struct svga_buffer *sbuf, * pending DMA upload and start clean. */ - if(sbuf->needs_flush) - svga_buffer_upload_flush(sbuf->hw.svga, sbuf); + if(sbuf->dma.pending) + svga_buffer_upload_flush(sbuf->dma.svga, sbuf); - assert(!sbuf->needs_flush); - assert(!sbuf->hw.svga); - assert(!sbuf->hw.boxes); + assert(!sbuf->dma.pending); + assert(!sbuf->dma.svga); + assert(!sbuf->dma.boxes); - /* - * Add a new range. - */ + if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) { + /* + * Add a new range. + */ - sbuf->hw.ranges[sbuf->hw.num_ranges].start = start; - sbuf->hw.ranges[sbuf->hw.num_ranges].end = end; - ++sbuf->hw.num_ranges; + sbuf->map.ranges[sbuf->map.num_ranges].start = start; + sbuf->map.ranges[sbuf->map.num_ranges].end = end; + ++sbuf->map.num_ranges; + } else { + /* + * Everything else failed, so just extend the nearest range. + * + * It is OK to do this because we always keep a local copy of the + * host buffer data, for SW TNL, and the host never modifies the buffer. + */ + + assert(nearest_range < SVGA_BUFFER_MAX_RANGES); + assert(nearest_range < sbuf->map.num_ranges); + sbuf->map.ranges[nearest_range].start = MIN2(sbuf->map.ranges[nearest_range].start, start); + sbuf->map.ranges[nearest_range].end = MAX2(sbuf->map.ranges[nearest_range].end, end); + } } @@ -430,66 +411,30 @@ svga_buffer_map_range( struct pipe_screen *screen, struct svga_buffer *sbuf = svga_buffer( buf ); void *map; - if(sbuf->swbuf) { + if (!sbuf->swbuf && !sbuf->hwbuf) { + if (svga_buffer_create_hw_storage(ss, sbuf) != PIPE_OK) { + /* + * We can't create a hardware buffer big enough, so create a malloc + * buffer instead. + */ + + debug_printf("%s: failed to allocate %u KB of DMA, splitting DMA transfers\n", + __FUNCTION__, + (sbuf->base.size + 1023)/1024); + + sbuf->swbuf = align_malloc(sbuf->base.size, sbuf->base.alignment); + } + } + + if (sbuf->swbuf) { /* User/malloc buffer */ map = sbuf->swbuf; } + else if (sbuf->hwbuf) { + map = sws->buffer_map(sws, sbuf->hwbuf, usage); + } else { - if(!sbuf->hw.buf) { - struct svga_winsys_surface *handle = sbuf->handle; - - if(svga_buffer_create_hw_storage(ss, sbuf) != PIPE_OK) - return NULL; - - /* Populate the hardware storage if the host surface pre-existed */ - if((usage & PIPE_BUFFER_USAGE_CPU_READ) && handle) { - SVGA3dSurfaceDMAFlags flags; - enum pipe_error ret; - struct pipe_fence_handle *fence = NULL; - - SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "dma from sid %p (buffer), bytes %u - %u\n", - sbuf->handle, 0, sbuf->base.size); - - memset(&flags, 0, sizeof flags); - - ret = SVGA3D_BufferDMA(ss->swc, - sbuf->hw.buf, - sbuf->handle, - SVGA3D_READ_HOST_VRAM, - sbuf->base.size, - 0, - flags); - if(ret != PIPE_OK) { - ss->swc->flush(ss->swc, NULL); - - ret = SVGA3D_BufferDMA(ss->swc, - sbuf->hw.buf, - sbuf->handle, - SVGA3D_READ_HOST_VRAM, - sbuf->base.size, - 0, - flags); - assert(ret == PIPE_OK); - } - - ss->swc->flush(ss->swc, &fence); - sws->fence_finish(sws, fence, 0); - sws->fence_reference(sws, &fence, NULL); - } - } - else { - if((usage & PIPE_BUFFER_USAGE_CPU_READ) && !sbuf->needs_flush) { - /* We already had the hardware storage but we would have to issue - * a download if we hadn't, so move the buffer to the begginning - * of the LRU list. - */ - assert(sbuf->head.prev && sbuf->head.next); - LIST_DEL(&sbuf->head); - LIST_ADD(&sbuf->head, &ss->cached_buffers); - } - } - - map = sws->buffer_map(sws, sbuf->hw.buf, usage); + map = NULL; } if(map) { @@ -522,8 +467,7 @@ svga_buffer_flush_mapped_range( struct pipe_screen *screen, assert(sbuf->map.writing); if(sbuf->map.writing) { assert(sbuf->map.flush_explicit); - if(sbuf->hw.buf) - svga_buffer_upload_queue(sbuf, offset, offset + length); + svga_buffer_add_range(sbuf, offset, offset + length); } pipe_mutex_unlock(ss->swc_mutex); } @@ -542,16 +486,15 @@ svga_buffer_unmap( struct pipe_screen *screen, if(sbuf->map.count) --sbuf->map.count; - if(sbuf->hw.buf) - sws->buffer_unmap(sws, sbuf->hw.buf); + if(sbuf->hwbuf) + sws->buffer_unmap(sws, sbuf->hwbuf); if(sbuf->map.writing) { if(!sbuf->map.flush_explicit) { /* No mapped range was flushed -- flush the whole buffer */ SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n"); - if(sbuf->hw.buf) - svga_buffer_upload_queue(sbuf, 0, sbuf->base.size); + svga_buffer_add_range(sbuf, 0, sbuf->base.size); } sbuf->map.writing = FALSE; @@ -569,14 +512,15 @@ svga_buffer_destroy( struct pipe_buffer *buf ) assert(!p_atomic_read(&buf->reference.count)); - assert(!sbuf->needs_flush); + assert(!sbuf->dma.pending); - if(sbuf->handle) { - SVGA_DBG(DEBUG_DMA, "release sid %p sz %d\n", sbuf->handle, sbuf->base.size); - svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle); - } + if(sbuf->handle) + svga_buffer_destroy_host_surface(ss, sbuf); - if(sbuf->hw.buf) + if(sbuf->uploaded.buffer) + pipe_buffer_reference(&sbuf->uploaded.buffer, NULL); + + if(sbuf->hwbuf) svga_buffer_destroy_hw_storage(ss, sbuf); if(sbuf->swbuf && !sbuf->user) @@ -594,6 +538,9 @@ svga_buffer_create(struct pipe_screen *screen, struct svga_screen *ss = svga_screen(screen); struct svga_buffer *sbuf; + assert(size); + assert(alignment); + sbuf = CALLOC_STRUCT(svga_buffer); if(!sbuf) goto error1; @@ -670,13 +617,14 @@ svga_screen_init_buffer_functions(struct pipe_screen *screen) } -/** - * Copy the contents of the user buffer / malloc buffer to a hardware buffer. +/** + * Copy the contents of the malloc buffer to a hardware buffer. */ static INLINE enum pipe_error svga_buffer_update_hw(struct svga_screen *ss, struct svga_buffer *sbuf) { - if(!sbuf->hw.buf) { + assert(!sbuf->user); + if(!sbuf->hwbuf) { enum pipe_error ret; void *map; @@ -685,20 +633,20 @@ svga_buffer_update_hw(struct svga_screen *ss, struct svga_buffer *sbuf) return PIPE_ERROR; ret = svga_buffer_create_hw_storage(ss, sbuf); - assert(ret == PIPE_OK); if(ret != PIPE_OK) return ret; pipe_mutex_lock(ss->swc_mutex); - map = ss->sws->buffer_map(ss->sws, sbuf->hw.buf, PIPE_BUFFER_USAGE_CPU_WRITE); + map = ss->sws->buffer_map(ss->sws, sbuf->hwbuf, PIPE_BUFFER_USAGE_CPU_WRITE); assert(map); if(!map) { pipe_mutex_unlock(ss->swc_mutex); - return PIPE_ERROR_OUT_OF_MEMORY; + svga_buffer_destroy_hw_storage(ss, sbuf); + return PIPE_ERROR; } memcpy(map, sbuf->swbuf, sbuf->base.size); - ss->sws->buffer_unmap(ss->sws, sbuf->hw.buf); + ss->sws->buffer_unmap(ss->sws, sbuf->hwbuf); /* This user/malloc buffer is now indistinguishable from a gpu buffer */ assert(!sbuf->map.count); @@ -710,10 +658,89 @@ svga_buffer_update_hw(struct svga_screen *ss, struct svga_buffer *sbuf) sbuf->swbuf = NULL; } - svga_buffer_upload_queue(sbuf, 0, sbuf->base.size); + pipe_mutex_unlock(ss->swc_mutex); } - pipe_mutex_unlock(ss->swc_mutex); + return PIPE_OK; +} + + +/** + * Upload the buffer to the host in a piecewise fashion. + * + * Used when the buffer is too big to fit in the GMR aperture. + */ +static INLINE enum pipe_error +svga_buffer_upload_piecewise(struct svga_screen *ss, + struct svga_context *svga, + struct svga_buffer *sbuf) +{ + struct svga_winsys_screen *sws = ss->sws; + const unsigned alignment = sizeof(void *); + const unsigned usage = 0; + unsigned i; + + assert(sbuf->map.num_ranges); + assert(!sbuf->dma.pending); + + SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle); + + for (i = 0; i < sbuf->map.num_ranges; ++i) { + struct svga_buffer_range *range = &sbuf->map.ranges[i]; + unsigned offset = range->start; + unsigned size = range->end - range->start; + + while (offset < range->end) { + struct svga_winsys_buffer *hwbuf; + uint8_t *map; + enum pipe_error ret; + + if (offset + size > range->end) + size = range->end - offset; + + hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size); + while (!hwbuf) { + size /= 2; + if (!size) + return PIPE_ERROR_OUT_OF_MEMORY; + hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size); + } + + SVGA_DBG(DEBUG_DMA, " bytes %u - %u\n", + offset, offset + size); + + map = sws->buffer_map(sws, hwbuf, + PIPE_BUFFER_USAGE_CPU_WRITE | + PIPE_BUFFER_USAGE_DISCARD); + assert(map); + if (map) { + memcpy(map, sbuf->swbuf, size); + sws->buffer_unmap(sws, hwbuf); + } + + ret = SVGA3D_BufferDMA(svga->swc, + hwbuf, sbuf->handle, + SVGA3D_WRITE_HOST_VRAM, + size, 0, offset, sbuf->dma.flags); + if(ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_BufferDMA(svga->swc, + hwbuf, sbuf->handle, + SVGA3D_WRITE_HOST_VRAM, + size, 0, offset, sbuf->dma.flags); + assert(ret == PIPE_OK); + } + + sbuf->dma.flags.discard = FALSE; + + sws->buffer_destroy(sws, hwbuf); + + offset += size; + } + } + + sbuf->map.num_ranges = 0; + return PIPE_OK; } @@ -733,35 +760,74 @@ svga_buffer_handle(struct svga_context *svga, sbuf = svga_buffer(buf); assert(!sbuf->map.count); + assert(!sbuf->user); if(!sbuf->handle) { ret = svga_buffer_create_host_surface(ss, sbuf); if(ret != PIPE_OK) return NULL; - - ret = svga_buffer_update_hw(ss, sbuf); - if(ret != PIPE_OK) - return NULL; } - if(!sbuf->needs_flush && sbuf->hw.num_ranges) { - /* Queue the buffer for flushing */ - ret = svga_buffer_upload_command(svga, sbuf); - if(ret != PIPE_OK) - /* XXX: Should probably have a richer return value */ - return NULL; + assert(sbuf->handle); + + if (sbuf->map.num_ranges) { + if (!sbuf->dma.pending) { + /* + * No pending DMA upload yet, so insert a DMA upload command now. + */ + + /* + * Migrate the data from swbuf -> hwbuf if necessary. + */ + ret = svga_buffer_update_hw(ss, sbuf); + if (ret == PIPE_OK) { + /* + * Queue a dma command. + */ - assert(sbuf->hw.svga == svga); + ret = svga_buffer_upload_command(svga, sbuf); + if (ret == PIPE_ERROR_OUT_OF_MEMORY) { + svga_context_flush(svga, NULL); + ret = svga_buffer_upload_command(svga, sbuf); + assert(ret == PIPE_OK); + } + if (ret == PIPE_OK) { + sbuf->dma.pending = TRUE; + assert(!sbuf->head.prev && !sbuf->head.next); + LIST_ADDTAIL(&sbuf->head, &svga->dirty_buffers); + } + } + else if (ret == PIPE_ERROR_OUT_OF_MEMORY) { + /* + * The buffer is too big to fit in the GMR aperture, so break it in + * smaller pieces. + */ + ret = svga_buffer_upload_piecewise(ss, svga, sbuf); + } - sbuf->needs_flush = TRUE; - assert(sbuf->head.prev && sbuf->head.next); - LIST_DEL(&sbuf->head); - LIST_ADDTAIL(&sbuf->head, &svga->dirty_buffers); + if (ret != PIPE_OK) { + /* + * Something unexpected happened above. There is very little that + * we can do other than proceeding while ignoring the dirty ranges. + */ + assert(0); + sbuf->map.num_ranges = 0; + } + } + else { + /* + * There a pending dma already. Make sure it is from this context. + */ + assert(sbuf->dma.svga == svga); + } } + assert(!sbuf->map.num_ranges || sbuf->dma.pending); + return sbuf->handle; } + struct pipe_buffer * svga_screen_buffer_wrap_surface(struct pipe_screen *screen, enum SVGA3dSurfaceFormat format, @@ -814,7 +880,7 @@ svga_context_flush_buffers(struct svga_context *svga) sbuf = LIST_ENTRY(struct svga_buffer, curr, head); assert(p_atomic_read(&sbuf->base.reference.count) != 0); - assert(sbuf->needs_flush); + assert(sbuf->dma.pending); svga_buffer_upload_flush(svga, sbuf);