From: Chia-I Wu Date: Mon, 1 Sep 2014 04:25:53 +0000 (+0800) Subject: ilo: add a builder for building BOs for submission X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dab4a676f7590e94640461ad454911e09d95fa88;p=mesa.git ilo: add a builder for building BOs for submission Comparing to how we manage batch and instruction buffers, the new builder - does not flush - manages both types of buffers - manages STATE_BASE_ADDRESS - uploads kernels using unsynchronized mapping - has its own decoder for the buffers - provides more helpers --- diff --git a/src/gallium/drivers/ilo/Makefile.sources b/src/gallium/drivers/ilo/Makefile.sources index f9be2450164..7f0cf75938d 100644 --- a/src/gallium/drivers/ilo/Makefile.sources +++ b/src/gallium/drivers/ilo/Makefile.sources @@ -15,6 +15,8 @@ C_SOURCES := \ ilo_blitter_blt.c \ ilo_blitter_pipe.c \ ilo_blitter_rectlist.c \ + ilo_builder.c \ + ilo_builder_decode.c \ ilo_common.h \ ilo_context.c \ ilo_context.h \ diff --git a/src/gallium/drivers/ilo/ilo_builder.c b/src/gallium/drivers/ilo/ilo_builder.c new file mode 100644 index 00000000000..229354f6cd6 --- /dev/null +++ b/src/gallium/drivers/ilo/ilo_builder.c @@ -0,0 +1,566 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2014 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 + */ + +#include "genhw/genhw.h" +#include "ilo_builder.h" + +enum ilo_builder_writer_flags { + /* + * When this bit is set, ilo_builder_begin() will not realllocate. New + * data will be appended instead. + */ + WRITER_FLAG_APPEND = 1 << 0, + + /* + * When this bit is set, the writer grows when full. When not, callers + * must make sure the writer never needs to grow. + */ + WRITER_FLAG_GROW = 1 << 1, + + /* + * The writer will be mapped directly. + */ + WRITER_FLAG_MAP = 1 << 2, +}; + +/** + * Set the initial size and flags of a writer. + */ +static void +ilo_builder_writer_init(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + + switch (which) { + case ILO_BUILDER_WRITER_BATCH: + writer->size = sizeof(uint32_t) * 8192; + break; + case ILO_BUILDER_WRITER_INSTRUCTION: + /* + * The EUs pretch some instructions. But since the kernel invalidates + * the instruction cache between batch buffers, we can set + * WRITER_FLAG_APPEND without worrying the EUs would see invalid + * instructions prefetched. + */ + writer->flags = WRITER_FLAG_APPEND | WRITER_FLAG_GROW; + writer->size = 8192; + break; + default: + assert(!"unknown builder writer"); + return; + break; + } + + if (builder->dev->has_llc) + writer->flags |= WRITER_FLAG_MAP; +} + +/** + * Free all resources used by a writer. Note that the initial size is not + * reset. + */ +static void +ilo_builder_writer_reset(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + + if (writer->ptr) { + if (writer->flags & WRITER_FLAG_MAP) + intel_bo_unmap(writer->bo); + else + FREE(writer->ptr); + + writer->ptr = NULL; + } + + if (writer->bo) { + intel_bo_unreference(writer->bo); + writer->bo = NULL; + } + + writer->used = 0; + writer->stolen = 0; + + if (writer->items) { + FREE(writer->items); + writer->item_alloc = 0; + writer->item_used = 0; + } +} + +/** + * Discard everything written so far. + */ +void +ilo_builder_writer_discard(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + + intel_bo_truncate_relocs(writer->bo, 0); + writer->used = 0; + writer->stolen = 0; + writer->item_used = 0; +} + +static struct intel_bo * +alloc_writer_bo(struct intel_winsys *winsys, + enum ilo_builder_writer_type which, + unsigned size) +{ + static const char *writer_names[ILO_BUILDER_WRITER_COUNT] = { + [ILO_BUILDER_WRITER_BATCH] = "batch", + [ILO_BUILDER_WRITER_INSTRUCTION] = "instruction", + }; + + return intel_winsys_alloc_buffer(winsys, writer_names[which], size, true); +} + +static void * +map_writer_bo(struct intel_bo *bo, unsigned flags) +{ + assert(flags & WRITER_FLAG_MAP); + + if (flags & WRITER_FLAG_APPEND) + return intel_bo_map_gtt_async(bo); + else + return intel_bo_map(bo, true); +} + +/** + * Allocate and map the buffer for writing. + */ +static bool +ilo_builder_writer_alloc_and_map(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + + /* allocate a new bo when not appending */ + if (!(writer->flags & WRITER_FLAG_APPEND) || !writer->bo) { + struct intel_bo *bo; + + bo = alloc_writer_bo(builder->winsys, which, writer->size); + if (bo) { + if (writer->bo) + intel_bo_unreference(writer->bo); + writer->bo = bo; + } else if (writer->bo) { + /* reuse the old bo */ + ilo_builder_writer_discard(builder, which); + } else { + return false; + } + + writer->used = 0; + writer->stolen = 0; + writer->item_used = 0; + } + + /* map the bo or allocate the staging system memory */ + if (writer->flags & WRITER_FLAG_MAP) + writer->ptr = map_writer_bo(writer->bo, writer->flags); + else if (!writer->ptr) + writer->ptr = MALLOC(writer->size); + + return (writer->ptr != NULL); +} + +/** + * Unmap the buffer for submission. + */ +static bool +ilo_builder_writer_unmap(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + unsigned offset; + int err = 0; + + if (writer->flags & WRITER_FLAG_MAP) { + intel_bo_unmap(writer->bo); + writer->ptr = NULL; + return true; + } + + offset = builder->begin_used[which]; + if (writer->used > offset) { + err = intel_bo_pwrite(writer->bo, offset, writer->used - offset, + (char *) writer->ptr + offset); + } + + if (writer->stolen && !err) { + const unsigned offset = writer->size - writer->stolen; + err = intel_bo_pwrite(writer->bo, offset, writer->stolen, + (const char *) writer->ptr + offset); + } + + /* keep writer->ptr */ + + return !err; +} + +/** + * Grow a mapped writer to at least \p new_size. + */ +bool +ilo_builder_writer_grow(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned new_size, bool preserve) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + struct intel_bo *new_bo; + void *new_ptr; + + if (!(writer->flags & WRITER_FLAG_GROW)) + return false; + + /* stolen data may already be referenced and cannot be moved */ + if (writer->stolen) + return false; + + if (new_size < writer->size << 1) + new_size = writer->size << 1; + /* STATE_BASE_ADDRESS requires page-aligned buffers */ + new_size = align(new_size, 4096); + + new_bo = alloc_writer_bo(builder->winsys, which, new_size); + if (!new_bo) + return false; + + /* map and copy the data over */ + if (writer->flags & WRITER_FLAG_MAP) { + new_ptr = map_writer_bo(new_bo, writer->flags); + + /* + * When WRITER_FLAG_APPEND and WRITER_FLAG_GROW are both set, we may end + * up copying between two GTT-mapped BOs. That is slow. The issue + * could be solved by adding intel_bo_map_async(), or callers may choose + * to manually grow the writer without preserving the data. + */ + if (new_ptr && preserve) + memcpy(new_ptr, writer->ptr, writer->used); + } else if (preserve) { + new_ptr = REALLOC(writer->ptr, writer->size, new_size); + } else { + new_ptr = MALLOC(new_size); + } + + if (!new_ptr) { + intel_bo_unreference(new_bo); + return false; + } + + if (writer->flags & WRITER_FLAG_MAP) + intel_bo_unmap(writer->bo); + else if (!preserve) + FREE(writer->ptr); + + intel_bo_unreference(writer->bo); + + writer->size = new_size; + writer->bo = new_bo; + writer->ptr = new_ptr; + + return true; +} + +/** + * Record an item for later decoding. + */ +bool +ilo_builder_writer_record(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + enum ilo_builder_item_type type, + unsigned offset, unsigned size) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + struct ilo_builder_item *item; + + if (writer->item_used == writer->item_alloc) { + const unsigned new_alloc = (writer->item_alloc) ? + writer->item_alloc << 1 : 256; + struct ilo_builder_item *items; + + items = REALLOC(writer->items, + sizeof(writer->items[0]) * writer->item_alloc, + sizeof(writer->items[0]) * new_alloc); + if (!items) + return false; + + writer->items = items; + writer->item_alloc = new_alloc; + } + + item = &writer->items[writer->item_used++]; + item->type = type; + item->offset = offset; + item->size = size; + + return true; +} + +/** + * Initialize the builder. + */ +void +ilo_builder_init(struct ilo_builder *builder, + const struct ilo_dev_info *dev, + struct intel_winsys *winsys) +{ + int i; + + memset(builder, 0, sizeof(*builder)); + + builder->dev = dev; + builder->winsys = winsys; + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) + ilo_builder_writer_init(builder, i); +} + +/** + * Reset the builder and free all resources used. After resetting, the + * builder behaves as if it is newly initialized, except for potentially + * larger initial bo sizes. + */ +void +ilo_builder_reset(struct ilo_builder *builder) +{ + int i; + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) + ilo_builder_writer_reset(builder, i); +} + +/** + * Allocate and map the BOs. It may re-allocate or reuse existing BOs if + * there is any. + * + * Most builder functions can only be called after ilo_builder_begin() and + * before ilo_builder_end(). + */ +bool +ilo_builder_begin(struct ilo_builder *builder) +{ + int i; + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { + if (!ilo_builder_writer_alloc_and_map(builder, i)) { + ilo_builder_reset(builder); + return false; + } + + builder->begin_used[i] = builder->writers[i].used; + } + + builder->unrecoverable_error = false; + builder->sba_instruction_pos = 0; + + return true; +} + +static void +ilo_builder_batch_patch_sba(struct ilo_builder *builder) +{ + const struct ilo_builder_writer *inst = + &builder->writers[ILO_BUILDER_WRITER_INSTRUCTION]; + + if (!builder->sba_instruction_pos) + return; + + ilo_builder_batch_reloc(builder, builder->sba_instruction_pos, + inst->bo, 1, 0); +} + +/** + * Unmap BOs and make sure the written data landed the BOs. The batch buffer + * ready for submission is returned. + */ +struct intel_bo * +ilo_builder_end(struct ilo_builder *builder, unsigned *used) +{ + struct ilo_builder_writer *bat; + int i; + + ilo_builder_batch_patch_sba(builder); + + assert(ilo_builder_validate(builder, 0, NULL)); + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { + if (!ilo_builder_writer_unmap(builder, i)) + builder->unrecoverable_error = true; + } + + if (builder->unrecoverable_error) + return NULL; + + bat = &builder->writers[ILO_BUILDER_WRITER_BATCH]; + + *used = bat->used; + + return bat->bo; +} + +/** + * Return true if the builder is in a valid state, after accounting for the + * additional BOs specified. The additional BOs can be listed to avoid + * snapshotting and restoring when they are known ahead of time. + * + * The number of additional BOs should not be more than a few. Like two, for + * copying between two BOs. + * + * Callers must make sure the builder is in a valid state when + * ilo_builder_end() is called. + */ +bool +ilo_builder_validate(struct ilo_builder *builder, + unsigned bo_count, struct intel_bo **bos) +{ + const unsigned max_bo_count = 2; + struct intel_bo *bos_to_submit[ILO_BUILDER_WRITER_COUNT + max_bo_count]; + int i; + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) + bos_to_submit[i] = builder->writers[i].bo; + + if (bo_count) { + assert(bo_count <= max_bo_count); + if (bo_count > max_bo_count) + return false; + + memcpy(&bos_to_submit[ILO_BUILDER_WRITER_COUNT], + bos, sizeof(*bos) * bo_count); + i += bo_count; + } + + return intel_winsys_can_submit_bo(builder->winsys, bos_to_submit, i); +} + +/** + * Take a snapshot of the writer state. + */ +void +ilo_builder_batch_snapshot(const struct ilo_builder *builder, + struct ilo_builder_snapshot *snapshot) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + const struct ilo_builder_writer *writer = &builder->writers[which]; + + snapshot->reloc_count = intel_bo_get_reloc_count(writer->bo); + snapshot->used = writer->used; + snapshot->stolen = writer->stolen; + snapshot->item_used = writer->item_used; +} + +/** + * Restore the writer state to when the snapshot was taken, except that it + * does not (unnecessarily) shrink BOs or the item array. + */ +void +ilo_builder_batch_restore(struct ilo_builder *builder, + const struct ilo_builder_snapshot *snapshot) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + struct ilo_builder_writer *writer = &builder->writers[which]; + + intel_bo_truncate_relocs(writer->bo, snapshot->reloc_count); + writer->used = snapshot->used; + writer->stolen = snapshot->stolen; + writer->item_used = snapshot->item_used; +} + +/** + * Add a STATE_BASE_ADDRESS to the batch buffer. + */ +void +ilo_builder_batch_state_base_address(struct ilo_builder *builder, + bool init_all) +{ + const uint8_t cmd_len = 10; + const struct ilo_builder_writer *bat = + &builder->writers[ILO_BUILDER_WRITER_BATCH]; + unsigned pos; + uint32_t *dw; + + pos = ilo_builder_batch_pointer(builder, cmd_len, &dw); + + dw[0] = GEN6_RENDER_CMD(COMMON, STATE_BASE_ADDRESS) | (cmd_len - 2); + dw[1] = init_all; + + ilo_builder_batch_reloc(builder, pos + 2, bat->bo, 1, 0); + ilo_builder_batch_reloc(builder, pos + 3, bat->bo, 1, 0); + + dw[4] = init_all; + + /* + * Since the instruction writer has WRITER_FLAG_APPEND set, it is tempting + * not to set Instruction Base Address. The problem is that we do not know + * if the bo has been or will be moved by the kernel. We need a relocation + * entry because of that. + * + * And since we also set WRITER_FLAG_GROW, we have to wait until + * ilo_builder_end(), when the final bo is known, to add the relocation + * entry. + */ + ilo_builder_batch_patch_sba(builder); + builder->sba_instruction_pos = pos + 5; + + /* skip range checks */ + dw[6] = init_all; + dw[7] = 0xfffff000 + init_all; + dw[8] = 0xfffff000 + init_all; + dw[9] = init_all; +} + +/** + * Add a MI_BATCH_BUFFER_END to the batch buffer. Pad if necessary. + */ +void +ilo_builder_batch_mi_batch_buffer_end(struct ilo_builder *builder) +{ + const struct ilo_builder_writer *bat = + &builder->writers[ILO_BUILDER_WRITER_BATCH]; + uint32_t *dw; + + /* + * 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 (bat->used & 0x7) { + ilo_builder_batch_pointer(builder, 1, &dw); + dw[0] = GEN6_MI_CMD(MI_BATCH_BUFFER_END); + } else { + ilo_builder_batch_pointer(builder, 2, &dw); + dw[0] = GEN6_MI_CMD(MI_BATCH_BUFFER_END); + dw[1] = GEN6_MI_CMD(MI_NOOP); + } +} diff --git a/src/gallium/drivers/ilo/ilo_builder.h b/src/gallium/drivers/ilo/ilo_builder.h new file mode 100644 index 00000000000..1c822183f12 --- /dev/null +++ b/src/gallium/drivers/ilo/ilo_builder.h @@ -0,0 +1,490 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2014 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 + */ + +#ifndef ILO_BUILDER_H +#define ILO_BUILDER_H + +#include "intel_winsys.h" +#include "ilo_common.h" + +enum ilo_builder_writer_type { + ILO_BUILDER_WRITER_BATCH, + ILO_BUILDER_WRITER_INSTRUCTION, + + ILO_BUILDER_WRITER_COUNT, +}; + +enum ilo_builder_item_type { + /* for state buffer */ + ILO_BUILDER_ITEM_BLOB, + ILO_BUILDER_ITEM_CLIP_VIEWPORT, + ILO_BUILDER_ITEM_SF_VIEWPORT, + ILO_BUILDER_ITEM_SCISSOR_RECT, + ILO_BUILDER_ITEM_CC_VIEWPORT, + ILO_BUILDER_ITEM_COLOR_CALC, + ILO_BUILDER_ITEM_DEPTH_STENCIL, + ILO_BUILDER_ITEM_BLEND, + ILO_BUILDER_ITEM_SAMPLER, + + /* for surface buffer */ + ILO_BUILDER_ITEM_SURFACE, + ILO_BUILDER_ITEM_BINDING_TABLE, + + /* for instruction buffer */ + ILO_BUILDER_ITEM_KERNEL, + + ILO_BUILDER_ITEM_COUNT, +}; + +struct ilo_builder_item { + enum ilo_builder_item_type type; + unsigned offset; + unsigned size; +}; + +struct ilo_builder_writer { + /* internal flags */ + unsigned flags; + + unsigned size; + struct intel_bo *bo; + void *ptr; + + /* data written to the bottom */ + unsigned used; + /* data written to the top */ + unsigned stolen; + + /* for decoding */ + struct ilo_builder_item *items; + unsigned item_alloc; + unsigned item_used; +}; + +/** + * A snapshot of the writer state. + */ +struct ilo_builder_snapshot { + unsigned reloc_count; + + unsigned used; + unsigned stolen; + unsigned item_used; +}; + +struct ilo_builder { + const struct ilo_dev_info *dev; + struct intel_winsys *winsys; + + struct ilo_builder_writer writers[ILO_BUILDER_WRITER_COUNT]; + bool unrecoverable_error; + + /* for writers that have their data appended */ + unsigned begin_used[ILO_BUILDER_WRITER_COUNT]; + + /* for STATE_BASE_ADDRESS */ + unsigned sba_instruction_pos; +}; + +void +ilo_builder_init(struct ilo_builder *builder, + const struct ilo_dev_info *dev, + struct intel_winsys *winsys); + +void +ilo_builder_reset(struct ilo_builder *builder); + +void +ilo_builder_decode(struct ilo_builder *builder); + +bool +ilo_builder_begin(struct ilo_builder *builder); + +struct intel_bo * +ilo_builder_end(struct ilo_builder *builder, unsigned *used); + +bool +ilo_builder_validate(struct ilo_builder *builder, + unsigned bo_count, struct intel_bo **bos); + +/** + * Return true if the builder has a relocation entry for \p bo. + */ +static inline bool +ilo_builder_has_reloc(const struct ilo_builder *builder, + struct intel_bo *bo) +{ + int i; + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { + const struct ilo_builder_writer *writer = &builder->writers[i]; + if (intel_bo_has_reloc(writer->bo, bo)) + return true; + } + + return false; +} + +void +ilo_builder_writer_discard(struct ilo_builder *builder, + enum ilo_builder_writer_type which); + +bool +ilo_builder_writer_grow(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned new_size, bool preserve); + +bool +ilo_builder_writer_record(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + enum ilo_builder_item_type type, + unsigned offset, unsigned size); + +static inline void +ilo_builder_writer_checked_record(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + enum ilo_builder_item_type item, + unsigned offset, unsigned size) +{ + if (unlikely(ilo_debug & ILO_DEBUG_3D)) { + if (!ilo_builder_writer_record(builder, which, item, offset, size)) { + builder->unrecoverable_error = true; + builder->writers[which].item_used = 0; + } + } +} + +/** + * Return an offset to a region that is aligned to \p alignment and has at + * least \p size bytes. The region is reserved from the bottom. + */ +static inline unsigned +ilo_builder_writer_reserve_bottom(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned alignment, unsigned size) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + unsigned offset; + + assert(alignment && util_is_power_of_two(alignment)); + offset = align(writer->used, alignment); + + if (unlikely(offset + size > writer->size - writer->stolen)) { + if (!ilo_builder_writer_grow(builder, which, + offset + size + writer->stolen, true)) { + builder->unrecoverable_error = true; + ilo_builder_writer_discard(builder, which); + offset = 0; + } + + assert(offset + size <= writer->size - writer->stolen); + } + + return offset; +} + +/** + * Similar to ilo_builder_writer_reserve_bottom(), but reserve from the top. + */ +static inline unsigned +ilo_builder_writer_reserve_top(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned alignment, unsigned size) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + unsigned offset; + + assert(alignment && util_is_power_of_two(alignment)); + offset = (writer->size - writer->stolen - size) & ~(alignment - 1); + + if (unlikely(offset < writer->used || + size > writer->size - writer->stolen)) { + if (!ilo_builder_writer_grow(builder, which, + align(writer->used, alignment) + size + writer->stolen, true)) { + builder->unrecoverable_error = true; + ilo_builder_writer_discard(builder, which); + } + + offset = (writer->size - writer->stolen - size) & ~(alignment - 1); + assert(offset + size <= writer->size - writer->stolen); + } + + return offset; +} + +/** + * Add a relocation entry to the writer. + */ +static inline void +ilo_builder_writer_reloc(struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned offset, struct intel_bo *bo, + unsigned bo_offset, unsigned reloc_flags) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + uint64_t presumed_offset; + int err; + + assert(offset + sizeof(uint32_t) <= writer->used || + (offset >= writer->size - writer->stolen && + offset + sizeof(uint32_t) <= writer->size)); + + err = intel_bo_add_reloc(writer->bo, offset, bo, bo_offset, + reloc_flags, &presumed_offset); + if (unlikely(err)) + builder->unrecoverable_error = true; + + /* 32-bit addressing */ + assert(presumed_offset == (uint64_t) ((uint32_t) presumed_offset)); + *((uint32_t *) ((char *) writer->ptr + offset)) = presumed_offset; +} + +/** + * Reserve a region from the state buffer. Both the offset, in bytes, and the + * pointer to the reserved region are returned. + * + * Note that \p alignment is in bytes and \p len is in DWords. + */ +static inline uint32_t +ilo_builder_state_pointer(struct ilo_builder *builder, + enum ilo_builder_item_type item, + unsigned alignment, unsigned len, + uint32_t **dw) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + const unsigned size = len << 2; + const unsigned offset = ilo_builder_writer_reserve_top(builder, + which, alignment, size); + struct ilo_builder_writer *writer = &builder->writers[which]; + + /* all states are at least aligned to 32-bytes */ + assert(alignment % 32 == 0); + + *dw = (uint32_t *) ((char *) writer->ptr + offset); + + writer->stolen = writer->size - offset; + + ilo_builder_writer_checked_record(builder, which, item, offset, size); + + return offset; +} + +/** + * Write a dynamic state to the state buffer. + */ +static inline uint32_t +ilo_builder_state_write(struct ilo_builder *builder, + enum ilo_builder_item_type item, + unsigned alignment, unsigned len, + const uint32_t *dw) +{ + uint32_t offset, *dst; + + offset = ilo_builder_state_pointer(builder, item, alignment, len, &dst); + memcpy(dst, dw, len << 2); + + return offset; +} + +/** + * Write a surface state to the surface buffer. The offset, in bytes, of the + * state is returned. + * + * Note that \p alignment is in bytes and \p len is in DWords. + */ +static inline uint32_t +ilo_builder_surface_write(struct ilo_builder *builder, + enum ilo_builder_item_type item, + unsigned alignment, unsigned len, + const uint32_t *dw) +{ + assert(item == ILO_BUILDER_ITEM_SURFACE || + item == ILO_BUILDER_ITEM_BINDING_TABLE); + + return ilo_builder_state_write(builder, item, alignment, len, dw); +} + +/** + * Add a relocation entry for a DWord of a surface state. + */ +static inline void +ilo_builder_surface_reloc(struct ilo_builder *builder, + uint32_t offset, unsigned dw_index, + struct intel_bo *bo, unsigned bo_offset, + unsigned reloc_flags) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + + ilo_builder_writer_reloc(builder, which, offset + (dw_index << 2), + bo, bo_offset, reloc_flags); +} + +/** + * Write a kernel to the instruction buffer. The offset, in bytes, of the + * kernel is returned. + */ +static inline uint32_t +ilo_builder_instruction_write(struct ilo_builder *builder, + unsigned size, const void *kernel) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_INSTRUCTION; + /* + * From the Sandy Bridge PRM, volume 4 part 2, page 112: + * + * "Due to prefetch of the instruction stream, the EUs may attempt to + * access up to 8 instructions (128 bytes) beyond the end of the + * kernel program - possibly into the next memory page. Although + * these instructions will not be executed, software must account for + * the prefetch in order to avoid invalid page access faults." + */ + const unsigned reserved_size = size + 128; + /* kernels are aligned to 64 bytes */ + const unsigned alignment = 64; + const unsigned offset = ilo_builder_writer_reserve_bottom(builder, + which, alignment, reserved_size); + struct ilo_builder_writer *writer = &builder->writers[which]; + + memcpy((char *) writer->ptr + offset, kernel, size); + + writer->used = offset + size; + + ilo_builder_writer_checked_record(builder, which, + ILO_BUILDER_ITEM_KERNEL, offset, size); + + return offset; +} + +/** + * Reserve a region from the batch buffer. Both the offset, in DWords, and + * the pointer to the reserved region are returned. + * + * Note that \p len is in DWords. + */ +static inline unsigned +ilo_builder_batch_pointer(struct ilo_builder *builder, + unsigned len, uint32_t **dw) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + /* + * We know the batch bo is always aligned. Using 1 here should allow the + * compiler to optimize away aligning. + */ + const unsigned alignment = 1; + const unsigned size = len << 2; + const unsigned offset = ilo_builder_writer_reserve_bottom(builder, + which, alignment, size); + struct ilo_builder_writer *writer = &builder->writers[which]; + + assert(offset % 4 == 0); + *dw = (uint32_t *) ((char *) writer->ptr + offset); + + writer->used = offset + size; + + return offset >> 2; +} + +/** + * Write a command to the batch buffer. + */ +static inline unsigned +ilo_builder_batch_write(struct ilo_builder *builder, + unsigned len, const uint32_t *dw) +{ + unsigned pos; + uint32_t *dst; + + pos = ilo_builder_batch_pointer(builder, len, &dst); + memcpy(dst, dw, len << 2); + + return pos; +} + +/** + * Add a relocation entry for a DWord of a command. + */ +static inline void +ilo_builder_batch_reloc(struct ilo_builder *builder, unsigned pos, + struct intel_bo *bo, unsigned bo_offset, + unsigned reloc_flags) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + + ilo_builder_writer_reloc(builder, which, pos << 2, + bo, bo_offset, reloc_flags); +} + +static inline unsigned +ilo_builder_batch_used(const struct ilo_builder *builder) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + const struct ilo_builder_writer *writer = &builder->writers[which]; + + return writer->used >> 2; +} + +static inline unsigned +ilo_builder_batch_space(const struct ilo_builder *builder) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + const struct ilo_builder_writer *writer = &builder->writers[which]; + + return (writer->size - writer->stolen - writer->used) >> 2; +} + +static inline void +ilo_builder_batch_discard(struct ilo_builder *builder) +{ + ilo_builder_writer_discard(builder, ILO_BUILDER_WRITER_BATCH); +} + +static inline void +ilo_builder_batch_print_stats(const struct ilo_builder *builder) +{ + const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; + const struct ilo_builder_writer *writer = &builder->writers[which]; + + ilo_printf("%d+%d bytes (%d%% full)\n", + writer->used, writer->stolen, + (writer->used + writer->stolen) * 100 / writer->size); +} + +void +ilo_builder_batch_snapshot(const struct ilo_builder *builder, + struct ilo_builder_snapshot *snapshot); + +void +ilo_builder_batch_restore(struct ilo_builder *builder, + const struct ilo_builder_snapshot *snapshot); + +void +ilo_builder_batch_state_base_address(struct ilo_builder *builder, + bool init_all); + +void +ilo_builder_batch_mi_batch_buffer_end(struct ilo_builder *builder); + +#endif /* ILO_BUILDER_H */ diff --git a/src/gallium/drivers/ilo/ilo_builder_decode.c b/src/gallium/drivers/ilo/ilo_builder_decode.c new file mode 100644 index 00000000000..eaa9efaf26a --- /dev/null +++ b/src/gallium/drivers/ilo/ilo_builder_decode.c @@ -0,0 +1,583 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2014 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 + */ + +#include +#include +#include "genhw/genhw.h" +#include "shader/toy_compiler.h" +#include "intel_winsys.h" +#include "ilo_builder.h" + +#define READ(dw, field) (((dw) & field ## __MASK) >> field ## __SHIFT) + +static const uint32_t * +writer_pointer(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned offset) +{ + const struct ilo_builder_writer *writer = &builder->writers[which]; + return (const uint32_t *) ((const char *) writer->ptr + offset); +} + +static uint32_t _util_printf_format(5, 6) +writer_dw(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + unsigned offset, unsigned dw_index, + const char *format, ...) +{ + const uint32_t *dw = writer_pointer(builder, which, offset); + va_list ap; + char desc[16]; + int len; + + ilo_printf("0x%08x: 0x%08x: ", + offset + (dw_index << 2), dw[dw_index]); + + va_start(ap, format); + len = vsnprintf(desc, sizeof(desc), format, ap); + va_end(ap); + + if (len >= sizeof(desc)) { + len = sizeof(desc) - 1; + desc[len] = '\0'; + } + + if (desc[len - 1] == '\n') { + desc[len - 1] = '\0'; + ilo_printf("%8s: \n", desc); + } else { + ilo_printf("%8s: ", desc); + } + + return dw[dw_index]; +} + +static void +writer_decode_blob(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 4; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + const uint32_t *dw = writer_pointer(builder, which, offset); + + writer_dw(builder, which, offset, 0, "BLOB%d", i); + /* output a single line for all four DWords */ + ilo_printf("(% f, % f, % f, % f) (0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + uif(dw[0]), uif(dw[1]), uif(dw[2]), uif(dw[3]), + dw[0], dw[1], dw[2], dw[3]); + + offset += state_size; + } +} + +static void +writer_decode_clip_viewport(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 4; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + uint32_t dw; + + dw = writer_dw(builder, which, offset, 0, "CLIP VP%d", i); + ilo_printf("xmin = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 1, "CLIP VP%d", i); + ilo_printf("xmax = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 2, "CLIP VP%d", i); + ilo_printf("ymin = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 3, "CLIP VP%d", i); + ilo_printf("ymax = %f\n", uif(dw)); + + offset += state_size; + } +} + +static void +writer_decode_sf_clip_viewport_gen7(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 16; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + uint32_t dw; + + dw = writer_dw(builder, which, offset, 0, "SF_CLIP VP%d", i); + ilo_printf("m00 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 1, "SF_CLIP VP%d", i); + ilo_printf("m11 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 2, "SF_CLIP VP%d", i); + ilo_printf("m22 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 3, "SF_CLIP VP%d", i); + ilo_printf("m30 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 4, "SF_CLIP VP%d", i); + ilo_printf("m31 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 5, "SF_CLIP VP%d", i); + ilo_printf("m32 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 8, "SF_CLIP VP%d", i); + ilo_printf("guardband xmin = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 9, "SF_CLIP VP%d", i); + ilo_printf("guardband xmax = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 10, "SF_CLIP VP%d", i); + ilo_printf("guardband ymin = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 11, "SF_CLIP VP%d", i); + ilo_printf("guardband ymax = %f\n", uif(dw)); + + offset += state_size; + } +} + +static void +writer_decode_sf_viewport_gen6(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 8; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + uint32_t dw; + + dw = writer_dw(builder, which, offset, 0, "SF VP%d", i); + ilo_printf("m00 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 1, "SF VP%d", i); + ilo_printf("m11 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 2, "SF VP%d", i); + ilo_printf("m22 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 3, "SF VP%d", i); + ilo_printf("m30 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 4, "SF VP%d", i); + ilo_printf("m31 = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 5, "SF VP%d", i); + ilo_printf("m32 = %f\n", uif(dw)); + + offset += state_size; + } +} + +static void +writer_decode_sf_viewport(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + if (builder->dev->gen >= ILO_GEN(7)) + writer_decode_sf_clip_viewport_gen7(builder, which, item); + else + writer_decode_sf_viewport_gen6(builder, which, item); +} + +static void +writer_decode_scissor_rect(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 2; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + uint32_t dw; + + dw = writer_dw(builder, which, offset, 0, "SCISSOR%d", i); + ilo_printf("xmin %d, ymin %d\n", + READ(dw, GEN6_SCISSOR_DW0_MIN_X), + READ(dw, GEN6_SCISSOR_DW0_MIN_Y)); + + dw = writer_dw(builder, which, offset, 1, "SCISSOR%d", i); + ilo_printf("xmax %d, ymax %d\n", + READ(dw, GEN6_SCISSOR_DW1_MAX_X), + READ(dw, GEN6_SCISSOR_DW1_MAX_Y)); + + offset += state_size; + } +} + +static void +writer_decode_cc_viewport(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 2; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + uint32_t dw; + + dw = writer_dw(builder, which, offset, 0, "CC VP%d", i); + ilo_printf("min_depth = %f\n", uif(dw)); + + dw = writer_dw(builder, which, offset, 1, "CC VP%d", i); + ilo_printf("max_depth = %f\n", uif(dw)); + + offset += state_size; + } +} + +static void +writer_decode_color_calc(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + uint32_t dw; + + dw = writer_dw(builder, which, item->offset, 0, "CC"); + ilo_printf("alpha test format %s, round disable %d, " + "stencil ref %d, bf stencil ref %d\n", + READ(dw, GEN6_CC_DW0_ALPHATEST) ? "FLOAT32" : "UNORM8", + (bool) (dw & GEN6_CC_DW0_ROUND_DISABLE_DISABLE), + READ(dw, GEN6_CC_DW0_STENCIL0_REF), + READ(dw, GEN6_CC_DW0_STENCIL1_REF)); + + writer_dw(builder, which, item->offset, 1, "CC\n"); + + dw = writer_dw(builder, which, item->offset, 2, "CC"); + ilo_printf("constant red %f\n", uif(dw)); + + dw = writer_dw(builder, which, item->offset, 3, "CC"); + ilo_printf("constant green %f\n", uif(dw)); + + dw = writer_dw(builder, which, item->offset, 4, "CC"); + ilo_printf("constant blue %f\n", uif(dw)); + + dw = writer_dw(builder, which, item->offset, 5, "CC"); + ilo_printf("constant alpha %f\n", uif(dw)); +} + +static void +writer_decode_depth_stencil(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + uint32_t dw; + + dw = writer_dw(builder, which, item->offset, 0, "D_S"); + ilo_printf("stencil %sable, func %d, write %sable\n", + (dw & GEN6_ZS_DW0_STENCIL_TEST_ENABLE) ? "en" : "dis", + READ(dw, GEN6_ZS_DW0_STENCIL0_FUNC), + (dw & GEN6_ZS_DW0_STENCIL_WRITE_ENABLE) ? "en" : "dis"); + + dw = writer_dw(builder, which, item->offset, 1, "D_S"); + ilo_printf("stencil test mask 0x%x, write mask 0x%x\n", + READ(dw, GEN6_ZS_DW1_STENCIL0_VALUEMASK), + READ(dw, GEN6_ZS_DW1_STENCIL0_WRITEMASK)); + + dw = writer_dw(builder, which, item->offset, 2, "D_S"); + ilo_printf("depth test %sable, func %d, write %sable\n", + (dw & GEN6_ZS_DW2_DEPTH_TEST_ENABLE) ? "en" : "dis", + READ(dw, GEN6_ZS_DW2_DEPTH_FUNC), + (dw & GEN6_ZS_DW2_DEPTH_WRITE_ENABLE) ? "en" : "dis"); +} + +static void +writer_decode_blend(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 2; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + writer_dw(builder, which, offset, 0, "BLEND%d\n", i); + writer_dw(builder, which, offset, 1, "BLEND%d\n", i); + + offset += state_size; + } +} + +static void +writer_decode_sampler(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 4; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + writer_dw(builder, which, offset, 0, "WM SAMP%d", i); + ilo_printf("filtering\n"); + + writer_dw(builder, which, offset, 1, "WM SAMP%d", i); + ilo_printf("wrapping, lod\n"); + + writer_dw(builder, which, offset, 2, "WM SAMP%d", i); + ilo_printf("default color pointer\n"); + + writer_dw(builder, which, offset, 3, "WM SAMP%d", i); + ilo_printf("chroma key, aniso\n"); + + offset += state_size; + } +} + +static void +writer_decode_surface_gen7(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + uint32_t dw; + + dw = writer_dw(builder, which, item->offset, 0, "SURF"); + ilo_printf("type 0x%x, format 0x%x, tiling %d, %s array\n", + READ(dw, GEN7_SURFACE_DW0_TYPE), + READ(dw, GEN7_SURFACE_DW0_FORMAT), + READ(dw, GEN7_SURFACE_DW0_TILING), + (dw & GEN7_SURFACE_DW0_IS_ARRAY) ? "is" : "not"); + + writer_dw(builder, which, item->offset, 1, "SURF"); + ilo_printf("offset\n"); + + dw = writer_dw(builder, which, item->offset, 2, "SURF"); + ilo_printf("%dx%d size\n", + READ(dw, GEN7_SURFACE_DW2_WIDTH), + READ(dw, GEN7_SURFACE_DW2_HEIGHT)); + + dw = writer_dw(builder, which, item->offset, 3, "SURF"); + ilo_printf("depth %d, pitch %d\n", + READ(dw, GEN7_SURFACE_DW3_DEPTH), + READ(dw, GEN7_SURFACE_DW3_PITCH)); + + dw = writer_dw(builder, which, item->offset, 4, "SURF"); + ilo_printf("min array element %d, array extent %d\n", + READ(dw, GEN7_SURFACE_DW4_MIN_ARRAY_ELEMENT), + READ(dw, GEN7_SURFACE_DW4_RT_VIEW_EXTENT)); + + dw = writer_dw(builder, which, item->offset, 5, "SURF"); + ilo_printf("mip base %d, mips %d, x,y offset: %d,%d\n", + READ(dw, GEN7_SURFACE_DW5_MIN_LOD), + READ(dw, GEN7_SURFACE_DW5_MIP_COUNT_LOD), + READ(dw, GEN7_SURFACE_DW5_X_OFFSET), + READ(dw, GEN7_SURFACE_DW5_Y_OFFSET)); + + writer_dw(builder, which, item->offset, 6, "SURF\n"); + writer_dw(builder, which, item->offset, 7, "SURF\n"); +} + +static void +writer_decode_surface_gen6(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + uint32_t dw; + + dw = writer_dw(builder, which, item->offset, 0, "SURF"); + ilo_printf("type 0x%x, format 0x%x\n", + READ(dw, GEN6_SURFACE_DW0_TYPE), + READ(dw, GEN6_SURFACE_DW0_FORMAT)); + + writer_dw(builder, which, item->offset, 1, "SURF"); + ilo_printf("offset\n"); + + dw = writer_dw(builder, which, item->offset, 2, "SURF"); + ilo_printf("%dx%d size, %d mips\n", + READ(dw, GEN6_SURFACE_DW2_WIDTH), + READ(dw, GEN6_SURFACE_DW2_HEIGHT), + READ(dw, GEN6_SURFACE_DW2_MIP_COUNT_LOD)); + + dw = writer_dw(builder, which, item->offset, 3, "SURF"); + ilo_printf("pitch %d, tiling %d\n", + READ(dw, GEN6_SURFACE_DW3_PITCH), + READ(dw, GEN6_SURFACE_DW3_TILING)); + + dw = writer_dw(builder, which, item->offset, 4, "SURF"); + ilo_printf("mip base %d\n", + READ(dw, GEN6_SURFACE_DW4_MIN_LOD)); + + dw = writer_dw(builder, which, item->offset, 5, "SURF"); + ilo_printf("x,y offset: %d,%d\n", + READ(dw, GEN6_SURFACE_DW5_X_OFFSET), + READ(dw, GEN6_SURFACE_DW5_Y_OFFSET)); +} + +static void +writer_decode_surface(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + if (builder->dev->gen >= ILO_GEN(7)) + writer_decode_surface_gen7(builder, which, item); + else + writer_decode_surface_gen6(builder, which, item); +} + +static void +writer_decode_binding_table(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const unsigned state_size = sizeof(uint32_t) * 1; + const unsigned count = item->size / state_size; + unsigned offset = item->offset; + unsigned i; + + for (i = 0; i < count; i++) { + writer_dw(builder, which, offset, 0, "BIND"); + ilo_printf("BINDING_TABLE_STATE[%d]\n", i); + + offset += state_size; + } +} + +static void +writer_decode_kernel(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item) +{ + const void *kernel; + + ilo_printf("0x%08x:\n", item->offset); + kernel = (const void *) writer_pointer(builder, which, item->offset); + toy_compiler_disassemble(builder->dev, kernel, item->size, true); +} + +static const struct { + void (*func)(const struct ilo_builder *builder, + enum ilo_builder_writer_type which, + const struct ilo_builder_item *item); +} writer_decode_table[ILO_BUILDER_ITEM_COUNT] = { + [ILO_BUILDER_ITEM_BLOB] = { writer_decode_blob }, + [ILO_BUILDER_ITEM_CLIP_VIEWPORT] = { writer_decode_clip_viewport }, + [ILO_BUILDER_ITEM_SF_VIEWPORT] = { writer_decode_sf_viewport }, + [ILO_BUILDER_ITEM_SCISSOR_RECT] = { writer_decode_scissor_rect }, + [ILO_BUILDER_ITEM_CC_VIEWPORT] = { writer_decode_cc_viewport }, + [ILO_BUILDER_ITEM_COLOR_CALC] = { writer_decode_color_calc }, + [ILO_BUILDER_ITEM_DEPTH_STENCIL] = { writer_decode_depth_stencil }, + [ILO_BUILDER_ITEM_BLEND] = { writer_decode_blend }, + [ILO_BUILDER_ITEM_SAMPLER] = { writer_decode_sampler }, + [ILO_BUILDER_ITEM_SURFACE] = { writer_decode_surface }, + [ILO_BUILDER_ITEM_BINDING_TABLE] = { writer_decode_binding_table }, + [ILO_BUILDER_ITEM_KERNEL] = { writer_decode_kernel }, +}; + +static void +ilo_builder_writer_decode_items(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + int i; + + if (!writer->item_used) + return; + + writer->ptr = intel_bo_map(writer->bo, false); + if (!writer->ptr) + return; + + for (i = 0; i < writer->item_used; i++) { + const struct ilo_builder_item *item = &writer->items[i]; + + writer_decode_table[item->type].func(builder, which, item); + } + + intel_bo_unmap(writer->bo); +} + +static void +ilo_builder_writer_decode(struct ilo_builder *builder, + enum ilo_builder_writer_type which) +{ + struct ilo_builder_writer *writer = &builder->writers[which]; + + assert(writer->bo && !writer->ptr); + + switch (which) { + case ILO_BUILDER_WRITER_BATCH: + ilo_printf("decoding batch buffer: %d bytes\n", writer->used); + if (writer->used) + intel_winsys_decode_bo(builder->winsys, writer->bo, writer->used); + + ilo_printf("decoding state buffer: %d states\n", + writer->item_used); + ilo_builder_writer_decode_items(builder, which); + break; + case ILO_BUILDER_WRITER_INSTRUCTION: + if (true) { + ilo_printf("skipping instruction buffer: %d kernels\n", + writer->item_used); + } else { + ilo_printf("decoding instruction buffer: %d kernels\n", + writer->item_used); + + ilo_builder_writer_decode_items(builder, which); + } + break; + default: + break; + } +} + +/** + * Decode the builder according to the recorded items. This can be called + * only after a successful ilo_builder_end(). + */ +void +ilo_builder_decode(struct ilo_builder *builder) +{ + int i; + + assert(!builder->unrecoverable_error); + + for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) + ilo_builder_writer_decode(builder, i); +}