From: Kristian Høgsberg Date: Tue, 12 May 2015 06:25:06 +0000 (-0700) Subject: vk: Add clear load-op for render passes X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d77c34d1d2ea8d0eaafc3058cc70238471f6858b;p=mesa.git vk: Add clear load-op for render passes --- diff --git a/src/vulkan/device.c b/src/vulkan/device.c index 56c8cb7240b..49384c7940c 100644 --- a/src/vulkan/device.c +++ b/src/vulkan/device.c @@ -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( diff --git a/src/vulkan/meta.c b/src/vulkan/meta.c index 5ff5bb9bd68..48fe5d32db0 100644 --- a/src/vulkan/meta.c +++ b/src/vulkan/meta.c @@ -29,6 +29,253 @@ #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, diff --git a/src/vulkan/private.h b/src/vulkan/private.h index f6298c19adb..4b47c1f55bb 100644 --- a/src/vulkan/private.h +++ b/src/vulkan/private.h @@ -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 }