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. #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.