Skip to content

Commit f0c9f53

Browse files
committed
layers: Fix image layout encoding for image views
1 parent 7a9792c commit f0c9f53

File tree

4 files changed

+89
-12
lines changed

4 files changed

+89
-12
lines changed

layers/core_checks/cc_image_layout.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/* Copyright (c) 2015-2025 The Khronos Group Inc.
2-
* Copyright (c) 2015-2025 Valve Corporation
3-
* Copyright (c) 2015-2025 LunarG, Inc.
1+
/* Copyright (c) 2015-2026 The Khronos Group Inc.
2+
* Copyright (c) 2015-2026 Valve Corporation
3+
* Copyright (c) 2015-2026 LunarG, Inc.
44
* Copyright (C) 2015-2025 Google Inc.
55
* Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
66
*
@@ -835,16 +835,16 @@ void CoreChecks::TransitionBeginRenderPassLayouts(vvl::CommandBuffer &cb_state,
835835
vku::FindStructInPNextChain<VkAttachmentDescriptionStencilLayout>(rpci->pAttachments[i].pNext);
836836
if (attachment_description_stencil_layout) {
837837
const auto stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout;
838-
VkImageSubresourceRange sub_range = view_state->normalized_subresource_range;
838+
VkImageSubresourceRange sub_range = view_state->GetRangeGeneratorRange(device_state->extensions);
839839
sub_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
840840
cb_state.TrackImageFirstLayout(*image_state, sub_range, 0, 0, initial_layout);
841841
sub_range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
842842
cb_state.TrackImageFirstLayout(*image_state, sub_range, 0, 0, stencil_initial_layout);
843843
} else {
844+
auto subresource_range = view_state->GetRangeGeneratorRange(device_state->extensions);
844845
// If layoutStencil is kInvalidLayout (meaning no separate depth/stencil layout), image view format has both depth
845846
// and stencil aspects, and subresource has only one of aspect out of depth or stencil, then the missing aspect will
846847
// also be transitioned and thus must be included explicitly
847-
auto subresource_range = view_state->normalized_subresource_range;
848848
if (const VkFormat format = view_state->create_info.format; vkuFormatIsDepthAndStencil(format)) {
849849
if (subresource_range.aspectMask & (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) {
850850
subresource_range.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;

layers/state_tracker/cmd_buffer_state.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,11 +1798,10 @@ void CommandBuffer::TrackImageFirstLayout(const vvl::Image &image_state, const V
17981798
}
17991799
}
18001800

1801-
// Set image layout for all slices of an image view
18021801
void CommandBuffer::SetImageViewLayout(const vvl::ImageView &view_state, VkImageLayout layout, VkImageLayout layoutStencil) {
18031802
const vvl::Image *image_state = view_state.image_state.get();
18041803

1805-
VkImageSubresourceRange sub_range = view_state.normalized_subresource_range;
1804+
VkImageSubresourceRange sub_range = view_state.GetRangeGeneratorRange(dev_data.extensions);
18061805

18071806
if (sub_range.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && layoutStencil != kInvalidLayout) {
18081807
sub_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;

layers/state_tracker/image_state.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/* Copyright (c) 2015-2025 The Khronos Group Inc.
2-
* Copyright (c) 2015-2025 Valve Corporation
3-
* Copyright (c) 2015-2025 LunarG, Inc.
1+
/* Copyright (c) 2015-2026 The Khronos Group Inc.
2+
* Copyright (c) 2015-2026 Valve Corporation
3+
* Copyright (c) 2015-2026 LunarG, Inc.
44
* Copyright (C) 2015-2025 Google Inc.
55
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
66
* Modifications Copyright (C) 2022 RasterGrid Kft.
@@ -317,6 +317,12 @@ class ImageView : public StateObject, public SubStateManager<ImageViewSubState>
317317

318318
static VkImageSubresourceRange NormalizeImageViewSubresourceRange(const Image &image_state,
319319
const VkImageViewCreateInfo &image_view_ci);
320+
321+
// The range that defines indexing space of all possible image layouts for this image view.
322+
// It is used by the RangeGenerator and the image layout maps.
323+
// In the general case, it is different than the number of subresources (described by
324+
// normalized_subresource_range), so when dealing with image layouts this function should
325+
// always be used instead
320326
VkImageSubresourceRange GetRangeGeneratorRange(const DeviceExtensions &extensions) const;
321327

322328
std::string DescribeImageUsage(const Logger& logger) const;

tests/unit/image_layout_positive.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* Copyright (c) 2024-2025 Valve Corporation
3-
* Copyright (c) 2024-2025 LunarG, Inc.
2+
* Copyright (c) 2024-2026 Valve Corporation
3+
* Copyright (c) 2024-2026 LunarG, Inc.
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -802,6 +802,78 @@ TEST_F(PositiveImageLayout, TransitionAll3dImageSlices) {
802802
m_command_buffer.End();
803803
}
804804

805+
TEST_F(PositiveImageLayout, TransitionAll3dImageSlicesUsing2DArrayView) {
806+
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11578
807+
SetTargetApiVersion(VK_API_VERSION_1_3);
808+
AddRequiredFeature(vkt::Feature::dynamicRendering);
809+
AddRequiredFeature(vkt::Feature::synchronization2);
810+
RETURN_IF_SKIP(Init());
811+
812+
const uint32_t image_depth = 10;
813+
814+
VkImageCreateInfo image_ci = vku::InitStructHelper();
815+
image_ci.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
816+
image_ci.imageType = VK_IMAGE_TYPE_3D;
817+
image_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
818+
image_ci.extent = {64, 64, image_depth};
819+
image_ci.mipLevels = 1;
820+
image_ci.arrayLayers = 1;
821+
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
822+
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
823+
image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
824+
image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
825+
vkt::Image image(*m_device, image_ci);
826+
827+
VkImageViewCreateInfo image_view_ci = vku::InitStructHelper();
828+
image_view_ci.image = image;
829+
image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
830+
image_view_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
831+
image_view_ci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, image_depth};
832+
vkt::ImageView image_view(*m_device, image_view_ci);
833+
834+
RenderPassSingleSubpass rp(*this);
835+
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL);
836+
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
837+
rp.CreateRenderPass();
838+
839+
VkFramebufferCreateInfo framebuffer_ci = vku::InitStructHelper();
840+
framebuffer_ci.renderPass = rp;
841+
framebuffer_ci.width = 64;
842+
framebuffer_ci.height = 64;
843+
framebuffer_ci.layers = image_depth;
844+
framebuffer_ci.attachmentCount = 1;
845+
framebuffer_ci.pAttachments = &image_view.handle();
846+
vkt::Framebuffer framebuffer(*m_device, framebuffer_ci);
847+
848+
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
849+
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
850+
layout_transition.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
851+
layout_transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
852+
layout_transition.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
853+
layout_transition.image = image;
854+
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
855+
856+
vkt::Buffer buffer(*m_device, 64 * 64 * 64, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
857+
858+
VkBufferImageCopy region{};
859+
region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
860+
region.imageExtent = {64, 64, 1};
861+
862+
m_command_buffer.Begin();
863+
864+
// Transition image to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
865+
m_command_buffer.Barrier(layout_transition);
866+
867+
// Transition image to VK_IMAGE_LAYOUT_GENERAL
868+
m_command_buffer.BeginRenderPass(rp, framebuffer, 64, 64);
869+
m_command_buffer.EndRenderPass();
870+
871+
// Expect GENERAL layout. The original issue reported layout mismatch
872+
vk::CmdCopyBufferToImage(m_command_buffer, buffer, image, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
873+
874+
m_command_buffer.End();
875+
}
876+
805877
TEST_F(PositiveImageLayout, DepthSliceTransitionCriteriaNotMet) {
806878
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10453
807879
TEST_DESCRIPTION("Enabled maintenance9 but do not set image flag VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT");

0 commit comments

Comments
 (0)