vk: Add clear load-op for render passes
authorKristian Høgsberg <kristian.h.kristensen@intel.com>
Tue, 12 May 2015 06:25:06 +0000 (23:25 -0700)
committerKristian Høgsberg <kristian.h.kristensen@intel.com>
Tue, 12 May 2015 06:25:29 +0000 (23:25 -0700)
src/vulkan/device.c
src/vulkan/meta.c
src/vulkan/private.h

index 56c8cb7240b8564e3abef86a4708b8d998950d66..49384c7940ca9af04a50cad4ec11645419054b73 100644 (file)
@@ -323,6 +323,8 @@ VkResult VKAPI vkCreateDevice(
 
    pthread_mutex_init(&device->mutex, NULL);
 
+   anv_device_init_meta(device);
+
    *pDevice = (VkDevice) device;
 
    return VK_SUCCESS;
@@ -1739,7 +1741,9 @@ VkResult VKAPI vkCreateCommandBuffer(
       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
    cmd_buffer->device = device;
-   
+   cmd_buffer->rs_state = NULL;
+   cmd_buffer->vp_state = NULL;
+
    result = anv_batch_init(&cmd_buffer->batch, device);
    if (result != VK_SUCCESS)
       goto fail;
@@ -2008,7 +2012,9 @@ void VKAPI vkCmdBindDynamicStateObject(
    switch (stateBindPoint) {
    case VK_STATE_BIND_POINT_VIEWPORT:
       vp_state = (struct anv_dynamic_vp_state *) dynamicState;
-
+      /* We emit state immediately, but set cmd_buffer->vp_state to indicate
+       * that vp state has been set in this command buffer. */
+      cmd_buffer->vp_state = vp_state;
       anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_SCISSOR_STATE_POINTERS,
                      .ScissorRectPointer = vp_state->scissor.offset);
       anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_VIEWPORT_STATE_POINTERS_CC,
@@ -2571,6 +2577,27 @@ VkResult VKAPI vkCreateFramebuffer(
    framebuffer->height = pCreateInfo->height;
    framebuffer->layers = pCreateInfo->layers;
 
+   vkCreateDynamicViewportState((VkDevice) device,
+                                &(VkDynamicVpStateCreateInfo) {
+                                   .sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO,
+                                   .viewportAndScissorCount = 2,
+                                   .pViewports = (VkViewport[]) {
+                                      {
+                                         .originX = 0,
+                                         .originY = 0,
+                                         .width = pCreateInfo->width,
+                                         .height = pCreateInfo->height,
+                                         .minDepth = 0,
+                                         .maxDepth = 1
+                                      },
+                                   },
+                                   .pScissors = (VkRect[]) {
+                                      { {  0,  0 },
+                                        { pCreateInfo->width, pCreateInfo->height } },
+                                   }
+                                },
+                                &framebuffer->vp_state);
+
    *pFramebuffer = (VkFramebuffer) framebuffer;
 
    return VK_SUCCESS;
@@ -2583,16 +2610,29 @@ VkResult VKAPI vkCreateRenderPass(
 {
    struct anv_device *device = (struct anv_device *) _device;
    struct anv_render_pass *pass;
+   size_t size;
 
    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO);
 
-   pass = anv_device_alloc(device, sizeof(*pass), 8,
+   size = sizeof(*pass) +
+      pCreateInfo->layers * sizeof(struct anv_render_pass_layer);
+   pass = anv_device_alloc(device, size, 8,
                            VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
    if (pass == NULL)
       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
    pass->render_area = pCreateInfo->renderArea;
 
+   pass->num_layers = pCreateInfo->layers;
+
+   pass->num_clear_layers = 0;
+   for (uint32_t i = 0; i < pCreateInfo->layers; i++) {
+      pass->layers[i].color_load_op = pCreateInfo->pColorLoadOps[i];
+      pass->layers[i].clear_color = pCreateInfo->pColorLoadClearValues[i];
+      if (pass->layers[i].color_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
+         pass->num_clear_layers++;
+   }
+
    *pRenderPass = (VkRenderPass) pass;
 
    return VK_SUCCESS;
@@ -2617,6 +2657,8 @@ void VKAPI vkCmdBeginRenderPass(
                      pass->render_area.offset.x + pass->render_area.extent.width - 1,
                   .DrawingRectangleOriginY = 0,
                   .DrawingRectangleOriginX = 0);
+
+   anv_cmd_buffer_clear(cmd_buffer, pass);
 }
 
 void VKAPI vkCmdEndRenderPass(
index 5ff5bb9bd68ac410f61c607605cfbc6740c11bed..48fe5d32db0afd9bccb28eafdaa47cd2196a2402 100644 (file)
 
 #include "private.h"
 
+#define GLSL(src) "#version 330\n" #src
+
+void
+anv_device_init_meta(struct anv_device *device)
+{
+   VkPipelineIaStateCreateInfo ia_create_info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO,
+      .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+      .disableVertexReuse = false,
+      .primitiveRestartEnable = false,
+      .primitiveRestartIndex = 0
+   };
+
+   /* We don't use a vertex shader for clearing, but instead build and pass
+    * the VUEs directly to the rasterization backend.
+    */
+   static const char fs_source[] = GLSL(
+      out vec4 f_color;
+      flat in vec4 v_color;
+      void main()
+      {
+         f_color = v_color;
+      });
+
+   VkShader fs;
+   vkCreateShader((VkDevice) device,
+                  &(VkShaderCreateInfo) {
+                     .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,
+                     .codeSize = sizeof(fs_source),
+                     .pCode = fs_source,
+                     .flags = 0
+                  },
+                  &fs);
+
+   VkPipelineShaderStageCreateInfo fs_create_info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+      .pNext = &ia_create_info,
+      .shader = {
+         .stage = VK_SHADER_STAGE_FRAGMENT,
+         .shader = fs,
+         .linkConstBufferCount = 0,
+         .pLinkConstBufferInfo = NULL,
+         .pSpecializationInfo = NULL
+      }
+   };
+
+   /* We use instanced rendering to clear multiple render targets. We have two
+    * vertex buffers: the first vertex buffer holds per-vertex data and
+    * provides the vertices for the clear rectangle. The second one holds
+    * per-instance data, which consists of the VUE header (which selects the
+    * layer) and the color (Vulkan supports per-RT clear colors).
+    */
+   VkPipelineVertexInputCreateInfo vi_create_info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO,
+      .pNext = &fs_create_info,
+      .bindingCount = 2,
+      .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
+         {
+            .binding = 0,
+            .strideInBytes = 8,
+            .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX
+         },
+         {
+            .binding = 1,
+            .strideInBytes = 32,
+            .stepRate = VK_VERTEX_INPUT_STEP_RATE_INSTANCE
+         },
+      },
+      .attributeCount = 3,
+      .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
+         {
+            /* VUE Header */
+            .location = 0,
+            .binding = 1,
+            .format = VK_FORMAT_R32G32B32A32_UINT,
+            .offsetInBytes = 0
+         },
+         {
+            /* Position */
+            .location = 1,
+            .binding = 0,
+            .format = VK_FORMAT_R32G32_SFLOAT,
+            .offsetInBytes = 0
+         },
+         {
+            /* Color */
+            .location = 2,
+            .binding = 1,
+            .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+            .offsetInBytes = 16
+         }
+      }
+   };
+
+   VkPipelineRsStateCreateInfo rs_create_info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO,
+      .pNext = &vi_create_info,
+      .depthClipEnable = true,
+      .rasterizerDiscardEnable = false,
+      .fillMode = VK_FILL_MODE_SOLID,
+      .cullMode = VK_CULL_MODE_NONE,
+      .frontFace = VK_FRONT_FACE_CCW
+   };
+
+   anv_pipeline_create((VkDevice) device,
+                       &(VkGraphicsPipelineCreateInfo) {
+                          .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+                          .pNext = &rs_create_info,
+                          .flags = 0,
+                          .layout = 0
+                       },
+                       &(struct anv_pipeline_create_info) {
+                          .use_repclear = true,
+                          .disable_viewport = true,
+                          .use_rectlist = true
+                       },
+                       &device->clear_state.pipeline);
+
+   vkDestroyObject((VkDevice) device, VK_OBJECT_TYPE_SHADER, fs);
+
+   vkCreateDynamicRasterState((VkDevice) device,
+                              &(VkDynamicRsStateCreateInfo) {
+                                 .sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO,
+                              },
+                              &device->clear_state.rs_state);
+}
+
+struct anv_saved_state {
+   struct {
+      struct anv_buffer *buffer;
+      VkDeviceSize offset;
+   } vb[2];
+   struct anv_pipeline *pipeline;
+};
+
+static void
+anv_cmd_buffer_save(struct anv_cmd_buffer *cmd_buffer, struct anv_saved_state *state)
+{
+   memcpy(state->vb, cmd_buffer->vb, sizeof(state->vb));
+   state->pipeline = cmd_buffer->pipeline;
+}
+
+static void
+anv_cmd_buffer_restore(struct anv_cmd_buffer *cmd_buffer, struct anv_saved_state *state)
+{
+   memcpy(cmd_buffer->vb, state->vb, sizeof(state->vb));
+   cmd_buffer->pipeline = state->pipeline;
+
+   cmd_buffer->vb_dirty |= (1 << ARRAY_SIZE(state->vb)) - 1;
+   cmd_buffer->dirty |= ANV_CMD_BUFFER_PIPELINE_DIRTY;
+}
+
+void
+anv_cmd_buffer_clear(struct anv_cmd_buffer *cmd_buffer,
+                     struct anv_render_pass *pass)
+{
+   struct anv_device *device = cmd_buffer->device;
+   struct anv_framebuffer *fb = cmd_buffer->framebuffer;
+   struct anv_saved_state saved_state;
+   struct anv_state state;
+   uint32_t size;
+
+   struct instance_data {
+      struct {
+         uint32_t Reserved;
+         uint32_t RTAIndex;
+         uint32_t ViewportIndex;
+         float PointWidth;
+      } vue_header;
+      float color[4];
+   } *instance_data;
+
+   const float vertex_data[] = {
+      /* Rect-list coordinates */
+            0.0,        0.0,
+      fb->width,        0.0,
+      fb->width, fb->height,
+
+      /* Align to 16 bytes */
+            0.0,        0.0,
+   };
+
+   size = sizeof(vertex_data) + pass->num_clear_layers * sizeof(instance_data[0]);
+   state = anv_state_stream_alloc(&cmd_buffer->surface_state_stream, size, 16);
+
+   memcpy(state.map, vertex_data, sizeof(vertex_data));
+   instance_data = state.map + sizeof(vertex_data);
+
+   for (uint32_t i = 0; i < pass->num_layers; i++) {
+      if (pass->layers[i].color_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
+         *instance_data++ = (struct instance_data) {
+            .vue_header = {
+               .RTAIndex = i,
+               .ViewportIndex = 0,
+               .PointWidth = 0.0
+            },
+            .color = {
+               pass->layers[i].clear_color.color.floatColor[0],
+               pass->layers[i].clear_color.color.floatColor[1],
+               pass->layers[i].clear_color.color.floatColor[2],
+               pass->layers[i].clear_color.color.floatColor[3],
+            }
+         };
+      }
+   }
+
+   struct anv_buffer vertex_buffer = {
+      .device = cmd_buffer->device,
+      .size = size,
+      .bo = &device->surface_state_block_pool.bo,
+      .offset = state.offset
+   };
+
+   anv_cmd_buffer_save(cmd_buffer, &saved_state);
+
+   vkCmdBindVertexBuffers((VkCmdBuffer) cmd_buffer, 0, 2,
+                          (VkBuffer[]) {
+                             (VkBuffer) &vertex_buffer,
+                             (VkBuffer) &vertex_buffer
+                          },
+                          (VkDeviceSize[]) {
+                             0,
+                             sizeof(vertex_data)
+                          });
+
+   if ((VkPipeline) cmd_buffer->pipeline != device->clear_state.pipeline)
+      vkCmdBindPipeline((VkCmdBuffer) cmd_buffer,
+                        VK_PIPELINE_BIND_POINT_GRAPHICS, device->clear_state.pipeline);
+
+   /* We don't need anything here, only set if not already set. */
+   if (cmd_buffer->rs_state == NULL)
+      vkCmdBindDynamicStateObject((VkCmdBuffer) cmd_buffer,
+                                  VK_STATE_BIND_POINT_RASTER,
+                                  device->clear_state.rs_state);
+
+   if (cmd_buffer->vp_state == NULL)
+      vkCmdBindDynamicStateObject((VkCmdBuffer) cmd_buffer,
+                                  VK_STATE_BIND_POINT_VIEWPORT,
+                                  cmd_buffer->framebuffer->vp_state);
+
+   vkCmdDraw((VkCmdBuffer) cmd_buffer, 0, 3, 0, pass->num_clear_layers);
+
+   /* Restore API state */
+   anv_cmd_buffer_restore(cmd_buffer, &saved_state);
+
+}
+
 void VKAPI vkCmdCopyBuffer(
     VkCmdBuffer                                 cmdBuffer,
     VkBuffer                                    srcBuffer,
index f6298c19adb306a2c85310ff7296513cdf611a19..4b47c1f55bbeb56e33e197605170881ec44e7507 100644 (file)
@@ -245,6 +245,11 @@ struct anv_instance {
     struct anv_physical_device                  physicalDevice;
 };
 
+struct anv_clear_state {
+   VkPipeline                                   pipeline;
+   VkDynamicRsState                             rs_state;
+};
+
 struct anv_device {
     struct anv_instance *                       instance;
     uint32_t                                    chipset_id;
@@ -261,6 +266,8 @@ struct anv_device {
     struct anv_block_pool                       surface_state_block_pool;
     struct anv_state_pool                       surface_state_pool;
 
+    struct anv_clear_state                      clear_state;
+
     struct anv_compiler *                       compiler;
     struct anv_aub_writer *                     aub_writer;
     pthread_mutex_t                             mutex;
@@ -486,6 +493,7 @@ struct anv_cmd_buffer {
    struct anv_pipeline *                        pipeline;
    struct anv_framebuffer *                     framebuffer;
    struct anv_dynamic_rs_state *                rs_state;
+   struct anv_dynamic_vp_state *                vp_state;
 };
 
 void anv_cmd_buffer_dump(struct anv_cmd_buffer *cmd_buffer);
@@ -604,12 +612,30 @@ struct anv_framebuffer {
    uint32_t                                     width;
    uint32_t                                     height;
    uint32_t                                     layers;
+
+   /* Viewport for clears */
+   VkDynamicVpState                             vp_state;
+};
+
+struct anv_render_pass_layer {
+   VkAttachmentLoadOp                           color_load_op;
+   VkClearColor                                 clear_color;
 };
 
 struct anv_render_pass {
    VkRect                                       render_area;
+
+   uint32_t                                     num_clear_layers;
+   uint32_t                                     num_layers;
+   struct anv_render_pass_layer                 layers[0];
 };
 
+void anv_device_init_meta(struct anv_device *device);
+
+void
+anv_cmd_buffer_clear(struct anv_cmd_buffer *cmd_buffer,
+                     struct anv_render_pass *pass);
+
 
 #ifdef __cplusplus
 }