vk: Add clear load-op for render passes

This commit is contained in:
Kristian Høgsberg
2015-05-11 23:25:06 -07:00
parent b734e0bcc5
commit d77c34d1d2
3 changed files with 318 additions and 3 deletions

View 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(

View File

@@ -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,

View 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
}