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 "ilo_builder.h"
29 #include "ilo_builder_render.h" /* for ilo_builder_batch_patch_sba() */
31 enum ilo_builder_writer_flags
{
33 * When this bit is set, ilo_builder_begin() will not realllocate. New
34 * data will be appended instead.
36 WRITER_FLAG_APPEND
= 1 << 0,
39 * When this bit is set, the writer grows when full. When not, callers
40 * must make sure the writer never needs to grow.
42 WRITER_FLAG_GROW
= 1 << 1,
45 * The writer will be mapped directly.
47 WRITER_FLAG_MAP
= 1 << 2,
51 * Set the initial size and flags of a writer.
54 ilo_builder_writer_init(struct ilo_builder
*builder
,
55 enum ilo_builder_writer_type which
)
57 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
60 case ILO_BUILDER_WRITER_BATCH
:
61 writer
->size
= sizeof(uint32_t) * 8192;
63 case ILO_BUILDER_WRITER_INSTRUCTION
:
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.
70 writer
->flags
= WRITER_FLAG_APPEND
| WRITER_FLAG_GROW
;
74 assert(!"unknown builder writer");
79 if (builder
->dev
->has_llc
)
80 writer
->flags
|= WRITER_FLAG_MAP
;
84 * Free all resources used by a writer. Note that the initial size is not
88 ilo_builder_writer_reset(struct ilo_builder
*builder
,
89 enum ilo_builder_writer_type which
)
91 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
94 if (writer
->flags
& WRITER_FLAG_MAP
)
95 intel_bo_unmap(writer
->bo
);
103 intel_bo_unreference(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
);
172 intel_bo_unreference(writer
->bo
);
174 } else if (writer
->bo
) {
175 /* reuse the old bo */
176 ilo_builder_writer_discard(builder
, which
);
183 writer
->item_used
= 0;
186 /* map the bo or allocate the staging system memory */
187 if (writer
->flags
& WRITER_FLAG_MAP
)
188 writer
->ptr
= map_writer_bo(writer
->bo
, writer
->flags
);
189 else if (!writer
->ptr
)
190 writer
->ptr
= MALLOC(writer
->size
);
192 return (writer
->ptr
!= NULL
);
196 * Unmap the buffer for submission.
199 ilo_builder_writer_unmap(struct ilo_builder
*builder
,
200 enum ilo_builder_writer_type which
)
202 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
206 if (writer
->flags
& WRITER_FLAG_MAP
) {
207 intel_bo_unmap(writer
->bo
);
212 offset
= builder
->begin_used
[which
];
213 if (writer
->used
> offset
) {
214 err
= intel_bo_pwrite(writer
->bo
, offset
, writer
->used
- offset
,
215 (char *) writer
->ptr
+ offset
);
218 if (writer
->stolen
&& !err
) {
219 const unsigned offset
= writer
->size
- writer
->stolen
;
220 err
= intel_bo_pwrite(writer
->bo
, offset
, writer
->stolen
,
221 (const char *) writer
->ptr
+ offset
);
224 /* keep writer->ptr */
230 * Grow a mapped writer to at least \p new_size.
233 ilo_builder_writer_grow(struct ilo_builder
*builder
,
234 enum ilo_builder_writer_type which
,
235 unsigned new_size
, bool preserve
)
237 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
238 struct intel_bo
*new_bo
;
241 if (!(writer
->flags
& WRITER_FLAG_GROW
))
244 /* stolen data may already be referenced and cannot be moved */
248 if (new_size
< writer
->size
<< 1)
249 new_size
= writer
->size
<< 1;
250 /* STATE_BASE_ADDRESS requires page-aligned buffers */
251 new_size
= align(new_size
, 4096);
253 new_bo
= alloc_writer_bo(builder
->winsys
, which
, new_size
);
257 /* map and copy the data over */
258 if (writer
->flags
& WRITER_FLAG_MAP
) {
259 new_ptr
= map_writer_bo(new_bo
, writer
->flags
);
262 * When WRITER_FLAG_APPEND and WRITER_FLAG_GROW are both set, we may end
263 * up copying between two GTT-mapped BOs. That is slow. The issue
264 * could be solved by adding intel_bo_map_async(), or callers may choose
265 * to manually grow the writer without preserving the data.
267 if (new_ptr
&& preserve
)
268 memcpy(new_ptr
, writer
->ptr
, writer
->used
);
269 } else if (preserve
) {
270 new_ptr
= REALLOC(writer
->ptr
, writer
->size
, new_size
);
272 new_ptr
= MALLOC(new_size
);
276 intel_bo_unreference(new_bo
);
280 if (writer
->flags
& WRITER_FLAG_MAP
)
281 intel_bo_unmap(writer
->bo
);
285 intel_bo_unreference(writer
->bo
);
287 writer
->size
= new_size
;
289 writer
->ptr
= new_ptr
;
295 * Record an item for later decoding.
298 ilo_builder_writer_record(struct ilo_builder
*builder
,
299 enum ilo_builder_writer_type which
,
300 enum ilo_builder_item_type type
,
301 unsigned offset
, unsigned size
)
303 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
304 struct ilo_builder_item
*item
;
306 if (writer
->item_used
== writer
->item_alloc
) {
307 const unsigned new_alloc
= (writer
->item_alloc
) ?
308 writer
->item_alloc
<< 1 : 256;
309 struct ilo_builder_item
*items
;
311 items
= REALLOC(writer
->items
,
312 sizeof(writer
->items
[0]) * writer
->item_alloc
,
313 sizeof(writer
->items
[0]) * new_alloc
);
317 writer
->items
= items
;
318 writer
->item_alloc
= new_alloc
;
321 item
= &writer
->items
[writer
->item_used
++];
323 item
->offset
= offset
;
330 * Initialize the builder.
333 ilo_builder_init(struct ilo_builder
*builder
,
334 const struct ilo_dev_info
*dev
,
335 struct intel_winsys
*winsys
)
339 memset(builder
, 0, sizeof(*builder
));
342 builder
->winsys
= winsys
;
344 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
345 ilo_builder_writer_init(builder
, i
);
349 * Reset the builder and free all resources used. After resetting, the
350 * builder behaves as if it is newly initialized, except for potentially
351 * larger initial bo sizes.
354 ilo_builder_reset(struct ilo_builder
*builder
)
358 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
359 ilo_builder_writer_reset(builder
, i
);
363 * Allocate and map the BOs. It may re-allocate or reuse existing BOs if
366 * Most builder functions can only be called after ilo_builder_begin() and
367 * before ilo_builder_end().
370 ilo_builder_begin(struct ilo_builder
*builder
)
374 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++) {
375 if (!ilo_builder_writer_alloc_and_map(builder
, i
)) {
376 ilo_builder_reset(builder
);
380 builder
->begin_used
[i
] = builder
->writers
[i
].used
;
383 builder
->unrecoverable_error
= false;
384 builder
->sba_instruction_pos
= 0;
390 * Unmap BOs and make sure the written data landed the BOs. The batch buffer
391 * ready for submission is returned.
394 ilo_builder_end(struct ilo_builder
*builder
, unsigned *used
)
396 struct ilo_builder_writer
*bat
;
399 ilo_builder_batch_patch_sba(builder
);
401 assert(ilo_builder_validate(builder
, 0, NULL
));
403 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++) {
404 if (!ilo_builder_writer_unmap(builder
, i
))
405 builder
->unrecoverable_error
= true;
408 if (builder
->unrecoverable_error
)
411 bat
= &builder
->writers
[ILO_BUILDER_WRITER_BATCH
];
419 * Return true if the builder is in a valid state, after accounting for the
420 * additional BOs specified. The additional BOs can be listed to avoid
421 * snapshotting and restoring when they are known ahead of time.
423 * The number of additional BOs should not be more than a few. Like two, for
424 * copying between two BOs.
426 * Callers must make sure the builder is in a valid state when
427 * ilo_builder_end() is called.
430 ilo_builder_validate(struct ilo_builder
*builder
,
431 unsigned bo_count
, struct intel_bo
**bos
)
433 const unsigned max_bo_count
= 2;
434 struct intel_bo
*bos_to_submit
[ILO_BUILDER_WRITER_COUNT
+ max_bo_count
];
437 for (i
= 0; i
< ILO_BUILDER_WRITER_COUNT
; i
++)
438 bos_to_submit
[i
] = builder
->writers
[i
].bo
;
441 assert(bo_count
<= max_bo_count
);
442 if (bo_count
> max_bo_count
)
445 memcpy(&bos_to_submit
[ILO_BUILDER_WRITER_COUNT
],
446 bos
, sizeof(*bos
) * bo_count
);
450 return intel_winsys_can_submit_bo(builder
->winsys
, bos_to_submit
, i
);
454 * Take a snapshot of the writer state.
457 ilo_builder_batch_snapshot(const struct ilo_builder
*builder
,
458 struct ilo_builder_snapshot
*snapshot
)
460 const enum ilo_builder_writer_type which
= ILO_BUILDER_WRITER_BATCH
;
461 const struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
463 snapshot
->reloc_count
= intel_bo_get_reloc_count(writer
->bo
);
464 snapshot
->used
= writer
->used
;
465 snapshot
->stolen
= writer
->stolen
;
466 snapshot
->item_used
= writer
->item_used
;
470 * Restore the writer state to when the snapshot was taken, except that it
471 * does not (unnecessarily) shrink BOs or the item array.
474 ilo_builder_batch_restore(struct ilo_builder
*builder
,
475 const struct ilo_builder_snapshot
*snapshot
)
477 const enum ilo_builder_writer_type which
= ILO_BUILDER_WRITER_BATCH
;
478 struct ilo_builder_writer
*writer
= &builder
->writers
[which
];
480 intel_bo_truncate_relocs(writer
->bo
, snapshot
->reloc_count
);
481 writer
->used
= snapshot
->used
;
482 writer
->stolen
= snapshot
->stolen
;
483 writer
->item_used
= snapshot
->item_used
;