1 /********************************************************** 2 * Copyright 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 27 #include "svga_cmd.h" 28 29 #include "util/u_debug.h" 30 #include "util/u_memory.h" 31 #include "util/u_debug_stack.h" 32 #include "pipebuffer/pb_buffer.h" 33 #include "pipebuffer/pb_validate.h" 34 35 #include "svga_winsys.h" 36 #include "vmw_context.h" 37 #include "vmw_screen.h" 38 #include "vmw_buffer.h" 39 #include "vmw_surface.h" 40 #include "vmw_fence.h" 41 42 #define VMW_COMMAND_SIZE (64*1024) 43 #define VMW_SURFACE_RELOCS (1024) 44 #define VMW_REGION_RELOCS (512) 45 46 #define VMW_MUST_FLUSH_STACK 8 47 48 struct vmw_region_relocation 49 { 50 struct SVGAGuestPtr *where; 51 struct pb_buffer *buffer; 52 /* TODO: put offset info inside where */ 53 uint32 offset; 54 }; 55 56 struct vmw_svga_winsys_context 57 { 58 struct svga_winsys_context base; 59 60 struct vmw_winsys_screen *vws; 61 62 #ifdef DEBUG 63 boolean must_flush; 64 struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK]; 65 #endif 66 67 struct { 68 uint8_t buffer[VMW_COMMAND_SIZE]; 69 uint32_t size; 70 uint32_t used; 71 uint32_t reserved; 72 } command; 73 74 struct { 75 struct vmw_svga_winsys_surface *handles[VMW_SURFACE_RELOCS]; 76 uint32_t size; 77 uint32_t used; 78 uint32_t staged; 79 uint32_t reserved; 80 } surface; 81 82 struct { 83 struct vmw_region_relocation relocs[VMW_REGION_RELOCS]; 84 uint32_t size; 85 uint32_t used; 86 uint32_t staged; 87 uint32_t reserved; 88 } region; 89 90 struct pb_validate *validate; 91 92 /** 93 * The amount of GMR that is referred by the commands currently batched 94 * in the context. 95 */ 96 uint32_t seen_regions; 97 98 /** 99 * Whether this context should fail to reserve more commands, not because it 100 * ran out of command space, but because a substantial ammount of GMR was 101 * referred. 102 */ 103 boolean preemptive_flush; 104 }; 105 106 107 static INLINE struct vmw_svga_winsys_context * 108 vmw_svga_winsys_context(struct svga_winsys_context *swc) 109 { 110 assert(swc); 111 return (struct vmw_svga_winsys_context *)swc; 112 } 113 114 115 static INLINE unsigned 116 vmw_translate_to_pb_flags(unsigned flags) 117 { 118 unsigned f = 0; 119 if (flags & SVGA_RELOC_READ) 120 f |= PB_USAGE_GPU_READ; 121 122 if (flags & SVGA_RELOC_WRITE) 123 f |= PB_USAGE_GPU_WRITE; 124 125 return f; 126 } 127 128 static enum pipe_error 129 vmw_swc_flush(struct svga_winsys_context *swc, 130 struct pipe_fence_handle **pfence) 131 { 132 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 133 struct pipe_fence_handle *fence = NULL; 134 unsigned i; 135 enum pipe_error ret; 136 137 ret = pb_validate_validate(vswc->validate); 138 assert(ret == PIPE_OK); 139 if(ret == PIPE_OK) { 140 141 /* Apply relocations */ 142 for(i = 0; i < vswc->region.used; ++i) { 143 struct vmw_region_relocation *reloc = &vswc->region.relocs[i]; 144 struct SVGAGuestPtr ptr; 145 146 if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr)) 147 assert(0); 148 149 ptr.offset += reloc->offset; 150 151 *reloc->where = ptr; 152 } 153 154 if (vswc->command.used || pfence != NULL) 155 vmw_ioctl_command(vswc->vws, 156 vswc->base.cid, 157 0, 158 vswc->command.buffer, 159 vswc->command.used, 160 &fence); 161 162 pb_validate_fence(vswc->validate, fence); 163 } 164 165 vswc->command.used = 0; 166 vswc->command.reserved = 0; 167 168 for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) { 169 struct vmw_svga_winsys_surface *vsurf = 170 vswc->surface.handles[i]; 171 p_atomic_dec(&vsurf->validated); 172 vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL); 173 } 174 175 vswc->surface.used = 0; 176 vswc->surface.reserved = 0; 177 178 for(i = 0; i < vswc->region.used + vswc->region.staged; ++i) { 179 pb_reference(&vswc->region.relocs[i].buffer, NULL); 180 } 181 182 vswc->region.used = 0; 183 vswc->region.reserved = 0; 184 185 #ifdef DEBUG 186 vswc->must_flush = FALSE; 187 #endif 188 vswc->preemptive_flush = FALSE; 189 vswc->seen_regions = 0; 190 191 if(pfence) 192 vmw_fence_reference(vswc->vws, pfence, fence); 193 194 vmw_fence_reference(vswc->vws, &fence, NULL); 195 196 return ret; 197 } 198 199 200 static void * 201 vmw_swc_reserve(struct svga_winsys_context *swc, 202 uint32_t nr_bytes, uint32_t nr_relocs ) 203 { 204 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 205 206 #ifdef DEBUG 207 /* Check if somebody forgot to check the previous failure */ 208 if(vswc->must_flush) { 209 debug_printf("Forgot to flush:\n"); 210 debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK); 211 assert(!vswc->must_flush); 212 } 213 #endif 214 215 assert(nr_bytes <= vswc->command.size); 216 if(nr_bytes > vswc->command.size) 217 return NULL; 218 219 if(vswc->preemptive_flush || 220 vswc->command.used + nr_bytes > vswc->command.size || 221 vswc->surface.used + nr_relocs > vswc->surface.size || 222 vswc->region.used + nr_relocs > vswc->region.size) { 223 #ifdef DEBUG 224 vswc->must_flush = TRUE; 225 debug_backtrace_capture(vswc->must_flush_stack, 1, 226 VMW_MUST_FLUSH_STACK); 227 #endif 228 return NULL; 229 } 230 231 assert(vswc->command.used + nr_bytes <= vswc->command.size); 232 assert(vswc->surface.used + nr_relocs <= vswc->surface.size); 233 assert(vswc->region.used + nr_relocs <= vswc->region.size); 234 235 vswc->command.reserved = nr_bytes; 236 vswc->surface.reserved = nr_relocs; 237 vswc->surface.staged = 0; 238 vswc->region.reserved = nr_relocs; 239 vswc->region.staged = 0; 240 241 return vswc->command.buffer + vswc->command.used; 242 } 243 244 245 static void 246 vmw_swc_surface_relocation(struct svga_winsys_context *swc, 247 uint32 *where, 248 struct svga_winsys_surface *surface, 249 unsigned flags) 250 { 251 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 252 struct vmw_svga_winsys_surface *vsurf; 253 254 if(!surface) { 255 *where = SVGA3D_INVALID_ID; 256 return; 257 } 258 259 assert(vswc->surface.staged < vswc->surface.reserved); 260 261 vsurf = vmw_svga_winsys_surface(surface); 262 263 *where = vsurf->sid; 264 265 vmw_svga_winsys_surface_reference(&vswc->surface.handles[vswc->surface.used + vswc->surface.staged], vsurf); 266 p_atomic_inc(&vsurf->validated); 267 ++vswc->surface.staged; 268 } 269 270 271 static void 272 vmw_swc_region_relocation(struct svga_winsys_context *swc, 273 struct SVGAGuestPtr *where, 274 struct svga_winsys_buffer *buffer, 275 uint32 offset, 276 unsigned flags) 277 { 278 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 279 struct vmw_region_relocation *reloc; 280 unsigned translated_flags; 281 enum pipe_error ret; 282 283 assert(vswc->region.staged < vswc->region.reserved); 284 285 reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged]; 286 reloc->where = where; 287 pb_reference(&reloc->buffer, vmw_pb_buffer(buffer)); 288 reloc->offset = offset; 289 290 ++vswc->region.staged; 291 292 translated_flags = vmw_translate_to_pb_flags(flags); 293 ret = pb_validate_add_buffer(vswc->validate, reloc->buffer, translated_flags); 294 /* TODO: Update pipebuffer to reserve buffers and not fail here */ 295 assert(ret == PIPE_OK); 296 (void)ret; 297 298 /* 299 * Flush preemptively the FIFO commands to keep the GMR working set within 300 * the GMR pool size. 301 * 302 * This is necessary for applications like SPECviewperf that generate huge 303 * amounts of immediate vertex data, so that we don't pile up too much of 304 * that vertex data neither in the guest nor in the host. 305 * 306 * Note that in the current implementation if a region is referred twice in 307 * a command stream, it will be accounted twice. We could detect repeated 308 * regions and count only once, but there is no incentive to do that, since 309 * regions are typically short-lived; always referred in a single command; 310 * and at the worst we just flush the commands a bit sooner, which for the 311 * SVGA virtual device it's not a performance issue since flushing commands 312 * to the FIFO won't cause flushing in the host. 313 */ 314 vswc->seen_regions += reloc->buffer->size; 315 if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/3) 316 vswc->preemptive_flush = TRUE; 317 } 318 319 320 static void 321 vmw_swc_commit(struct svga_winsys_context *swc) 322 { 323 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 324 325 assert(vswc->command.reserved); 326 assert(vswc->command.used + vswc->command.reserved <= vswc->command.size); 327 vswc->command.used += vswc->command.reserved; 328 vswc->command.reserved = 0; 329 330 assert(vswc->surface.staged <= vswc->surface.reserved); 331 assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size); 332 vswc->surface.used += vswc->surface.staged; 333 vswc->surface.staged = 0; 334 vswc->surface.reserved = 0; 335 336 assert(vswc->region.staged <= vswc->region.reserved); 337 assert(vswc->region.used + vswc->region.staged <= vswc->region.size); 338 vswc->region.used += vswc->region.staged; 339 vswc->region.staged = 0; 340 vswc->region.reserved = 0; 341 } 342 343 344 static void 345 vmw_swc_destroy(struct svga_winsys_context *swc) 346 { 347 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc); 348 unsigned i; 349 350 for(i = 0; i < vswc->region.used; ++i) { 351 pb_reference(&vswc->region.relocs[i].buffer, NULL); 352 } 353 354 for(i = 0; i < vswc->surface.used; ++i) { 355 p_atomic_dec(&vswc->surface.handles[i]->validated); 356 vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL); 357 } 358 pb_validate_destroy(vswc->validate); 359 vmw_ioctl_context_destroy(vswc->vws, swc->cid); 360 FREE(vswc); 361 } 362 363 364 struct svga_winsys_context * 365 vmw_svga_winsys_context_create(struct svga_winsys_screen *sws) 366 { 367 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 368 struct vmw_svga_winsys_context *vswc; 369 370 vswc = CALLOC_STRUCT(vmw_svga_winsys_context); 371 if(!vswc) 372 return NULL; 373 374 vswc->base.destroy = vmw_swc_destroy; 375 vswc->base.reserve = vmw_swc_reserve; 376 vswc->base.surface_relocation = vmw_swc_surface_relocation; 377 vswc->base.region_relocation = vmw_swc_region_relocation; 378 vswc->base.commit = vmw_swc_commit; 379 vswc->base.flush = vmw_swc_flush; 380 381 vswc->base.cid = vmw_ioctl_context_create(vws); 382 383 vswc->vws = vws; 384 385 vswc->command.size = VMW_COMMAND_SIZE; 386 vswc->surface.size = VMW_SURFACE_RELOCS; 387 vswc->region.size = VMW_REGION_RELOCS; 388 389 vswc->validate = pb_validate_create(); 390 if(!vswc->validate) { 391 FREE(vswc); 392 return NULL; 393 } 394 395 return &vswc->base; 396 } 397