[Mesa-dev] Batchbuffer question

Kenneth Graunke kenneth at whitecape.org
Mon Nov 11 09:25:20 PST 2013


On 11/11/2013 07:31 AM, Paul Berry wrote:
> On 8 November 2013 13:38, Kenneth Graunke <kenneth at whitecape.org
> <mailto:kenneth at whitecape.org>> wrote:
> 
>     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.
> 
> 
> Ken,
> 
> When you say "If we run out of space before emitting the 3DPRIMITIVE",
> it sounds from context like you are saying "if we run out of batch
> buffer space".  I used to think the same thing, however before answering
> Kevin's email I looked at the code, and found that this isn't the case. 
> In fact, we only use intel_batchbuffer_reset_to_saved() if we run out of
> space in the *aperture*.  There is no mechanism for retrying in the
> event that we run out of batch buffer space.  The way we avoid running
> out of batchbuffer space is that before starting the draw call, we make
> an estimate of how much batch buffer space is needed, and we flush if
> that much space isn't available.  If our estimate was wrong and we wind
> up running out of batch space anyhow, then we assertion fail (see the
> "assert(!brw->no_batch_wrap);" in _intel_batchbuffer_flush()).
> 
> Just trying to make sure we keep the record straight,
> 
> Paul

Good grief...you're right.  That's garbage.

We should really fix that...

--Ken


More information about the mesa-dev mailing list