1/* 2 * Copyright © 2014 Broadcom 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * 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 NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24/** 25 * @file vc4_simulator.c 26 * 27 * Implements VC4 simulation on top of a non-VC4 GEM fd. 28 * 29 * This file's goal is to emulate the VC4 ioctls' behavior in the kernel on 30 * top of the simpenrose software simulator. Generally, VC4 driver BOs have a 31 * GEM-side copy of their contents and a simulator-side memory area that the 32 * GEM contents get copied into during simulation. Once simulation is done, 33 * the simulator's data is copied back out to the GEM BOs, so that rendering 34 * appears on the screen as if actual hardware rendering had been done. 35 * 36 * One of the limitations of this code is that we shouldn't really need a 37 * GEM-side BO for non-window-system BOs. However, do we need unique BO 38 * handles for each of our GEM bos so that this file can look up its state 39 * from the handle passed in at submit ioctl time (also, a couple of places 40 * outside of this file still call ioctls directly on the fd). 41 * 42 * Another limitation is that BO import doesn't work unless the underlying 43 * window system's BO size matches what VC4 is going to use, which of course 44 * doesn't work out in practice. This means that for now, only DRI3 (VC4 45 * makes the winsys BOs) is supported, not DRI2 (window system makes the winys 46 * BOs). 47 */ 48 49#ifdef USE_VC4_SIMULATOR 50 51#include <sys/mman.h> 52#include "xf86drm.h" 53#include "util/u_memory.h" 54#include "util/u_mm.h" 55#include "util/ralloc.h" 56 57#include "vc4_screen.h" 58#include "vc4_cl_dump.h" 59#include "vc4_context.h" 60#include "kernel/vc4_drv.h" 61#include "vc4_simulator_validate.h" 62#include "simpenrose/simpenrose.h" 63 64/** Global (across GEM fds) state for the simulator */ 65static struct vc4_simulator_state { 66 mtx_t mutex; 67 68 void *mem; 69 ssize_t mem_size; 70 struct mem_block *heap; 71 struct mem_block *overflow; 72 73 /** Mapping from GEM handle to struct vc4_simulator_bo * */ 74 struct hash_table *fd_map; 75 76 int refcount; 77} sim_state = { 78 .mutex = _MTX_INITIALIZER_NP, 79}; 80 81/** Per-GEM-fd state for the simulator. */ 82struct vc4_simulator_file { 83 int fd; 84 85 /* This is weird -- we make a "vc4_device" per file, even though on 86 * the kernel side this is a global. We do this so that kernel code 87 * calling us for BO allocation can get to our screen. 88 */ 89 struct drm_device dev; 90 91 /** Mapping from GEM handle to struct vc4_simulator_bo * */ 92 struct hash_table *bo_map; 93}; 94 95/** Wrapper for drm_vc4_bo tracking the simulator-specific state. */ 96struct vc4_simulator_bo { 97 struct drm_vc4_bo base; 98 struct vc4_simulator_file *file; 99 100 /** Area for this BO within sim_state->mem */ 101 struct mem_block *block; 102 103 int handle; 104 105 /* Mapping of the underlying GEM object that we copy in/out of 106 * simulator memory. 107 */ 108 void *gem_vaddr; 109}; 110 111static void * 112int_to_key(int key) 113{ 114 return (void *)(uintptr_t)key; 115} 116 117static struct vc4_simulator_file * 118vc4_get_simulator_file_for_fd(int fd) 119{ 120 struct hash_entry *entry = _mesa_hash_table_search(sim_state.fd_map, 121 int_to_key(fd + 1)); 122 return entry ? entry->data : NULL; 123} 124 125/* A marker placed just after each BO, then checked after rendering to make 126 * sure it's still there. 127 */ 128#define BO_SENTINEL 0xfedcba98 129 130#define PAGE_ALIGN2 12 131 132/** 133 * Allocates space in simulator memory and returns a tracking struct for it 134 * that also contains the drm_gem_cma_object struct. 135 */ 136static struct vc4_simulator_bo * 137vc4_create_simulator_bo(int fd, int handle, unsigned size) 138{ 139 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 140 struct vc4_simulator_bo *sim_bo = rzalloc(file, 141 struct vc4_simulator_bo); 142 struct drm_vc4_bo *bo = &sim_bo->base; 143 struct drm_gem_cma_object *obj = &bo->base; 144 size = align(size, 4096); 145 146 sim_bo->file = file; 147 sim_bo->handle = handle; 148 149 /* Allocate space for the buffer in simulator memory. */ 150 mtx_lock(&sim_state.mutex); 151 sim_bo->block = u_mmAllocMem(sim_state.heap, size + 4, PAGE_ALIGN2, 0); 152 mtx_unlock(&sim_state.mutex); 153 assert(sim_bo->block); 154 155 obj->base.size = size; 156 obj->base.dev = &file->dev; 157 obj->vaddr = sim_state.mem + sim_bo->block->ofs; 158 obj->paddr = simpenrose_hw_addr(obj->vaddr); 159 160 *(uint32_t *)(obj->vaddr + size) = BO_SENTINEL; 161 162 /* A handle of 0 is used for vc4_gem.c internal allocations that 163 * don't need to go in the lookup table. 164 */ 165 if (handle != 0) { 166 mtx_lock(&sim_state.mutex); 167 _mesa_hash_table_insert(file->bo_map, int_to_key(handle), bo); 168 mtx_unlock(&sim_state.mutex); 169 170 /* Map the GEM buffer for copy in/out to the simulator. */ 171 struct drm_mode_map_dumb map = { 172 .handle = handle, 173 }; 174 int ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); 175 if (ret) { 176 fprintf(stderr, "Failed to get MMAP offset: %d\n", 177 errno); 178 abort(); 179 } 180 sim_bo->gem_vaddr = mmap(NULL, obj->base.size, 181 PROT_READ | PROT_WRITE, MAP_SHARED, 182 fd, map.offset); 183 if (sim_bo->gem_vaddr == MAP_FAILED) { 184 fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n", 185 handle, (long long)map.offset, (int)obj->base.size); 186 abort(); 187 } 188 } 189 190 return sim_bo; 191} 192 193static void 194vc4_free_simulator_bo(struct vc4_simulator_bo *sim_bo) 195{ 196 struct vc4_simulator_file *sim_file = sim_bo->file; 197 struct drm_vc4_bo *bo = &sim_bo->base; 198 struct drm_gem_cma_object *obj = &bo->base; 199 200 if (bo->validated_shader) { 201 free(bo->validated_shader->texture_samples); 202 free(bo->validated_shader); 203 } 204 205 if (sim_bo->gem_vaddr) 206 munmap(sim_bo->gem_vaddr, obj->base.size); 207 208 mtx_lock(&sim_state.mutex); 209 u_mmFreeMem(sim_bo->block); 210 if (sim_bo->handle) { 211 _mesa_hash_table_remove_key(sim_file->bo_map, 212 int_to_key(sim_bo->handle)); 213 } 214 mtx_unlock(&sim_state.mutex); 215 ralloc_free(sim_bo); 216} 217 218static struct vc4_simulator_bo * 219vc4_get_simulator_bo(struct vc4_simulator_file *file, int gem_handle) 220{ 221 mtx_lock(&sim_state.mutex); 222 struct hash_entry *entry = 223 _mesa_hash_table_search(file->bo_map, int_to_key(gem_handle)); 224 mtx_unlock(&sim_state.mutex); 225 226 return entry ? entry->data : NULL; 227} 228 229struct drm_gem_cma_object * 230drm_gem_cma_create(struct drm_device *dev, size_t size) 231{ 232 struct vc4_screen *screen = dev->screen; 233 struct vc4_simulator_bo *sim_bo = vc4_create_simulator_bo(screen->fd, 234 0, size); 235 return &sim_bo->base.base; 236} 237 238static int 239vc4_simulator_pin_bos(struct vc4_simulator_file *file, 240 struct vc4_exec_info *exec) 241{ 242 struct drm_vc4_submit_cl *args = exec->args; 243 uint32_t *bo_handles = (uint32_t *)(uintptr_t)args->bo_handles; 244 245 exec->bo_count = args->bo_handle_count; 246 exec->bo = calloc(exec->bo_count, sizeof(void *)); 247 for (int i = 0; i < exec->bo_count; i++) { 248 struct vc4_simulator_bo *sim_bo = 249 vc4_get_simulator_bo(file, bo_handles[i]); 250 struct drm_vc4_bo *drm_bo = &sim_bo->base; 251 struct drm_gem_cma_object *obj = &drm_bo->base; 252 253 memcpy(obj->vaddr, sim_bo->gem_vaddr, obj->base.size); 254 255 exec->bo[i] = obj; 256 } 257 return 0; 258} 259 260static int 261vc4_simulator_unpin_bos(struct vc4_exec_info *exec) 262{ 263 for (int i = 0; i < exec->bo_count; i++) { 264 struct drm_gem_cma_object *obj = exec->bo[i]; 265 struct drm_vc4_bo *drm_bo = to_vc4_bo(&obj->base); 266 struct vc4_simulator_bo *sim_bo = 267 (struct vc4_simulator_bo *)drm_bo; 268 269 assert(*(uint32_t *)(obj->vaddr + 270 obj->base.size) == BO_SENTINEL); 271 if (sim_bo->gem_vaddr) 272 memcpy(sim_bo->gem_vaddr, obj->vaddr, obj->base.size); 273 } 274 275 free(exec->bo); 276 277 return 0; 278} 279 280static void 281vc4_dump_to_file(struct vc4_exec_info *exec) 282{ 283 static int dumpno = 0; 284 struct drm_vc4_get_hang_state *state; 285 struct drm_vc4_get_hang_state_bo *bo_state; 286 unsigned int dump_version = 0; 287 288 if (!(vc4_debug & VC4_DEBUG_DUMP)) 289 return; 290 291 state = calloc(1, sizeof(*state)); 292 293 int unref_count = 0; 294 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 295 unref_head) { 296 unref_count++; 297 } 298 299 /* Add one more for the overflow area that isn't wrapped in a BO. */ 300 state->bo_count = exec->bo_count + unref_count + 1; 301 bo_state = calloc(state->bo_count, sizeof(*bo_state)); 302 303 char *filename = NULL; 304 asprintf(&filename, "vc4-dri-%d.dump", dumpno++); 305 FILE *f = fopen(filename, "w+"); 306 if (!f) { 307 fprintf(stderr, "Couldn't open %s: %s", filename, 308 strerror(errno)); 309 return; 310 } 311 312 fwrite(&dump_version, sizeof(dump_version), 1, f); 313 314 state->ct0ca = exec->ct0ca; 315 state->ct0ea = exec->ct0ea; 316 state->ct1ca = exec->ct1ca; 317 state->ct1ea = exec->ct1ea; 318 state->start_bin = exec->ct0ca; 319 state->start_render = exec->ct1ca; 320 fwrite(state, sizeof(*state), 1, f); 321 322 int i; 323 for (i = 0; i < exec->bo_count; i++) { 324 struct drm_gem_cma_object *cma_bo = exec->bo[i]; 325 bo_state[i].handle = i; /* Not used by the parser. */ 326 bo_state[i].paddr = cma_bo->paddr; 327 bo_state[i].size = cma_bo->base.size; 328 } 329 330 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 331 unref_head) { 332 struct drm_gem_cma_object *cma_bo = &bo->base; 333 bo_state[i].handle = 0; 334 bo_state[i].paddr = cma_bo->paddr; 335 bo_state[i].size = cma_bo->base.size; 336 i++; 337 } 338 339 /* Add the static overflow memory area. */ 340 bo_state[i].handle = exec->bo_count; 341 bo_state[i].paddr = sim_state.overflow->ofs; 342 bo_state[i].size = sim_state.overflow->size; 343 i++; 344 345 fwrite(bo_state, sizeof(*bo_state), state->bo_count, f); 346 347 for (int i = 0; i < exec->bo_count; i++) { 348 struct drm_gem_cma_object *cma_bo = exec->bo[i]; 349 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f); 350 } 351 352 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 353 unref_head) { 354 struct drm_gem_cma_object *cma_bo = &bo->base; 355 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f); 356 } 357 358 void *overflow = calloc(1, sim_state.overflow->size); 359 fwrite(overflow, 1, sim_state.overflow->size, f); 360 free(overflow); 361 362 free(state); 363 free(bo_state); 364 fclose(f); 365} 366 367static int 368vc4_simulator_submit_cl_ioctl(int fd, struct drm_vc4_submit_cl *args) 369{ 370 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 371 struct vc4_exec_info exec; 372 struct drm_device *dev = &file->dev; 373 int ret; 374 375 memset(&exec, 0, sizeof(exec)); 376 list_inithead(&exec.unref_list); 377 378 exec.args = args; 379 380 ret = vc4_simulator_pin_bos(file, &exec); 381 if (ret) 382 return ret; 383 384 ret = vc4_cl_validate(dev, &exec); 385 if (ret) 386 return ret; 387 388 if (vc4_debug & VC4_DEBUG_CL) { 389 fprintf(stderr, "RCL:\n"); 390 vc4_dump_cl(sim_state.mem + exec.ct1ca, 391 exec.ct1ea - exec.ct1ca, true); 392 } 393 394 vc4_dump_to_file(&exec); 395 396 if (exec.ct0ca != exec.ct0ea) { 397 int bfc = simpenrose_do_binning(exec.ct0ca, exec.ct0ea); 398 if (bfc != 1) { 399 fprintf(stderr, "Binning returned %d flushes, should be 1.\n", 400 bfc); 401 fprintf(stderr, "Relocated binning command list:\n"); 402 vc4_dump_cl(sim_state.mem + exec.ct0ca, 403 exec.ct0ea - exec.ct0ca, false); 404 abort(); 405 } 406 } 407 int rfc = simpenrose_do_rendering(exec.ct1ca, exec.ct1ea); 408 if (rfc != 1) { 409 fprintf(stderr, "Rendering returned %d frames, should be 1.\n", 410 rfc); 411 fprintf(stderr, "Relocated render command list:\n"); 412 vc4_dump_cl(sim_state.mem + exec.ct1ca, 413 exec.ct1ea - exec.ct1ca, true); 414 abort(); 415 } 416 417 ret = vc4_simulator_unpin_bos(&exec); 418 if (ret) 419 return ret; 420 421 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec.unref_list, 422 unref_head) { 423 struct vc4_simulator_bo *sim_bo = (struct vc4_simulator_bo *)bo; 424 ASSERTED struct drm_gem_cma_object *obj = &sim_bo->base.base; 425 list_del(&bo->unref_head); 426 assert(*(uint32_t *)(obj->vaddr + obj->base.size) == 427 BO_SENTINEL); 428 vc4_free_simulator_bo(sim_bo); 429 } 430 431 return 0; 432} 433 434/** 435 * Do fixups after a BO has been opened from a handle. 436 * 437 * This could be done at DRM_IOCTL_GEM_OPEN/DRM_IOCTL_GEM_PRIME_FD_TO_HANDLE 438 * time, but we're still using drmPrimeFDToHandle() so we have this helper to 439 * be called afterward instead. 440 */ 441void vc4_simulator_open_from_handle(int fd, int handle, uint32_t size) 442{ 443 vc4_create_simulator_bo(fd, handle, size); 444} 445 446/** 447 * Simulated ioctl(fd, DRM_VC4_CREATE_BO) implementation. 448 * 449 * Making a VC4 BO is just a matter of making a corresponding BO on the host. 450 */ 451static int 452vc4_simulator_create_bo_ioctl(int fd, struct drm_vc4_create_bo *args) 453{ 454 int ret; 455 struct drm_mode_create_dumb create = { 456 .width = 128, 457 .bpp = 8, 458 .height = (args->size + 127) / 128, 459 }; 460 461 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 462 assert(create.size >= args->size); 463 464 args->handle = create.handle; 465 466 vc4_create_simulator_bo(fd, create.handle, args->size); 467 468 return ret; 469} 470 471/** 472 * Simulated ioctl(fd, DRM_VC4_CREATE_SHADER_BO) implementation. 473 * 474 * In simulation we defer shader validation until exec time. Just make a host 475 * BO and memcpy the contents in. 476 */ 477static int 478vc4_simulator_create_shader_bo_ioctl(int fd, 479 struct drm_vc4_create_shader_bo *args) 480{ 481 int ret; 482 struct drm_mode_create_dumb create = { 483 .width = 128, 484 .bpp = 8, 485 .height = (args->size + 127) / 128, 486 }; 487 488 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 489 if (ret) 490 return ret; 491 assert(create.size >= args->size); 492 493 args->handle = create.handle; 494 495 struct vc4_simulator_bo *sim_bo = 496 vc4_create_simulator_bo(fd, create.handle, args->size); 497 struct drm_vc4_bo *drm_bo = &sim_bo->base; 498 struct drm_gem_cma_object *obj = &drm_bo->base; 499 500 /* Copy into the simulator's BO for validation. */ 501 memcpy(obj->vaddr, (void *)(uintptr_t)args->data, args->size); 502 503 /* Copy into the GEM BO to prevent the simulator_pin_bos() from 504 * smashing it. 505 */ 506 memcpy(sim_bo->gem_vaddr, (void *)(uintptr_t)args->data, args->size); 507 508 drm_bo->validated_shader = vc4_validate_shader(obj); 509 if (!drm_bo->validated_shader) 510 return -EINVAL; 511 512 return 0; 513} 514 515/** 516 * Simulated ioctl(fd, DRM_VC4_MMAP_BO) implementation. 517 * 518 * We just pass this straight through to dumb mmap. 519 */ 520static int 521vc4_simulator_mmap_bo_ioctl(int fd, struct drm_vc4_mmap_bo *args) 522{ 523 int ret; 524 struct drm_mode_map_dumb map = { 525 .handle = args->handle, 526 }; 527 528 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); 529 args->offset = map.offset; 530 531 return ret; 532} 533 534static int 535vc4_simulator_gem_close_ioctl(int fd, struct drm_gem_close *args) 536{ 537 /* Free the simulator's internal tracking. */ 538 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 539 struct vc4_simulator_bo *sim_bo = vc4_get_simulator_bo(file, 540 args->handle); 541 542 vc4_free_simulator_bo(sim_bo); 543 544 /* Pass the call on down. */ 545 return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, args); 546} 547 548static int 549vc4_simulator_get_param_ioctl(int fd, struct drm_vc4_get_param *args) 550{ 551 switch (args->param) { 552 case DRM_VC4_PARAM_SUPPORTS_BRANCHES: 553 case DRM_VC4_PARAM_SUPPORTS_ETC1: 554 case DRM_VC4_PARAM_SUPPORTS_THREADED_FS: 555 case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER: 556 args->value = true; 557 return 0; 558 559 case DRM_VC4_PARAM_SUPPORTS_MADVISE: 560 case DRM_VC4_PARAM_SUPPORTS_PERFMON: 561 errno = -EINVAL; 562 return -1; 563 564 case DRM_VC4_PARAM_V3D_IDENT0: 565 args->value = 0x02000000; 566 return 0; 567 568 case DRM_VC4_PARAM_V3D_IDENT1: 569 args->value = 0x00000001; 570 return 0; 571 572 default: 573 fprintf(stderr, "Unknown DRM_IOCTL_VC4_GET_PARAM(%lld)\n", 574 (long long)args->param); 575 abort(); 576 }; 577} 578 579int 580vc4_simulator_ioctl(int fd, unsigned long request, void *args) 581{ 582 switch (request) { 583 case DRM_IOCTL_VC4_SUBMIT_CL: 584 return vc4_simulator_submit_cl_ioctl(fd, args); 585 case DRM_IOCTL_VC4_CREATE_BO: 586 return vc4_simulator_create_bo_ioctl(fd, args); 587 case DRM_IOCTL_VC4_CREATE_SHADER_BO: 588 return vc4_simulator_create_shader_bo_ioctl(fd, args); 589 case DRM_IOCTL_VC4_MMAP_BO: 590 return vc4_simulator_mmap_bo_ioctl(fd, args); 591 592 case DRM_IOCTL_VC4_WAIT_BO: 593 case DRM_IOCTL_VC4_WAIT_SEQNO: 594 /* We do all of the vc4 rendering synchronously, so we just 595 * return immediately on the wait ioctls. This ignores any 596 * native rendering to the host BO, so it does mean we race on 597 * front buffer rendering. 598 */ 599 return 0; 600 601 case DRM_IOCTL_VC4_LABEL_BO: 602 /* This is just debug information, nothing to do. */ 603 return 0; 604 605 case DRM_IOCTL_VC4_GET_TILING: 606 case DRM_IOCTL_VC4_SET_TILING: 607 /* Disable these for now, since the sharing with i965 requires 608 * linear buffers. 609 */ 610 errno = -EINVAL; 611 return -1; 612 613 case DRM_IOCTL_VC4_GET_PARAM: 614 return vc4_simulator_get_param_ioctl(fd, args); 615 616 case DRM_IOCTL_GEM_CLOSE: 617 return vc4_simulator_gem_close_ioctl(fd, args); 618 619 case DRM_IOCTL_GEM_OPEN: 620 case DRM_IOCTL_GEM_FLINK: 621 return drmIoctl(fd, request, args); 622 default: 623 fprintf(stderr, "Unknown ioctl 0x%08x\n", (int)request); 624 abort(); 625 } 626} 627 628static void 629vc4_simulator_init_global(void) 630{ 631 mtx_lock(&sim_state.mutex); 632 if (sim_state.refcount++) { 633 mtx_unlock(&sim_state.mutex); 634 return; 635 } 636 637 sim_state.mem_size = 256 * 1024 * 1024; 638 sim_state.mem = calloc(sim_state.mem_size, 1); 639 if (!sim_state.mem) 640 abort(); 641 sim_state.heap = u_mmInit(0, sim_state.mem_size); 642 643 /* We supply our own memory so that we can have more aperture 644 * available (256MB instead of simpenrose's default 64MB). 645 */ 646 simpenrose_init_hardware_supply_mem(sim_state.mem, sim_state.mem_size); 647 648 /* Carve out low memory for tile allocation overflow. The kernel 649 * should be automatically handling overflow memory setup on real 650 * hardware, but for simulation we just get one shot to set up enough 651 * overflow memory before execution. This overflow mem will be used 652 * up over the whole lifetime of simpenrose (not reused on each 653 * flush), so it had better be big. 654 */ 655 sim_state.overflow = u_mmAllocMem(sim_state.heap, 32 * 1024 * 1024, 656 PAGE_ALIGN2, 0); 657 simpenrose_supply_overflow_mem(sim_state.overflow->ofs, 658 sim_state.overflow->size); 659 660 mtx_unlock(&sim_state.mutex); 661 662 sim_state.fd_map = 663 _mesa_hash_table_create(NULL, 664 _mesa_hash_pointer, 665 _mesa_key_pointer_equal); 666} 667 668void 669vc4_simulator_init(struct vc4_screen *screen) 670{ 671 vc4_simulator_init_global(); 672 673 screen->sim_file = rzalloc(screen, struct vc4_simulator_file); 674 675 screen->sim_file->bo_map = 676 _mesa_hash_table_create(screen->sim_file, 677 _mesa_hash_pointer, 678 _mesa_key_pointer_equal); 679 680 mtx_lock(&sim_state.mutex); 681 _mesa_hash_table_insert(sim_state.fd_map, int_to_key(screen->fd + 1), 682 screen->sim_file); 683 mtx_unlock(&sim_state.mutex); 684 685 screen->sim_file->dev.screen = screen; 686} 687 688void 689vc4_simulator_destroy(struct vc4_screen *screen) 690{ 691 mtx_lock(&sim_state.mutex); 692 if (!--sim_state.refcount) { 693 _mesa_hash_table_destroy(sim_state.fd_map, NULL); 694 u_mmDestroy(sim_state.heap); 695 free(sim_state.mem); 696 /* No memsetting it, because it contains the mutex. */ 697 } 698 mtx_unlock(&sim_state.mutex); 699} 700 701#endif /* USE_VC4_SIMULATOR */ 702