[Mesa-dev] Batchbuffer question
Kenneth Graunke
kenneth at whitecape.org
Fri Nov 8 13:38:36 PST 2013
On 11/08/2013 04:49 AM, Rogovin, Kevin wrote:
> Hi all,
>
> As I was poking into the magicks for the batchbuffer, I saw the
> following logical bits of code, that make sense by themselves but get
> me paranoid together. Firstly in intel_batchbuffer_begin() [
> intel_batchbuffer.h, and this is what BEGIN_BATCH maps to] there is a
> intel_batchbuffer_require_space() call that if too much room is
> needed then calls intel_batchbuffer_begin():
>
> from intel_batchbuffer_require_space():
>
> 115 if (intel_batchbuffer_space(brw) < sz)
> 116 intel_batchbuffer_flush(brw);
>
> and from intel_batchbuffer_space():
>
> 80 intel_batchbuffer_space(struct brw_context *brw)
> 81 {
> 82 return (brw->batch.state_batch_offset - brw->batch.reserved_space)
> 83 - brw->batch.used*4;
> 84 }
>
>
> Now, for allocating space for state, there is brw_state_batch():
>
>
> 128 offset = ROUND_DOWN_TO(batch->state_batch_offset - size, alignment);
> 129
> 130 /* If allocating from the top would wrap below the batchbuffer, or
> 131 * if the batch's used space (plus the reserved pad) collides with our
> 132 * space, then flush and try again.
> 133 */
> 134 if (batch->state_batch_offset < size ||
> 135 offset < 4*batch->used + batch->reserved_space) {
> 136 intel_batchbuffer_flush(brw);
> 137 offset = ROUND_DOWN_TO(batch->state_batch_offset - size, alignment);
> 138 }
>
>
> These taken together, I interpret as meaning that state and commands
> try to be separated by atleast batch->reserved_space bytes. I guess
> state could take up more than (batch->bo->size -
> batch->reserved_space) from that second ROUND_DOWN_TO, but that would
> only happen right after a flush and any state or command afterwards
> would flush too.
>
> Now my questions: 1) it looks like the reserved space is not to be
> used for either state or commands. Is that correct? What is it used
> for?
To explain a bit more...we store commands (like 3DSTATE_VS) and indirect
state (like BLEND_STATE) in the same buffer (the batchbuffer).
We emit commands starting at the top of the buffer, since they need to
be in order. Indirect state is always pointed to by a command (i.e.
3DSTATE_BLEND_STATE_POINTERS), so it can be in any order. We fill
indirect state backwards, starting from the end of the buffer.
Should they meet in the middle, we flush the batch and start a new one.
It's sort of like how the stack and heap start at opposite sides and
grow towards each other.
When we finish a batch, we need to append a few final commands. These
use the reserved space. From intel_batchbuffer.c:
brw->batch.reserved_space = 0;
brw_finish_batch(brw);
/* Mark the end of the buffer. */
intel_batchbuffer_emit_dword(brw, MI_BATCH_BUFFER_END);
if (brw->batch.used & 1) {
/* Round batchbuffer usage to 2 DWORDs. */
intel_batchbuffer_emit_dword(brw, MI_NOOP);
}
MI_BATCH_BUFFER_END is fairly self-explanatory, but there are others.
On Gen4-5, we need to take a snapshot of the PS_DEPTH_COUNT register in
order to make occlusion queries, so there's a PIPE_CONTROL. With my
upcoming performance monitor changes, we also need to take snapshots of
the observability architecture counters as well, so there will be an
MI_REPORT_PERF_COUNT.
See the comments above the BATCH_RESERVED #define, which list all the
things we might emit.
Note that, prior to emitting this state, we set
brw->batch.reserved_space to 0, which makes that space available for
these final commands. So we'll always have space and never try to flush
in the middle of flushing.
> 2) if a function first calls brw_state_batch() to place state and it
> barely fits and then calls BEGIN_BATCH that does not fit, then the
> command will refer to an offset on the previous batch buffer, that
> cannot be good. Or does this never happen for other reasons? If so
> what are those reasons?
Leaving additional indirect state in the buffer is harmless. We do need
to remove commands.
OpenGL draw calls involve emitting a bunch of commands, finishing with a
3DPRIMITIVE command. Prior to emitting anything, we call:
intel_batchbuffer_save_state(brw);
which saves batch->used and the current number of relocations. If we
run out of space before emitting the 3DPRIMITIVE, we call:
intel_batchbuffer_reset_to_saved(brw);
which resets the batch->used to the saved value, effectively throwing
away those commands. It also calls into libdrm to throw away the extra
relocations.
Hope this helps!
--Ken
More information about the mesa-dev
mailing list