/* * 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_core.h" #include "ilo_debug.h" #include "ilo_dev.h" enum ilo_builder_writer_type { ILO_BUILDER_WRITER_BATCH, ILO_BUILDER_WRITER_INSTRUCTION, ILO_BUILDER_WRITER_COUNT, }; enum ilo_builder_item_type { /* for dynamic 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, ILO_BUILDER_ITEM_INTERFACE_DESCRIPTOR, /* 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 *dev; struct intel_winsys *winsys; uint32_t mocs; 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 *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_BATCH | ILO_DEBUG_HANG))) { 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, bool write_presumed_offset_hi) { struct ilo_builder_writer *writer = &builder->writers[which]; uint64_t presumed_offset; int err; if (write_presumed_offset_hi) ILO_DEV_ASSERT(builder->dev, 8, 8); else ILO_DEV_ASSERT(builder->dev, 6, 7.5); 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; if (write_presumed_offset_hi) { *((uint64_t *) ((char *) writer->ptr + offset)) = presumed_offset; } else { /* 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 dynamic buffer. Both the offset, in bytes, and * the pointer to the reserved region are returned. The pointer is only valid * until the next reserve call. * * Note that \p alignment is in bytes and \p len is in DWords. */ static inline uint32_t ilo_builder_dynamic_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 */ if (item != ILO_BUILDER_ITEM_BLOB) 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 dynamic buffer. */ static inline uint32_t ilo_builder_dynamic_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_dynamic_pointer(builder, item, alignment, len, &dst); memcpy(dst, dw, len << 2); return offset; } /** * Reserve some space from the top (for prefetches). */ static inline void ilo_builder_dynamic_pad_top(struct ilo_builder *builder, unsigned len) { const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; const unsigned size = len << 2; struct ilo_builder_writer *writer = &builder->writers[which]; if (writer->stolen < size) { ilo_builder_writer_reserve_top(builder, which, 1, size - writer->stolen); writer->stolen = size; } } static inline unsigned ilo_builder_dynamic_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->stolen >> 2; } /** * Reserve a region from the surface buffer. Both the offset, in bytes, and * the pointer to the reserved region are returned. The pointer is only valid * until the next reserve call. * * Note that \p alignment is in bytes and \p len is in DWords. */ static inline uint32_t ilo_builder_surface_pointer(struct ilo_builder *builder, enum ilo_builder_item_type item, unsigned alignment, unsigned len, uint32_t **dw) { assert(item == ILO_BUILDER_ITEM_SURFACE || item == ILO_BUILDER_ITEM_BINDING_TABLE); return ilo_builder_dynamic_pointer(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, false); } static inline void ilo_builder_surface_reloc64(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, true); } static inline unsigned ilo_builder_surface_used(const struct ilo_builder *builder) { return ilo_builder_dynamic_used(builder); } /** * 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. The pointer is only valid * until the next reserve call. * * 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, false); } static inline void ilo_builder_batch_reloc64(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, true); } 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); #endif /* ILO_BUILDER_H */