1/* 2 * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#include <assert.h> 28#include <inttypes.h> 29 30#include "util/hash_table.h" 31#include "util/set.h" 32#include "util/slab.h" 33 34#include "drm/freedreno_ringbuffer.h" 35#include "msm_priv.h" 36 37/* The legacy implementation of submit/ringbuffer, which still does the 38 * traditional reloc and cmd tracking 39 */ 40 41 42#define INIT_SIZE 0x1000 43 44static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; 45 46 47struct msm_submit { 48 struct fd_submit base; 49 50 DECLARE_ARRAY(struct drm_msm_gem_submit_bo, submit_bos); 51 DECLARE_ARRAY(struct fd_bo *, bos); 52 53 unsigned seqno; 54 55 /* maps fd_bo to idx in bos table: */ 56 struct hash_table *bo_table; 57 58 struct slab_mempool ring_pool; 59 60 /* hash-set of associated rings: */ 61 struct set *ring_set; 62 63 struct fd_ringbuffer *primary; 64 65 /* Allow for sub-allocation of stateobj ring buffers (ie. sharing 66 * the same underlying bo).. 67 * 68 * We also rely on previous stateobj having been fully constructed 69 * so we can reclaim extra space at it's end. 70 */ 71 struct fd_ringbuffer *suballoc_ring; 72}; 73FD_DEFINE_CAST(fd_submit, msm_submit); 74 75/* for FD_RINGBUFFER_GROWABLE rb's, tracks the 'finalized' cmdstream buffers 76 * and sizes. Ie. a finalized buffer can have no more commands appended to 77 * it. 78 */ 79struct msm_cmd { 80 struct fd_bo *ring_bo; 81 unsigned size; 82 DECLARE_ARRAY(struct drm_msm_gem_submit_reloc, relocs); 83}; 84 85static struct msm_cmd * 86cmd_new(struct fd_bo *ring_bo) 87{ 88 struct msm_cmd *cmd = malloc(sizeof(*cmd)); 89 cmd->ring_bo = fd_bo_ref(ring_bo); 90 cmd->size = 0; 91 cmd->nr_relocs = cmd->max_relocs = 0; 92 cmd->relocs = NULL; 93 return cmd; 94} 95 96static void 97cmd_free(struct msm_cmd *cmd) 98{ 99 fd_bo_del(cmd->ring_bo); 100 free(cmd->relocs); 101 free(cmd); 102} 103 104/* for _FD_RINGBUFFER_OBJECT rb's we need to track the bo's and flags to 105 * later copy into the submit when the stateobj rb is later referenced by 106 * a regular rb: 107 */ 108struct msm_reloc_bo { 109 struct fd_bo *bo; 110 unsigned flags; 111}; 112 113struct msm_ringbuffer { 114 struct fd_ringbuffer base; 115 116 /* for FD_RINGBUFFER_STREAMING rb's which are sub-allocated */ 117 unsigned offset; 118 119 union { 120 /* for _FD_RINGBUFFER_OBJECT case: */ 121 struct { 122 struct fd_pipe *pipe; 123 DECLARE_ARRAY(struct msm_reloc_bo, reloc_bos); 124 struct set *ring_set; 125 }; 126 /* for other cases: */ 127 struct { 128 struct fd_submit *submit; 129 DECLARE_ARRAY(struct msm_cmd *, cmds); 130 }; 131 } u; 132 133 struct msm_cmd *cmd; /* current cmd */ 134 struct fd_bo *ring_bo; 135}; 136FD_DEFINE_CAST(fd_ringbuffer, msm_ringbuffer); 137 138static void finalize_current_cmd(struct fd_ringbuffer *ring); 139static struct fd_ringbuffer * msm_ringbuffer_init( 140 struct msm_ringbuffer *msm_ring, 141 uint32_t size, enum fd_ringbuffer_flags flags); 142 143/* add (if needed) bo to submit and return index: */ 144static uint32_t 145append_bo(struct msm_submit *submit, struct fd_bo *bo, uint32_t flags) 146{ 147 struct msm_bo *msm_bo = to_msm_bo(bo); 148 uint32_t idx; 149 pthread_mutex_lock(&idx_lock); 150 if (likely(msm_bo->current_submit_seqno == submit->seqno)) { 151 idx = msm_bo->idx; 152 } else { 153 uint32_t hash = _mesa_hash_pointer(bo); 154 struct hash_entry *entry; 155 156 entry = _mesa_hash_table_search_pre_hashed(submit->bo_table, hash, bo); 157 if (entry) { 158 /* found */ 159 idx = (uint32_t)(uintptr_t)entry->data; 160 } else { 161 idx = APPEND(submit, submit_bos); 162 idx = APPEND(submit, bos); 163 164 submit->submit_bos[idx].flags = 0; 165 submit->submit_bos[idx].handle = bo->handle; 166 submit->submit_bos[idx].presumed = 0; 167 168 submit->bos[idx] = fd_bo_ref(bo); 169 170 _mesa_hash_table_insert_pre_hashed(submit->bo_table, hash, bo, 171 (void *)(uintptr_t)idx); 172 } 173 msm_bo->current_submit_seqno = submit->seqno; 174 msm_bo->idx = idx; 175 } 176 pthread_mutex_unlock(&idx_lock); 177 if (flags & FD_RELOC_READ) 178 submit->submit_bos[idx].flags |= MSM_SUBMIT_BO_READ; 179 if (flags & FD_RELOC_WRITE) 180 submit->submit_bos[idx].flags |= MSM_SUBMIT_BO_WRITE; 181 return idx; 182} 183 184static void 185append_ring(struct set *set, struct fd_ringbuffer *ring) 186{ 187 uint32_t hash = _mesa_hash_pointer(ring); 188 189 if (!_mesa_set_search_pre_hashed(set, hash, ring)) { 190 fd_ringbuffer_ref(ring); 191 _mesa_set_add_pre_hashed(set, hash, ring); 192 } 193} 194 195static void 196msm_submit_suballoc_ring_bo(struct fd_submit *submit, 197 struct msm_ringbuffer *msm_ring, uint32_t size) 198{ 199 struct msm_submit *msm_submit = to_msm_submit(submit); 200 unsigned suballoc_offset = 0; 201 struct fd_bo *suballoc_bo = NULL; 202 203 if (msm_submit->suballoc_ring) { 204 struct msm_ringbuffer *suballoc_ring = 205 to_msm_ringbuffer(msm_submit->suballoc_ring); 206 207 suballoc_bo = suballoc_ring->ring_bo; 208 suballoc_offset = fd_ringbuffer_size(msm_submit->suballoc_ring) + 209 suballoc_ring->offset; 210 211 suballoc_offset = align(suballoc_offset, 0x10); 212 213 if ((size + suballoc_offset) > suballoc_bo->size) { 214 suballoc_bo = NULL; 215 } 216 } 217 218 if (!suballoc_bo) { 219 // TODO possibly larger size for streaming bo? 220 msm_ring->ring_bo = fd_bo_new_ring( 221 submit->pipe->dev, 0x8000, 0); 222 msm_ring->offset = 0; 223 } else { 224 msm_ring->ring_bo = fd_bo_ref(suballoc_bo); 225 msm_ring->offset = suballoc_offset; 226 } 227 228 struct fd_ringbuffer *old_suballoc_ring = msm_submit->suballoc_ring; 229 230 msm_submit->suballoc_ring = fd_ringbuffer_ref(&msm_ring->base); 231 232 if (old_suballoc_ring) 233 fd_ringbuffer_del(old_suballoc_ring); 234} 235 236static struct fd_ringbuffer * 237msm_submit_new_ringbuffer(struct fd_submit *submit, uint32_t size, 238 enum fd_ringbuffer_flags flags) 239{ 240 struct msm_submit *msm_submit = to_msm_submit(submit); 241 struct msm_ringbuffer *msm_ring; 242 243 msm_ring = slab_alloc_st(&msm_submit->ring_pool); 244 245 msm_ring->u.submit = submit; 246 247 /* NOTE: needs to be before _suballoc_ring_bo() since it could 248 * increment the refcnt of the current ring 249 */ 250 msm_ring->base.refcnt = 1; 251 252 if (flags & FD_RINGBUFFER_STREAMING) { 253 msm_submit_suballoc_ring_bo(submit, msm_ring, size); 254 } else { 255 if (flags & FD_RINGBUFFER_GROWABLE) 256 size = INIT_SIZE; 257 258 msm_ring->offset = 0; 259 msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, size, 0); 260 } 261 262 if (!msm_ringbuffer_init(msm_ring, size, flags)) 263 return NULL; 264 265 if (flags & FD_RINGBUFFER_PRIMARY) { 266 debug_assert(!msm_submit->primary); 267 msm_submit->primary = fd_ringbuffer_ref(&msm_ring->base); 268 } 269 270 return &msm_ring->base; 271} 272 273static struct drm_msm_gem_submit_reloc * 274handle_stateobj_relocs(struct msm_submit *submit, struct msm_ringbuffer *ring) 275{ 276 struct msm_cmd *cmd = ring->cmd; 277 struct drm_msm_gem_submit_reloc *relocs; 278 279 relocs = malloc(cmd->nr_relocs * sizeof(*relocs)); 280 281 for (unsigned i = 0; i < cmd->nr_relocs; i++) { 282 unsigned idx = cmd->relocs[i].reloc_idx; 283 struct fd_bo *bo = ring->u.reloc_bos[idx].bo; 284 unsigned flags = 0; 285 286 if (ring->u.reloc_bos[idx].flags & MSM_SUBMIT_BO_READ) 287 flags |= FD_RELOC_READ; 288 if (ring->u.reloc_bos[idx].flags & MSM_SUBMIT_BO_WRITE) 289 flags |= FD_RELOC_WRITE; 290 291 relocs[i] = cmd->relocs[i]; 292 relocs[i].reloc_idx = append_bo(submit, bo, flags); 293 } 294 295 return relocs; 296} 297 298static int 299msm_submit_flush(struct fd_submit *submit, int in_fence_fd, 300 int *out_fence_fd, uint32_t *out_fence) 301{ 302 struct msm_submit *msm_submit = to_msm_submit(submit); 303 struct msm_pipe *msm_pipe = to_msm_pipe(submit->pipe); 304 struct drm_msm_gem_submit req = { 305 .flags = msm_pipe->pipe, 306 .queueid = msm_pipe->queue_id, 307 }; 308 int ret; 309 310 debug_assert(msm_submit->primary); 311 312 finalize_current_cmd(msm_submit->primary); 313 append_ring(msm_submit->ring_set, msm_submit->primary); 314 315 unsigned nr_cmds = 0; 316 unsigned nr_objs = 0; 317 318 set_foreach(msm_submit->ring_set, entry) { 319 struct fd_ringbuffer *ring = (void *)entry->key; 320 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 321 nr_cmds += 1; 322 nr_objs += 1; 323 } else { 324 if (ring != msm_submit->primary) 325 finalize_current_cmd(ring); 326 nr_cmds += to_msm_ringbuffer(ring)->u.nr_cmds; 327 } 328 } 329 330 void *obj_relocs[nr_objs]; 331 struct drm_msm_gem_submit_cmd cmds[nr_cmds]; 332 unsigned i = 0, o = 0; 333 334 set_foreach(msm_submit->ring_set, entry) { 335 struct fd_ringbuffer *ring = (void *)entry->key; 336 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 337 338 debug_assert(i < nr_cmds); 339 340 // TODO handle relocs: 341 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 342 343 debug_assert(o < nr_objs); 344 345 void *relocs = handle_stateobj_relocs(msm_submit, msm_ring); 346 obj_relocs[o++] = relocs; 347 348 cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 349 cmds[i].submit_idx = 350 append_bo(msm_submit, msm_ring->ring_bo, FD_RELOC_READ); 351 cmds[i].submit_offset = msm_ring->offset; 352 cmds[i].size = offset_bytes(ring->cur, ring->start); 353 cmds[i].pad = 0; 354 cmds[i].nr_relocs = msm_ring->cmd->nr_relocs; 355 cmds[i].relocs = VOID2U64(relocs); 356 357 i++; 358 } else { 359 for (unsigned j = 0; j < msm_ring->u.nr_cmds; j++) { 360 if (ring->flags & FD_RINGBUFFER_PRIMARY) { 361 cmds[i].type = MSM_SUBMIT_CMD_BUF; 362 } else { 363 cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 364 } 365 cmds[i].submit_idx = append_bo(msm_submit, 366 msm_ring->u.cmds[j]->ring_bo, FD_RELOC_READ); 367 cmds[i].submit_offset = msm_ring->offset; 368 cmds[i].size = msm_ring->u.cmds[j]->size; 369 cmds[i].pad = 0; 370 cmds[i].nr_relocs = msm_ring->u.cmds[j]->nr_relocs; 371 cmds[i].relocs = VOID2U64(msm_ring->u.cmds[j]->relocs); 372 373 i++; 374 } 375 } 376 } 377 378 if (in_fence_fd != -1) { 379 req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT; 380 req.fence_fd = in_fence_fd; 381 } 382 383 if (out_fence_fd) { 384 req.flags |= MSM_SUBMIT_FENCE_FD_OUT; 385 } 386 387 /* needs to be after get_cmd() as that could create bos/cmds table: */ 388 req.bos = VOID2U64(msm_submit->submit_bos), 389 req.nr_bos = msm_submit->nr_submit_bos; 390 req.cmds = VOID2U64(cmds), 391 req.nr_cmds = nr_cmds; 392 393 DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 394 395 ret = drmCommandWriteRead(submit->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, 396 &req, sizeof(req)); 397 if (ret) { 398 ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 399 msm_dump_submit(&req); 400 } else if (!ret) { 401 if (out_fence) 402 *out_fence = req.fence; 403 404 if (out_fence_fd) 405 *out_fence_fd = req.fence_fd; 406 } 407 408 for (unsigned o = 0; o < nr_objs; o++) 409 free(obj_relocs[o]); 410 411 return ret; 412} 413 414static void 415unref_rings(struct set_entry *entry) 416{ 417 struct fd_ringbuffer *ring = (void *)entry->key; 418 fd_ringbuffer_del(ring); 419} 420 421static void 422msm_submit_destroy(struct fd_submit *submit) 423{ 424 struct msm_submit *msm_submit = to_msm_submit(submit); 425 426 if (msm_submit->primary) 427 fd_ringbuffer_del(msm_submit->primary); 428 if (msm_submit->suballoc_ring) 429 fd_ringbuffer_del(msm_submit->suballoc_ring); 430 431 _mesa_hash_table_destroy(msm_submit->bo_table, NULL); 432 _mesa_set_destroy(msm_submit->ring_set, unref_rings); 433 434 // TODO it would be nice to have a way to debug_assert() if all 435 // rb's haven't been free'd back to the slab, because that is 436 // an indication that we are leaking bo's 437 slab_destroy(&msm_submit->ring_pool); 438 439 for (unsigned i = 0; i < msm_submit->nr_bos; i++) 440 fd_bo_del(msm_submit->bos[i]); 441 442 free(msm_submit->submit_bos); 443 free(msm_submit->bos); 444 free(msm_submit); 445} 446 447static const struct fd_submit_funcs submit_funcs = { 448 .new_ringbuffer = msm_submit_new_ringbuffer, 449 .flush = msm_submit_flush, 450 .destroy = msm_submit_destroy, 451}; 452 453struct fd_submit * 454msm_submit_new(struct fd_pipe *pipe) 455{ 456 struct msm_submit *msm_submit = calloc(1, sizeof(*msm_submit)); 457 struct fd_submit *submit; 458 static unsigned submit_cnt = 0; 459 460 msm_submit->seqno = ++submit_cnt; 461 msm_submit->bo_table = _mesa_hash_table_create(NULL, 462 _mesa_hash_pointer, _mesa_key_pointer_equal); 463 msm_submit->ring_set = _mesa_set_create(NULL, 464 _mesa_hash_pointer, _mesa_key_pointer_equal); 465 // TODO tune size: 466 slab_create(&msm_submit->ring_pool, sizeof(struct msm_ringbuffer), 16); 467 468 submit = &msm_submit->base; 469 submit->pipe = pipe; 470 submit->funcs = &submit_funcs; 471 472 return submit; 473} 474 475 476static void 477finalize_current_cmd(struct fd_ringbuffer *ring) 478{ 479 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 480 481 debug_assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 482 483 if (!msm_ring->cmd) 484 return; 485 486 debug_assert(msm_ring->cmd->ring_bo == msm_ring->ring_bo); 487 488 unsigned idx = APPEND(&msm_ring->u, cmds); 489 490 msm_ring->u.cmds[idx] = msm_ring->cmd; 491 msm_ring->cmd = NULL; 492 493 msm_ring->u.cmds[idx]->size = offset_bytes(ring->cur, ring->start); 494} 495 496static void 497msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) 498{ 499 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 500 struct fd_pipe *pipe = msm_ring->u.submit->pipe; 501 502 debug_assert(ring->flags & FD_RINGBUFFER_GROWABLE); 503 504 finalize_current_cmd(ring); 505 506 fd_bo_del(msm_ring->ring_bo); 507 msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size, 0); 508 msm_ring->cmd = cmd_new(msm_ring->ring_bo); 509 510 ring->start = fd_bo_map(msm_ring->ring_bo); 511 ring->end = &(ring->start[size/4]); 512 ring->cur = ring->start; 513 ring->size = size; 514} 515 516static void 517msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 518 const struct fd_reloc *reloc) 519{ 520 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 521 struct fd_pipe *pipe; 522 unsigned reloc_idx; 523 524 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 525 unsigned idx = APPEND(&msm_ring->u, reloc_bos); 526 527 msm_ring->u.reloc_bos[idx].bo = fd_bo_ref(reloc->bo); 528 msm_ring->u.reloc_bos[idx].flags = reloc->flags; 529 530 /* this gets fixed up at submit->flush() time, since this state- 531 * object rb can be used with many different submits 532 */ 533 reloc_idx = idx; 534 535 pipe = msm_ring->u.pipe; 536 } else { 537 struct msm_submit *msm_submit = 538 to_msm_submit(msm_ring->u.submit); 539 540 reloc_idx = append_bo(msm_submit, reloc->bo, reloc->flags); 541 542 pipe = msm_ring->u.submit->pipe; 543 } 544 545 struct drm_msm_gem_submit_reloc *r; 546 unsigned idx = APPEND(msm_ring->cmd, relocs); 547 548 r = &msm_ring->cmd->relocs[idx]; 549 550 r->reloc_idx = reloc_idx; 551 r->reloc_offset = reloc->offset; 552 r->or = reloc->or; 553 r->shift = reloc->shift; 554 r->submit_offset = offset_bytes(ring->cur, ring->start) + 555 msm_ring->offset; 556 557 ring->cur++; 558 559 if (pipe->gpu_id >= 500) { 560 idx = APPEND(msm_ring->cmd, relocs); 561 r = &msm_ring->cmd->relocs[idx]; 562 563 r->reloc_idx = reloc_idx; 564 r->reloc_offset = reloc->offset; 565 r->or = reloc->orhi; 566 r->shift = reloc->shift - 32; 567 r->submit_offset = offset_bytes(ring->cur, ring->start) + 568 msm_ring->offset; 569 570 ring->cur++; 571 } 572} 573 574static void 575append_stateobj_rings(struct msm_submit *submit, struct fd_ringbuffer *target) 576{ 577 struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 578 579 debug_assert(target->flags & _FD_RINGBUFFER_OBJECT); 580 581 set_foreach(msm_target->u.ring_set, entry) { 582 struct fd_ringbuffer *ring = (void *)entry->key; 583 584 append_ring(submit->ring_set, ring); 585 586 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 587 append_stateobj_rings(submit, ring); 588 } 589 } 590} 591 592static uint32_t 593msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 594 struct fd_ringbuffer *target, uint32_t cmd_idx) 595{ 596 struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 597 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 598 struct fd_bo *bo; 599 uint32_t size; 600 601 if ((target->flags & FD_RINGBUFFER_GROWABLE) && 602 (cmd_idx < msm_target->u.nr_cmds)) { 603 bo = msm_target->u.cmds[cmd_idx]->ring_bo; 604 size = msm_target->u.cmds[cmd_idx]->size; 605 } else { 606 bo = msm_target->ring_bo; 607 size = offset_bytes(target->cur, target->start); 608 } 609 610 msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 611 .bo = bo, 612 .flags = FD_RELOC_READ, 613 .offset = msm_target->offset, 614 }); 615 616 if ((target->flags & _FD_RINGBUFFER_OBJECT) && 617 !(ring->flags & _FD_RINGBUFFER_OBJECT)) { 618 struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 619 620 append_stateobj_rings(msm_submit, target); 621 } 622 623 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 624 append_ring(msm_ring->u.ring_set, target); 625 } else { 626 struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 627 append_ring(msm_submit->ring_set, target); 628 } 629 630 return size; 631} 632 633static uint32_t 634msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) 635{ 636 if (ring->flags & FD_RINGBUFFER_GROWABLE) 637 return to_msm_ringbuffer(ring)->u.nr_cmds + 1; 638 return 1; 639} 640 641static void 642msm_ringbuffer_destroy(struct fd_ringbuffer *ring) 643{ 644 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 645 646 fd_bo_del(msm_ring->ring_bo); 647 if (msm_ring->cmd) 648 cmd_free(msm_ring->cmd); 649 650 if (ring->flags & _FD_RINGBUFFER_OBJECT) { 651 for (unsigned i = 0; i < msm_ring->u.nr_reloc_bos; i++) { 652 fd_bo_del(msm_ring->u.reloc_bos[i].bo); 653 } 654 655 _mesa_set_destroy(msm_ring->u.ring_set, unref_rings); 656 657 free(msm_ring->u.reloc_bos); 658 free(msm_ring); 659 } else { 660 struct fd_submit *submit = msm_ring->u.submit; 661 662 for (unsigned i = 0; i < msm_ring->u.nr_cmds; i++) { 663 cmd_free(msm_ring->u.cmds[i]); 664 } 665 666 free(msm_ring->u.cmds); 667 slab_free_st(&to_msm_submit(submit)->ring_pool, msm_ring); 668 } 669} 670 671static const struct fd_ringbuffer_funcs ring_funcs = { 672 .grow = msm_ringbuffer_grow, 673 .emit_reloc = msm_ringbuffer_emit_reloc, 674 .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 675 .cmd_count = msm_ringbuffer_cmd_count, 676 .destroy = msm_ringbuffer_destroy, 677}; 678 679static inline struct fd_ringbuffer * 680msm_ringbuffer_init(struct msm_ringbuffer *msm_ring, uint32_t size, 681 enum fd_ringbuffer_flags flags) 682{ 683 struct fd_ringbuffer *ring = &msm_ring->base; 684 685 debug_assert(msm_ring->ring_bo); 686 687 uint8_t *base = fd_bo_map(msm_ring->ring_bo); 688 ring->start = (void *)(base + msm_ring->offset); 689 ring->end = &(ring->start[size/4]); 690 ring->cur = ring->start; 691 692 ring->size = size; 693 ring->flags = flags; 694 695 ring->funcs = &ring_funcs; 696 697 msm_ring->u.cmds = NULL; 698 msm_ring->u.nr_cmds = msm_ring->u.max_cmds = 0; 699 700 msm_ring->cmd = cmd_new(msm_ring->ring_bo); 701 702 return ring; 703} 704 705struct fd_ringbuffer * 706msm_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size) 707{ 708 struct msm_ringbuffer *msm_ring = malloc(sizeof(*msm_ring)); 709 710 msm_ring->u.pipe = pipe; 711 msm_ring->offset = 0; 712 msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size, 0); 713 msm_ring->base.refcnt = 1; 714 715 msm_ring->u.reloc_bos = NULL; 716 msm_ring->u.nr_reloc_bos = msm_ring->u.max_reloc_bos = 0; 717 718 msm_ring->u.ring_set = _mesa_set_create(NULL, 719 _mesa_hash_pointer, _mesa_key_pointer_equal); 720 721 return msm_ringbuffer_init(msm_ring, size, _FD_RINGBUFFER_OBJECT); 722} 723