• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ilo_builder_has_reloc(const struct ilo_builder * builder,struct intel_bo * bo)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
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)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
ilo_builder_writer_reserve_bottom(struct ilo_builder * builder,enum ilo_builder_writer_type which,unsigned alignment,unsigned size)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
ilo_builder_writer_reserve_top(struct ilo_builder * builder,enum ilo_builder_writer_type which,unsigned alignment,unsigned size)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
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)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
ilo_builder_dynamic_pointer(struct ilo_builder * builder,enum ilo_builder_item_type item,unsigned alignment,unsigned len,uint32_t ** dw)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
ilo_builder_dynamic_write(struct ilo_builder * builder,enum ilo_builder_item_type item,unsigned alignment,unsigned len,const uint32_t * dw)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
ilo_builder_dynamic_pad_top(struct ilo_builder * builder,unsigned len)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
ilo_builder_dynamic_used(const struct ilo_builder * builder)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
ilo_builder_surface_pointer(struct ilo_builder * builder,enum ilo_builder_item_type item,unsigned alignment,unsigned len,uint32_t ** dw)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
ilo_builder_surface_reloc(struct ilo_builder * builder,uint32_t offset,unsigned dw_index,struct intel_bo * bo,unsigned bo_offset,unsigned reloc_flags)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
ilo_builder_surface_reloc64(struct ilo_builder * builder,uint32_t offset,unsigned dw_index,struct intel_bo * bo,unsigned bo_offset,unsigned reloc_flags)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
ilo_builder_surface_used(const struct ilo_builder * builder)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
ilo_builder_instruction_write(struct ilo_builder * builder,unsigned size,const void * kernel)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
ilo_builder_batch_pointer(struct ilo_builder * builder,unsigned len,uint32_t ** dw)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
ilo_builder_batch_write(struct ilo_builder * builder,unsigned len,const uint32_t * dw)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
ilo_builder_batch_reloc(struct ilo_builder * builder,unsigned pos,struct intel_bo * bo,unsigned bo_offset,unsigned reloc_flags)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
ilo_builder_batch_reloc64(struct ilo_builder * builder,unsigned pos,struct intel_bo * bo,unsigned bo_offset,unsigned reloc_flags)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
ilo_builder_batch_used(const struct ilo_builder * builder)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
ilo_builder_batch_space(const struct ilo_builder * builder)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
ilo_builder_batch_discard(struct ilo_builder * builder)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
ilo_builder_batch_print_stats(const struct ilo_builder * builder)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