1/* 2 * Copyright 2014, 2015 Red Hat. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "util/u_inlines.h" 25#include "util/u_memory.h" 26#include "virgl_context.h" 27#include "virgl_resource.h" 28#include "virgl_screen.h" 29 30static void *virgl_buffer_transfer_map(struct pipe_context *ctx, 31 struct pipe_resource *resource, 32 unsigned level, 33 unsigned usage, 34 const struct pipe_box *box, 35 struct pipe_transfer **transfer) 36{ 37 struct virgl_context *vctx = virgl_context(ctx); 38 struct virgl_screen *vs = virgl_screen(ctx->screen); 39 struct virgl_resource *vbuf = virgl_resource(resource); 40 struct virgl_transfer *trans; 41 bool readback; 42 bool flush = false; 43 44 trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource, 45 &vbuf->metadata, level, usage, box); 46 if (usage & PIPE_TRANSFER_READ) 47 flush = true; 48 else 49 flush = virgl_res_needs_flush(vctx, trans); 50 51 if (flush) 52 ctx->flush(ctx, NULL, 0); 53 54 readback = virgl_res_needs_readback(vctx, vbuf, usage, 0); 55 if (readback) 56 vs->vws->transfer_get(vs->vws, vbuf->hw_res, box, trans->base.stride, 57 trans->l_stride, trans->offset, level); 58 59 if (readback || flush) 60 vs->vws->resource_wait(vs->vws, vbuf->hw_res); 61 62 trans->hw_res_map = vs->vws->resource_map(vs->vws, vbuf->hw_res); 63 if (!trans->hw_res_map) { 64 virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); 65 return NULL; 66 } 67 68 *transfer = &trans->base; 69 return trans->hw_res_map + trans->offset; 70} 71 72static void virgl_buffer_transfer_unmap(struct pipe_context *ctx, 73 struct pipe_transfer *transfer) 74{ 75 struct virgl_context *vctx = virgl_context(ctx); 76 struct virgl_transfer *trans = virgl_transfer(transfer); 77 78 if (trans->base.usage & PIPE_TRANSFER_WRITE) { 79 if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { 80 if (trans->range.end <= trans->range.start) { 81 virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); 82 return; 83 } 84 85 transfer->box.x += trans->range.start; 86 transfer->box.width = trans->range.end - trans->range.start; 87 trans->offset = transfer->box.x; 88 } 89 90 virgl_transfer_queue_unmap(&vctx->queue, trans); 91 } else 92 virgl_resource_destroy_transfer(&vctx->transfer_pool, trans); 93} 94 95static void virgl_buffer_transfer_flush_region(struct pipe_context *ctx, 96 struct pipe_transfer *transfer, 97 const struct pipe_box *box) 98{ 99 struct virgl_transfer *trans = virgl_transfer(transfer); 100 101 /* 102 * FIXME: This is not optimal. For example, 103 * 104 * glMapBufferRange(.., 0, 100, GL_MAP_FLUSH_EXPLICIT_BIT) 105 * glFlushMappedBufferRange(.., 25, 30) 106 * glFlushMappedBufferRange(.., 65, 70) 107 * 108 * We'll end up flushing 25 --> 70. 109 */ 110 util_range_add(&trans->range, box->x, box->x + box->width); 111} 112 113static const struct u_resource_vtbl virgl_buffer_vtbl = 114{ 115 u_default_resource_get_handle, /* get_handle */ 116 virgl_resource_destroy, /* resource_destroy */ 117 virgl_buffer_transfer_map, /* transfer_map */ 118 virgl_buffer_transfer_flush_region, /* transfer_flush_region */ 119 virgl_buffer_transfer_unmap, /* transfer_unmap */ 120}; 121 122void virgl_buffer_init(struct virgl_resource *res) 123{ 124 res->u.vtbl = &virgl_buffer_vtbl; 125} 126