anv: Deduplicate render pass code

This lets us share the renderpass code and depth/stencil state code
between gen 7 and gen 8.
This commit is contained in:
Kristian Høgsberg Kristensen 2016-02-14 23:01:42 -08:00
parent ac4fd0ed21
commit 85f67cf16e
3 changed files with 179 additions and 343 deletions

View file

@ -556,176 +556,6 @@ genX(cmd_buffer_flush_state)(struct anv_cmd_buffer *cmd_buffer)
cmd_buffer->state.dirty = 0;
}
static void
cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
{
struct anv_device *device = cmd_buffer->device;
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
const struct anv_image_view *iview =
anv_cmd_buffer_get_depth_stencil_view(cmd_buffer);
const struct anv_image *image = iview ? iview->image : NULL;
const struct anv_format *anv_format =
iview ? anv_format_for_vk_format(iview->vk_format) : NULL;
const bool has_depth = iview && anv_format->has_depth;
const bool has_stencil = iview && anv_format->has_stencil;
/* Emit 3DSTATE_DEPTH_BUFFER */
if (has_depth) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.DepthWriteEnable = true,
.StencilWriteEnable = has_stencil,
.HierarchicalDepthBufferEnable = false,
.SurfaceFormat = isl_surf_get_depth_format(&device->isl_dev,
&image->depth_surface.isl),
.SurfacePitch = image->depth_surface.isl.row_pitch - 1,
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->depth_surface.offset,
},
.Height = fb->height - 1,
.Width = fb->width - 1,
.LOD = 0,
.Depth = 1 - 1,
.MinimumArrayElement = 0,
.DepthBufferObjectControlState = GENX(MOCS),
.RenderTargetViewExtent = 1 - 1);
} else {
/* Even when no depth buffer is present, the hardware requires that
* 3DSTATE_DEPTH_BUFFER be programmed correctly. The Broadwell PRM says:
*
* If a null depth buffer is bound, the driver must instead bind depth as:
* 3DSTATE_DEPTH.SurfaceType = SURFTYPE_2D
* 3DSTATE_DEPTH.Width = 1
* 3DSTATE_DEPTH.Height = 1
* 3DSTATE_DEPTH.SuraceFormat = D16_UNORM
* 3DSTATE_DEPTH.SurfaceBaseAddress = 0
* 3DSTATE_DEPTH.HierarchicalDepthBufferEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthTestEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthBufferWriteEnable = 0
*
* The PRM is wrong, though. The width and height must be programmed to
* actual framebuffer's width and height, even when neither depth buffer
* nor stencil buffer is present.
*/
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.SurfaceFormat = D16_UNORM,
.Width = fb->width - 1,
.Height = fb->height - 1,
.StencilWriteEnable = has_stencil);
}
/* Emit 3DSTATE_STENCIL_BUFFER */
if (has_stencil) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_STENCIL_BUFFER),
# if (ANV_IS_HASWELL)
.StencilBufferEnable = true,
# endif
.StencilBufferObjectControlState = GENX(MOCS),
/* Stencil buffers have strange pitch. The PRM says:
*
* The pitch must be set to 2x the value computed based on width,
* as the stencil buffer is stored with two rows interleaved.
*/
.SurfacePitch = 2 * image->stencil_surface.isl.row_pitch - 1,
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->offset + image->stencil_surface.offset,
});
} else {
anv_batch_emit(&cmd_buffer->batch, GEN7_3DSTATE_STENCIL_BUFFER);
}
/* Disable hierarchial depth buffers. */
anv_batch_emit(&cmd_buffer->batch, GEN7_3DSTATE_HIER_DEPTH_BUFFER);
/* Clear the clear params. */
anv_batch_emit(&cmd_buffer->batch, GEN7_3DSTATE_CLEAR_PARAMS);
}
/**
* @see anv_cmd_buffer_set_subpass()
*/
GENX_FUNC(GEN7, GEN7) void
genX(cmd_buffer_set_subpass)(struct anv_cmd_buffer *cmd_buffer,
struct anv_subpass *subpass)
{
cmd_buffer->state.subpass = subpass;
cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_FRAGMENT_BIT;
cmd_buffer->state.dirty |= ANV_CMD_DIRTY_RENDER_TARGETS;
cmd_buffer_emit_depth_stencil(cmd_buffer);
}
void genX(CmdBeginRenderPass)(
VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_render_pass, pass, pRenderPassBegin->renderPass);
ANV_FROM_HANDLE(anv_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
cmd_buffer->state.framebuffer = framebuffer;
cmd_buffer->state.pass = pass;
anv_cmd_state_setup_attachments(cmd_buffer, pRenderPassBegin);
genX(flush_pipeline_select_3d)(cmd_buffer);
const VkRect2D *render_area = &pRenderPassBegin->renderArea;
anv_batch_emit(&cmd_buffer->batch, GEN7_3DSTATE_DRAWING_RECTANGLE,
.ClippedDrawingRectangleYMin = render_area->offset.y,
.ClippedDrawingRectangleXMin = render_area->offset.x,
.ClippedDrawingRectangleYMax =
render_area->offset.y + render_area->extent.height - 1,
.ClippedDrawingRectangleXMax =
render_area->offset.x + render_area->extent.width - 1,
.DrawingRectangleOriginY = 0,
.DrawingRectangleOriginX = 0);
gen7_cmd_buffer_set_subpass(cmd_buffer, pass->subpasses);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdNextSubpass)(
VkCommandBuffer commandBuffer,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
gen7_cmd_buffer_set_subpass(cmd_buffer, cmd_buffer->state.subpass + 1);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdEndRenderPass)(
VkCommandBuffer commandBuffer)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
/* Emit a flushing pipe control at the end of a pass. This is kind of a
* hack but it ensures that render targets always actually get written.
* Eventually, we should do flushing based on image format transitions
* or something of that nature.
*/
anv_batch_emit(&cmd_buffer->batch, GEN7_PIPE_CONTROL,
.PostSyncOperation = NoWrite,
.RenderTargetCacheFlushEnable = true,
.InstructionCacheInvalidateEnable = true,
.DepthCacheFlushEnable = true,
.VFCacheInvalidationEnable = true,
.TextureCacheInvalidationEnable = true,
.CommandStreamerStallEnable = true);
}
void genX(CmdSetEvent)(
VkCommandBuffer commandBuffer,
VkEvent event,

View file

@ -602,179 +602,6 @@ genX(cmd_buffer_flush_compute_state)(struct anv_cmd_buffer *cmd_buffer)
cmd_buffer->state.compute_dirty = 0;
}
static void
cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
{
struct anv_device *device = cmd_buffer->device;
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
const struct anv_image_view *iview =
anv_cmd_buffer_get_depth_stencil_view(cmd_buffer);
const struct anv_image *image = iview ? iview->image : NULL;
const struct anv_format *anv_format =
iview ? anv_format_for_vk_format(iview->vk_format) : NULL;
const bool has_depth = iview && anv_format->has_depth;
const bool has_stencil = iview && anv_format->has_stencil;
/* FIXME: Implement the PMA stall W/A */
/* FIXME: Width and Height are wrong */
/* Emit 3DSTATE_DEPTH_BUFFER */
if (has_depth) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.DepthWriteEnable = true,
.StencilWriteEnable = has_stencil,
.HierarchicalDepthBufferEnable = false,
.SurfaceFormat = isl_surf_get_depth_format(&device->isl_dev,
&image->depth_surface.isl),
.SurfacePitch = image->depth_surface.isl.row_pitch - 1,
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->depth_surface.offset,
},
.Height = fb->height - 1,
.Width = fb->width - 1,
.LOD = 0,
.Depth = 1 - 1,
.MinimumArrayElement = 0,
.DepthBufferObjectControlState = GENX(MOCS),
.RenderTargetViewExtent = 1 - 1,
.SurfaceQPitch = isl_surf_get_array_pitch_el_rows(&image->depth_surface.isl) >> 2);
} else {
/* Even when no depth buffer is present, the hardware requires that
* 3DSTATE_DEPTH_BUFFER be programmed correctly. The Broadwell PRM says:
*
* If a null depth buffer is bound, the driver must instead bind depth as:
* 3DSTATE_DEPTH.SurfaceType = SURFTYPE_2D
* 3DSTATE_DEPTH.Width = 1
* 3DSTATE_DEPTH.Height = 1
* 3DSTATE_DEPTH.SuraceFormat = D16_UNORM
* 3DSTATE_DEPTH.SurfaceBaseAddress = 0
* 3DSTATE_DEPTH.HierarchicalDepthBufferEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthTestEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthBufferWriteEnable = 0
*
* The PRM is wrong, though. The width and height must be programmed to
* actual framebuffer's width and height, even when neither depth buffer
* nor stencil buffer is present.
*/
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.SurfaceFormat = D16_UNORM,
.Width = fb->width - 1,
.Height = fb->height - 1,
.StencilWriteEnable = has_stencil);
}
/* Emit 3DSTATE_STENCIL_BUFFER */
if (has_stencil) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_STENCIL_BUFFER),
.StencilBufferEnable = true,
.StencilBufferObjectControlState = GENX(MOCS),
/* Stencil buffers have strange pitch. The PRM says:
*
* The pitch must be set to 2x the value computed based on width,
* as the stencil buffer is stored with two rows interleaved.
*/
.SurfacePitch = 2 * image->stencil_surface.isl.row_pitch - 1,
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->offset + image->stencil_surface.offset,
},
.SurfaceQPitch = isl_surf_get_array_pitch_el_rows(&image->stencil_surface.isl) >> 2);
} else {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_STENCIL_BUFFER));
}
/* Disable hierarchial depth buffers. */
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_HIER_DEPTH_BUFFER));
/* Clear the clear params. */
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_CLEAR_PARAMS));
}
/**
* @see anv_cmd_buffer_set_subpass()
*/
void
genX(cmd_buffer_set_subpass)(struct anv_cmd_buffer *cmd_buffer,
struct anv_subpass *subpass)
{
cmd_buffer->state.subpass = subpass;
cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_FRAGMENT_BIT;
cmd_buffer_emit_depth_stencil(cmd_buffer);
}
void genX(CmdBeginRenderPass)(
VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_render_pass, pass, pRenderPassBegin->renderPass);
ANV_FROM_HANDLE(anv_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
cmd_buffer->state.framebuffer = framebuffer;
cmd_buffer->state.pass = pass;
anv_cmd_state_setup_attachments(cmd_buffer, pRenderPassBegin);
genX(flush_pipeline_select_3d)(cmd_buffer);
const VkRect2D *render_area = &pRenderPassBegin->renderArea;
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DRAWING_RECTANGLE),
.ClippedDrawingRectangleYMin = render_area->offset.y,
.ClippedDrawingRectangleXMin = render_area->offset.x,
.ClippedDrawingRectangleYMax =
render_area->offset.y + render_area->extent.height - 1,
.ClippedDrawingRectangleXMax =
render_area->offset.x + render_area->extent.width - 1,
.DrawingRectangleOriginY = 0,
.DrawingRectangleOriginX = 0);
genX(cmd_buffer_set_subpass)(cmd_buffer, pass->subpasses);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdNextSubpass)(
VkCommandBuffer commandBuffer,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
genX(cmd_buffer_set_subpass)(cmd_buffer, cmd_buffer->state.subpass + 1);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdEndRenderPass)(
VkCommandBuffer commandBuffer)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
/* Emit a flushing pipe control at the end of a pass. This is kind of a
* hack but it ensures that render targets always actually get written.
* Eventually, we should do flushing based on image format transitions
* or something of that nature.
*/
anv_batch_emit(&cmd_buffer->batch, GENX(PIPE_CONTROL),
.PostSyncOperation = NoWrite,
.RenderTargetCacheFlushEnable = true,
.InstructionCacheInvalidateEnable = true,
.DepthCacheFlushEnable = true,
.VFCacheInvalidationEnable = true,
.TextureCacheInvalidationEnable = true,
.CommandStreamerStallEnable = true);
}
static void
emit_ps_depth_count(struct anv_batch *batch,
struct anv_bo *bo, uint32_t offset)

View file

@ -548,3 +548,182 @@ genX(flush_pipeline_select_3d)(struct anv_cmd_buffer *cmd_buffer)
cmd_buffer->state.current_pipeline = _3D;
}
}
static void
cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
{
struct anv_device *device = cmd_buffer->device;
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
const struct anv_image_view *iview =
anv_cmd_buffer_get_depth_stencil_view(cmd_buffer);
const struct anv_image *image = iview ? iview->image : NULL;
const struct anv_format *anv_format =
iview ? anv_format_for_vk_format(iview->vk_format) : NULL;
const bool has_depth = iview && anv_format->has_depth;
const bool has_stencil = iview && anv_format->has_stencil;
/* FIXME: Implement the PMA stall W/A */
/* FIXME: Width and Height are wrong */
/* Emit 3DSTATE_DEPTH_BUFFER */
if (has_depth) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.DepthWriteEnable = true,
.StencilWriteEnable = has_stencil,
.HierarchicalDepthBufferEnable = false,
.SurfaceFormat = isl_surf_get_depth_format(&device->isl_dev,
&image->depth_surface.isl),
.SurfacePitch = image->depth_surface.isl.row_pitch - 1,
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->depth_surface.offset,
},
.Height = fb->height - 1,
.Width = fb->width - 1,
.LOD = 0,
.Depth = 1 - 1,
.MinimumArrayElement = 0,
.DepthBufferObjectControlState = GENX(MOCS),
#if ANV_GEN >= 8
.SurfaceQPitch = isl_surf_get_array_pitch_el_rows(&image->depth_surface.isl) >> 2,
#endif
.RenderTargetViewExtent = 1 - 1);
} else {
/* Even when no depth buffer is present, the hardware requires that
* 3DSTATE_DEPTH_BUFFER be programmed correctly. The Broadwell PRM says:
*
* If a null depth buffer is bound, the driver must instead bind depth as:
* 3DSTATE_DEPTH.SurfaceType = SURFTYPE_2D
* 3DSTATE_DEPTH.Width = 1
* 3DSTATE_DEPTH.Height = 1
* 3DSTATE_DEPTH.SuraceFormat = D16_UNORM
* 3DSTATE_DEPTH.SurfaceBaseAddress = 0
* 3DSTATE_DEPTH.HierarchicalDepthBufferEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthTestEnable = 0
* 3DSTATE_WM_DEPTH_STENCIL.DepthBufferWriteEnable = 0
*
* The PRM is wrong, though. The width and height must be programmed to
* actual framebuffer's width and height, even when neither depth buffer
* nor stencil buffer is present.
*/
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DEPTH_BUFFER),
.SurfaceType = SURFTYPE_2D,
.SurfaceFormat = D16_UNORM,
.Width = fb->width - 1,
.Height = fb->height - 1,
.StencilWriteEnable = has_stencil);
}
/* Emit 3DSTATE_STENCIL_BUFFER */
if (has_stencil) {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_STENCIL_BUFFER),
#if ANV_GEN >= 8 || ANV_IS_HASWELL
.StencilBufferEnable = true,
#endif
.StencilBufferObjectControlState = GENX(MOCS),
/* Stencil buffers have strange pitch. The PRM says:
*
* The pitch must be set to 2x the value computed based on width,
* as the stencil buffer is stored with two rows interleaved.
*/
.SurfacePitch = 2 * image->stencil_surface.isl.row_pitch - 1,
#if ANV_GEN >= 8
.SurfaceQPitch = isl_surf_get_array_pitch_el_rows(&image->stencil_surface.isl) >> 2,
#endif
.SurfaceBaseAddress = {
.bo = image->bo,
.offset = image->offset + image->stencil_surface.offset,
});
} else {
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_STENCIL_BUFFER));
}
/* Disable hierarchial depth buffers. */
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_HIER_DEPTH_BUFFER));
/* Clear the clear params. */
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_CLEAR_PARAMS));
}
/**
* @see anv_cmd_buffer_set_subpass()
*/
void
genX(cmd_buffer_set_subpass)(struct anv_cmd_buffer *cmd_buffer,
struct anv_subpass *subpass)
{
cmd_buffer->state.subpass = subpass;
cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_FRAGMENT_BIT;
cmd_buffer_emit_depth_stencil(cmd_buffer);
}
void genX(CmdBeginRenderPass)(
VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_render_pass, pass, pRenderPassBegin->renderPass);
ANV_FROM_HANDLE(anv_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
cmd_buffer->state.framebuffer = framebuffer;
cmd_buffer->state.pass = pass;
anv_cmd_state_setup_attachments(cmd_buffer, pRenderPassBegin);
genX(flush_pipeline_select_3d)(cmd_buffer);
const VkRect2D *render_area = &pRenderPassBegin->renderArea;
anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_DRAWING_RECTANGLE),
.ClippedDrawingRectangleYMin = render_area->offset.y,
.ClippedDrawingRectangleXMin = render_area->offset.x,
.ClippedDrawingRectangleYMax =
render_area->offset.y + render_area->extent.height - 1,
.ClippedDrawingRectangleXMax =
render_area->offset.x + render_area->extent.width - 1,
.DrawingRectangleOriginY = 0,
.DrawingRectangleOriginX = 0);
genX(cmd_buffer_set_subpass)(cmd_buffer, pass->subpasses);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdNextSubpass)(
VkCommandBuffer commandBuffer,
VkSubpassContents contents)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
genX(cmd_buffer_set_subpass)(cmd_buffer, cmd_buffer->state.subpass + 1);
anv_cmd_buffer_clear_subpass(cmd_buffer);
}
void genX(CmdEndRenderPass)(
VkCommandBuffer commandBuffer)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
anv_cmd_buffer_resolve_subpass(cmd_buffer);
/* Emit a flushing pipe control at the end of a pass. This is kind of a
* hack but it ensures that render targets always actually get written.
* Eventually, we should do flushing based on image format transitions
* or something of that nature.
*/
anv_batch_emit(&cmd_buffer->batch, GENX(PIPE_CONTROL),
.PostSyncOperation = NoWrite,
.RenderTargetCacheFlushEnable = true,
.InstructionCacheInvalidateEnable = true,
.DepthCacheFlushEnable = true,
.VFCacheInvalidationEnable = true,
.TextureCacheInvalidationEnable = true,
.CommandStreamerStallEnable = true);
}