anv: Deduplicate render pass code
authorKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>
Mon, 15 Feb 2016 07:01:42 +0000 (23:01 -0800)
committerKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>
Tue, 16 Feb 2016 01:32:07 +0000 (17:32 -0800)
This lets us share the renderpass code and depth/stencil state code
between gen 7 and gen 8.

src/vulkan/gen7_cmd_buffer.c
src/vulkan/gen8_cmd_buffer.c
src/vulkan/genX_cmd_buffer.c

index 18b36487c5ffdd2cd74e8077f72028ac375de62d..7c12394b0886d484071d97a4a67e82e1b76b48e2 100644 (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,
index 1635a53b32a303500798f021b36aba1b8bdecfc7..ebd6123454de5eeb9e5e5bc10af180d36e942d6e 100644 (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)
index 7c6ad43a9b234921b34b095cac132c55c114c84b..e8b215e637790d62a01118f9bd8d3f3034fbd8e4 100644 (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);
+}