blob: 39b7b968662d40f7bc77bd169d4567931d079ab3 [file] [log] [blame]
/*
* Copyright © 2015 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "anv_meta.h"
#include "anv_meta_clear.h"
#include "anv_private.h"
#include "glsl/nir/nir_builder.h"
/** Vertex attributes for color clears. */
struct color_clear_vattrs {
struct anv_vue_header vue_header;
float position[2]; /**< 3DPRIM_RECTLIST */
VkClearColorValue color;
};
/** Vertex attributes for depthstencil clears. */
struct depthstencil_clear_vattrs {
struct anv_vue_header vue_header;
float position[2]; /*<< 3DPRIM_RECTLIST */
};
static void
meta_clear_begin(struct anv_meta_saved_state *saved_state,
struct anv_cmd_buffer *cmd_buffer)
{
anv_meta_save(saved_state, cmd_buffer,
(1 << VK_DYNAMIC_STATE_VIEWPORT) |
(1 << VK_DYNAMIC_STATE_SCISSOR) |
(1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE));
cmd_buffer->state.dynamic.viewport.count = 0;
cmd_buffer->state.dynamic.scissor.count = 0;
}
static void
meta_clear_end(struct anv_meta_saved_state *saved_state,
struct anv_cmd_buffer *cmd_buffer)
{
anv_meta_restore(saved_state, cmd_buffer);
}
static void
build_color_shaders(struct nir_shader **out_vs,
struct nir_shader **out_fs,
uint32_t frag_output)
{
nir_builder vs_b;
nir_builder fs_b;
nir_builder_init_simple_shader(&vs_b, NULL, MESA_SHADER_VERTEX, NULL);
nir_builder_init_simple_shader(&fs_b, NULL, MESA_SHADER_FRAGMENT, NULL);
vs_b.shader->info.name = ralloc_strdup(vs_b.shader, "meta_clear_color_vs");
fs_b.shader->info.name = ralloc_strdup(fs_b.shader, "meta_clear_color_fs");
const struct glsl_type *position_type = glsl_vec4_type();
const struct glsl_type *color_type = glsl_vec4_type();
nir_variable *vs_in_pos =
nir_variable_create(vs_b.shader, nir_var_shader_in, position_type,
"a_position");
vs_in_pos->data.location = VERT_ATTRIB_GENERIC0;
nir_variable *vs_out_pos =
nir_variable_create(vs_b.shader, nir_var_shader_out, position_type,
"gl_Position");
vs_out_pos->data.location = VARYING_SLOT_POS;
nir_variable *vs_in_color =
nir_variable_create(vs_b.shader, nir_var_shader_in, color_type,
"a_color");
vs_in_color->data.location = VERT_ATTRIB_GENERIC1;
nir_variable *vs_out_color =
nir_variable_create(vs_b.shader, nir_var_shader_out, color_type,
"v_color");
vs_out_color->data.location = VARYING_SLOT_VAR0;
vs_out_color->data.interpolation = INTERP_QUALIFIER_FLAT;
nir_variable *fs_in_color =
nir_variable_create(fs_b.shader, nir_var_shader_in, color_type,
"v_color");
fs_in_color->data.location = vs_out_color->data.location;
fs_in_color->data.interpolation = vs_out_color->data.interpolation;
nir_variable *fs_out_color =
nir_variable_create(fs_b.shader, nir_var_shader_out, color_type,
"f_color");
fs_out_color->data.location = FRAG_RESULT_DATA0 + frag_output;
nir_copy_var(&vs_b, vs_out_pos, vs_in_pos);
nir_copy_var(&vs_b, vs_out_color, vs_in_color);
nir_copy_var(&fs_b, fs_out_color, fs_in_color);
*out_vs = vs_b.shader;
*out_fs = fs_b.shader;
}
static VkResult
create_pipeline(struct anv_device *device,
struct nir_shader *vs_nir,
struct nir_shader *fs_nir,
const VkPipelineVertexInputStateCreateInfo *vi_state,
const VkPipelineDepthStencilStateCreateInfo *ds_state,
const VkPipelineColorBlendStateCreateInfo *cb_state,
const VkAllocationCallbacks *alloc,
bool use_repclear,
struct anv_pipeline **pipeline)
{
VkDevice device_h = anv_device_to_handle(device);
VkResult result;
struct anv_shader_module vs_m = { .nir = vs_nir };
struct anv_shader_module fs_m = { .nir = fs_nir };
VkPipeline pipeline_h;
result = anv_graphics_pipeline_create(device_h,
VK_NULL_HANDLE,
&(VkGraphicsPipelineCreateInfo) {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = (VkPipelineShaderStageCreateInfo[]) {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = anv_shader_module_to_handle(&vs_m),
.pName = "main",
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = anv_shader_module_to_handle(&fs_m),
.pName = "main",
},
},
.pVertexInputState = vi_state,
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
.primitiveRestartEnable = false,
},
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = NULL, /* dynamic */
.scissorCount = 1,
.pScissors = NULL, /* dynamic */
},
.pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = false,
},
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = 1, /* FINISHME: Multisampling */
.sampleShadingEnable = false,
.pSampleMask = (VkSampleMask[]) { UINT32_MAX },
.alphaToCoverageEnable = false,
.alphaToOneEnable = false,
},
.pDepthStencilState = ds_state,
.pColorBlendState = cb_state,
.pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
/* The meta clear pipeline declares all state as dynamic.
* As a consequence, vkCmdBindPipeline writes no dynamic state
* to the cmd buffer. Therefore, at the end of the meta clear,
* we need only restore dynamic state was vkCmdSet.
*/
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = 9,
.pDynamicStates = (VkDynamicState[]) {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_LINE_WIDTH,
VK_DYNAMIC_STATE_DEPTH_BIAS,
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BOUNDS,
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
},
},
.flags = 0,
.renderPass = anv_render_pass_to_handle(&anv_meta_dummy_renderpass),
.subpass = 0,
},
&(struct anv_graphics_pipeline_create_info) {
.color_attachment_count = MAX_RTS,
.use_repclear = use_repclear,
.disable_viewport = true,
.disable_vs = true,
.use_rectlist = true
},
alloc,
&pipeline_h);
ralloc_free(vs_nir);
ralloc_free(fs_nir);
*pipeline = anv_pipeline_from_handle(pipeline_h);
return result;
}
static VkResult
create_color_pipeline(struct anv_device *device, uint32_t frag_output,
struct anv_pipeline **pipeline)
{
struct nir_shader *vs_nir;
struct nir_shader *fs_nir;
build_color_shaders(&vs_nir, &fs_nir, frag_output);
const VkPipelineVertexInputStateCreateInfo vi_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
{
.binding = 0,
.stride = sizeof(struct color_clear_vattrs),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
},
},
.vertexAttributeDescriptionCount = 3,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
{
/* VUE Header */
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_UINT,
.offset = offsetof(struct color_clear_vattrs, vue_header),
},
{
/* Position */
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct color_clear_vattrs, position),
},
{
/* Color */
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(struct color_clear_vattrs, color),
},
},
};
const VkPipelineDepthStencilStateCreateInfo ds_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = false,
.depthWriteEnable = false,
.depthBoundsTestEnable = false,
.stencilTestEnable = false,
};
const VkPipelineColorBlendStateCreateInfo cb_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = false,
.attachmentCount = 1,
.pAttachments = (VkPipelineColorBlendAttachmentState []) {
{
.blendEnable = false,
.colorWriteMask = VK_COLOR_COMPONENT_A_BIT |
VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT,
},
},
};
/* Disable repclear because we do not want the compiler to replace the
* shader. We need the shader to write to the specified color attachment,
* but the repclear shader writes to all color attachments.
*/
return
create_pipeline(device, vs_nir, fs_nir, &vi_state, &ds_state,
&cb_state, NULL, /*use_repclear*/ false,
pipeline);
}
static VkResult
init_color_pipelines(struct anv_device *device)
{
VkResult result;
struct anv_pipeline **pipelines = device->meta_state.clear.color_pipelines;
uint32_t n = ARRAY_SIZE(device->meta_state.clear.color_pipelines);
zero(device->meta_state.clear.color_pipelines);
for (uint32_t i = 0; i < n; ++i) {
result = create_color_pipeline(device, i, &pipelines[i]);
if (result < 0)
goto fail;
}
return VK_SUCCESS;
fail:
for (uint32_t i = 0; i < n; ++i) {
if (pipelines[i] == NULL)
break;
anv_DestroyPipeline(anv_device_to_handle(device),
anv_pipeline_to_handle(pipelines[i]),
NULL);
}
return result;
}
static void
emit_color_clear(struct anv_cmd_buffer *cmd_buffer,
const VkClearAttachment *clear_att)
{
struct anv_device *device = cmd_buffer->device;
const struct anv_subpass *subpass = cmd_buffer->state.subpass;
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
VkClearColorValue clear_value = clear_att->clearValue.color;
struct anv_pipeline *pipeline =
device->meta_state.clear.color_pipelines[clear_att->colorAttachment];
VkCommandBuffer cmd_buffer_h = anv_cmd_buffer_to_handle(cmd_buffer);
VkPipeline pipeline_h = anv_pipeline_to_handle(pipeline);
assert(clear_att->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
assert(clear_att->colorAttachment < subpass->color_count);
const struct color_clear_vattrs vertex_data[3] = {
{
.vue_header = { 0 },
.position = { 0.0, 0.0 },
.color = clear_value,
},
{
.vue_header = { 0 },
.position = { fb->width, 0.0 },
.color = clear_value,
},
{
.vue_header = { 0 },
.position = { fb->width, fb->height },
.color = clear_value,
},
};
struct anv_state state =
anv_cmd_buffer_emit_dynamic(cmd_buffer, vertex_data, sizeof(vertex_data), 16);
struct anv_buffer vertex_buffer = {
.device = device,
.size = sizeof(vertex_data),
.bo = &device->dynamic_state_block_pool.bo,
.offset = state.offset,
};
ANV_CALL(CmdSetViewport)(cmd_buffer_h, 0, 1,
(VkViewport[]) {
{
.x = 0,
.y = 0,
.width = fb->width,
.height = fb->height,
.minDepth = 0.0,
.maxDepth = 1.0,
},
});
ANV_CALL(CmdSetScissor)(cmd_buffer_h, 0, 1,
(VkRect2D[]) {
{
.offset = { 0, 0 },
.extent = { fb->width, fb->height },
}
});
ANV_CALL(CmdBindVertexBuffers)(cmd_buffer_h, 0, 1,
(VkBuffer[]) { anv_buffer_to_handle(&vertex_buffer) },
(VkDeviceSize[]) { 0 });
if (cmd_buffer->state.pipeline != pipeline) {
ANV_CALL(CmdBindPipeline)(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_h);
}
ANV_CALL(CmdDraw)(cmd_buffer_h, 3, 1, 0, 0);
}
static void
build_depthstencil_shaders(struct nir_shader **out_vs,
struct nir_shader **out_fs)
{
nir_builder vs_b;
nir_builder fs_b;
nir_builder_init_simple_shader(&vs_b, NULL, MESA_SHADER_VERTEX, NULL);
nir_builder_init_simple_shader(&fs_b, NULL, MESA_SHADER_FRAGMENT, NULL);
vs_b.shader->info.name = ralloc_strdup(vs_b.shader, "meta_clear_depthstencil_vs");
fs_b.shader->info.name = ralloc_strdup(fs_b.shader, "meta_clear_depthstencil_fs");
const struct glsl_type *position_type = glsl_vec4_type();
nir_variable *vs_in_pos =
nir_variable_create(vs_b.shader, nir_var_shader_in, position_type,
"a_position");
vs_in_pos->data.location = VERT_ATTRIB_GENERIC0;
nir_variable *vs_out_pos =
nir_variable_create(vs_b.shader, nir_var_shader_out, position_type,
"gl_Position");
vs_out_pos->data.location = VARYING_SLOT_POS;
nir_copy_var(&vs_b, vs_out_pos, vs_in_pos);
*out_vs = vs_b.shader;
*out_fs = fs_b.shader;
}
static VkResult
create_depthstencil_pipeline(struct anv_device *device,
VkImageAspectFlags aspects,
struct anv_pipeline **pipeline)
{
struct nir_shader *vs_nir;
struct nir_shader *fs_nir;
build_depthstencil_shaders(&vs_nir, &fs_nir);
const VkPipelineVertexInputStateCreateInfo vi_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
{
.binding = 0,
.stride = sizeof(struct depthstencil_clear_vattrs),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
},
},
.vertexAttributeDescriptionCount = 2,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
{
/* VUE Header */
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_UINT,
.offset = offsetof(struct depthstencil_clear_vattrs, vue_header),
},
{
/* Position */
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct depthstencil_clear_vattrs, position),
},
},
};
const VkPipelineDepthStencilStateCreateInfo ds_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = (aspects & VK_IMAGE_ASPECT_DEPTH_BIT),
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
.depthWriteEnable = (aspects & VK_IMAGE_ASPECT_DEPTH_BIT),
.depthBoundsTestEnable = false,
.stencilTestEnable = (aspects & VK_IMAGE_ASPECT_STENCIL_BIT),
.front = {
.passOp = VK_STENCIL_OP_REPLACE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.writeMask = UINT32_MAX,
.reference = 0, /* dynamic */
},
.back = { 0 /* dont care */ },
};
const VkPipelineColorBlendStateCreateInfo cb_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = false,
.attachmentCount = 0,
.pAttachments = NULL,
};
return create_pipeline(device, vs_nir, fs_nir, &vi_state, &ds_state,
&cb_state, NULL, /*use_repclear*/ true, pipeline);
}
static void
emit_depthstencil_clear(struct anv_cmd_buffer *cmd_buffer,
const VkClearAttachment *clear_att)
{
struct anv_device *device = cmd_buffer->device;
const struct anv_subpass *subpass = cmd_buffer->state.subpass;
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
uint32_t attachment = subpass->depth_stencil_attachment;
VkClearDepthStencilValue clear_value = clear_att->clearValue.depthStencil;
VkImageAspectFlags aspects = clear_att->aspectMask;
VkCommandBuffer cmd_buffer_h = anv_cmd_buffer_to_handle(cmd_buffer);
assert(aspects == VK_IMAGE_ASPECT_DEPTH_BIT ||
aspects == VK_IMAGE_ASPECT_STENCIL_BIT ||
aspects == (VK_IMAGE_ASPECT_DEPTH_BIT |
VK_IMAGE_ASPECT_STENCIL_BIT));
assert(attachment != VK_ATTACHMENT_UNUSED);
const struct depthstencil_clear_vattrs vertex_data[3] = {
{
.vue_header = { 0 },
.position = { 0.0, 0.0 },
},
{
.vue_header = { 0 },
.position = { fb->width, 0.0 },
},
{
.vue_header = { 0 },
.position = { fb->width, fb->height },
},
};
struct anv_state state =
anv_cmd_buffer_emit_dynamic(cmd_buffer, vertex_data, sizeof(vertex_data), 16);
struct anv_buffer vertex_buffer = {
.device = device,
.size = sizeof(vertex_data),
.bo = &device->dynamic_state_block_pool.bo,
.offset = state.offset,
};
ANV_CALL(CmdSetViewport)(cmd_buffer_h, 0, 1,
(VkViewport[]) {
{
.x = 0,
.y = 0,
.width = fb->width,
.height = fb->height,
/* Ignored when clearing only stencil. */
.minDepth = clear_value.depth,
.maxDepth = clear_value.depth,
},
});
ANV_CALL(CmdSetScissor)(cmd_buffer_h, 0, 1,
(VkRect2D[]) {
{
.offset = { 0, 0 },
.extent = { fb->width, fb->height },
}
});
if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
ANV_CALL(CmdSetStencilReference)(cmd_buffer_h, VK_STENCIL_FACE_FRONT_BIT,
clear_value.stencil);
}
ANV_CALL(CmdBindVertexBuffers)(cmd_buffer_h, 0, 1,
(VkBuffer[]) { anv_buffer_to_handle(&vertex_buffer) },
(VkDeviceSize[]) { 0 });
struct anv_pipeline *pipeline;
switch (aspects) {
case VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT:
pipeline = device->meta_state.clear.depthstencil_pipeline;
break;
case VK_IMAGE_ASPECT_DEPTH_BIT:
pipeline = device->meta_state.clear.depth_only_pipeline;
break;
case VK_IMAGE_ASPECT_STENCIL_BIT:
pipeline = device->meta_state.clear.stencil_only_pipeline;
break;
default:
unreachable("expected depth or stencil aspect");
}
if (cmd_buffer->state.pipeline != pipeline) {
ANV_CALL(CmdBindPipeline)(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
anv_pipeline_to_handle(pipeline));
}
ANV_CALL(CmdDraw)(cmd_buffer_h, 3, 1, 0, 0);
}
static VkResult
init_depthstencil_pipelines(struct anv_device *device)
{
VkResult result;
struct anv_meta_state *state = &device->meta_state;
result =
create_depthstencil_pipeline(device, VK_IMAGE_ASPECT_DEPTH_BIT,
&state->clear.depth_only_pipeline);
if (result != VK_SUCCESS)
goto fail;
result =
create_depthstencil_pipeline(device, VK_IMAGE_ASPECT_STENCIL_BIT,
&state->clear.stencil_only_pipeline);
if (result != VK_SUCCESS)
goto fail_depth_only;
result =
create_depthstencil_pipeline(device,
VK_IMAGE_ASPECT_DEPTH_BIT |
VK_IMAGE_ASPECT_STENCIL_BIT,
&state->clear.depthstencil_pipeline);
if (result != VK_SUCCESS)
goto fail_stencil_only;
return result;
fail_stencil_only:
anv_DestroyPipeline(anv_device_to_handle(device),
anv_pipeline_to_handle(state->clear.stencil_only_pipeline),
NULL);
fail_depth_only:
anv_DestroyPipeline(anv_device_to_handle(device),
anv_pipeline_to_handle(state->clear.depth_only_pipeline),
NULL);
fail:
return result;
}
VkResult
anv_device_init_meta_clear_state(struct anv_device *device)
{
VkResult result;
result = init_color_pipelines(device);
if (result != VK_SUCCESS)
return result;
result = init_depthstencil_pipelines(device);
if (result != VK_SUCCESS)
return result;
return VK_SUCCESS;
}
void
anv_device_finish_meta_clear_state(struct anv_device *device)
{
VkDevice device_h = anv_device_to_handle(device);
for (uint32_t i = 0;
i < ARRAY_SIZE(device->meta_state.clear.color_pipelines); ++i) {
ANV_CALL(DestroyPipeline)(device_h,
anv_pipeline_to_handle(device->meta_state.clear.color_pipelines[i]),
NULL);
}
ANV_CALL(DestroyPipeline)(device_h,
anv_pipeline_to_handle(device->meta_state.clear.depth_only_pipeline),
NULL);
ANV_CALL(DestroyPipeline)(device_h,
anv_pipeline_to_handle(device->meta_state.clear.stencil_only_pipeline),
NULL);
ANV_CALL(DestroyPipeline)(device_h,
anv_pipeline_to_handle(device->meta_state.clear.depthstencil_pipeline),
NULL);
}
/**
* The parameters mean that same as those in vkCmdClearAttachments.
*/
static void
emit_clear(struct anv_cmd_buffer *cmd_buffer,
const VkClearAttachment *clear_att)
{
if (clear_att->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
emit_color_clear(cmd_buffer, clear_att);
} else {
assert(clear_att->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
VK_IMAGE_ASPECT_STENCIL_BIT));
emit_depthstencil_clear(cmd_buffer, clear_att);
}
}
static bool
subpass_needs_clear(const struct anv_cmd_buffer *cmd_buffer)
{
const struct anv_cmd_state *cmd_state = &cmd_buffer->state;
uint32_t ds = cmd_state->subpass->depth_stencil_attachment;
for (uint32_t i = 0; i < cmd_state->subpass->color_count; ++i) {
uint32_t a = cmd_state->subpass->color_attachments[i];
if (cmd_state->attachments[a].pending_clear_aspects) {
return true;
}
}
if (ds != VK_ATTACHMENT_UNUSED &&
cmd_state->attachments[ds].pending_clear_aspects) {
return true;
}
return false;
}
/**
* Emit any pending attachment clears for the current subpass.
*
* @see anv_attachment_state::pending_clear_aspects
*/
void
anv_cmd_buffer_clear_subpass(struct anv_cmd_buffer *cmd_buffer)
{
struct anv_cmd_state *cmd_state = &cmd_buffer->state;
struct anv_meta_saved_state saved_state;
if (!subpass_needs_clear(cmd_buffer))
return;
meta_clear_begin(&saved_state, cmd_buffer);
if (cmd_state->framebuffer->layers > 1)
anv_finishme("clearing multi-layer framebuffer");
for (uint32_t i = 0; i < cmd_state->subpass->color_count; ++i) {
uint32_t a = cmd_state->subpass->color_attachments[i];
if (!cmd_state->attachments[a].pending_clear_aspects)
continue;
assert(cmd_state->attachments[a].pending_clear_aspects ==
VK_IMAGE_ASPECT_COLOR_BIT);
VkClearAttachment clear_att = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.colorAttachment = i, /* Use attachment index relative to subpass */
.clearValue = cmd_state->attachments[a].clear_value,
};
emit_clear(cmd_buffer, &clear_att);
cmd_state->attachments[a].pending_clear_aspects = 0;
}
uint32_t ds = cmd_state->subpass->depth_stencil_attachment;
if (ds != VK_ATTACHMENT_UNUSED &&
cmd_state->attachments[ds].pending_clear_aspects) {
VkClearAttachment clear_att = {
.aspectMask = cmd_state->attachments[ds].pending_clear_aspects,
.clearValue = cmd_state->attachments[ds].clear_value,
};
emit_clear(cmd_buffer, &clear_att);
cmd_state->attachments[ds].pending_clear_aspects = 0;
}
meta_clear_end(&saved_state, cmd_buffer);
}
void anv_CmdClearColorImage(
VkCommandBuffer commandBuffer,
VkImage _image,
VkImageLayout imageLayout,
const VkClearColorValue* pColor,
uint32_t rangeCount,
const VkImageSubresourceRange* pRanges)
{
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_image, image, _image);
struct anv_meta_saved_state saved_state;
meta_clear_begin(&saved_state, cmd_buffer);
for (uint32_t r = 0; r < rangeCount; r++) {
for (uint32_t l = 0; l < pRanges[r].levelCount; l++) {
for (uint32_t s = 0; s < pRanges[r].layerCount; s++) {
struct anv_image_view iview;
anv_image_view_init(&iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = _image,
.viewType = anv_meta_get_view_type(image),
.format = image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = pRanges[r].baseMipLevel + l,
.levelCount = 1,
.baseArrayLayer = pRanges[r].baseArrayLayer + s,
.layerCount = 1
},
},
cmd_buffer);
VkFramebuffer fb;
anv_CreateFramebuffer(anv_device_to_handle(cmd_buffer->device),
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = (VkImageView[]) {
anv_image_view_to_handle(&iview),
},
.width = iview.extent.width,
.height = iview.extent.height,
.layers = 1
}, &cmd_buffer->pool->alloc, &fb);
VkRenderPass pass;
anv_CreateRenderPass(anv_device_to_handle(cmd_buffer->device),
&(VkRenderPassCreateInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = &(VkAttachmentDescription) {
.format = iview.vk_format,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
},
.subpassCount = 1,
.pSubpasses = &(VkSubpassDescription) {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.colorAttachmentCount = 1,
.pColorAttachments = &(VkAttachmentReference) {
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_GENERAL,
},
.pResolveAttachments = NULL,
.pDepthStencilAttachment = &(VkAttachmentReference) {
.attachment = VK_ATTACHMENT_UNUSED,
.layout = VK_IMAGE_LAYOUT_GENERAL,
},
.preserveAttachmentCount = 1,
.pPreserveAttachments = (uint32_t[]) { 0 },
},
.dependencyCount = 0,
}, &cmd_buffer->pool->alloc, &pass);
ANV_CALL(CmdBeginRenderPass)(anv_cmd_buffer_to_handle(cmd_buffer),
&(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderArea = {
.offset = { 0, 0, },
.extent = {
.width = iview.extent.width,
.height = iview.extent.height,
},
},
.renderPass = pass,
.framebuffer = fb,
.clearValueCount = 1,
.pClearValues = (VkClearValue[]) {
{ .color = *pColor },
},
}, VK_SUBPASS_CONTENTS_INLINE);
ANV_CALL(CmdEndRenderPass)(anv_cmd_buffer_to_handle(cmd_buffer));
/* XXX: We're leaking the render pass and framebuffer */
}
}
}
meta_clear_end(&saved_state, cmd_buffer);
}
void anv_CmdClearDepthStencilImage(
VkCommandBuffer commandBuffer,
VkImage image,
VkImageLayout imageLayout,
const VkClearDepthStencilValue* pDepthStencil,
uint32_t rangeCount,
const VkImageSubresourceRange* pRanges)
{
stub();
}
void anv_CmdClearAttachments(
VkCommandBuffer commandBuffer,
uint32_t attachmentCount,
const VkClearAttachment* pAttachments,
uint32_t rectCount,
const VkClearRect* pRects)
{
stub();
}