<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Nov 10, 2016 at 1:56 PM, Nanley Chery <span dir="ltr"><<a href="mailto:nanleychery@gmail.com" target="_blank">nanleychery@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Nov 10, 2016 at 12:52:44PM -0800, Jason Ekstrand wrote:<br>
> On Nov 10, 2016 11:44, "Nanley Chery" <<a href="mailto:nanleychery@gmail.com">nanleychery@gmail.com</a>> wrote:<br>
> ><br>
> > On Wed, Nov 09, 2016 at 06:43:23PM -0800, Jason Ekstrand wrote:<br>
> > > On Wed, Nov 9, 2016 at 5:09 PM, Nanley Chery <<a href="mailto:nanleychery@gmail.com">nanleychery@gmail.com</a>><br>
> wrote:<br>
> > ><br>
> > > > On Sat, Oct 22, 2016 at 10:50:31AM -0700, Jason Ekstrand wrote:<br>
> > > > > This series does some fairly major surgery on color attachment<br>
> surface<br>
> > > > > state allocation and fill-out in the Intel Vulkan driver.  This is<br>
> in<br>
> > > > > preparation for doing color compression, fast-clears, and<br>
> HiZ-capable<br>
> > > > input<br>
> > > > > attachments.  Naturally, as with everything else I've done in the<br>
> last 2<br>
> > > > > months, it also involves some non-trivial blorp work.<br>
> > > > ><br>
> > > > > Let's start off at the beginning...  For a variety of reasons, we<br>
> can't<br>
> > > > > really know 100% of the details of an attachment's surface state at<br>
> any<br>
> > > > > other places than vkCmdBeginRenderPass and vkCmdNextSubpss.  The<br>
> same<br>
> > > > > applies for depth buffers if you consider 3DSTATE_DEPTH_BUFFER and<br>
> > > > friends<br>
> > > > > to be the depth and stencil buffer's "surface state".  That's a<br>
> fairly<br>
> > > > > strong statement, but there are a couple of reasons for this:<br>
> > > > ><br>
> > > > >  1) In order for fast-clears to work, the surface state has to<br>
> contain<br>
> > > > the<br>
> > > > >     clear color.  (This is it's own packet for HiZ but not for<br>
> color.)<br>
> > > > We<br>
> > > > >     don't know the clear value until BeginRenderPass.  This means we<br>
> > > > can't<br>
> > > > >     fully fill out the surface state in vkCmdCreateImageView.<br>
> > > > ><br>
> > > > >  2) The Vulkan spec requires that you be able to call<br>
> > > > vkBeginCommandBuffer<br>
> > > > >     on a secondary command buffer with<br>
> USAGE_RENDER_PASS_CONTINUE_BIT set<br>
> > > > >     but with a null framebuffer.  In this case, the secondary is<br>
> supposed<br>
> > > > >     to inherit the framebuffer from the primary.  (This is not<br>
> something<br>
> > > > we<br>
> > > > >     have properly implemented until now.)  This means that anything<br>
> that<br>
> > > > is<br>
> > > > >     callable from a render-pass-continuing secondary command buffer<br>
> has<br>
> > > > to<br>
> > > > >     be able to operate without knowing any surface details that<br>
> aren't<br>
> > > > part<br>
> > > > >     of the VkRenderPass object.  Basically, all you know is the<br>
> Vulkan<br>
> > > > >     format (not the isl format) and the sample count.<br>
> > > > ><br>
> > > > > Between the two of those, about the only two entrypoints left at<br>
> which we<br>
> > > > > actually know surface details are vkCmdBeginRenderPass and<br>
> > > > vkCmdNextSubpass<br>
> > > > > so we have to figure out how to do everything there.  As it turns<br>
> out,<br>
> > > > this<br>
> > > > > works out surprisingly well.  The format and the sample count turn<br>
> out to<br>
> > > > > be exactly the data we actually need in order to do all of our<br>
> pipeline<br>
> > > > > programming.  The only hard part is refactoring things so that it<br>
> pulls<br>
> > > > the<br>
> > > > > data from the render pass instead of the framebuffer.  There are a<br>
> number<br>
> > > > > of places where we were grabbing the image view for an attachment<br>
> because<br>
> > > > > we either wanted to shove something into blorp or because we wanted<br>
> the<br>
> > > > > format and we were lazy.<br>
> > > > ><br>
> > > > > The approach taken in this patch series is the following:<br>
> > > > ><br>
> > > > >  1) Instead of allocating render target surface states in<br>
> > > > vkCreateImageView,<br>
> > > > >     we allocate them as part of render pass setup in<br>
> > > > vkCmdBeginRenderPass.<br>
> > > > >     All of the surface states we will ever need (including a null<br>
> surface<br>
> > > > >     state) are allocated up-front out of a single contiguous block.<br>
> > > > ><br>
> > > > >  2) For secondary command buffers with<br>
> USAGE_RENDER_PASS_CONTINUE_BIT<br>
> > > > set,<br>
> > > > >     we allocate storage for all of the surface states but don't<br>
> actually<br>
> > > > >     fill them out.  In the secondary command buffer, all binding<br>
> tables<br>
> > > > >     refer to these surface states rather than the ones in the<br>
> primary.<br>
> > > > ><br>
> > > > >  3) A blorp entrypoint is added that performs a clear operation<br>
> without<br>
> > > > >     touching the depth/stencil buffer state and with a color<br>
> attachment<br>
> > > > >     binding table explicitly provided by the caller.  This means<br>
> that<br>
> > > > even<br>
> > > > >     our blorp clears are using the surface states allocated in<br>
> > > > >     vkCmdBeginRenderPass.  Unfortunately, this turned out to be<br>
> more work<br>
> > > > >     than expected because I had to add vertex shader support to<br>
> blorp<br>
> > > > along<br>
> > > > >     the way.<br>
> > > > ><br>
> > > > >  4) Here's the tricky bit.  When vkCmdExecuteCommands is called<br>
> during a<br>
> > > > >     render pass, we use transform feedback (yeah, crazy) to copy the<br>
> > > > block<br>
> > > > >     of surface states from the primary into the secondary right<br>
> before<br>
> > > > >     executing the secondary.<br>
> > > ><br>
> > > > Could we perform a CPU memcpy at this stage?<br>
> > > ><br>
> > ><br>
> > > We can but only if the secondary is created with the<br>
> SIMULTANEOUS_USE_BIT<br>
> > > unset.  If SIMULTANEOUS_USE_BIT is set, then it may be used in multiple<br>
> > > primaries at the same time.  In this case, since we don't know the order<br>
> > > they will be submitted to the GPU, we have to do the copy at the last<br>
> > > minute.  It may be a bit more performant to do the CPU memcpy in that<br>
> case.<br>
> > ><br>
> > > I didn't do that yet because I wanted to let it bake for a while with<br>
> just<br>
> > > the GPU memcpy.  The CPU memcpy is guaranteed to be reliable but the GPU<br>
> > > memcpy isn't.  By leaving it as just GPU memcpy, we'll get better tests<br>
> > > coverage of the crazy path.  If we find that it's causing problems,<br>
> doing a<br>
> > > CPU copy is a nice little optimization to have in our back pockets.<br>
> > ><br>
> ><br>
> > Got it. For this series, I think it would be helpful to print some sort<br>
> > of warning that surface states may be invalid in aub dumps.<br>
><br>
> We could, I suppose.  It would print every time someone uses a secondary<br>
> but that's probably OK as long as it's only in debug builds.<br>
><br>
> > We don't need to do the following now, but if we wanted to, I think we<br>
> > could always do a CPU memcpy. One way to accomplish this is to make<br>
> > secondaries with both SIMULTANEOUS_USE_BIT and RENDER_PASS_CONTINUE_BIT<br>
> > set use a contiguous batch. We could then emit this batch into the<br>
> > primary and replace the surface state block at vkCmdExecuteCommands().<br>
><br>
> Replacing surface state blocks is much harder than it sound.  You not only<br>
> have to allocate and copy but you also have to go in and patch up every<br>
> STATE_BASE_ADDRESS and probably patch up all the binding tables as well<br>
> because their address relative to the center of the surface state pool and<br>
> with it their address relative to the surface states had changed.<br>
><br>
<br>
</div></div>By replace the surface state block, I mean copy primary->state.render_pass_<wbr>states<br>
into secondary->state.render_pass_<wbr>states. That is what we're doing with<br>
the GPU memcpy isn't it? (I'm intentionally omitting bo and offset<br>
details here).<br></blockquote><div><br></div><div>Yes but we can only do a CPU memcpy of SIMULTANEOUS_USE_BIT isn't set.  If it is set, then the only way to do a CPU copy is if we allocate a new copy of render_pass_states for each primary it's used in.  If we make a copy of render_pass_states, then we have to update all of the binding tables to point to it.  This means we have to allocate new binding tables which means we have to patch STATE_BASE_ADDRESS and on down the rabbit hole you go.  In other words, we can't just patch up the one part of it from the CPU.  As soon as we make a new copy of one part, we're making a new copy of almost everything.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
> So, yes, we *can* do it in the sense that is allowed by the api but it will<br>
> add substantial complexity to ExecuteCommands.<br>
><br>
> > This matches the following note from the spec:<br>
> ><br>
> >   On some implementations, not using the<br>
> >   VK_COMMAND_BUFFER_USAGE_<wbr>SIMULTANEOUS_USE_BIT bit enables command<br>
> >   buffers to be patched in-place if needed, rather than creating a copy<br>
> >   of the command buffer.<br>
> ><br>
> > - Nanley<br>
</div></div></blockquote></div><br></div></div>