1/********************************************************** 2 * Copyright 2009-2015 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/** 27 * @file 28 * SVGA buffer manager for Guest Memory Regions (GMRs). 29 * 30 * GMRs are used for pixel and vertex data upload/download to/from the virtual 31 * SVGA hardware. There is a limited number of GMRs available, and 32 * creating/destroying them is also a slow operation so we must suballocate 33 * them. 34 * 35 * This file implements a pipebuffer library's buffer manager, so that we can 36 * use pipepbuffer's suballocation, fencing, and debugging facilities with GMRs. 37 * 38 * @author Jose Fonseca <jfonseca@vmware.com> 39 */ 40 41 42#include "svga_cmd.h" 43 44#include "util/u_inlines.h" 45#include "util/u_memory.h" 46#include "pipebuffer/pb_buffer.h" 47#include "pipebuffer/pb_bufmgr.h" 48 49#include "svga_winsys.h" 50 51#include "vmw_screen.h" 52#include "vmw_buffer.h" 53 54struct vmw_gmr_bufmgr; 55 56 57struct vmw_gmr_buffer 58{ 59 struct pb_buffer base; 60 61 struct vmw_gmr_bufmgr *mgr; 62 63 struct vmw_region *region; 64 void *map; 65 unsigned map_flags; 66}; 67 68 69extern const struct pb_vtbl vmw_gmr_buffer_vtbl; 70 71 72static inline struct vmw_gmr_buffer * 73vmw_gmr_buffer(struct pb_buffer *buf) 74{ 75 assert(buf); 76 assert(buf->vtbl == &vmw_gmr_buffer_vtbl); 77 return (struct vmw_gmr_buffer *)buf; 78} 79 80 81struct vmw_gmr_bufmgr 82{ 83 struct pb_manager base; 84 85 struct vmw_winsys_screen *vws; 86}; 87 88 89static inline struct vmw_gmr_bufmgr * 90vmw_gmr_bufmgr(struct pb_manager *mgr) 91{ 92 assert(mgr); 93 94 /* Make sure our extra flags don't collide with pipebuffer's flags */ 95 STATIC_ASSERT((VMW_BUFFER_USAGE_SHARED & PB_USAGE_ALL) == 0); 96 STATIC_ASSERT((VMW_BUFFER_USAGE_SYNC & PB_USAGE_ALL) == 0); 97 98 return (struct vmw_gmr_bufmgr *)mgr; 99} 100 101 102static void 103vmw_gmr_buffer_destroy(struct pb_buffer *_buf) 104{ 105 struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf); 106 107 vmw_ioctl_region_unmap(buf->region); 108 109 vmw_ioctl_region_destroy(buf->region); 110 111 FREE(buf); 112} 113 114 115static void * 116vmw_gmr_buffer_map(struct pb_buffer *_buf, 117 enum pb_usage_flags flags, 118 void *flush_ctx) 119{ 120 struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf); 121 int ret; 122 123 if (!buf->map) 124 buf->map = vmw_ioctl_region_map(buf->region); 125 126 if (!buf->map) 127 return NULL; 128 129 130 if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) && 131 !(flags & PB_USAGE_UNSYNCHRONIZED)) { 132 ret = vmw_ioctl_syncforcpu(buf->region, 133 !!(flags & PB_USAGE_DONTBLOCK), 134 !(flags & PB_USAGE_CPU_WRITE), 135 FALSE); 136 if (ret) 137 return NULL; 138 } 139 140 return buf->map; 141} 142 143 144static void 145vmw_gmr_buffer_unmap(struct pb_buffer *_buf) 146{ 147 struct vmw_gmr_buffer *buf = vmw_gmr_buffer(_buf); 148 enum pb_usage_flags flags = buf->map_flags; 149 150 if ((_buf->usage & VMW_BUFFER_USAGE_SYNC) && 151 !(flags & PB_USAGE_UNSYNCHRONIZED)) { 152 vmw_ioctl_releasefromcpu(buf->region, 153 !(flags & PB_USAGE_CPU_WRITE), 154 FALSE); 155 } 156} 157 158 159static void 160vmw_gmr_buffer_get_base_buffer(struct pb_buffer *buf, 161 struct pb_buffer **base_buf, 162 pb_size *offset) 163{ 164 *base_buf = buf; 165 *offset = 0; 166} 167 168 169static enum pipe_error 170vmw_gmr_buffer_validate( struct pb_buffer *_buf, 171 struct pb_validate *vl, 172 enum pb_usage_flags flags ) 173{ 174 /* Always pinned */ 175 return PIPE_OK; 176} 177 178 179static void 180vmw_gmr_buffer_fence( struct pb_buffer *_buf, 181 struct pipe_fence_handle *fence ) 182{ 183 /* We don't need to do anything, as the pipebuffer library 184 * will take care of delaying the destruction of fenced buffers */ 185} 186 187 188const struct pb_vtbl vmw_gmr_buffer_vtbl = { 189 vmw_gmr_buffer_destroy, 190 vmw_gmr_buffer_map, 191 vmw_gmr_buffer_unmap, 192 vmw_gmr_buffer_validate, 193 vmw_gmr_buffer_fence, 194 vmw_gmr_buffer_get_base_buffer 195}; 196 197 198static struct pb_buffer * 199vmw_gmr_bufmgr_create_buffer(struct pb_manager *_mgr, 200 pb_size size, 201 const struct pb_desc *pb_desc) 202{ 203 struct vmw_gmr_bufmgr *mgr = vmw_gmr_bufmgr(_mgr); 204 struct vmw_winsys_screen *vws = mgr->vws; 205 struct vmw_gmr_buffer *buf; 206 const struct vmw_buffer_desc *desc = 207 (const struct vmw_buffer_desc *) pb_desc; 208 209 buf = CALLOC_STRUCT(vmw_gmr_buffer); 210 if(!buf) 211 goto error1; 212 213 pipe_reference_init(&buf->base.reference, 1); 214 buf->base.alignment = pb_desc->alignment; 215 buf->base.usage = pb_desc->usage & ~VMW_BUFFER_USAGE_SHARED; 216 buf->base.vtbl = &vmw_gmr_buffer_vtbl; 217 buf->mgr = mgr; 218 buf->base.size = size; 219 if ((pb_desc->usage & VMW_BUFFER_USAGE_SHARED) && desc->region) { 220 buf->region = desc->region; 221 } else { 222 buf->region = vmw_ioctl_region_create(vws, size); 223 if(!buf->region) 224 goto error2; 225 } 226 227 return &buf->base; 228error2: 229 FREE(buf); 230error1: 231 return NULL; 232} 233 234 235static void 236vmw_gmr_bufmgr_flush(struct pb_manager *mgr) 237{ 238 /* No-op */ 239} 240 241 242static void 243vmw_gmr_bufmgr_destroy(struct pb_manager *_mgr) 244{ 245 struct vmw_gmr_bufmgr *mgr = vmw_gmr_bufmgr(_mgr); 246 FREE(mgr); 247} 248 249 250struct pb_manager * 251vmw_gmr_bufmgr_create(struct vmw_winsys_screen *vws) 252{ 253 struct vmw_gmr_bufmgr *mgr; 254 255 mgr = CALLOC_STRUCT(vmw_gmr_bufmgr); 256 if(!mgr) 257 return NULL; 258 259 mgr->base.destroy = vmw_gmr_bufmgr_destroy; 260 mgr->base.create_buffer = vmw_gmr_bufmgr_create_buffer; 261 mgr->base.flush = vmw_gmr_bufmgr_flush; 262 263 mgr->vws = vws; 264 265 return &mgr->base; 266} 267 268 269boolean 270vmw_gmr_bufmgr_region_ptr(struct pb_buffer *buf, 271 struct SVGAGuestPtr *ptr) 272{ 273 struct pb_buffer *base_buf; 274 pb_size offset = 0; 275 struct vmw_gmr_buffer *gmr_buf; 276 277 pb_get_base_buffer( buf, &base_buf, &offset ); 278 279 gmr_buf = vmw_gmr_buffer(base_buf); 280 if(!gmr_buf) 281 return FALSE; 282 283 *ptr = vmw_ioctl_region_ptr(gmr_buf->region); 284 285 ptr->offset += offset; 286 287 return TRUE; 288} 289 290#ifdef DEBUG 291struct svga_winsys_buffer { 292 struct pb_buffer *pb_buf; 293 struct debug_flush_buf *fbuf; 294}; 295 296struct pb_buffer * 297vmw_pb_buffer(struct svga_winsys_buffer *buffer) 298{ 299 assert(buffer); 300 return buffer->pb_buf; 301} 302 303struct svga_winsys_buffer * 304vmw_svga_winsys_buffer_wrap(struct pb_buffer *buffer) 305{ 306 struct svga_winsys_buffer *buf; 307 308 if (!buffer) 309 return NULL; 310 311 buf = CALLOC_STRUCT(svga_winsys_buffer); 312 if (!buf) { 313 pb_reference(&buffer, NULL); 314 return NULL; 315 } 316 317 buf->pb_buf = buffer; 318 buf->fbuf = debug_flush_buf_create(TRUE, VMW_DEBUG_FLUSH_STACK); 319 return buf; 320} 321 322struct debug_flush_buf * 323vmw_debug_flush_buf(struct svga_winsys_buffer *buffer) 324{ 325 return buffer->fbuf; 326} 327 328#endif 329 330void 331vmw_svga_winsys_buffer_destroy(struct svga_winsys_screen *sws, 332 struct svga_winsys_buffer *buf) 333{ 334 struct pb_buffer *pbuf = vmw_pb_buffer(buf); 335 (void)sws; 336 pb_reference(&pbuf, NULL); 337#ifdef DEBUG 338 debug_flush_buf_reference(&buf->fbuf, NULL); 339 FREE(buf); 340#endif 341} 342 343void * 344vmw_svga_winsys_buffer_map(struct svga_winsys_screen *sws, 345 struct svga_winsys_buffer *buf, 346 enum pipe_transfer_usage flags) 347{ 348 void *map; 349 350 (void)sws; 351 if (flags & PIPE_TRANSFER_UNSYNCHRONIZED) 352 flags &= ~PIPE_TRANSFER_DONTBLOCK; 353 354 /* NOTE: we're passing PIPE_TRANSFER_x flags instead of 355 * PB_USAGE_x flags here. We should probably fix that. 356 */ 357 STATIC_ASSERT((unsigned) PB_USAGE_CPU_READ == 358 (unsigned) PIPE_TRANSFER_READ); 359 STATIC_ASSERT((unsigned) PB_USAGE_CPU_WRITE == 360 (unsigned) PIPE_TRANSFER_WRITE); 361 STATIC_ASSERT((unsigned) PB_USAGE_GPU_READ == 362 (unsigned) PIPE_TRANSFER_MAP_DIRECTLY); 363 STATIC_ASSERT((unsigned) PB_USAGE_DONTBLOCK == 364 (unsigned) PIPE_TRANSFER_DONTBLOCK); 365 STATIC_ASSERT((unsigned) PB_USAGE_UNSYNCHRONIZED == 366 (unsigned) PIPE_TRANSFER_UNSYNCHRONIZED); 367 368 map = pb_map(vmw_pb_buffer(buf), flags, NULL); 369 370#ifdef DEBUG 371 if (map != NULL) 372 debug_flush_map(buf->fbuf, flags); 373#endif 374 375 return map; 376} 377 378 379void 380vmw_svga_winsys_buffer_unmap(struct svga_winsys_screen *sws, 381 struct svga_winsys_buffer *buf) 382{ 383 (void)sws; 384 385#ifdef DEBUG 386 debug_flush_unmap(buf->fbuf); 387#endif 388 389 pb_unmap(vmw_pb_buffer(buf)); 390} 391