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 #include "util/u_memory.h"
     29 
     30 #include "ilo_builder.h"
     31 #include "ilo_builder_render.h" /* for ilo_builder_batch_patch_sba() */
     32 
     33 enum ilo_builder_writer_flags {
     34    /*
     35     * When this bit is set, ilo_builder_begin() will not realllocate.  New
     36     * data will be appended instead.
     37     */
     38    WRITER_FLAG_APPEND    = 1 << 0,
     39 
     40    /*
     41     * When this bit is set, the writer grows when full.  When not, callers
     42     * must make sure the writer never needs to grow.
     43     */
     44    WRITER_FLAG_GROW      = 1 << 1,
     45 
     46    /*
     47     * The writer will be mapped directly.
     48     */
     49    WRITER_FLAG_MAP       = 1 << 2,
     50 };
     51 
     52 /**
     53  * Set the initial size and flags of a writer.
     54  */
     55 static void
     56 ilo_builder_writer_init(struct ilo_builder *builder,
     57                         enum ilo_builder_writer_type which)
     58 {
     59    struct ilo_builder_writer *writer = &builder->writers[which];
     60 
     61    switch (which) {
     62    case ILO_BUILDER_WRITER_BATCH:
     63       writer->size = sizeof(uint32_t) * 8192;
     64       break;
     65    case ILO_BUILDER_WRITER_INSTRUCTION:
     66       /*
     67        * The EUs pretch some instructions.  But since the kernel invalidates
     68        * the instruction cache between batch buffers, we can set
     69        * WRITER_FLAG_APPEND without worrying the EUs would see invalid
     70        * instructions prefetched.
     71        */
     72       writer->flags = WRITER_FLAG_APPEND | WRITER_FLAG_GROW;
     73       writer->size = 8192;
     74       break;
     75    default:
     76       assert(!"unknown builder writer");
     77       return;
     78       break;
     79    }
     80 
     81    if (builder->dev->has_llc)
     82       writer->flags |= WRITER_FLAG_MAP;
     83 }
     84 
     85 /**
     86  * Free all resources used by a writer.  Note that the initial size is not
     87  * reset.
     88  */
     89 static void
     90 ilo_builder_writer_reset(struct ilo_builder *builder,
     91                          enum ilo_builder_writer_type which)
     92 {
     93    struct ilo_builder_writer *writer = &builder->writers[which];
     94 
     95    if (writer->ptr) {
     96       if (writer->flags & WRITER_FLAG_MAP)
     97          intel_bo_unmap(writer->bo);
     98       else
     99          FREE(writer->ptr);
    100 
    101       writer->ptr = NULL;
    102    }
    103 
    104    intel_bo_unref(writer->bo);
    105    writer->bo = NULL;
    106 
    107    writer->used = 0;
    108    writer->stolen = 0;
    109 
    110    if (writer->items) {
    111       FREE(writer->items);
    112       writer->item_alloc = 0;
    113       writer->item_used = 0;
    114    }
    115 }
    116 
    117 /**
    118  * Discard everything written so far.
    119  */
    120 void
    121 ilo_builder_writer_discard(struct ilo_builder *builder,
    122                            enum ilo_builder_writer_type which)
    123 {
    124    struct ilo_builder_writer *writer = &builder->writers[which];
    125 
    126    intel_bo_truncate_relocs(writer->bo, 0);
    127    writer->used = 0;
    128    writer->stolen = 0;
    129    writer->item_used = 0;
    130 }
    131 
    132 static struct intel_bo *
    133 alloc_writer_bo(struct intel_winsys *winsys,
    134                 enum ilo_builder_writer_type which,
    135                 unsigned size)
    136 {
    137    static const char *writer_names[ILO_BUILDER_WRITER_COUNT] = {
    138       [ILO_BUILDER_WRITER_BATCH] = "batch",
    139       [ILO_BUILDER_WRITER_INSTRUCTION] = "instruction",
    140    };
    141 
    142    return intel_winsys_alloc_bo(winsys, writer_names[which], size, true);
    143 }
    144 
    145 static void *
    146 map_writer_bo(struct intel_bo *bo, unsigned flags)
    147 {
    148    assert(flags & WRITER_FLAG_MAP);
    149 
    150    if (flags & WRITER_FLAG_APPEND)
    151       return intel_bo_map_gtt_async(bo);
    152    else
    153       return intel_bo_map(bo, true);
    154 }
    155 
    156 /**
    157  * Allocate and map the buffer for writing.
    158  */
    159 static bool
    160 ilo_builder_writer_alloc_and_map(struct ilo_builder *builder,
    161                                  enum ilo_builder_writer_type which)
    162 {
    163    struct ilo_builder_writer *writer = &builder->writers[which];
    164 
    165    /* allocate a new bo when not appending */
    166    if (!(writer->flags & WRITER_FLAG_APPEND) || !writer->bo) {
    167       struct intel_bo *bo;
    168 
    169       bo = alloc_writer_bo(builder->winsys, which, writer->size);
    170       if (bo) {
    171          intel_bo_unref(writer->bo);
    172          writer->bo = bo;
    173       } else if (writer->bo) {
    174          /* reuse the old bo */
    175          ilo_builder_writer_discard(builder, which);
    176       } else {
    177          return false;
    178       }
    179 
    180       writer->used = 0;
    181       writer->stolen = 0;
    182       writer->item_used = 0;
    183    }
    184 
    185    /* map the bo or allocate the staging system memory */
    186    if (writer->flags & WRITER_FLAG_MAP)
    187       writer->ptr = map_writer_bo(writer->bo, writer->flags);
    188    else if (!writer->ptr)
    189       writer->ptr = MALLOC(writer->size);
    190 
    191    return (writer->ptr != NULL);
    192 }
    193 
    194 /**
    195  * Unmap the buffer for submission.
    196  */
    197 static bool
    198 ilo_builder_writer_unmap(struct ilo_builder *builder,
    199                          enum ilo_builder_writer_type which)
    200 {
    201    struct ilo_builder_writer *writer = &builder->writers[which];
    202    unsigned offset;
    203    int err = 0;
    204 
    205    if (writer->flags & WRITER_FLAG_MAP) {
    206       intel_bo_unmap(writer->bo);
    207       writer->ptr = NULL;
    208       return true;
    209    }
    210 
    211    offset = builder->begin_used[which];
    212    if (writer->used > offset) {
    213       err = intel_bo_pwrite(writer->bo, offset, writer->used - offset,
    214             (char *) writer->ptr + offset);
    215    }
    216 
    217    if (writer->stolen && !err) {
    218       const unsigned offset = writer->size - writer->stolen;
    219       err = intel_bo_pwrite(writer->bo, offset, writer->stolen,
    220             (const char *) writer->ptr + offset);
    221    }
    222 
    223    /* keep writer->ptr */
    224 
    225    return !err;
    226 }
    227 
    228 /**
    229  * Grow a mapped writer to at least \p new_size.
    230  */
    231 bool
    232 ilo_builder_writer_grow(struct ilo_builder *builder,
    233                         enum ilo_builder_writer_type which,
    234                         unsigned new_size, bool preserve)
    235 {
    236    struct ilo_builder_writer *writer = &builder->writers[which];
    237    struct intel_bo *new_bo;
    238    void *new_ptr;
    239 
    240    if (!(writer->flags & WRITER_FLAG_GROW))
    241       return false;
    242 
    243    /* stolen data may already be referenced and cannot be moved */
    244    if (writer->stolen)
    245       return false;
    246 
    247    if (new_size < writer->size << 1)
    248       new_size = writer->size << 1;
    249    /* STATE_BASE_ADDRESS requires page-aligned buffers */
    250    new_size = align(new_size, 4096);
    251 
    252    new_bo = alloc_writer_bo(builder->winsys, which, new_size);
    253    if (!new_bo)
    254       return false;
    255 
    256    /* map and copy the data over */
    257    if (writer->flags & WRITER_FLAG_MAP) {
    258       new_ptr = map_writer_bo(new_bo, writer->flags);
    259 
    260       /*
    261        * When WRITER_FLAG_APPEND and WRITER_FLAG_GROW are both set, we may end
    262        * up copying between two GTT-mapped BOs.  That is slow.  The issue
    263        * could be solved by adding intel_bo_map_async(), or callers may choose
    264        * to manually grow the writer without preserving the data.
    265        */
    266       if (new_ptr && preserve)
    267          memcpy(new_ptr, writer->ptr, writer->used);
    268    } else if (preserve) {
    269       new_ptr = REALLOC(writer->ptr, writer->size, new_size);
    270    } else {
    271       new_ptr = MALLOC(new_size);
    272    }
    273 
    274    if (!new_ptr) {
    275       intel_bo_unref(new_bo);
    276       return false;
    277    }
    278 
    279    if (writer->flags & WRITER_FLAG_MAP)
    280       intel_bo_unmap(writer->bo);
    281    else if (!preserve)
    282       FREE(writer->ptr);
    283 
    284    intel_bo_unref(writer->bo);
    285 
    286    writer->size = new_size;
    287    writer->bo = new_bo;
    288    writer->ptr = new_ptr;
    289 
    290    return true;
    291 }
    292 
    293 /**
    294  * Record an item for later decoding.
    295  */
    296 bool
    297 ilo_builder_writer_record(struct ilo_builder *builder,
    298                           enum ilo_builder_writer_type which,
    299                           enum ilo_builder_item_type type,
    300                           unsigned offset, unsigned size)
    301 {
    302    struct ilo_builder_writer *writer = &builder->writers[which];
    303    struct ilo_builder_item *item;
    304 
    305    if (writer->item_used == writer->item_alloc) {
    306       const unsigned new_alloc = (writer->item_alloc) ?
    307          writer->item_alloc << 1 : 256;
    308       struct ilo_builder_item *items;
    309 
    310       items = REALLOC(writer->items,
    311             sizeof(writer->items[0]) * writer->item_alloc,
    312             sizeof(writer->items[0]) * new_alloc);
    313       if (!items)
    314          return false;
    315 
    316       writer->items = items;
    317       writer->item_alloc = new_alloc;
    318    }
    319 
    320    item = &writer->items[writer->item_used++];
    321    item->type = type;
    322    item->offset = offset;
    323    item->size = size;
    324 
    325    return true;
    326 }
    327 
    328 /**
    329  * Initialize the builder.
    330  */
    331 void
    332 ilo_builder_init(struct ilo_builder *builder,
    333                  const struct ilo_dev *dev,
    334                  struct intel_winsys *winsys)
    335 {
    336    unsigned i;
    337 
    338    assert(ilo_is_zeroed(builder, sizeof(*builder)));
    339 
    340    builder->dev = dev;
    341    builder->winsys = winsys;
    342 
    343    /* gen6_SURFACE_STATE() may override this */
    344    switch (ilo_dev_gen(dev)) {
    345    case ILO_GEN(8):
    346       builder->mocs = GEN8_MOCS_MT_WB | GEN8_MOCS_CT_L3;
    347       break;
    348    case ILO_GEN(7.5):
    349    case ILO_GEN(7):
    350       builder->mocs = GEN7_MOCS_L3_WB;
    351       break;
    352    default:
    353       builder->mocs = 0;
    354       break;
    355    }
    356 
    357    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++)
    358       ilo_builder_writer_init(builder, i);
    359 }
    360 
    361 /**
    362  * Reset the builder and free all resources used.  After resetting, the
    363  * builder behaves as if it is newly initialized, except for potentially
    364  * larger initial bo sizes.
    365  */
    366 void
    367 ilo_builder_reset(struct ilo_builder *builder)
    368 {
    369    unsigned i;
    370 
    371    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++)
    372       ilo_builder_writer_reset(builder, i);
    373 }
    374 
    375 /**
    376  * Allocate and map the BOs.  It may re-allocate or reuse existing BOs if
    377  * there is any.
    378  *
    379  * Most builder functions can only be called after ilo_builder_begin() and
    380  * before ilo_builder_end().
    381  */
    382 bool
    383 ilo_builder_begin(struct ilo_builder *builder)
    384 {
    385    unsigned i;
    386 
    387    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) {
    388       if (!ilo_builder_writer_alloc_and_map(builder, i)) {
    389          ilo_builder_reset(builder);
    390          return false;
    391       }
    392 
    393       builder->begin_used[i] = builder->writers[i].used;
    394    }
    395 
    396    builder->unrecoverable_error = false;
    397    builder->sba_instruction_pos = 0;
    398 
    399    return true;
    400 }
    401 
    402 /**
    403  * Unmap BOs and make sure the written data landed the BOs.  The batch buffer
    404  * ready for submission is returned.
    405  */
    406 struct intel_bo *
    407 ilo_builder_end(struct ilo_builder *builder, unsigned *used)
    408 {
    409    struct ilo_builder_writer *bat;
    410    unsigned i;
    411 
    412    ilo_builder_batch_patch_sba(builder);
    413 
    414    assert(ilo_builder_validate(builder, 0, NULL));
    415 
    416    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) {
    417       if (!ilo_builder_writer_unmap(builder, i))
    418          builder->unrecoverable_error = true;
    419    }
    420 
    421    if (builder->unrecoverable_error)
    422       return NULL;
    423 
    424    bat = &builder->writers[ILO_BUILDER_WRITER_BATCH];
    425 
    426    *used = bat->used;
    427 
    428    return bat->bo;
    429 }
    430 
    431 /**
    432  * Return true if the builder is in a valid state, after accounting for the
    433  * additional BOs specified.  The additional BOs can be listed to avoid
    434  * snapshotting and restoring when they are known ahead of time.
    435  *
    436  * The number of additional BOs should not be more than a few.  Like two, for
    437  * copying between two BOs.
    438  *
    439  * Callers must make sure the builder is in a valid state when
    440  * ilo_builder_end() is called.
    441  */
    442 bool
    443 ilo_builder_validate(struct ilo_builder *builder,
    444                      unsigned bo_count, struct intel_bo **bos)
    445 {
    446    const unsigned max_bo_count = 2;
    447    struct intel_bo *bos_to_submit[ILO_BUILDER_WRITER_COUNT + max_bo_count];
    448    int i;
    449 
    450    for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++)
    451       bos_to_submit[i] = builder->writers[i].bo;
    452 
    453    if (bo_count) {
    454       assert(bo_count <= max_bo_count);
    455       if (bo_count > max_bo_count)
    456          return false;
    457 
    458       memcpy(&bos_to_submit[ILO_BUILDER_WRITER_COUNT],
    459             bos, sizeof(*bos) * bo_count);
    460       i += bo_count;
    461    }
    462 
    463    return intel_winsys_can_submit_bo(builder->winsys, bos_to_submit, i);
    464 }
    465 
    466 /**
    467  * Take a snapshot of the writer state.
    468  */
    469 void
    470 ilo_builder_batch_snapshot(const struct ilo_builder *builder,
    471                            struct ilo_builder_snapshot *snapshot)
    472 {
    473    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    474    const struct ilo_builder_writer *writer = &builder->writers[which];
    475 
    476    snapshot->reloc_count = intel_bo_get_reloc_count(writer->bo);
    477    snapshot->used = writer->used;
    478    snapshot->stolen = writer->stolen;
    479    snapshot->item_used = writer->item_used;
    480 }
    481 
    482 /**
    483  * Restore the writer state to when the snapshot was taken, except that it
    484  * does not (unnecessarily) shrink BOs or the item array.
    485  */
    486 void
    487 ilo_builder_batch_restore(struct ilo_builder *builder,
    488                           const struct ilo_builder_snapshot *snapshot)
    489 {
    490    const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH;
    491    struct ilo_builder_writer *writer = &builder->writers[which];
    492 
    493    intel_bo_truncate_relocs(writer->bo, snapshot->reloc_count);
    494    writer->used = snapshot->used;
    495    writer->stolen = snapshot->stolen;
    496    writer->item_used = snapshot->item_used;
    497 }
    498