0,0 → 1,313 |
/* |
* 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 <olv@lunarg.com> |
*/ |
|
#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 can only be called in the flush |
* callback. |
*/ |
void |
ilo_cp_dump(struct ilo_cp *cp) |
{ |
ilo_printf("dumping %d bytes\n", cp->used * 4); |
if (cp->used) |
intel_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 = intel_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; |
intel_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 ilo_cp_private are added to cp->size in |
* ilo_cp_end_buffer(). |
*/ |
cp->size = cp->bo_size - 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; |
|
if (!cp->sys) { |
intel_bo_unmap(cp->bo); |
return 0; |
} |
|
err = intel_bo_pwrite(cp->bo, 0, cp->used * 4, cp->ptr); |
if (likely(!err && cp->stolen)) { |
const int offset = cp->bo_size - cp->stolen; |
|
err = intel_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 = intel_winsys_alloc_buffer(cp->winsys, |
"batch buffer", cp->bo_size * 4, 0); |
if (unlikely(!bo)) { |
/* reuse the old one */ |
bo = cp->bo; |
intel_bo_reference(bo); |
} |
|
if (cp->bo) |
intel_bo_unreference(cp->bo); |
cp->bo = bo; |
|
if (!cp->sys) { |
intel_bo_map(cp->bo, true); |
cp->ptr = intel_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); |
struct intel_context *ctx; |
unsigned long flags; |
int err; |
|
switch (cp->ring) { |
case ILO_CP_RING_RENDER: |
ctx = cp->render_ctx; |
flags = INTEL_EXEC_RENDER; |
break; |
case ILO_CP_RING_BLT: |
ctx = NULL; |
flags = INTEL_EXEC_BLT; |
break; |
default: |
ctx = NULL; |
flags = 0; |
break; |
} |
|
flags |= cp->one_off_flags; |
|
if (likely(do_exec)) |
err = intel_bo_exec(cp->bo, cp->used * 4, ctx, flags); |
else |
err = 0; |
|
cp->one_off_flags = 0; |
|
return err; |
} |
|
/** |
* Flush the command parser and execute the commands. When the parser buffer |
* is empty, the callback is not invoked. |
*/ |
void |
ilo_cp_flush(struct ilo_cp *cp) |
{ |
int err; |
|
ilo_cp_set_owner(cp, NULL, 0); |
|
/* sanity check */ |
assert(cp->bo_size == cp->size + cp->stolen + ilo_cp_private); |
|
if (!cp->used) { |
/* return the space stolen and etc. */ |
ilo_cp_clear_buffer(cp); |
|
return; |
} |
|
ilo_cp_end_buffer(cp); |
|
/* upload and execute */ |
err = ilo_cp_upload_buffer(cp); |
if (likely(!err)) |
err = ilo_cp_exec_bo(cp); |
|
if (likely(!err && cp->flush_callback)) |
cp->flush_callback(cp, cp->flush_callback_data); |
|
ilo_cp_clear_buffer(cp); |
ilo_cp_realloc_bo(cp); |
} |
|
/** |
* Destroy the command parser. |
*/ |
void |
ilo_cp_destroy(struct ilo_cp *cp) |
{ |
if (cp->bo) { |
if (!cp->sys) |
intel_bo_unmap(cp->bo); |
|
intel_bo_unreference(cp->bo); |
} |
|
if (cp->render_ctx) |
intel_winsys_destroy_context(cp->winsys, cp->render_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->render_ctx = intel_winsys_create_context(winsys); |
|
cp->ring = ILO_CP_RING_RENDER; |
cp->no_implicit_flush = false; |
|
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; |
} |