#include "anv_meta.h"
#include "nir/nir_builder.h"
+enum blit2d_src_type {
+ /* We can make a "normal" image view of this source and just texture
+ * from it like you would in any other shader.
+ */
+ BLIT2D_SRC_TYPE_NORMAL,
+
+ /* The source is W-tiled and we need to detile manually in the shader.
+ * This will work on any platform but is needed for all W-tiled sources
+ * prior to Broadwell.
+ */
+ BLIT2D_SRC_TYPE_W_DETILE,
+
+ BLIT2D_NUM_SRC_TYPES,
+};
+
+enum blit2d_dst_type {
+ /* We can bind this destination as a "normal" render target and render
+ * to it just like you would anywhere else.
+ */
+ BLIT2D_DST_TYPE_NORMAL,
+
+ /* The destination is W-tiled and we need to do the tiling manually in
+ * the shader. This is required for all W-tiled destinations.
+ *
+ * Sky Lake adds a feature for providing explicit stencil values in the
+ * shader but mesa doesn't support that yet so neither do we.
+ */
+ BLIT2D_DST_TYPE_W_TILE,
+
+ /* The destination has a 3-channel RGB format. Since we can't render to
+ * non-power-of-two textures, we have to bind it as a red texture and
+ * select the correct component for the given red pixel in the shader.
+ */
+ BLIT2D_DST_TYPE_RGB,
+
+ BLIT2D_NUM_DST_TYPES,
+};
+
static VkFormat
vk_format_for_size(int bs)
{
static void
blit2d_bind_src(struct anv_cmd_buffer *cmd_buffer,
struct anv_meta_blit2d_surf *src,
+ enum blit2d_src_type src_type,
struct anv_meta_blit2d_rect *rect,
struct blit2d_src_temps *tmp)
{
static void
blit2d_unbind_src(struct anv_cmd_buffer *cmd_buffer,
+ enum blit2d_src_type src_type,
struct blit2d_src_temps *tmp)
{
anv_DestroyDescriptorPool(anv_device_to_handle(cmd_buffer->device),
(1 << VK_DYNAMIC_STATE_VIEWPORT));
}
-void
-anv_meta_blit2d(struct anv_cmd_buffer *cmd_buffer,
- struct anv_meta_blit2d_surf *src,
- struct anv_meta_blit2d_surf *dst,
- unsigned num_rects,
- struct anv_meta_blit2d_rect *rects)
+static void
+bind_pipeline(struct anv_cmd_buffer *cmd_buffer,
+ enum blit2d_src_type src_type,
+ enum blit2d_dst_type dst_type)
+{
+ VkPipeline pipeline =
+ cmd_buffer->device->meta_state.blit2d.pipelines[src_type][dst_type];
+
+ if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(pipeline)) {
+ anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer),
+ VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ }
+}
+
+static void
+anv_meta_blit2d_normal_dst(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_meta_blit2d_surf *src,
+ enum blit2d_src_type src_type,
+ struct anv_meta_blit2d_surf *dst,
+ unsigned num_rects,
+ struct anv_meta_blit2d_rect *rects)
{
struct anv_device *device = cmd_buffer->device;
VkDevice vk_device = anv_device_to_handle(cmd_buffer->device);
for (unsigned r = 0; r < num_rects; ++r) {
struct blit2d_src_temps src_temps;
- blit2d_bind_src(cmd_buffer, src, &rects[r], &src_temps);
+ blit2d_bind_src(cmd_buffer, src, src_type, &rects[r], &src_temps);
VkImage dst_img;
struct anv_image_view dst_iview;
.pClearValues = NULL,
}, VK_SUBPASS_CONTENTS_INLINE);
- VkPipeline pipeline = device->meta_state.blit2d.pipeline_2d_src;
-
- if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(pipeline)) {
- anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer),
- VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
- }
+ bind_pipeline(cmd_buffer, src_type, BLIT2D_DST_TYPE_NORMAL);
anv_CmdSetViewport(anv_cmd_buffer_to_handle(cmd_buffer), 0, 1,
&(VkViewport) {
/* At the point where we emit the draw call, all data from the
* descriptor sets, etc. has been used. We are free to delete it.
*/
- blit2d_unbind_src(cmd_buffer, &src_temps);
+ blit2d_unbind_src(cmd_buffer, src_type, &src_temps);
anv_DestroyFramebuffer(vk_device, fb, &cmd_buffer->pool->alloc);
anv_DestroyImage(vk_device, dst_img, &cmd_buffer->pool->alloc);
}
}
+void
+anv_meta_blit2d(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_meta_blit2d_surf *src,
+ struct anv_meta_blit2d_surf *dst,
+ unsigned num_rects,
+ struct anv_meta_blit2d_rect *rects)
+{
+ enum blit2d_src_type src_type;
+ if (src->tiling == ISL_TILING_W && cmd_buffer->device->info.gen < 8) {
+ src_type = BLIT2D_SRC_TYPE_W_DETILE;
+ } else {
+ src_type = BLIT2D_SRC_TYPE_NORMAL;
+ }
+
+ if (dst->tiling == ISL_TILING_W) {
+ assert(dst->bs == 1);
+ anv_finishme("Blitting to w-tiled destinations not yet supported");
+ return;
+ } else if (dst->bs % 3 == 0) {
+ anv_finishme("Blitting to RGB destinations not yet supported");
+ return;
+ } else {
+ assert(util_is_power_of_two(dst->bs));
+ anv_meta_blit2d_normal_dst(cmd_buffer, src, src_type, dst,
+ num_rects, rects);
+ }
+}
static nir_shader *
build_nir_vertex_shader(void)
&device->meta_state.alloc);
}
- if (device->meta_state.blit2d.pipeline_2d_src) {
- anv_DestroyPipeline(anv_device_to_handle(device),
- device->meta_state.blit2d.pipeline_2d_src,
- &device->meta_state.alloc);
- }
-
if (device->meta_state.blit2d.img_p_layout) {
anv_DestroyPipelineLayout(anv_device_to_handle(device),
device->meta_state.blit2d.img_p_layout,
device->meta_state.blit2d.buf_ds_layout,
&device->meta_state.alloc);
}
+
+ for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
+ for (unsigned dst = 0; dst < BLIT2D_NUM_DST_TYPES; dst++) {
+ if (device->meta_state.blit2d.pipelines[src][dst]) {
+ anv_DestroyPipeline(anv_device_to_handle(device),
+ device->meta_state.blit2d.pipelines[src][dst],
+ &device->meta_state.alloc);
+ }
+ }
+ }
}
-VkResult
-anv_device_init_meta_blit2d_state(struct anv_device *device)
+static VkResult
+blit2d_init_pipeline(struct anv_device *device,
+ enum blit2d_src_type src_type,
+ enum blit2d_dst_type dst_type)
{
VkResult result;
- zero(device->meta_state.blit2d);
-
- result = anv_CreateRenderPass(anv_device_to_handle(device),
- &(VkRenderPassCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- .attachmentCount = 1,
- .pAttachments = &(VkAttachmentDescription) {
- .format = VK_FORMAT_UNDEFINED, /* Our shaders don't care */
- .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,
- }, &device->meta_state.alloc, &device->meta_state.blit2d.render_pass);
- if (result != VK_SUCCESS)
- goto fail;
-
- result = anv_CreateDescriptorSetLayout(anv_device_to_handle(device),
- &(VkDescriptorSetLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
- .bindingCount = 1,
- .pBindings = (VkDescriptorSetLayoutBinding[]) {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- .pImmutableSamplers = NULL
- },
- }
- }, &device->meta_state.alloc, &device->meta_state.blit2d.img_ds_layout);
- if (result != VK_SUCCESS)
- goto fail;
-
- result = anv_CreatePipelineLayout(anv_device_to_handle(device),
- &(VkPipelineLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = 1,
- .pSetLayouts = &device->meta_state.blit2d.img_ds_layout,
- },
- &device->meta_state.alloc, &device->meta_state.blit2d.img_p_layout);
- if (result != VK_SUCCESS)
- goto fail;
-
- result = anv_CreateDescriptorSetLayout(anv_device_to_handle(device),
- &(VkDescriptorSetLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
- .bindingCount = 1,
- .pBindings = (VkDescriptorSetLayoutBinding[]) {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- .pImmutableSamplers = NULL
- },
- }
- }, &device->meta_state.alloc, &device->meta_state.blit2d.buf_ds_layout);
- if (result != VK_SUCCESS)
- goto fail;
+ texel_fetch_build_func src_func;
+ switch (src_type) {
+ case BLIT2D_SRC_TYPE_NORMAL:
+ src_func = build_nir_texel_fetch;
+ break;
+ case BLIT2D_SRC_TYPE_W_DETILE:
+ /* Not yet supported */
+ default:
+ return VK_SUCCESS;
+ }
- result = anv_CreatePipelineLayout(anv_device_to_handle(device),
- &(VkPipelineLayoutCreateInfo) {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = 1,
- .pSetLayouts = &device->meta_state.blit2d.buf_ds_layout,
- },
- &device->meta_state.alloc, &device->meta_state.blit2d.buf_p_layout);
- if (result != VK_SUCCESS)
- goto fail;
+ struct anv_shader_module fs = { .nir = NULL };
+ switch (dst_type) {
+ case BLIT2D_DST_TYPE_NORMAL:
+ fs.nir = build_nir_copy_fragment_shader(device, src_func);
+ break;
+ case BLIT2D_DST_TYPE_W_TILE:
+ case BLIT2D_DST_TYPE_RGB:
+ /* Not yet supported */
+ default:
+ return VK_SUCCESS;
+ }
/* We don't use a vertex shader for blitting, but instead build and pass
* the VUEs directly to the rasterization backend. However, we do need
.nir = build_nir_vertex_shader(),
};
- struct anv_shader_module fs_2d = {
- .nir = build_nir_copy_fragment_shader(device, build_nir_texel_fetch),
- };
-
VkPipelineVertexInputStateCreateInfo vi_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 2,
}, {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
- .module = VK_NULL_HANDLE, /* TEMPLATE VALUE! FILL ME IN! */
+ .module = anv_shader_module_to_handle(&fs),
.pName = "main",
.pSpecializationInfo = NULL
},
.use_rectlist = true
};
- pipeline_shader_stages[1].module = anv_shader_module_to_handle(&fs_2d);
result = anv_graphics_pipeline_create(anv_device_to_handle(device),
VK_NULL_HANDLE,
&vk_pipeline_info, &anv_pipeline_info,
- &device->meta_state.alloc, &device->meta_state.blit2d.pipeline_2d_src);
+ &device->meta_state.alloc,
+ &device->meta_state.blit2d.pipelines[src_type][dst_type]);
ralloc_free(vs.nir);
- ralloc_free(fs_2d.nir);
+ ralloc_free(fs.nir);
+
+ return result;
+}
+
+VkResult
+anv_device_init_meta_blit2d_state(struct anv_device *device)
+{
+ VkResult result;
+ zero(device->meta_state.blit2d);
+
+ result = anv_CreateRenderPass(anv_device_to_handle(device),
+ &(VkRenderPassCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = &(VkAttachmentDescription) {
+ .format = VK_FORMAT_UNDEFINED, /* Our shaders don't care */
+ .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,
+ }, &device->meta_state.alloc, &device->meta_state.blit2d.render_pass);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ result = anv_CreateDescriptorSetLayout(anv_device_to_handle(device),
+ &(VkDescriptorSetLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .bindingCount = 1,
+ .pBindings = (VkDescriptorSetLayoutBinding[]) {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = NULL
+ },
+ }
+ }, &device->meta_state.alloc, &device->meta_state.blit2d.img_ds_layout);
if (result != VK_SUCCESS)
goto fail;
+ result = anv_CreatePipelineLayout(anv_device_to_handle(device),
+ &(VkPipelineLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = 1,
+ .pSetLayouts = &device->meta_state.blit2d.img_ds_layout,
+ },
+ &device->meta_state.alloc, &device->meta_state.blit2d.img_p_layout);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ result = anv_CreateDescriptorSetLayout(anv_device_to_handle(device),
+ &(VkDescriptorSetLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .bindingCount = 1,
+ .pBindings = (VkDescriptorSetLayoutBinding[]) {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = NULL
+ },
+ }
+ }, &device->meta_state.alloc, &device->meta_state.blit2d.buf_ds_layout);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ result = anv_CreatePipelineLayout(anv_device_to_handle(device),
+ &(VkPipelineLayoutCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = 1,
+ .pSetLayouts = &device->meta_state.blit2d.buf_ds_layout,
+ },
+ &device->meta_state.alloc, &device->meta_state.blit2d.buf_p_layout);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ for (unsigned src = 0; src < BLIT2D_NUM_SRC_TYPES; src++) {
+ for (unsigned dst = 0; dst < BLIT2D_NUM_DST_TYPES; dst++) {
+ result = blit2d_init_pipeline(device, src, dst);
+ if (result != VK_SUCCESS)
+ goto fail;
+ }
+ }
+
return VK_SUCCESS;
fail: