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 */ 65 static 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. */ 82 struct 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. */ 96 struct 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 void *winsys_map; 103 uint32_t winsys_stride; 104 105 int handle; 106 }; 107 108 static void * 109 int_to_key(int key) 110 { 111 return (void *)(uintptr_t)key; 112 } 113 114 static struct vc4_simulator_file * 115 vc4_get_simulator_file_for_fd(int fd) 116 { 117 struct hash_entry *entry = _mesa_hash_table_search(sim_state.fd_map, 118 int_to_key(fd + 1)); 119 return entry ? entry->data : NULL; 120 } 121 122 /* A marker placed just after each BO, then checked after rendering to make 123 * sure it's still there. 124 */ 125 #define BO_SENTINEL 0xfedcba98 126 127 #define PAGE_ALIGN2 12 128 129 /** 130 * Allocates space in simulator memory and returns a tracking struct for it 131 * that also contains the drm_gem_cma_object struct. 132 */ 133 static struct vc4_simulator_bo * 134 vc4_create_simulator_bo(int fd, int handle, unsigned size) 135 { 136 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 137 struct vc4_simulator_bo *sim_bo = rzalloc(file, 138 struct vc4_simulator_bo); 139 struct drm_vc4_bo *bo = &sim_bo->base; 140 struct drm_gem_cma_object *obj = &bo->base; 141 size = align(size, 4096); 142 143 sim_bo->file = file; 144 sim_bo->handle = handle; 145 146 mtx_lock(&sim_state.mutex); 147 sim_bo->block = u_mmAllocMem(sim_state.heap, size + 4, PAGE_ALIGN2, 0); 148 mtx_unlock(&sim_state.mutex); 149 assert(sim_bo->block); 150 151 obj->base.size = size; 152 obj->base.dev = &file->dev; 153 obj->vaddr = sim_state.mem + sim_bo->block->ofs; 154 obj->paddr = simpenrose_hw_addr(obj->vaddr); 155 156 *(uint32_t *)(obj->vaddr + size) = BO_SENTINEL; 157 158 /* A handle of 0 is used for vc4_gem.c internal allocations that 159 * don't need to go in the lookup table. 160 */ 161 if (handle != 0) { 162 mtx_lock(&sim_state.mutex); 163 _mesa_hash_table_insert(file->bo_map, int_to_key(handle), bo); 164 mtx_unlock(&sim_state.mutex); 165 } 166 167 return sim_bo; 168 } 169 170 static void 171 vc4_free_simulator_bo(struct vc4_simulator_bo *sim_bo) 172 { 173 struct vc4_simulator_file *sim_file = sim_bo->file; 174 struct drm_vc4_bo *bo = &sim_bo->base; 175 struct drm_gem_cma_object *obj = &bo->base; 176 177 if (sim_bo->winsys_map) 178 munmap(sim_bo->winsys_map, obj->base.size); 179 180 mtx_lock(&sim_state.mutex); 181 u_mmFreeMem(sim_bo->block); 182 if (sim_bo->handle) { 183 struct hash_entry *entry = 184 _mesa_hash_table_search(sim_file->bo_map, 185 int_to_key(sim_bo->handle)); 186 _mesa_hash_table_remove(sim_file->bo_map, entry); 187 } 188 mtx_unlock(&sim_state.mutex); 189 ralloc_free(sim_bo); 190 } 191 192 static struct vc4_simulator_bo * 193 vc4_get_simulator_bo(struct vc4_simulator_file *file, int gem_handle) 194 { 195 mtx_lock(&sim_state.mutex); 196 struct hash_entry *entry = 197 _mesa_hash_table_search(file->bo_map, int_to_key(gem_handle)); 198 mtx_unlock(&sim_state.mutex); 199 200 return entry ? entry->data : NULL; 201 } 202 203 struct drm_gem_cma_object * 204 drm_gem_cma_create(struct drm_device *dev, size_t size) 205 { 206 struct vc4_screen *screen = dev->screen; 207 struct vc4_simulator_bo *sim_bo = vc4_create_simulator_bo(screen->fd, 208 0, size); 209 return &sim_bo->base.base; 210 } 211 212 static int 213 vc4_simulator_pin_bos(struct drm_device *dev, struct vc4_job *job, 214 struct vc4_exec_info *exec) 215 { 216 int fd = dev->screen->fd; 217 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 218 struct drm_vc4_submit_cl *args = exec->args; 219 struct vc4_bo **bos = job->bo_pointers.base; 220 221 exec->bo_count = args->bo_handle_count; 222 exec->bo = calloc(exec->bo_count, sizeof(void *)); 223 for (int i = 0; i < exec->bo_count; i++) { 224 struct vc4_bo *bo = bos[i]; 225 struct vc4_simulator_bo *sim_bo = 226 vc4_get_simulator_bo(file, bo->handle); 227 struct drm_vc4_bo *drm_bo = &sim_bo->base; 228 struct drm_gem_cma_object *obj = &drm_bo->base; 229 230 drm_bo->bo = bo; 231 #if 0 232 fprintf(stderr, "bo hindex %d: %s\n", i, bo->name); 233 #endif 234 235 vc4_bo_map(bo); 236 memcpy(obj->vaddr, bo->map, bo->size); 237 238 exec->bo[i] = obj; 239 240 /* The kernel does this validation at shader create ioctl 241 * time. 242 */ 243 if (strcmp(bo->name, "code") == 0) { 244 drm_bo->validated_shader = vc4_validate_shader(obj); 245 if (!drm_bo->validated_shader) 246 abort(); 247 } 248 } 249 return 0; 250 } 251 252 static int 253 vc4_simulator_unpin_bos(struct vc4_exec_info *exec) 254 { 255 for (int i = 0; i < exec->bo_count; i++) { 256 struct drm_gem_cma_object *obj = exec->bo[i]; 257 struct drm_vc4_bo *drm_bo = to_vc4_bo(&obj->base); 258 struct vc4_bo *bo = drm_bo->bo; 259 260 assert(*(uint32_t *)(obj->vaddr + 261 obj->base.size) == BO_SENTINEL); 262 memcpy(bo->map, obj->vaddr, bo->size); 263 264 if (drm_bo->validated_shader) { 265 free(drm_bo->validated_shader->texture_samples); 266 free(drm_bo->validated_shader); 267 } 268 } 269 270 free(exec->bo); 271 272 return 0; 273 } 274 275 static void 276 vc4_dump_to_file(struct vc4_exec_info *exec) 277 { 278 static int dumpno = 0; 279 struct drm_vc4_get_hang_state *state; 280 struct drm_vc4_get_hang_state_bo *bo_state; 281 unsigned int dump_version = 0; 282 283 if (!(vc4_debug & VC4_DEBUG_DUMP)) 284 return; 285 286 state = calloc(1, sizeof(*state)); 287 288 int unref_count = 0; 289 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 290 unref_head) { 291 unref_count++; 292 } 293 294 /* Add one more for the overflow area that isn't wrapped in a BO. */ 295 state->bo_count = exec->bo_count + unref_count + 1; 296 bo_state = calloc(state->bo_count, sizeof(*bo_state)); 297 298 char *filename = NULL; 299 asprintf(&filename, "vc4-dri-%d.dump", dumpno++); 300 FILE *f = fopen(filename, "w+"); 301 if (!f) { 302 fprintf(stderr, "Couldn't open %s: %s", filename, 303 strerror(errno)); 304 return; 305 } 306 307 fwrite(&dump_version, sizeof(dump_version), 1, f); 308 309 state->ct0ca = exec->ct0ca; 310 state->ct0ea = exec->ct0ea; 311 state->ct1ca = exec->ct1ca; 312 state->ct1ea = exec->ct1ea; 313 state->start_bin = exec->ct0ca; 314 state->start_render = exec->ct1ca; 315 fwrite(state, sizeof(*state), 1, f); 316 317 int i; 318 for (i = 0; i < exec->bo_count; i++) { 319 struct drm_gem_cma_object *cma_bo = exec->bo[i]; 320 bo_state[i].handle = i; /* Not used by the parser. */ 321 bo_state[i].paddr = cma_bo->paddr; 322 bo_state[i].size = cma_bo->base.size; 323 } 324 325 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 326 unref_head) { 327 struct drm_gem_cma_object *cma_bo = &bo->base; 328 bo_state[i].handle = 0; 329 bo_state[i].paddr = cma_bo->paddr; 330 bo_state[i].size = cma_bo->base.size; 331 i++; 332 } 333 334 /* Add the static overflow memory area. */ 335 bo_state[i].handle = exec->bo_count; 336 bo_state[i].paddr = sim_state.overflow->ofs; 337 bo_state[i].size = sim_state.overflow->size; 338 i++; 339 340 fwrite(bo_state, sizeof(*bo_state), state->bo_count, f); 341 342 for (int i = 0; i < exec->bo_count; i++) { 343 struct drm_gem_cma_object *cma_bo = exec->bo[i]; 344 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f); 345 } 346 347 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list, 348 unref_head) { 349 struct drm_gem_cma_object *cma_bo = &bo->base; 350 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f); 351 } 352 353 void *overflow = calloc(1, sim_state.overflow->size); 354 fwrite(overflow, 1, sim_state.overflow->size, f); 355 free(overflow); 356 357 free(state); 358 free(bo_state); 359 fclose(f); 360 } 361 362 int 363 vc4_simulator_flush(struct vc4_context *vc4, 364 struct drm_vc4_submit_cl *args, struct vc4_job *job) 365 { 366 struct vc4_screen *screen = vc4->screen; 367 int fd = screen->fd; 368 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 369 struct vc4_surface *csurf = vc4_surface(vc4->framebuffer.cbufs[0]); 370 struct vc4_resource *ctex = csurf ? vc4_resource(csurf->base.texture) : NULL; 371 struct vc4_simulator_bo *csim_bo = ctex ? vc4_get_simulator_bo(file, ctex->bo->handle) : NULL; 372 uint32_t winsys_stride = ctex ? csim_bo->winsys_stride : 0; 373 uint32_t sim_stride = ctex ? ctex->slices[0].stride : 0; 374 uint32_t row_len = MIN2(sim_stride, winsys_stride); 375 struct vc4_exec_info exec; 376 struct drm_device *dev = &file->dev; 377 int ret; 378 379 memset(&exec, 0, sizeof(exec)); 380 list_inithead(&exec.unref_list); 381 382 if (ctex && csim_bo->winsys_map) { 383 #if 0 384 fprintf(stderr, "%dx%d %d %d %d\n", 385 ctex->base.b.width0, ctex->base.b.height0, 386 winsys_stride, 387 sim_stride, 388 ctex->bo->size); 389 #endif 390 391 for (int y = 0; y < ctex->base.height0; y++) { 392 memcpy(ctex->bo->map + y * sim_stride, 393 csim_bo->winsys_map + y * winsys_stride, 394 row_len); 395 } 396 } 397 398 exec.args = args; 399 400 ret = vc4_simulator_pin_bos(dev, job, &exec); 401 if (ret) 402 return ret; 403 404 ret = vc4_cl_validate(dev, &exec); 405 if (ret) 406 return ret; 407 408 if (vc4_debug & VC4_DEBUG_CL) { 409 fprintf(stderr, "RCL:\n"); 410 vc4_dump_cl(sim_state.mem + exec.ct1ca, 411 exec.ct1ea - exec.ct1ca, true); 412 } 413 414 vc4_dump_to_file(&exec); 415 416 if (exec.ct0ca != exec.ct0ea) { 417 int bfc = simpenrose_do_binning(exec.ct0ca, exec.ct0ea); 418 if (bfc != 1) { 419 fprintf(stderr, "Binning returned %d flushes, should be 1.\n", 420 bfc); 421 fprintf(stderr, "Relocated binning command list:\n"); 422 vc4_dump_cl(sim_state.mem + exec.ct0ca, 423 exec.ct0ea - exec.ct0ca, false); 424 abort(); 425 } 426 } 427 int rfc = simpenrose_do_rendering(exec.ct1ca, exec.ct1ea); 428 if (rfc != 1) { 429 fprintf(stderr, "Rendering returned %d frames, should be 1.\n", 430 rfc); 431 fprintf(stderr, "Relocated render command list:\n"); 432 vc4_dump_cl(sim_state.mem + exec.ct1ca, 433 exec.ct1ea - exec.ct1ca, true); 434 abort(); 435 } 436 437 ret = vc4_simulator_unpin_bos(&exec); 438 if (ret) 439 return ret; 440 441 list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec.unref_list, 442 unref_head) { 443 struct vc4_simulator_bo *sim_bo = (struct vc4_simulator_bo *)bo; 444 struct drm_gem_cma_object *obj = &sim_bo->base.base; 445 list_del(&bo->unref_head); 446 assert(*(uint32_t *)(obj->vaddr + obj->base.size) == 447 BO_SENTINEL); 448 vc4_free_simulator_bo(sim_bo); 449 } 450 451 if (ctex && csim_bo->winsys_map) { 452 for (int y = 0; y < ctex->base.height0; y++) { 453 memcpy(csim_bo->winsys_map + y * winsys_stride, 454 ctex->bo->map + y * sim_stride, 455 row_len); 456 } 457 } 458 459 return 0; 460 } 461 462 /** 463 * Map the underlying GEM object from the real hardware GEM handle. 464 */ 465 static void * 466 vc4_simulator_map_winsys_bo(int fd, struct vc4_simulator_bo *sim_bo) 467 { 468 struct drm_vc4_bo *bo = &sim_bo->base; 469 struct drm_gem_cma_object *obj = &bo->base; 470 int ret; 471 void *map; 472 473 struct drm_mode_map_dumb map_dumb = { 474 .handle = sim_bo->handle, 475 }; 476 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); 477 if (ret != 0) { 478 fprintf(stderr, "map ioctl failure\n"); 479 abort(); 480 } 481 482 map = mmap(NULL, obj->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, 483 fd, map_dumb.offset); 484 if (map == MAP_FAILED) { 485 fprintf(stderr, 486 "mmap of bo %d (offset 0x%016llx, size %d) failed\n", 487 sim_bo->handle, (long long)map_dumb.offset, 488 (int)obj->base.size); 489 abort(); 490 } 491 492 return map; 493 } 494 495 /** 496 * Do fixups after a BO has been opened from a handle. 497 * 498 * This could be done at DRM_IOCTL_GEM_OPEN/DRM_IOCTL_GEM_PRIME_FD_TO_HANDLE 499 * time, but we're still using drmPrimeFDToHandle() so we have this helper to 500 * be called afterward instead. 501 */ 502 void vc4_simulator_open_from_handle(int fd, uint32_t winsys_stride, 503 int handle, uint32_t size) 504 { 505 struct vc4_simulator_bo *sim_bo = 506 vc4_create_simulator_bo(fd, handle, size); 507 508 sim_bo->winsys_stride = winsys_stride; 509 sim_bo->winsys_map = vc4_simulator_map_winsys_bo(fd, sim_bo); 510 } 511 512 /** 513 * Simulated ioctl(fd, DRM_VC4_CREATE_BO) implementation. 514 * 515 * Making a VC4 BO is just a matter of making a corresponding BO on the host. 516 */ 517 static int 518 vc4_simulator_create_bo_ioctl(int fd, struct drm_vc4_create_bo *args) 519 { 520 int ret; 521 struct drm_mode_create_dumb create = { 522 .width = 128, 523 .bpp = 8, 524 .height = (args->size + 127) / 128, 525 }; 526 527 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 528 assert(create.size >= args->size); 529 530 args->handle = create.handle; 531 532 vc4_create_simulator_bo(fd, create.handle, args->size); 533 534 return ret; 535 } 536 537 /** 538 * Simulated ioctl(fd, DRM_VC4_CREATE_SHADER_BO) implementation. 539 * 540 * In simulation we defer shader validation until exec time. Just make a host 541 * BO and memcpy the contents in. 542 */ 543 static int 544 vc4_simulator_create_shader_bo_ioctl(int fd, 545 struct drm_vc4_create_shader_bo *args) 546 { 547 int ret; 548 struct drm_mode_create_dumb create = { 549 .width = 128, 550 .bpp = 8, 551 .height = (args->size + 127) / 128, 552 }; 553 554 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); 555 if (ret) 556 return ret; 557 assert(create.size >= args->size); 558 559 args->handle = create.handle; 560 561 vc4_create_simulator_bo(fd, create.handle, args->size); 562 563 struct drm_mode_map_dumb map = { 564 .handle = create.handle 565 }; 566 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); 567 if (ret) 568 return ret; 569 570 void *shader = mmap(NULL, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, 571 fd, map.offset); 572 memcpy(shader, (void *)(uintptr_t)args->data, args->size); 573 munmap(shader, args->size); 574 575 return 0; 576 } 577 578 /** 579 * Simulated ioctl(fd, DRM_VC4_MMAP_BO) implementation. 580 * 581 * We just pass this straight through to dumb mmap. 582 */ 583 static int 584 vc4_simulator_mmap_bo_ioctl(int fd, struct drm_vc4_mmap_bo *args) 585 { 586 int ret; 587 struct drm_mode_map_dumb map = { 588 .handle = args->handle, 589 }; 590 591 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); 592 args->offset = map.offset; 593 594 return ret; 595 } 596 597 static int 598 vc4_simulator_gem_close_ioctl(int fd, struct drm_gem_close *args) 599 { 600 /* Free the simulator's internal tracking. */ 601 struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd); 602 struct vc4_simulator_bo *sim_bo = vc4_get_simulator_bo(file, 603 args->handle); 604 605 vc4_free_simulator_bo(sim_bo); 606 607 /* Pass the call on down. */ 608 return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, args); 609 } 610 611 static int 612 vc4_simulator_get_param_ioctl(int fd, struct drm_vc4_get_param *args) 613 { 614 switch (args->param) { 615 case DRM_VC4_PARAM_SUPPORTS_BRANCHES: 616 case DRM_VC4_PARAM_SUPPORTS_ETC1: 617 case DRM_VC4_PARAM_SUPPORTS_THREADED_FS: 618 case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER: 619 args->value = true; 620 return 0; 621 622 case DRM_VC4_PARAM_SUPPORTS_MADVISE: 623 errno = -EINVAL; 624 return -1; 625 626 case DRM_VC4_PARAM_V3D_IDENT0: 627 args->value = 0x02000000; 628 return 0; 629 630 case DRM_VC4_PARAM_V3D_IDENT1: 631 args->value = 0x00000001; 632 return 0; 633 634 default: 635 fprintf(stderr, "Unknown DRM_IOCTL_VC4_GET_PARAM(%lld)\n", 636 (long long)args->param); 637 abort(); 638 }; 639 } 640 641 int 642 vc4_simulator_ioctl(int fd, unsigned long request, void *args) 643 { 644 switch (request) { 645 case DRM_IOCTL_VC4_CREATE_BO: 646 return vc4_simulator_create_bo_ioctl(fd, args); 647 case DRM_IOCTL_VC4_CREATE_SHADER_BO: 648 return vc4_simulator_create_shader_bo_ioctl(fd, args); 649 case DRM_IOCTL_VC4_MMAP_BO: 650 return vc4_simulator_mmap_bo_ioctl(fd, args); 651 652 case DRM_IOCTL_VC4_WAIT_BO: 653 case DRM_IOCTL_VC4_WAIT_SEQNO: 654 /* We do all of the vc4 rendering synchronously, so we just 655 * return immediately on the wait ioctls. This ignores any 656 * native rendering to the host BO, so it does mean we race on 657 * front buffer rendering. 658 */ 659 return 0; 660 661 case DRM_IOCTL_VC4_LABEL_BO: 662 /* This is just debug information, nothing to do. */ 663 return 0; 664 665 case DRM_IOCTL_VC4_GET_TILING: 666 case DRM_IOCTL_VC4_SET_TILING: 667 /* Disable these for now, since the sharing with i965 requires 668 * linear buffers. 669 */ 670 errno = -EINVAL; 671 return -1; 672 673 case DRM_IOCTL_VC4_GET_PARAM: 674 return vc4_simulator_get_param_ioctl(fd, args); 675 676 case DRM_IOCTL_GEM_CLOSE: 677 return vc4_simulator_gem_close_ioctl(fd, args); 678 679 case DRM_IOCTL_GEM_OPEN: 680 case DRM_IOCTL_GEM_FLINK: 681 return drmIoctl(fd, request, args); 682 default: 683 fprintf(stderr, "Unknown ioctl 0x%08x\n", (int)request); 684 abort(); 685 } 686 } 687 688 static void 689 vc4_simulator_init_global(void) 690 { 691 mtx_lock(&sim_state.mutex); 692 if (sim_state.refcount++) { 693 mtx_unlock(&sim_state.mutex); 694 return; 695 } 696 697 sim_state.mem_size = 256 * 1024 * 1024; 698 sim_state.mem = calloc(sim_state.mem_size, 1); 699 if (!sim_state.mem) 700 abort(); 701 sim_state.heap = u_mmInit(0, sim_state.mem_size); 702 703 /* We supply our own memory so that we can have more aperture 704 * available (256MB instead of simpenrose's default 64MB). 705 */ 706 simpenrose_init_hardware_supply_mem(sim_state.mem, sim_state.mem_size); 707 708 /* Carve out low memory for tile allocation overflow. The kernel 709 * should be automatically handling overflow memory setup on real 710 * hardware, but for simulation we just get one shot to set up enough 711 * overflow memory before execution. This overflow mem will be used 712 * up over the whole lifetime of simpenrose (not reused on each 713 * flush), so it had better be big. 714 */ 715 sim_state.overflow = u_mmAllocMem(sim_state.heap, 32 * 1024 * 1024, 716 PAGE_ALIGN2, 0); 717 simpenrose_supply_overflow_mem(sim_state.overflow->ofs, 718 sim_state.overflow->size); 719 720 mtx_unlock(&sim_state.mutex); 721 722 sim_state.fd_map = 723 _mesa_hash_table_create(NULL, 724 _mesa_hash_pointer, 725 _mesa_key_pointer_equal); 726 } 727 728 void 729 vc4_simulator_init(struct vc4_screen *screen) 730 { 731 vc4_simulator_init_global(); 732 733 screen->sim_file = rzalloc(screen, struct vc4_simulator_file); 734 735 screen->sim_file->bo_map = 736 _mesa_hash_table_create(screen->sim_file, 737 _mesa_hash_pointer, 738 _mesa_key_pointer_equal); 739 740 mtx_lock(&sim_state.mutex); 741 _mesa_hash_table_insert(sim_state.fd_map, int_to_key(screen->fd + 1), 742 screen->sim_file); 743 mtx_unlock(&sim_state.mutex); 744 745 screen->sim_file->dev.screen = screen; 746 } 747 748 void 749 vc4_simulator_destroy(struct vc4_screen *screen) 750 { 751 mtx_lock(&sim_state.mutex); 752 if (!--sim_state.refcount) { 753 _mesa_hash_table_destroy(sim_state.fd_map, NULL); 754 u_mmDestroy(sim_state.heap); 755 free(sim_state.mem); 756 /* No memsetting it, because it contains the mutex. */ 757 } 758 mtx_unlock(&sim_state.mutex); 759 } 760 761 #endif /* USE_VC4_SIMULATOR */ 762