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