Path: blob/21.2-virgl/src/gallium/winsys/svga/drm/vmw_buffer.c
4573 views
/**********************************************************1* Copyright 2009-2015 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23**********************************************************/2425/**26* @file27* SVGA buffer manager for Guest Memory Regions (GMRs).28*29* GMRs are used for pixel and vertex data upload/download to/from the virtual30* SVGA hardware. There is a limited number of GMRs available, and31* creating/destroying them is also a slow operation so we must suballocate32* them.33*34* This file implements a pipebuffer library's buffer manager, so that we can35* use pipepbuffer's suballocation, fencing, and debugging facilities with GMRs.36*37* @author Jose Fonseca <[email protected]>38*/394041#include "svga_cmd.h"4243#include "util/u_inlines.h"44#include "util/u_memory.h"45#include "pipebuffer/pb_buffer.h"46#include "pipebuffer/pb_bufmgr.h"4748#include "svga_winsys.h"4950#include "vmw_screen.h"51#include "vmw_buffer.h"5253struct vmw_gmr_bufmgr;545556struct vmw_gmr_buffer57{58struct pb_buffer base;5960struct vmw_gmr_bufmgr *mgr;6162struct vmw_region *region;63void *map;64unsigned map_flags;65unsigned map_count;66};676869extern const struct pb_vtbl vmw_gmr_buffer_vtbl;707172static inline struct vmw_gmr_buffer *73vmw_gmr_buffer(struct pb_buffer *buf)74{75assert(buf);76assert(buf->vtbl == &vmw_gmr_buffer_vtbl);77return (struct vmw_gmr_buffer *)buf;78}798081struct vmw_gmr_bufmgr82{83struct pb_manager base;8485struct vmw_winsys_screen *vws;86};878889static inline struct vmw_gmr_bufmgr *90vmw_gmr_bufmgr(struct pb_manager *mgr)91{92assert(mgr);9394/* Make sure our extra flags don't collide with pipebuffer's flags */95STATIC_ASSERT((VMW_BUFFER_USAGE_SHARED & PB_USAGE_ALL) == 0);96STATIC_ASSERT((VMW_BUFFER_USAGE_SYNC & PB_USAGE_ALL) == 0);9798return (struct vmw_gmr_bufmgr *)mgr;99}100101102static void103vmw_gmr_buffer_destroy(void *winsys, struct pb_buffer *_buf)104{105struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf);106107assert(buf->map_count == 0);108if (buf->map) {109assert(buf->mgr->vws->cache_maps);110vmw_ioctl_region_unmap(buf->region);111}112113vmw_ioctl_region_destroy(buf->region);114115FREE(buf);116}117118119static void *120vmw_gmr_buffer_map(struct pb_buffer *_buf,121enum pb_usage_flags flags,122void *flush_ctx)123{124struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf);125int ret;126127if (!buf->map)128buf->map = vmw_ioctl_region_map(buf->region);129130if (!buf->map)131return NULL;132133if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) &&134!(flags & PB_USAGE_UNSYNCHRONIZED)) {135ret = vmw_ioctl_syncforcpu(buf->region,136!!(flags & PB_USAGE_DONTBLOCK),137!(flags & PB_USAGE_CPU_WRITE),138FALSE);139if (ret)140return NULL;141}142143buf->map_count++;144return buf->map;145}146147148static void149vmw_gmr_buffer_unmap(struct pb_buffer *_buf)150{151struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf);152enum pb_usage_flags flags = buf->map_flags;153154if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) &&155!(flags & PB_USAGE_UNSYNCHRONIZED)) {156vmw_ioctl_releasefromcpu(buf->region,157!(flags & PB_USAGE_CPU_WRITE),158FALSE);159}160161assert(buf->map_count > 0);162if (!--buf->map_count && !buf->mgr->vws->cache_maps) {163vmw_ioctl_region_unmap(buf->region);164buf->map = NULL;165}166}167168169static void170vmw_gmr_buffer_get_base_buffer(struct pb_buffer *buf,171struct pb_buffer **base_buf,172pb_size *offset)173{174*base_buf = buf;175*offset = 0;176}177178179static enum pipe_error180vmw_gmr_buffer_validate( struct pb_buffer *_buf,181struct pb_validate *vl,182enum pb_usage_flags flags )183{184/* Always pinned */185return PIPE_OK;186}187188189static void190vmw_gmr_buffer_fence( struct pb_buffer *_buf,191struct pipe_fence_handle *fence )192{193/* We don't need to do anything, as the pipebuffer library194* will take care of delaying the destruction of fenced buffers */195}196197198const struct pb_vtbl vmw_gmr_buffer_vtbl = {199vmw_gmr_buffer_destroy,200vmw_gmr_buffer_map,201vmw_gmr_buffer_unmap,202vmw_gmr_buffer_validate,203vmw_gmr_buffer_fence,204vmw_gmr_buffer_get_base_buffer205};206207208static struct pb_buffer *209vmw_gmr_bufmgr_create_buffer(struct pb_manager *_mgr,210pb_size size,211const struct pb_desc *pb_desc)212{213struct vmw_gmr_bufmgr *mgr = vmw_gmr_bufmgr(_mgr);214struct vmw_winsys_screen *vws = mgr->vws;215struct vmw_gmr_buffer *buf;216const struct vmw_buffer_desc *desc =217(const struct vmw_buffer_desc *) pb_desc;218219buf = CALLOC_STRUCT(vmw_gmr_buffer);220if(!buf)221goto error1;222223pipe_reference_init(&buf->base.reference, 1);224buf->base.alignment_log2 = util_logbase2(pb_desc->alignment);225buf->base.usage = pb_desc->usage & ~VMW_BUFFER_USAGE_SHARED;226buf->base.vtbl = &vmw_gmr_buffer_vtbl;227buf->mgr = mgr;228buf->base.size = size;229if ((pb_desc->usage & VMW_BUFFER_USAGE_SHARED) && desc->region) {230buf->region = desc->region;231} else {232buf->region = vmw_ioctl_region_create(vws, size);233if(!buf->region)234goto error2;235}236237return &buf->base;238error2:239FREE(buf);240error1:241return NULL;242}243244245static void246vmw_gmr_bufmgr_flush(struct pb_manager *mgr)247{248/* No-op */249}250251252static void253vmw_gmr_bufmgr_destroy(struct pb_manager *_mgr)254{255struct vmw_gmr_bufmgr *mgr = vmw_gmr_bufmgr(_mgr);256FREE(mgr);257}258259260struct pb_manager *261vmw_gmr_bufmgr_create(struct vmw_winsys_screen *vws)262{263struct vmw_gmr_bufmgr *mgr;264265mgr = CALLOC_STRUCT(vmw_gmr_bufmgr);266if(!mgr)267return NULL;268269mgr->base.destroy = vmw_gmr_bufmgr_destroy;270mgr->base.create_buffer = vmw_gmr_bufmgr_create_buffer;271mgr->base.flush = vmw_gmr_bufmgr_flush;272273mgr->vws = vws;274275return &mgr->base;276}277278279boolean280vmw_gmr_bufmgr_region_ptr(struct pb_buffer *buf,281struct SVGAGuestPtr *ptr)282{283struct pb_buffer *base_buf;284pb_size offset = 0;285struct vmw_gmr_buffer *gmr_buf;286287pb_get_base_buffer( buf, &base_buf, &offset );288289gmr_buf = vmw_gmr_buffer(base_buf);290if(!gmr_buf)291return FALSE;292293*ptr = vmw_ioctl_region_ptr(gmr_buf->region);294295ptr->offset += offset;296297return TRUE;298}299300#ifdef DEBUG301struct svga_winsys_buffer {302struct pb_buffer *pb_buf;303struct debug_flush_buf *fbuf;304};305306struct pb_buffer *307vmw_pb_buffer(struct svga_winsys_buffer *buffer)308{309assert(buffer);310return buffer->pb_buf;311}312313struct svga_winsys_buffer *314vmw_svga_winsys_buffer_wrap(struct pb_buffer *buffer)315{316struct svga_winsys_buffer *buf;317318if (!buffer)319return NULL;320321buf = CALLOC_STRUCT(svga_winsys_buffer);322if (!buf) {323pb_reference(&buffer, NULL);324return NULL;325}326327buf->pb_buf = buffer;328buf->fbuf = debug_flush_buf_create(FALSE, VMW_DEBUG_FLUSH_STACK);329return buf;330}331332struct debug_flush_buf *333vmw_debug_flush_buf(struct svga_winsys_buffer *buffer)334{335return buffer->fbuf;336}337338#endif339340void341vmw_svga_winsys_buffer_destroy(struct svga_winsys_screen *sws,342struct svga_winsys_buffer *buf)343{344struct pb_buffer *pbuf = vmw_pb_buffer(buf);345(void)sws;346pb_reference(&pbuf, NULL);347#ifdef DEBUG348debug_flush_buf_reference(&buf->fbuf, NULL);349FREE(buf);350#endif351}352353void *354vmw_svga_winsys_buffer_map(struct svga_winsys_screen *sws,355struct svga_winsys_buffer *buf,356enum pipe_map_flags flags)357{358void *map;359360(void)sws;361if (flags & PIPE_MAP_UNSYNCHRONIZED)362flags &= ~PIPE_MAP_DONTBLOCK;363364/* NOTE: we're passing PIPE_MAP_x flags instead of365* PB_USAGE_x flags here. We should probably fix that.366*/367STATIC_ASSERT((unsigned) PB_USAGE_CPU_READ ==368(unsigned) PIPE_MAP_READ);369STATIC_ASSERT((unsigned) PB_USAGE_CPU_WRITE ==370(unsigned) PIPE_MAP_WRITE);371STATIC_ASSERT((unsigned) PB_USAGE_GPU_READ ==372(unsigned) PIPE_MAP_DIRECTLY);373STATIC_ASSERT((unsigned) PB_USAGE_DONTBLOCK ==374(unsigned) PIPE_MAP_DONTBLOCK);375STATIC_ASSERT((unsigned) PB_USAGE_UNSYNCHRONIZED ==376(unsigned) PIPE_MAP_UNSYNCHRONIZED);377STATIC_ASSERT((unsigned) PB_USAGE_PERSISTENT ==378(unsigned) PIPE_MAP_PERSISTENT);379380map = pb_map(vmw_pb_buffer(buf), flags & PB_USAGE_ALL, NULL);381382#ifdef DEBUG383if (map != NULL)384debug_flush_map(buf->fbuf, flags);385#endif386387return map;388}389390391void392vmw_svga_winsys_buffer_unmap(struct svga_winsys_screen *sws,393struct svga_winsys_buffer *buf)394{395(void)sws;396397#ifdef DEBUG398debug_flush_unmap(buf->fbuf);399#endif400401pb_unmap(vmw_pb_buffer(buf));402}403404405