Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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