diff options
Diffstat (limited to 'src/gallium/drivers/ilo/ilo_cp.c')
-rw-r--r-- | src/gallium/drivers/ilo/ilo_cp.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/gallium/drivers/ilo/ilo_cp.c b/src/gallium/drivers/ilo/ilo_cp.c new file mode 100644 index 00000000000..e0e53d91cd7 --- /dev/null +++ b/src/gallium/drivers/ilo/ilo_cp.c @@ -0,0 +1,323 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2012-2013 LunarG, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Chia-I Wu <[email protected]> + */ + +#include "intel_reg.h" /* for MI_xxx */ +#include "intel_winsys.h" + +#include "ilo_cp.h" + +/* the size of the private space */ +static const int ilo_cp_private = 2; + +/** + * Dump the contents of the parser bo. This must be called in a post-flush + * hook. + */ +void +ilo_cp_dump(struct ilo_cp *cp) +{ + ilo_printf("dumping %d bytes\n", cp->used * 4); + if (cp->used) + cp->winsys->decode_commands(cp->winsys, cp->bo, cp->used * 4); +} + +/** + * Save the command parser state for rewind. + * + * Note that this cannot rewind a flush, and the caller must make sure + * that does not happend. + */ +void +ilo_cp_setjmp(struct ilo_cp *cp, struct ilo_cp_jmp_buf *jmp) +{ + jmp->id = pointer_to_intptr(cp->bo); + + jmp->size = cp->size; + jmp->used = cp->used; + jmp->stolen = cp->stolen; + /* save reloc count to rewind ilo_cp_write_bo() */ + jmp->reloc_count = cp->bo->get_reloc_count(cp->bo); +} + +/** + * Rewind to the saved state. + */ +void +ilo_cp_longjmp(struct ilo_cp *cp, const struct ilo_cp_jmp_buf *jmp) +{ + if (jmp->id != pointer_to_intptr(cp->bo)) { + assert(!"invalid use of CP longjmp"); + return; + } + + cp->size = jmp->size; + cp->used = jmp->used; + cp->stolen = jmp->stolen; + cp->bo->clear_relocs(cp->bo, jmp->reloc_count); +} + +/** + * Clear the parser buffer. + */ +static void +ilo_cp_clear_buffer(struct ilo_cp *cp) +{ + cp->cmd_cur = 0; + cp->cmd_end = 0; + + cp->used = 0; + cp->stolen = 0; + + /* + * Recalculate cp->size. This is needed not only because cp->stolen is + * reset above, but also that we added cp->reserve_for_pre_flush and + * ilo_cp_private to cp->size in ilo_cp_flush(). + */ + cp->size = cp->bo_size - (cp->reserve_for_pre_flush + ilo_cp_private); +} + +/** + * Add MI_BATCH_BUFFER_END to the private space of the parser buffer. + */ +static void +ilo_cp_end_buffer(struct ilo_cp *cp) +{ + /* make the private space available */ + cp->size += ilo_cp_private; + + assert(cp->used + 2 <= cp->size); + + cp->ptr[cp->used++] = MI_BATCH_BUFFER_END; + + /* + * From the Sandy Bridge PRM, volume 1 part 1, page 107: + * + * "The batch buffer must be QWord aligned and a multiple of QWords in + * length." + */ + if (cp->used & 1) + cp->ptr[cp->used++] = MI_NOOP; +} + +/** + * Upload the parser buffer to the bo. + */ +static int +ilo_cp_upload_buffer(struct ilo_cp *cp) +{ + int err; + + err = cp->bo->pwrite(cp->bo, 0, cp->used * 4, cp->ptr); + if (likely(!err && cp->stolen)) { + const int offset = cp->bo_size - cp->stolen; + + err = cp->bo->pwrite(cp->bo, offset * 4, + cp->stolen * 4, &cp->ptr[offset]); + } + + return err; +} + +/** + * Reallocate the parser bo. + */ +static void +ilo_cp_realloc_bo(struct ilo_cp *cp) +{ + struct intel_bo *bo; + + /* + * allocate the new bo before unreferencing the old one so that they + * won't point at the same address, which is needed for jmpbuf + */ + bo = cp->winsys->alloc_buffer(cp->winsys, + "batch buffer", cp->bo_size * 4, 0); + if (unlikely(!bo)) + return; + + if (cp->bo) + cp->bo->unreference(cp->bo); + cp->bo = bo; + + if (!cp->sys) { + cp->bo->map(cp->bo, true); + cp->ptr = cp->bo->get_virtual(cp->bo); + } +} + +/** + * Execute the parser bo. + */ +static int +ilo_cp_exec_bo(struct ilo_cp *cp) +{ + const bool do_exec = !(ilo_debug & ILO_DEBUG_NOHW); + unsigned long flags; + int err; + + switch (cp->ring) { + case ILO_CP_RING_RENDER: + flags = INTEL_EXEC_RENDER; + break; + case ILO_CP_RING_BLT: + flags = INTEL_EXEC_BLT; + break; + default: + flags = 0; + break; + } + + if (likely(do_exec)) + err = cp->bo->exec(cp->bo, cp->used * 4, cp->hw_ctx, flags); + else + err = 0; + + return err; +} + +static void +ilo_cp_call_hook(struct ilo_cp *cp, enum ilo_cp_hook hook) +{ + const bool no_implicit_flush = cp->no_implicit_flush; + + if (!cp->hooks[hook].func) + return; + + /* no implicit flush in hooks */ + cp->no_implicit_flush = true; + cp->hooks[hook].func(cp, cp->hooks[hook].data); + + cp->no_implicit_flush = no_implicit_flush; +} + +/** + * Flush the command parser and execute the commands. When the parser buffer + * is empty, the hooks are not invoked. + */ +void +ilo_cp_flush(struct ilo_cp *cp) +{ + int err; + + /* sanity check */ + assert(cp->bo_size == cp->size + + cp->reserve_for_pre_flush + ilo_cp_private + cp->stolen); + + if (!cp->used) { + ilo_cp_clear_buffer(cp); + return; + } + + /* make the reserved space available temporarily */ + cp->size += cp->reserve_for_pre_flush; + ilo_cp_call_hook(cp, ILO_CP_HOOK_PRE_FLUSH); + + ilo_cp_end_buffer(cp); + + if (cp->sys) { + err = ilo_cp_upload_buffer(cp); + if (likely(!err)) + err = ilo_cp_exec_bo(cp); + } + else { + cp->bo->unmap(cp->bo); + err = ilo_cp_exec_bo(cp); + } + + if (likely(!err)) { + ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH); + ilo_cp_clear_buffer(cp); + } + else { + /* reset first so that post-flush hook knows nothing was executed */ + ilo_cp_clear_buffer(cp); + ilo_cp_call_hook(cp, ILO_CP_HOOK_POST_FLUSH); + } + + ilo_cp_realloc_bo(cp); + ilo_cp_call_hook(cp, ILO_CP_HOOK_NEW_BATCH); +} + +/** + * Destroy the command parser. + */ +void +ilo_cp_destroy(struct ilo_cp *cp) +{ + if (cp->bo) + cp->bo->unreference(cp->bo); + if (cp->hw_ctx) + cp->winsys->destroy_context(cp->winsys, cp->hw_ctx); + + FREE(cp->sys); + FREE(cp); +} + +/** + * Create a command parser. + */ +struct ilo_cp * +ilo_cp_create(struct intel_winsys *winsys, bool direct_map) +{ + struct ilo_cp *cp; + + cp = CALLOC_STRUCT(ilo_cp); + if (!cp) + return NULL; + + cp->winsys = winsys; + cp->hw_ctx = winsys->create_context(winsys); + + cp->ring = ILO_CP_RING_RENDER; + cp->no_implicit_flush = false; + cp->reserve_for_pre_flush = 0; + + memset(cp->hooks, 0, sizeof(cp->hooks)); + + cp->bo_size = 8192; + + if (!direct_map) { + cp->sys = MALLOC(cp->bo_size * 4); + if (!cp->sys) { + FREE(cp); + return NULL; + } + + cp->ptr = cp->sys; + } + + ilo_cp_realloc_bo(cp); + if (!cp->bo) { + FREE(cp->sys); + FREE(cp); + return NULL; + } + + ilo_cp_clear_buffer(cp); + + return cp; +} |