2 * Mesa 3-D graphics library
4 * Copyright (C) 2014 LunarG, Inc.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Chia-I Wu <olv@lunarg.com>
28 #include "util/u_memory.h"
30 #include "ilo_builder.h"
31 #include "ilo_builder_render.h" /* for ilo_builder_batch_patch_sba() */
33 enum ilo_builder_writer_flags
{
35 * When this bit is set, ilo_builder_begin() will not realllocate. New
36 * data will be appended instead.
38 WRITER_FLAG_APPEND
= 1 << 0,
41 * When this bit is set, the writer grows when full. When not, callers
42 * must make sure the writer never needs to grow.
44 WRITER_FLAG_GROW
= 1 << 1,
47 * The writer will be mapped directly.
49 WRITER_FLAG_MAP
= 1 << 2,
53 * Set the initial size and flags of a writer.
56 ilo_builder_writer_init(struct ilo_builder
*builder
,
57 enum ilo_builder_writer_type which
)
59 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
62 case ILO_BUILDER_WRITER_BATCH
:
63 writer
->size
= sizeof(uint32_t) * 8192;
65 case ILO_BUILDER_WRITER_INSTRUCTION
:
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.
72 writer
->flags
= WRITER_FLAG_APPEND
| WRITER_FLAG_GROW
;
76 assert(!"unknown builder writer");
81 if (builder
->dev
->has_llc
)
82 writer
->flags
|= WRITER_FLAG_MAP
;
86 * Free all resources used by a writer. Note that the initial size is not
90 ilo_builder_writer_reset(struct ilo_builder
*builder
,
91 enum ilo_builder_writer_type which
)
93 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
96 if (writer
->flags
& WRITER_FLAG_MAP
)
97 intel_bo_unmap(writer
->bo
);
104 intel_bo_unref(writer
->bo
);
112 writer
->item_alloc
= 0;
113 writer
->item_used
= 0;
118 * Discard everything written so far.
121 ilo_builder_writer_discard(struct ilo_builder
*builder
,
122 enum ilo_builder_writer_type which
)
124 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
126 intel_bo_truncate_relocs(writer
->bo
, 0);
129 writer
->item_used
= 0;
132 static struct intel_bo
*
133 alloc_writer_bo(struct intel_winsys
*winsys
,
134 enum ilo_builder_writer_type which
,
137 static const char *writer_names
[ILO_BUILDER_WRITER_COUNT
] = {
138 [ILO_BUILDER_WRITER_BATCH
] = "batch",
139 [ILO_BUILDER_WRITER_INSTRUCTION
] = "instruction",
142 return intel_winsys_alloc_bo(winsys
, writer_names
[which
], size
, true);
146 map_writer_bo(struct intel_bo
*bo
, unsigned flags
)
148 assert(flags
& WRITER_FLAG_MAP
);
150 if (flags
& WRITER_FLAG_APPEND
)
151 return intel_bo_map_gtt_async(bo
);
153 return intel_bo_map(bo
, true);
157 * Allocate and map the buffer for writing.
160 ilo_builder_writer_alloc_and_map(struct ilo_builder
*builder
,
161 enum ilo_builder_writer_type which
)
163 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
165 /* allocate a new bo when not appending */
166 if (!(writer
->flags
& WRITER_FLAG_APPEND
) || !writer
->bo
) {
169 bo
= alloc_writer_bo(builder
->winsys
, which
, writer
->size
);
171 intel_bo_unref(writer
->bo
);
173 } else if (writer
->bo
) {
174 /* reuse the old bo */
175 ilo_builder_writer_discard(builder
, which
);
182 writer
->item_used
= 0;
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
);
191 return (writer
->ptr
!= NULL
);
195 * Unmap the buffer for submission.
198 ilo_builder_writer_unmap(struct ilo_builder
*builder
,
199 enum ilo_builder_writer_type which
)
201 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
205 if (writer
->flags
& WRITER_FLAG_MAP
) {
206 intel_bo_unmap(writer
->bo
);
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
);
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
);
223 /* keep writer->ptr */
229 * Grow a mapped writer to at least \p new_size.
232 ilo_builder_writer_grow(struct ilo_builder
*builder
,
233 enum ilo_builder_writer_type which
,
234 unsigned new_size
, bool preserve
)
236 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
237 struct intel_bo
*new_bo
;
240 if (!(writer
->flags
& WRITER_FLAG_GROW
))
243 /* stolen data may already be referenced and cannot be moved */
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);
252 new_bo
= alloc_writer_bo(builder
->winsys
, which
, new_size
);
256 /* map and copy the data over */
257 if (writer
->flags
& WRITER_FLAG_MAP
) {
258 new_ptr
= map_writer_bo(new_bo
, writer
->flags
);
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.
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
);
271 new_ptr
= MALLOC(new_size
);
275 intel_bo_unref(new_bo
);
279 if (writer
->flags
& WRITER_FLAG_MAP
)
280 intel_bo_unmap(writer
->bo
);
284 intel_bo_unref(writer
->bo
);
286 writer
->size
= new_size
;
288 writer
->ptr
= new_ptr
;
294 * Record an item for later decoding.
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
)
302 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
303 struct ilo_builder_item
*item
;
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
;
310 items
= REALLOC(writer
->items
,
311 sizeof(writer
->items
[0]) * writer
->item_alloc
,
312 sizeof(writer
->items
[0]) * new_alloc
);
316 writer
->items
= items
;
317 writer
->item_alloc
= new_alloc
;
320 item
= &writer
->items
[writer
->item_used
++];
322 item
->offset
= offset
;
329 * Initialize the builder.
332 ilo_builder_init(struct ilo_builder
*builder
,
333 const struct ilo_dev
*dev
,
334 struct intel_winsys
*winsys
)
338 assert(ilo_is_zeroed(builder
, sizeof(*builder
)));
341 builder
->winsys
= winsys
;
343 /* gen6_SURFACE_STATE() may override this */
344 switch (ilo_dev_gen(dev
)) {
346 builder
->mocs
= GEN8_MOCS_MT_WB
| GEN8_MOCS_CT_L3
;
350 builder
->mocs
= GEN7_MOCS_L3_WB
;
357 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
358 ilo_builder_writer_init(builder
, i
);
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.
367 ilo_builder_reset(struct ilo_builder
*builder
)
371 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
372 ilo_builder_writer_reset(builder
, i
);
376 * Allocate and map the BOs. It may re-allocate or reuse existing BOs if
379 * Most builder functions can only be called after ilo_builder_begin() and
380 * before ilo_builder_end().
383 ilo_builder_begin(struct ilo_builder
*builder
)
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
);
393 builder
->begin_used
[i
] = builder
->writers
[i
].used
;
396 builder
->unrecoverable_error
= false;
397 builder
->sba_instruction_pos
= 0;
403 * Unmap BOs and make sure the written data landed the BOs. The batch buffer
404 * ready for submission is returned.
407 ilo_builder_end(struct ilo_builder
*builder
, unsigned *used
)
409 struct ilo_builder_writer
*bat
;
412 ilo_builder_batch_patch_sba(builder
);
414 assert(ilo_builder_validate(builder
, 0, NULL
));
416 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++) {
417 if (!ilo_builder_writer_unmap(builder
, i
))
418 builder
->unrecoverable_error
= true;
421 if (builder
->unrecoverable_error
)
424 bat
= &builder
->writers
[ILO_BUILDER_WRITER_BATCH
];
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.
436 * The number of additional BOs should not be more than a few. Like two, for
437 * copying between two BOs.
439 * Callers must make sure the builder is in a valid state when
440 * ilo_builder_end() is called.
443 ilo_builder_validate(struct ilo_builder
*builder
,
444 unsigned bo_count
, struct intel_bo
**bos
)
446 const unsigned max_bo_count
= 2;
447 struct intel_bo
*bos_to_submit
[ILO_BUILDER_WRITER_COUNT
+ max_bo_count
];
450 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
451 bos_to_submit
[i
] = builder
->writers
[i
].bo
;
454 assert(bo_count
<= max_bo_count
);
455 if (bo_count
> max_bo_count
)
458 memcpy(&bos_to_submit
[ILO_BUILDER_WRITER_COUNT
],
459 bos
, sizeof(*bos
) * bo_count
);
463 return intel_winsys_can_submit_bo(builder
->winsys
, bos_to_submit
, i
);
467 * Take a snapshot of the writer state.
470 ilo_builder_batch_snapshot(const struct ilo_builder
*builder
,
471 struct ilo_builder_snapshot
*snapshot
)
473 const enum ilo_builder_writer_type which
= ILO_BUILDER_WRITER_BATCH
;
474 const struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
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
;
483 * Restore the writer state to when the snapshot was taken, except that it
484 * does not (unnecessarily) shrink BOs or the item array.
487 ilo_builder_batch_restore(struct ilo_builder
*builder
,
488 const struct ilo_builder_snapshot
*snapshot
)
490 const enum ilo_builder_writer_type which
= ILO_BUILDER_WRITER_BATCH
;
491 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
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
;