*/
static struct VkExtent3D
meta_region_extent_el(const struct radv_image *image,
+ const VkImageType imageType,
const struct VkExtent3D *extent)
{
const VkExtent3D block = meta_image_block_size(image);
- return radv_sanitize_image_extent(image->type, (VkExtent3D) {
+ return radv_sanitize_image_extent(imageType, (VkExtent3D) {
.width = DIV_ROUND_UP(extent->width , block.width),
.height = DIV_ROUND_UP(extent->height, block.height),
.depth = DIV_ROUND_UP(extent->depth , block.depth),
case 2: return VK_FORMAT_R8G8_UINT;
case 4: return VK_FORMAT_R8G8B8A8_UINT;
case 8: return VK_FORMAT_R16G16B16A16_UINT;
+ case 12: return VK_FORMAT_R32G32B32_UINT;
case 16: return VK_FORMAT_R32G32B32A32_UINT;
default:
unreachable("Invalid format block size");
static struct radv_meta_blit2d_surf
blit_surf_for_image_level_layer(struct radv_image *image,
- const VkImageSubresourceLayers *subres)
+ VkImageLayout layout,
+ const VkImageSubresourceLayers *subres,
+ VkImageAspectFlags aspect_mask)
{
- VkFormat format = image->vk_format;
- if (subres->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
- format = vk_format_depth_only(format);
- else if (subres->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
- format = vk_format_stencil_only(format);
+ VkFormat format = radv_get_aspect_format(image, aspect_mask);
- if (!image->surface.dcc_size)
+ if (!radv_dcc_enabled(image, subres->mipLevel) &&
+ !(radv_image_is_tc_compat_htile(image)))
format = vk_format_for_size(vk_format_get_blocksize(format));
+ format = vk_format_no_srgb(format);
+
return (struct radv_meta_blit2d_surf) {
.format = format,
.bs = vk_format_get_blocksize(format),
.level = subres->mipLevel,
.layer = subres->baseArrayLayer,
.image = image,
- .aspect_mask = subres->aspectMask,
+ .aspect_mask = aspect_mask,
+ .current_layout = layout,
};
}
-union meta_saved_state {
- struct radv_meta_saved_state gfx;
- struct radv_meta_saved_compute_state compute;
-};
+static bool
+image_is_renderable(struct radv_device *device, struct radv_image *image)
+{
+ if (image->vk_format == VK_FORMAT_R32G32B32_UINT ||
+ image->vk_format == VK_FORMAT_R32G32B32_SINT ||
+ image->vk_format == VK_FORMAT_R32G32B32_SFLOAT)
+ return false;
+
+ if (device->physical_device->rad_info.chip_class >= GFX9 &&
+ image->type == VK_IMAGE_TYPE_3D &&
+ vk_format_get_blocksizebits(image->vk_format) == 128 &&
+ vk_format_is_compressed(image->vk_format))
+ return false;
+ return true;
+}
static void
meta_copy_buffer_to_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_buffer* buffer,
struct radv_image* image,
+ VkImageLayout layout,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
bool cs = cmd_buffer->queue_family_index == RADV_QUEUE_COMPUTE;
- union meta_saved_state saved_state;
+ struct radv_meta_saved_state saved_state;
+ bool old_predicating;
/* The Vulkan 1.0 spec says "dstImage must have a sample count equal to
* VK_SAMPLE_COUNT_1_BIT."
*/
- assert(image->samples == 1);
+ assert(image->info.samples == 1);
- if (cs)
- radv_meta_begin_bufimage(cmd_buffer, &saved_state.compute);
- else
- radv_meta_save_graphics_reset_vport_scissor(&saved_state.gfx, cmd_buffer);
+ radv_meta_save(&saved_state, cmd_buffer,
+ (cs ? RADV_META_SAVE_COMPUTE_PIPELINE :
+ RADV_META_SAVE_GRAPHICS_PIPELINE) |
+ RADV_META_SAVE_CONSTANTS |
+ RADV_META_SAVE_DESCRIPTORS);
+
+ /* VK_EXT_conditional_rendering says that copy commands should not be
+ * affected by conditional rendering.
+ */
+ old_predicating = cmd_buffer->state.predicating;
+ cmd_buffer->state.predicating = false;
for (unsigned r = 0; r < regionCount; r++) {
pRegions[r].bufferImageHeight : pRegions[r].imageExtent.height,
};
const VkExtent3D buf_extent_el =
- meta_region_extent_el(image, &bufferExtent);
+ meta_region_extent_el(image, image->type, &bufferExtent);
/* Start creating blit rect */
const VkExtent3D img_extent_el =
- meta_region_extent_el(image, &pRegions[r].imageExtent);
+ meta_region_extent_el(image, image->type, &pRegions[r].imageExtent);
struct radv_meta_blit2d_rect rect = {
.width = img_extent_el.width,
.height = img_extent_el.height,
/* Create blit surfaces */
struct radv_meta_blit2d_surf img_bsurf =
blit_surf_for_image_level_layer(image,
- &pRegions[r].imageSubresource);
+ layout,
+ &pRegions[r].imageSubresource,
+ pRegions[r].imageSubresource.aspectMask);
+
+ if (!radv_is_buffer_format_supported(img_bsurf.format, NULL)) {
+ uint32_t queue_mask = radv_image_queue_family_mask(image,
+ cmd_buffer->queue_family_index,
+ cmd_buffer->queue_family_index);
+ bool compressed = radv_layout_dcc_compressed(cmd_buffer->device, image, layout, false, queue_mask);
+ if (compressed) {
+ radv_decompress_dcc(cmd_buffer, image, &(VkImageSubresourceRange) {
+ .aspectMask = pRegions[r].imageSubresource.aspectMask,
+ .baseMipLevel = pRegions[r].imageSubresource.mipLevel,
+ .levelCount = 1,
+ .baseArrayLayer = pRegions[r].imageSubresource.baseArrayLayer,
+ .layerCount = pRegions[r].imageSubresource.layerCount,
+ });
+ }
+ img_bsurf.format = vk_format_for_size(vk_format_get_blocksize(img_bsurf.format));
+ img_bsurf.current_layout = VK_IMAGE_LAYOUT_GENERAL;
+ }
struct radv_meta_blit2d_buffer buf_bsurf = {
.bs = img_bsurf.bs,
/* Perform Blit */
- if (cs)
+ if (cs ||
+ !image_is_renderable(cmd_buffer->device, img_bsurf.image)) {
radv_meta_buffer_to_image_cs(cmd_buffer, &buf_bsurf, &img_bsurf, 1, &rect);
- else
+ } else {
radv_meta_blit2d(cmd_buffer, NULL, &buf_bsurf, &img_bsurf, 1, &rect);
+ }
/* Once we've done the blit, all of the actual information about
* the image is embedded in the command buffer so we can just
slice_array++;
}
}
- if (cs)
- radv_meta_end_bufimage(cmd_buffer, &saved_state.compute);
- else
- radv_meta_restore(&saved_state.gfx, cmd_buffer);
+
+ /* Restore conditional rendering. */
+ cmd_buffer->state.predicating = old_predicating;
+
+ radv_meta_restore(&saved_state, cmd_buffer);
}
void radv_CmdCopyBufferToImage(
RADV_FROM_HANDLE(radv_image, dest_image, destImage);
RADV_FROM_HANDLE(radv_buffer, src_buffer, srcBuffer);
- meta_copy_buffer_to_image(cmd_buffer, src_buffer, dest_image,
+ meta_copy_buffer_to_image(cmd_buffer, src_buffer, dest_image, destImageLayout,
regionCount, pRegions);
}
meta_copy_image_to_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radv_buffer* buffer,
struct radv_image* image,
+ VkImageLayout layout,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
- struct radv_meta_saved_compute_state saved_state;
+ struct radv_meta_saved_state saved_state;
+ bool old_predicating;
+
+ radv_meta_save(&saved_state, cmd_buffer,
+ RADV_META_SAVE_COMPUTE_PIPELINE |
+ RADV_META_SAVE_CONSTANTS |
+ RADV_META_SAVE_DESCRIPTORS);
+
+ /* VK_EXT_conditional_rendering says that copy commands should not be
+ * affected by conditional rendering.
+ */
+ old_predicating = cmd_buffer->state.predicating;
+ cmd_buffer->state.predicating = false;
- radv_meta_begin_bufimage(cmd_buffer, &saved_state);
for (unsigned r = 0; r < regionCount; r++) {
/**
pRegions[r].bufferImageHeight : pRegions[r].imageExtent.height,
};
const VkExtent3D buf_extent_el =
- meta_region_extent_el(image, &bufferExtent);
+ meta_region_extent_el(image, image->type, &bufferExtent);
/* Start creating blit rect */
const VkExtent3D img_extent_el =
- meta_region_extent_el(image, &pRegions[r].imageExtent);
+ meta_region_extent_el(image, image->type, &pRegions[r].imageExtent);
struct radv_meta_blit2d_rect rect = {
.width = img_extent_el.width,
.height = img_extent_el.height,
/* Create blit surfaces */
struct radv_meta_blit2d_surf img_info =
blit_surf_for_image_level_layer(image,
- &pRegions[r].imageSubresource);
+ layout,
+ &pRegions[r].imageSubresource,
+ pRegions[r].imageSubresource.aspectMask);
+
+ if (!radv_is_buffer_format_supported(img_info.format, NULL)) {
+ uint32_t queue_mask = radv_image_queue_family_mask(image,
+ cmd_buffer->queue_family_index,
+ cmd_buffer->queue_family_index);
+ bool compressed = radv_layout_dcc_compressed(cmd_buffer->device, image, layout, false, queue_mask);
+ if (compressed) {
+ radv_decompress_dcc(cmd_buffer, image, &(VkImageSubresourceRange) {
+ .aspectMask = pRegions[r].imageSubresource.aspectMask,
+ .baseMipLevel = pRegions[r].imageSubresource.mipLevel,
+ .levelCount = 1,
+ .baseArrayLayer = pRegions[r].imageSubresource.baseArrayLayer,
+ .layerCount = pRegions[r].imageSubresource.layerCount,
+ });
+ }
+ img_info.format = vk_format_for_size(vk_format_get_blocksize(img_info.format));
+ img_info.current_layout = VK_IMAGE_LAYOUT_GENERAL;
+ }
struct radv_meta_blit2d_buffer buf_info = {
.bs = img_info.bs,
slice_array++;
}
}
- radv_meta_end_bufimage(cmd_buffer, &saved_state);
+
+ /* Restore conditional rendering. */
+ cmd_buffer->state.predicating = old_predicating;
+
+ radv_meta_restore(&saved_state, cmd_buffer);
}
void radv_CmdCopyImageToBuffer(
RADV_FROM_HANDLE(radv_buffer, dst_buffer, destBuffer);
meta_copy_image_to_buffer(cmd_buffer, dst_buffer, src_image,
+ srcImageLayout,
regionCount, pRegions);
}
static void
meta_copy_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *src_image,
+ VkImageLayout src_image_layout,
struct radv_image *dest_image,
+ VkImageLayout dest_image_layout,
uint32_t regionCount,
const VkImageCopy *pRegions)
{
bool cs = cmd_buffer->queue_family_index == RADV_QUEUE_COMPUTE;
- union meta_saved_state saved_state;
+ struct radv_meta_saved_state saved_state;
+ bool old_predicating;
/* From the Vulkan 1.0 spec:
*
* vkCmdCopyImage can be used to copy image data between multisample
* images, but both images must have the same number of samples.
*/
- assert(src_image->samples == dest_image->samples);
- if (cs)
- radv_meta_begin_itoi(cmd_buffer, &saved_state.compute);
- else
- radv_meta_save_graphics_reset_vport_scissor(&saved_state.gfx, cmd_buffer);
-
- for (unsigned r = 0; r < regionCount; r++) {
- assert(pRegions[r].srcSubresource.aspectMask ==
- pRegions[r].dstSubresource.aspectMask);
-
- /* Create blit surfaces */
- struct radv_meta_blit2d_surf b_src =
- blit_surf_for_image_level_layer(src_image,
- &pRegions[r].srcSubresource);
-
- struct radv_meta_blit2d_surf b_dst =
- blit_surf_for_image_level_layer(dest_image,
- &pRegions[r].dstSubresource);
-
- /* for DCC */
- b_src.format = b_dst.format;
-
- /**
- * From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images
- * imageExtent is the size in texels of the image to copy in width, height
- * and depth. 1D images use only x and width. 2D images use x, y, width
- * and height. 3D images use x, y, z, width, height and depth.
- *
- * Also, convert the offsets and extent from units of texels to units of
- * blocks - which is the highest resolution accessible in this command.
- */
- const VkOffset3D dst_offset_el =
- meta_region_offset_el(dest_image, &pRegions[r].dstOffset);
- const VkOffset3D src_offset_el =
- meta_region_offset_el(src_image, &pRegions[r].srcOffset);
- const VkExtent3D img_extent_el =
- meta_region_extent_el(dest_image, &pRegions[r].extent);
+ assert(src_image->info.samples == dest_image->info.samples);
- /* Start creating blit rect */
- struct radv_meta_blit2d_rect rect = {
- .width = img_extent_el.width,
- .height = img_extent_el.height,
- };
+ radv_meta_save(&saved_state, cmd_buffer,
+ (cs ? RADV_META_SAVE_COMPUTE_PIPELINE :
+ RADV_META_SAVE_GRAPHICS_PIPELINE) |
+ RADV_META_SAVE_CONSTANTS |
+ RADV_META_SAVE_DESCRIPTORS);
- if (dest_image->type == VK_IMAGE_TYPE_3D)
- b_dst.layer = dst_offset_el.z;
+ /* VK_EXT_conditional_rendering says that copy commands should not be
+ * affected by conditional rendering.
+ */
+ old_predicating = cmd_buffer->state.predicating;
+ cmd_buffer->state.predicating = false;
- /* Loop through each 3D or array slice */
- unsigned num_slices_3d = img_extent_el.depth;
- unsigned num_slices_array = pRegions[r].dstSubresource.layerCount;
- unsigned slice_3d = 0;
- unsigned slice_array = 0;
- while (slice_3d < num_slices_3d && slice_array < num_slices_array) {
+ for (unsigned r = 0; r < regionCount; r++) {
+ VkImageAspectFlags src_aspects[3] = {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
+ VkImageAspectFlags dst_aspects[3] = {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
+ unsigned aspect_count = pRegions[r].srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT ? src_image->plane_count : 1;
+ if (pRegions[r].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)
+ src_aspects[0] = pRegions[r].srcSubresource.aspectMask;
+ if (pRegions[r].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)
+ dst_aspects[0] = pRegions[r].dstSubresource.aspectMask;
+
+ for (unsigned a = 0; a < aspect_count; ++a) {
+ /* Create blit surfaces */
+ struct radv_meta_blit2d_surf b_src =
+ blit_surf_for_image_level_layer(src_image,
+ src_image_layout,
+ &pRegions[r].srcSubresource,
+ src_aspects[a]);
+
+ struct radv_meta_blit2d_surf b_dst =
+ blit_surf_for_image_level_layer(dest_image,
+ dest_image_layout,
+ &pRegions[r].dstSubresource,
+ dst_aspects[a]);
+
+ uint32_t dst_queue_mask = radv_image_queue_family_mask(dest_image,
+ cmd_buffer->queue_family_index,
+ cmd_buffer->queue_family_index);
+ bool dst_compressed = radv_layout_dcc_compressed(cmd_buffer->device, dest_image, dest_image_layout, false, dst_queue_mask);
+ uint32_t src_queue_mask = radv_image_queue_family_mask(src_image,
+ cmd_buffer->queue_family_index,
+ cmd_buffer->queue_family_index);
+ bool src_compressed = radv_layout_dcc_compressed(cmd_buffer->device, src_image, src_image_layout, false, src_queue_mask);
+
+ if (!src_compressed || radv_dcc_formats_compatible(b_src.format, b_dst.format)) {
+ b_src.format = b_dst.format;
+ } else if (!dst_compressed) {
+ b_dst.format = b_src.format;
+ } else {
+ radv_decompress_dcc(cmd_buffer, dest_image, &(VkImageSubresourceRange) {
+ .aspectMask = dst_aspects[a],
+ .baseMipLevel = pRegions[r].dstSubresource.mipLevel,
+ .levelCount = 1,
+ .baseArrayLayer = pRegions[r].dstSubresource.baseArrayLayer,
+ .layerCount = pRegions[r].dstSubresource.layerCount,
+ });
+ b_dst.format = b_src.format;
+ b_dst.current_layout = VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+
+ /**
+ * From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images
+ * imageExtent is the size in texels of the image to copy in width, height
+ * and depth. 1D images use only x and width. 2D images use x, y, width
+ * and height. 3D images use x, y, z, width, height and depth.
+ *
+ * Also, convert the offsets and extent from units of texels to units of
+ * blocks - which is the highest resolution accessible in this command.
+ */
+ const VkOffset3D dst_offset_el =
+ meta_region_offset_el(dest_image, &pRegions[r].dstOffset);
+ const VkOffset3D src_offset_el =
+ meta_region_offset_el(src_image, &pRegions[r].srcOffset);
+
+ /*
+ * From Vulkan 1.0.68, "Copying Data Between Images":
+ * "When copying between compressed and uncompressed formats
+ * the extent members represent the texel dimensions of the
+ * source image and not the destination."
+ * However, we must use the destination image type to avoid
+ * clamping depth when copying multiple layers of a 2D image to
+ * a 3D image.
+ */
+ const VkExtent3D img_extent_el =
+ meta_region_extent_el(src_image, dest_image->type, &pRegions[r].extent);
- /* Finish creating blit rect */
- rect.dst_x = dst_offset_el.x;
- rect.dst_y = dst_offset_el.y;
- rect.src_x = src_offset_el.x;
- rect.src_y = src_offset_el.y;
+ /* Start creating blit rect */
+ struct radv_meta_blit2d_rect rect = {
+ .width = img_extent_el.width,
+ .height = img_extent_el.height,
+ };
- /* Perform Blit */
- if (cs)
- radv_meta_image_to_image_cs(cmd_buffer, &b_src, &b_dst, 1, &rect);
- else
- radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect);
+ if (src_image->type == VK_IMAGE_TYPE_3D)
+ b_src.layer = src_offset_el.z;
- b_src.layer++;
- b_dst.layer++;
if (dest_image->type == VK_IMAGE_TYPE_3D)
- slice_3d++;
- else
- slice_array++;
+ b_dst.layer = dst_offset_el.z;
+
+ /* Loop through each 3D or array slice */
+ unsigned num_slices_3d = img_extent_el.depth;
+ unsigned num_slices_array = pRegions[r].dstSubresource.layerCount;
+ unsigned slice_3d = 0;
+ unsigned slice_array = 0;
+ while (slice_3d < num_slices_3d && slice_array < num_slices_array) {
+
+ /* Finish creating blit rect */
+ rect.dst_x = dst_offset_el.x;
+ rect.dst_y = dst_offset_el.y;
+ rect.src_x = src_offset_el.x;
+ rect.src_y = src_offset_el.y;
+
+ /* Perform Blit */
+ if (cs ||
+ !image_is_renderable(cmd_buffer->device, b_dst.image)) {
+ radv_meta_image_to_image_cs(cmd_buffer, &b_src, &b_dst, 1, &rect);
+ } else {
+ radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect);
+ }
+
+ b_src.layer++;
+ b_dst.layer++;
+ if (dest_image->type == VK_IMAGE_TYPE_3D)
+ slice_3d++;
+ else
+ slice_array++;
+ }
}
}
- if (cs)
- radv_meta_end_itoi(cmd_buffer, &saved_state.compute);
- else
- radv_meta_restore(&saved_state.gfx, cmd_buffer);
+ /* Restore conditional rendering. */
+ cmd_buffer->state.predicating = old_predicating;
+
+ radv_meta_restore(&saved_state, cmd_buffer);
}
void radv_CmdCopyImage(
RADV_FROM_HANDLE(radv_image, src_image, srcImage);
RADV_FROM_HANDLE(radv_image, dest_image, destImage);
- meta_copy_image(cmd_buffer, src_image, dest_image,
+ meta_copy_image(cmd_buffer,
+ src_image, srcImageLayout,
+ dest_image, destImageLayout,
regionCount, pRegions);
}
-
-void radv_blit_to_prime_linear(struct radv_cmd_buffer *cmd_buffer,
- struct radv_image *image,
- struct radv_image *linear_image)
-{
- struct VkImageCopy image_copy = { 0 };
-
- image_copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- image_copy.srcSubresource.layerCount = 1;
-
- image_copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- image_copy.dstSubresource.layerCount = 1;
-
- image_copy.extent.width = image->extent.width;
- image_copy.extent.height = image->extent.height;
- image_copy.extent.depth = 1;
-
- meta_copy_image(cmd_buffer, image, linear_image,
- 1, &image_copy);
-}