Home | History | Annotate | Download | only in core
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2014 LunarG, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Chia-I Wu <olv (at) lunarg.com>
     26  */
     27 
     28 #ifndef ILO_BUILDER_H
     29 #define ILO_BUILDER_H
     30 
     31 #include "intel_winsys.h"
     32 
     33 #include "ilo_core.h"
     34 #include "ilo_debug.h"
     35 #include "ilo_dev.h"
     36 
     37 enum ilo_builder_writer_type {
     38    ILO_BUILDER_WRITER_BATCH,
     39    ILO_BUILDER_WRITER_INSTRUCTION,
     40 
     41    ILO_BUILDER_WRITER_COUNT,
     42 };
     43 
     44 enum ilo_builder_item_type {
     45    /* for dynamic buffer */
     46    ILO_BUILDER_ITEM_BLOB,
     47    ILO_BUILDER_ITEM_CLIP_VIEWPORT,
     48    ILO_BUILDER_ITEM_SF_VIEWPORT,
     49    ILO_BUILDER_ITEM_SCISSOR_RECT,
     50    ILO_BUILDER_ITEM_CC_VIEWPORT,
     51    ILO_BUILDER_ITEM_COLOR_CALC,
     52    ILO_BUILDER_ITEM_DEPTH_STENCIL,
     53    ILO_BUILDER_ITEM_BLEND,
     54    ILO_BUILDER_ITEM_SAMPLER,
     55    ILO_BUILDER_ITEM_INTERFACE_DESCRIPTOR,
     56 
     57    /* for surface buffer */
     58    ILO_BUILDER_ITEM_SURFACE,
     59    ILO_BUILDER_ITEM_BINDING_TABLE,
     60 
     61    /* for instruction buffer */
     62    ILO_BUILDER_ITEM_KERNEL,
     63 
     64    ILO_BUILDER_ITEM_COUNT,
     65 };
     66 
     67 struct ilo_builder_item {
     68    enum ilo_builder_item_type type;
     69    unsigned offset;
     70    unsigned size;
     71 };
     72 
     73 struct ilo_builder_writer {
     74    /* internal flags */
     75    unsigned flags;
     76 
     77    unsigned size;
     78    struct intel_bo *bo;
     79    void *ptr;
     80 
     81    /* data written to the bottom */
     82    unsigned used;
     83    /* data written to the top */
     84    unsigned stolen;
     85 
     86    /* for decoding */
     87    struct ilo_builder_item *items;
     88    unsigned item_alloc;
     89    unsigned item_used;
     90 };
     91 
     92 /**
     93  * A snapshot of the writer state.
     94  */
     95 struct ilo_builder_snapshot {
     96    unsigned reloc_count;
     97 
     98    unsigned used;
     99    unsigned stolen;
    100    unsigned item_used;
    101 };
    102 
    103 struct ilo_builder {
    104    const struct ilo_dev *dev;
    105    struct intel_winsys *winsys;
    106    uint32_t mocs;
    107 
    108    struct ilo_builder_writer writers[ILO_BUILDER_WRITER_COUNT];
    109    bool unrecoverable_error;
    110 
    111    /* for writers that have their data appended */
    112    unsigned begin_used[ILO_BUILDER_WRITER_COUNT];
    113 
    114    /* for STATE_BASE_ADDRESS */
    115    unsigned sba_instruction_pos;
    116 };
    117 
    118 void
    119 ilo_builder_init(struct ilo_builder *builder,
    120                  const struct ilo_dev *dev,
    121                  struct intel_winsys *winsys);
    122 
    123 void
    124 ilo_builder_reset(struct ilo_builder *builder);
    125 
    126 void
    127 ilo_builder_decode(struct ilo_builder *builder);
    128 
    129 bool
    130 ilo_builder_begin(struct ilo_builder *builder);
    131 
    132 struct intel_bo *
    133 ilo_builder_end(struct ilo_builder *builder, unsigned *used);
    134 
    135 bool
    136 ilo_builder_validate(struct ilo_builder *builder,
    137                      unsigned bo_count, struct intel_bo **bos);
    138 
    139 /**
    140  * Return true if the builder has a relocation entry for \p bo.
    141  */
    142 static inline bool
    143 ilo_builder_has_reloc(const struct ilo_builder *builder,
    144                       struct intel_bo *bo)
    145 {
    146    int i;
    147 
    148    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) {
    149       const struct ilo_builder_writer *writer = &builder->writers[i];
    150       if (intel_bo_has_reloc(writer->bo, bo))
    151          return true;
    152    }
    153 
    154    return false;
    155 }
    156 
    157 void
    158 ilo_builder_writer_discard(struct ilo_builder *builder,
    159                            enum ilo_builder_writer_type which);
    160 
    161 bool
    162 ilo_builder_writer_grow(struct ilo_builder *builder,
    163                         enum ilo_builder_writer_type which,
    164                         unsigned new_size, bool preserve);
    165 
    166 bool
    167 ilo_builder_writer_record(struct ilo_builder *builder,
    168                           enum ilo_builder_writer_type which,
    169                           enum ilo_builder_item_type type,
    170                           unsigned offset, unsigned size);
    171 
    172 static inline void
    173 ilo_builder_writer_checked_record(struct ilo_builder *builder,
    174                                   enum ilo_builder_writer_type which,
    175                                   enum ilo_builder_item_type item,
    176                                   unsigned offset, unsigned size)
    177 {
    178    if (unlikely(ilo_debug & (ILO_DEBUG_BATCH | ILO_DEBUG_HANG))) {
    179       if (!ilo_builder_writer_record(builder, which, item, offset, size)) {
    180          builder->unrecoverable_error = true;
    181          builder->writers[which].item_used = 0;
    182       }
    183    }
    184 }
    185 
    186 /**
    187  * Return an offset to a region that is aligned to \p alignment and has at
    188  * least \p size bytes.  The region is reserved from the bottom.
    189  */
    190 static inline unsigned
    191 ilo_builder_writer_reserve_bottom(struct ilo_builder *builder,
    192                                   enum ilo_builder_writer_type which,
    193                                   unsigned alignment, unsigned size)
    194 {
    195    struct ilo_builder_writer *writer = &builder->writers[which];
    196    unsigned offset;
    197 
    198    assert(alignment && util_is_power_of_two(alignment));
    199    offset = align(writer->used, alignment);
    200 
    201    if (unlikely(offset + size > writer->size - writer->stolen)) {
    202       if (!ilo_builder_writer_grow(builder, which,
    203             offset + size + writer->stolen, true)) {
    204          builder->unrecoverable_error = true;
    205          ilo_builder_writer_discard(builder, which);
    206          offset = 0;
    207       }
    208 
    209       assert(offset + size <= writer->size - writer->stolen);
    210    }
    211 
    212    return offset;
    213 }
    214 
    215 /**
    216  * Similar to ilo_builder_writer_reserve_bottom(), but reserve from the top.
    217  */
    218 static inline unsigned
    219 ilo_builder_writer_reserve_top(struct ilo_builder *builder,
    220                                enum ilo_builder_writer_type which,
    221                                unsigned alignment, unsigned size)
    222 {
    223    struct ilo_builder_writer *writer = &builder->writers[which];
    224    unsigned offset;
    225 
    226    assert(alignment && util_is_power_of_two(alignment));
    227    offset = (writer->size - writer->stolen - size) & ~(alignment - 1);
    228 
    229    if (unlikely(offset < writer->used ||
    230             size > writer->size - writer->stolen)) {
    231       if (!ilo_builder_writer_grow(builder, which,
    232             align(writer->used, alignment) + size + writer->stolen, true)) {
    233          builder->unrecoverable_error = true;
    234          ilo_builder_writer_discard(builder, which);
    235       }
    236 
    237       offset = (writer->size - writer->stolen - size) & ~(alignment - 1);
    238       assert(offset + size <= writer->size - writer->stolen);
    239    }
    240 
    241    return offset;
    242 }
    243 
    244 /**
    245  * Add a relocation entry to the writer.
    246  */
    247 static inline void
    248 ilo_builder_writer_reloc(struct ilo_builder *builder,
    249                          enum ilo_builder_writer_type which,
    250                          unsigned offset, struct intel_bo *bo,
    251                          unsigned bo_offset, unsigned reloc_flags,
    252                          bool write_presumed_offset_hi)
    253 {
    254    struct ilo_builder_writer *writer = &builder->writers[which];
    255    uint64_t presumed_offset;
    256    int err;
    257 
    258    if (write_presumed_offset_hi)
    259       ILO_DEV_ASSERT(builder->dev, 8, 8);
    260    else
    261       ILO_DEV_ASSERT(builder->dev, 6, 7.5);
    262 
    263    assert(offset + sizeof(uint32_t) <= writer->used ||
    264           (offset >= writer->size - writer->stolen &&
    265            offset + sizeof(uint32_t) <= writer->size));
    266 
    267    err = intel_bo_add_reloc(writer->bo, offset, bo, bo_offset,
    268          reloc_flags, &presumed_offset);
    269    if (unlikely(err))
    270       builder->unrecoverable_error = true;
    271 
    272    if (write_presumed_offset_hi) {
    273       *((uint64_t *) ((char *) writer->ptr + offset)) = presumed_offset;
    274    } else {
    275       /* 32-bit addressing */
    276       assert(presumed_offset == (uint64_t) ((uint32_t) presumed_offset));
    277       *((uint32_t *) ((char *) writer->ptr + offset)) = presumed_offset;
    278    }
    279 }
    280 
    281 /**
    282  * Reserve a region from the dynamic buffer.  Both the offset, in bytes, and
    283  * the pointer to the reserved region are returned.  The pointer is only valid
    284  * until the next reserve call.
    285  *
    286  * Note that \p alignment is in bytes and \p len is in DWords.
    287  */
    288 static inline uint32_t
    289 ilo_builder_dynamic_pointer(struct ilo_builder *builder,
    290                             enum ilo_builder_item_type item,
    291                             unsigned alignment, unsigned len,
    292                             uint32_t **dw)
    293 {
    294    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    295    const unsigned size = len << 2;
    296    const unsigned offset = ilo_builder_writer_reserve_top(builder,
    297          which, alignment, size);
    298    struct ilo_builder_writer *writer = &builder->writers[which];
    299 
    300    /* all states are at least aligned to 32-bytes */
    301    if (item != ILO_BUILDER_ITEM_BLOB)
    302       assert(alignment % 32 == 0);
    303 
    304    *dw = (uint32_t *) ((char *) writer->ptr + offset);
    305 
    306    writer->stolen = writer->size - offset;
    307 
    308    ilo_builder_writer_checked_record(builder, which, item, offset, size);
    309 
    310    return offset;
    311 }
    312 
    313 /**
    314  * Write a dynamic state to the dynamic buffer.
    315  */
    316 static inline uint32_t
    317 ilo_builder_dynamic_write(struct ilo_builder *builder,
    318                           enum ilo_builder_item_type item,
    319                           unsigned alignment, unsigned len,
    320                           const uint32_t *dw)
    321 {
    322    uint32_t offset, *dst;
    323 
    324    offset = ilo_builder_dynamic_pointer(builder, item, alignment, len, &dst);
    325    memcpy(dst, dw, len << 2);
    326 
    327    return offset;
    328 }
    329 
    330 /**
    331  * Reserve some space from the top (for prefetches).
    332  */
    333 static inline void
    334 ilo_builder_dynamic_pad_top(struct ilo_builder *builder, unsigned len)
    335 {
    336    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    337    const unsigned size = len << 2;
    338    struct ilo_builder_writer *writer = &builder->writers[which];
    339 
    340    if (writer->stolen < size) {
    341       ilo_builder_writer_reserve_top(builder, which,
    342             1, size - writer->stolen);
    343       writer->stolen = size;
    344    }
    345 }
    346 
    347 static inline unsigned
    348 ilo_builder_dynamic_used(const struct ilo_builder *builder)
    349 {
    350    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    351    const struct ilo_builder_writer *writer = &builder->writers[which];
    352 
    353    return writer->stolen >> 2;
    354 }
    355 
    356 /**
    357  * Reserve a region from the surface buffer.  Both the offset, in bytes, and
    358  * the pointer to the reserved region are returned.  The pointer is only valid
    359  * until the next reserve call.
    360  *
    361  * Note that \p alignment is in bytes and \p len is in DWords.
    362  */
    363 static inline uint32_t
    364 ilo_builder_surface_pointer(struct ilo_builder *builder,
    365                             enum ilo_builder_item_type item,
    366                             unsigned alignment, unsigned len,
    367                             uint32_t **dw)
    368 {
    369    assert(item == ILO_BUILDER_ITEM_SURFACE ||
    370           item == ILO_BUILDER_ITEM_BINDING_TABLE);
    371 
    372    return ilo_builder_dynamic_pointer(builder, item, alignment, len, dw);
    373 }
    374 
    375 /**
    376  * Add a relocation entry for a DWord of a surface state.
    377  */
    378 static inline void
    379 ilo_builder_surface_reloc(struct ilo_builder *builder,
    380                           uint32_t offset, unsigned dw_index,
    381                           struct intel_bo *bo, unsigned bo_offset,
    382                           unsigned reloc_flags)
    383 {
    384    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    385 
    386    ilo_builder_writer_reloc(builder, which, offset + (dw_index << 2),
    387          bo, bo_offset, reloc_flags, false);
    388 }
    389 
    390 static inline void
    391 ilo_builder_surface_reloc64(struct ilo_builder *builder,
    392                             uint32_t offset, unsigned dw_index,
    393                             struct intel_bo *bo, unsigned bo_offset,
    394                             unsigned reloc_flags)
    395 {
    396    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    397 
    398    ilo_builder_writer_reloc(builder, which, offset + (dw_index << 2),
    399          bo, bo_offset, reloc_flags, true);
    400 }
    401 
    402 static inline unsigned
    403 ilo_builder_surface_used(const struct ilo_builder *builder)
    404 {
    405    return ilo_builder_dynamic_used(builder);
    406 }
    407 
    408 /**
    409  * Write a kernel to the instruction buffer.  The offset, in bytes, of the
    410  * kernel is returned.
    411  */
    412 static inline uint32_t
    413 ilo_builder_instruction_write(struct ilo_builder *builder,
    414                               unsigned size, const void *kernel)
    415 {
    416    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_INSTRUCTION;
    417    /*
    418     * From the Sandy Bridge PRM, volume 4 part 2, page 112:
    419     *
    420     *     "Due to prefetch of the instruction stream, the EUs may attempt to
    421     *      access up to 8 instructions (128 bytes) beyond the end of the
    422     *      kernel program - possibly into the next memory page.  Although
    423     *      these instructions will not be executed, software must account for
    424     *      the prefetch in order to avoid invalid page access faults."
    425     */
    426    const unsigned reserved_size = size + 128;
    427    /* kernels are aligned to 64 bytes */
    428    const unsigned alignment = 64;
    429    const unsigned offset = ilo_builder_writer_reserve_bottom(builder,
    430          which, alignment, reserved_size);
    431    struct ilo_builder_writer *writer = &builder->writers[which];
    432 
    433    memcpy((char *) writer->ptr + offset, kernel, size);
    434 
    435    writer->used = offset + size;
    436 
    437    ilo_builder_writer_checked_record(builder, which,
    438          ILO_BUILDER_ITEM_KERNEL, offset, size);
    439 
    440    return offset;
    441 }
    442 
    443 /**
    444  * Reserve a region from the batch buffer.  Both the offset, in DWords, and
    445  * the pointer to the reserved region are returned.  The pointer is only valid
    446  * until the next reserve call.
    447  *
    448  * Note that \p len is in DWords.
    449  */
    450 static inline unsigned
    451 ilo_builder_batch_pointer(struct ilo_builder *builder,
    452                           unsigned len, uint32_t **dw)
    453 {
    454    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    455    /*
    456     * We know the batch bo is always aligned.  Using 1 here should allow the
    457     * compiler to optimize away aligning.
    458     */
    459    const unsigned alignment = 1;
    460    const unsigned size = len << 2;
    461    const unsigned offset = ilo_builder_writer_reserve_bottom(builder,
    462          which, alignment, size);
    463    struct ilo_builder_writer *writer = &builder->writers[which];
    464 
    465    assert(offset % 4 == 0);
    466    *dw = (uint32_t *) ((char *) writer->ptr + offset);
    467 
    468    writer->used = offset + size;
    469 
    470    return offset >> 2;
    471 }
    472 
    473 /**
    474  * Write a command to the batch buffer.
    475  */
    476 static inline unsigned
    477 ilo_builder_batch_write(struct ilo_builder *builder,
    478                         unsigned len, const uint32_t *dw)
    479 {
    480    unsigned pos;
    481    uint32_t *dst;
    482 
    483    pos = ilo_builder_batch_pointer(builder, len, &dst);
    484    memcpy(dst, dw, len << 2);
    485 
    486    return pos;
    487 }
    488 
    489 /**
    490  * Add a relocation entry for a DWord of a command.
    491  */
    492 static inline void
    493 ilo_builder_batch_reloc(struct ilo_builder *builder, unsigned pos,
    494                         struct intel_bo *bo, unsigned bo_offset,
    495                         unsigned reloc_flags)
    496 {
    497    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    498 
    499    ilo_builder_writer_reloc(builder, which, pos << 2,
    500          bo, bo_offset, reloc_flags, false);
    501 }
    502 
    503 static inline void
    504 ilo_builder_batch_reloc64(struct ilo_builder *builder, unsigned pos,
    505                           struct intel_bo *bo, unsigned bo_offset,
    506                           unsigned reloc_flags)
    507 {
    508    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    509 
    510    ilo_builder_writer_reloc(builder, which, pos << 2,
    511          bo, bo_offset, reloc_flags, true);
    512 }
    513 
    514 static inline unsigned
    515 ilo_builder_batch_used(const struct ilo_builder *builder)
    516 {
    517    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    518    const struct ilo_builder_writer *writer = &builder->writers[which];
    519 
    520    return writer->used >> 2;
    521 }
    522 
    523 static inline unsigned
    524 ilo_builder_batch_space(const struct ilo_builder *builder)
    525 {
    526    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    527    const struct ilo_builder_writer *writer = &builder->writers[which];
    528 
    529    return (writer->size - writer->stolen - writer->used) >> 2;
    530 }
    531 
    532 static inline void
    533 ilo_builder_batch_discard(struct ilo_builder *builder)
    534 {
    535    ilo_builder_writer_discard(builder, ILO_BUILDER_WRITER_BATCH);
    536 }
    537 
    538 static inline void
    539 ilo_builder_batch_print_stats(const struct ilo_builder *builder)
    540 {
    541    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    542    const struct ilo_builder_writer *writer = &builder->writers[which];
    543 
    544    ilo_printf("%d+%d bytes (%d%% full)\n",
    545          writer->used, writer->stolen,
    546          (writer->used + writer->stolen) * 100 / writer->size);
    547 }
    548 
    549 void
    550 ilo_builder_batch_snapshot(const struct ilo_builder *builder,
    551                            struct ilo_builder_snapshot *snapshot);
    552 
    553 void
    554 ilo_builder_batch_restore(struct ilo_builder *builder,
    555                           const struct ilo_builder_snapshot *snapshot);
    556 
    557 #endif /* ILO_BUILDER_H */
    558