Skip to content

Commit e4c6869

Browse files
layers: Add VK_QCOM_multiview_per_view_render_areas
1 parent 26e60ac commit e4c6869

File tree

6 files changed

+199
-16
lines changed

6 files changed

+199
-16
lines changed

layers/core_checks/cc_image.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,15 +1075,6 @@ bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer comman
10751075
return skip;
10761076
}
10771077

1078-
// Returns true if sub_rect is entirely contained within rect
1079-
static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
1080-
if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
1081-
(sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height)) {
1082-
return false;
1083-
}
1084-
return true;
1085-
}
1086-
10871078
bool CoreChecks::ValidateClearAttachmentExtent(const vvl::CommandBuffer &cb_state, const VkRect2D &render_area,
10881079
uint32_t render_pass_layer_count, uint32_t rect_count,
10891080
const VkClearRect *clear_rects, const Location &loc) const {

layers/core_checks/cc_render_pass.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -508,9 +508,8 @@ bool CoreChecks::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const
508508
uint32_t clear_op_size = 0; // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
509509

510510
// Handle extension struct from EXT_sample_locations
511-
const auto *sample_locations_begin_info =
512-
vku::FindStructInPNextChain<VkRenderPassSampleLocationsBeginInfoEXT>(pRenderPassBegin->pNext);
513-
if (sample_locations_begin_info) {
511+
if (const auto* sample_locations_begin_info =
512+
vku::FindStructInPNextChain<VkRenderPassSampleLocationsBeginInfoEXT>(pRenderPassBegin->pNext)) {
514513
for (uint32_t i = 0; i < sample_locations_begin_info->attachmentInitialSampleLocationsCount; ++i) {
515514
const Location sampler_loc =
516515
rp_begin_loc.pNext(Struct::VkRenderPassSampleLocationsBeginInfoEXT, Field::pAttachmentInitialSampleLocations, i);
@@ -616,8 +615,8 @@ bool CoreChecks::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const
616615
"maintenance7 were not enabled.");
617616
}
618617

619-
const auto counters_begin_info = vku::FindStructInPNextChain<VkRenderPassPerformanceCountersByRegionBeginInfoARM>(pRenderPassBegin->pNext);
620-
if (counters_begin_info) {
618+
if (const auto counters_begin_info =
619+
vku::FindStructInPNextChain<VkRenderPassPerformanceCountersByRegionBeginInfoARM>(pRenderPassBegin->pNext)) {
621620
const LogObjectList objlist(cb_state.Handle(), rp_state->Handle());
622621
uint32_t layer_or_view_count = 0;
623622
if (rp_state->has_multiview_enabled) {
@@ -3847,8 +3846,8 @@ bool CoreChecks::PreCallValidateCmdBeginRendering(VkCommandBuffer commandBuffer,
38473846
pRenderingInfo->viewMask, phys_dev_props_core11.maxMultiviewViewCount);
38483847
}
38493848

3850-
const auto counters_begin_info = vku::FindStructInPNextChain<VkRenderPassPerformanceCountersByRegionBeginInfoARM>(pRenderingInfo->pNext);
3851-
if (counters_begin_info) {
3849+
if (const auto counters_begin_info =
3850+
vku::FindStructInPNextChain<VkRenderPassPerformanceCountersByRegionBeginInfoARM>(pRenderingInfo->pNext)) {
38523851
const LogObjectList objlist(cb_state->Handle());
38533852
uint32_t layer_or_view_count = 0;
38543853
if (enabled_features.multiview) {

layers/stateless/sl_render_pass.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "utils/math_utils.h"
2525
#include "utils/image_utils.h"
2626
#include "utils/sync_utils.h"
27+
#include "utils/vk_api_utils.h"
2728

2829
namespace stateless {
2930

@@ -579,6 +580,82 @@ bool Device::ValidateRenderPassStripeBeginInfo(VkCommandBuffer commandBuffer, co
579580
return skip;
580581
}
581582

583+
bool Device::ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(
584+
VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* rp_begin_info, const VkRenderingInfo* rendering_info,
585+
const VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM& multiview_per_view_info, const Location& loc) const {
586+
bool skip = false;
587+
if (multiview_per_view_info.perViewRenderAreaCount != 0 && !enabled_features.multiviewPerViewRenderAreas) {
588+
const char* vuid = rp_begin_info ? "VUID-VkRenderPassBeginInfo-perViewRenderAreaCount-07859"
589+
: "VUID-VkRenderingInfo-perViewRenderAreaCount-07857";
590+
skip |= LogError(vuid, commandBuffer,
591+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::perViewRenderAreaCount),
592+
"is %" PRIu32 " but the multiviewPerViewRenderAreas feature was not enabled.",
593+
multiview_per_view_info.perViewRenderAreaCount);
594+
}
595+
596+
if (rendering_info) {
597+
const uint32_t msb = (uint32_t)MostSignificantBit(rendering_info->viewMask);
598+
if (multiview_per_view_info.perViewRenderAreaCount != msb + 1) {
599+
skip |= LogError(
600+
"VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-pNext-07866", commandBuffer,
601+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::perViewRenderAreaCount),
602+
"(%" PRIu32 ") must be VkRenderingInfo::viewMask (0x%" PRIx32 ") most significant bit index (%" PRIu32 ") + 1",
603+
multiview_per_view_info.perViewRenderAreaCount, rendering_info->viewMask, msb);
604+
}
605+
}
606+
607+
const VkRect2D full_render_area = rendering_info ? rendering_info->renderArea : rp_begin_info->renderArea;
608+
609+
for (uint32_t i = 0; i < multiview_per_view_info.perViewRenderAreaCount; i++) {
610+
const VkRect2D view_rect = multiview_per_view_info.pPerViewRenderAreas[i];
611+
if (view_rect.offset.x < 0) {
612+
skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07861", commandBuffer,
613+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM)
614+
.dot(Field::pPerViewRenderAreas, i)
615+
.dot(Field::offset)
616+
.dot(Field::x),
617+
"(%" PRId32 ") is less than zero.", view_rect.offset.x);
618+
}
619+
if (view_rect.offset.y < 0) {
620+
skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07862", commandBuffer,
621+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM)
622+
.dot(Field::pPerViewRenderAreas, i)
623+
.dot(Field::offset)
624+
.dot(Field::y),
625+
"(%" PRId32 ") is less than zero.", view_rect.offset.y);
626+
}
627+
if ((view_rect.offset.x + view_rect.extent.width) > phys_dev_props.limits.maxFramebufferWidth) {
628+
skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07863", commandBuffer,
629+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM)
630+
.dot(Field::pPerViewRenderAreas, i)
631+
.dot(Field::offset)
632+
.dot(Field::x),
633+
"%" PRId32 " + extent.width (%" PRIu32 ") greater than maxFramebufferWidth (%" PRIu32 ").",
634+
view_rect.offset.x, view_rect.extent.width, phys_dev_props.limits.maxFramebufferWidth);
635+
}
636+
if ((view_rect.offset.y + view_rect.extent.height) > phys_dev_props.limits.maxFramebufferHeight) {
637+
skip |= LogError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07864", commandBuffer,
638+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM)
639+
.dot(Field::pPerViewRenderAreas, i)
640+
.dot(Field::offset)
641+
.dot(Field::y),
642+
"%" PRId32 " + extent.height (%" PRIu32 ") greater than maxFramebufferHeight (%" PRIu32 ").",
643+
view_rect.offset.y, view_rect.extent.height, phys_dev_props.limits.maxFramebufferHeight);
644+
}
645+
646+
if (!ContainsRect(full_render_area, view_rect)) {
647+
const char* vuid = rp_begin_info ? "VUID-VkRenderPassBeginInfo-perViewRenderAreaCount-07860"
648+
: "VUID-VkRenderingInfo-perViewRenderAreaCount-07858";
649+
skip |=
650+
LogError(vuid, commandBuffer,
651+
loc.pNext(Struct::VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM).dot(Field::pPerViewRenderAreas, i),
652+
"(%s) is not contained in %s::renderArea (%s)", string_VkRect2D(view_rect).c_str(),
653+
rendering_info ? "VkRenderingInfo" : "VkRenderPassBeginInfo", string_VkRect2D(full_render_area).c_str());
654+
}
655+
}
656+
return skip;
657+
}
658+
582659
bool Device::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *const rp_begin,
583660
const ErrorObject &error_obj) const {
584661
bool skip = false;
@@ -592,6 +669,12 @@ bool Device::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkR
592669
const Location loc = error_obj.location.dot(Field::pRenderPassBegin);
593670
skip |= ValidateRenderPassStripeBeginInfo(commandBuffer, rp_begin->pNext, rp_begin->renderArea, loc);
594671

672+
if (const auto multiview_per_view_info =
673+
vku::FindStructInPNextChain<VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM>(rp_begin->pNext)) {
674+
skip |=
675+
ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(commandBuffer, rp_begin, nullptr, *multiview_per_view_info, loc);
676+
}
677+
595678
return skip;
596679
}
597680

@@ -735,6 +818,12 @@ bool Device::manual_PreCallValidateCmdBeginRendering(VkCommandBuffer commandBuff
735818
}
736819
}
737820

821+
if (const auto multiview_per_view_info =
822+
vku::FindStructInPNextChain<VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM>(pRenderingInfo->pNext)) {
823+
skip |= ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(commandBuffer, nullptr, pRenderingInfo,
824+
*multiview_per_view_info, rendering_info_loc);
825+
}
826+
738827
skip |= ValidateRenderPassStripeBeginInfo(commandBuffer, pRenderingInfo->pNext, pRenderingInfo->renderArea, rendering_info_loc);
739828
skip |= ValidateBeginRenderingColorAttachment(commandBuffer, *pRenderingInfo, rendering_info_loc);
740829
skip |= ValidateBeginRenderingDepthAttachment(commandBuffer, *pRenderingInfo, rendering_info_loc);

layers/stateless/stateless_validation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,9 @@ class Device : public vvl::base::Device {
10361036
const VkClearColorValue *pColor, uint32_t rangeCount,
10371037
const VkImageSubresourceRange *pRanges, const Context &context) const;
10381038

1039+
bool ValidateMultiviewPerViewRenderAreasRenderPassBeginInfo(
1040+
VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* rp_begin_info, const VkRenderingInfo* rendering_info,
1041+
const VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM& multiview_per_view_info, const Location& loc) const;
10391042
bool ValidateRenderPassStripeBeginInfo(VkCommandBuffer commandBuffer, const void *pNext, const VkRect2D render_area,
10401043
const Location &loc) const;
10411044
bool ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *const rp_begin,

layers/utils/vk_api_utils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ static inline VkOffset3D CastTo3D(const VkOffset2D &d2) {
141141
return d3;
142142
}
143143

144+
// Returns true if sub_rect is entirely contained within rect
145+
static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
146+
if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
147+
(sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height)) {
148+
return false;
149+
}
150+
return true;
151+
}
152+
144153
static constexpr VkPipelineStageFlags2 kFramebufferStagePipelineStageFlags =
145154
(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
146155
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);

tests/unit/multiview.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
* http://www.apache.org/licenses/LICENSE-2.0
1414
*/
1515

16+
#include <vulkan/vulkan_core.h>
1617
#include "../framework/layer_validation_tests.h"
1718
#include "../framework/pipeline_helper.h"
1819
#include "../framework/descriptor_helper.h"
1920
#include "../framework/render_pass_helper.h"
21+
#include "binding.h"
2022
#include "utils/convert_utils.h"
2123

2224
class NegativeMultiview : public VkLayerTest {};
@@ -1282,6 +1284,96 @@ TEST_F(NegativeMultiview, ShaderLayerBuiltInDynamicRendering) {
12821284
m_errorMonitor->VerifyFound();
12831285
}
12841286

1287+
TEST_F(NegativeMultiview, MultiviewPerViewRenderAreasFeature) {
1288+
SetTargetApiVersion(VK_API_VERSION_1_2);
1289+
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
1290+
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
1291+
AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME);
1292+
AddRequiredFeature(vkt::Feature::multiview);
1293+
AddRequiredFeature(vkt::Feature::dynamicRendering);
1294+
RETURN_IF_SKIP(Init());
1295+
1296+
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1297+
vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
1298+
1299+
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
1300+
color_attachment.imageView = image_view;
1301+
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1302+
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1303+
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1304+
1305+
VkRect2D view_render_area = {{0, 0}, {32, 32}};
1306+
VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM multiview_pre_view = vku::InitStructHelper();
1307+
multiview_pre_view.perViewRenderAreaCount = 1;
1308+
multiview_pre_view.pPerViewRenderAreas = &view_render_area;
1309+
1310+
VkRenderingInfo rendering_info = vku::InitStructHelper(&multiview_pre_view);
1311+
rendering_info.renderArea = {{0, 0}, {32, 32}};
1312+
rendering_info.layerCount = 1u;
1313+
rendering_info.colorAttachmentCount = 1u;
1314+
rendering_info.pColorAttachments = &color_attachment;
1315+
rendering_info.viewMask = 0x1;
1316+
1317+
m_command_buffer.Begin();
1318+
m_errorMonitor->SetDesiredError("VUID-VkRenderingInfo-perViewRenderAreaCount-07857");
1319+
m_command_buffer.BeginRendering(rendering_info);
1320+
m_errorMonitor->VerifyFound();
1321+
m_command_buffer.End();
1322+
}
1323+
1324+
TEST_F(NegativeMultiview, MultiviewPerViewRenderAreas) {
1325+
SetTargetApiVersion(VK_API_VERSION_1_2);
1326+
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
1327+
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
1328+
AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME);
1329+
AddRequiredFeature(vkt::Feature::multiview);
1330+
AddRequiredFeature(vkt::Feature::dynamicRendering);
1331+
AddRequiredFeature(vkt::Feature::multiviewPerViewRenderAreas);
1332+
RETURN_IF_SKIP(Init());
1333+
1334+
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1335+
vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
1336+
1337+
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
1338+
color_attachment.imageView = image_view;
1339+
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1340+
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1341+
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1342+
1343+
VkRect2D view_render_area[2] = {{{-1, 0}, {16, 16}}, {{0, -1}, {16, 16}}};
1344+
VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM multiview_pre_view = vku::InitStructHelper();
1345+
multiview_pre_view.perViewRenderAreaCount = 2;
1346+
multiview_pre_view.perViewRenderAreaCount = 2;
1347+
multiview_pre_view.pPerViewRenderAreas = view_render_area;
1348+
1349+
VkRenderingInfo rendering_info = vku::InitStructHelper(&multiview_pre_view);
1350+
rendering_info.renderArea = {{-1, -1}, {31, 31}};
1351+
rendering_info.layerCount = 1u;
1352+
rendering_info.colorAttachmentCount = 1u;
1353+
rendering_info.pColorAttachments = &color_attachment;
1354+
rendering_info.viewMask = 0x3;
1355+
1356+
m_command_buffer.Begin();
1357+
m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07861");
1358+
m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07862");
1359+
m_command_buffer.BeginRendering(rendering_info);
1360+
m_errorMonitor->VerifyFound();
1361+
1362+
view_render_area[0] = {{0, 0}, {16, 16}};
1363+
view_render_area[1] = {{0, 0}, {32, 16}};
1364+
1365+
m_errorMonitor->SetDesiredError("VUID-VkRenderingInfo-perViewRenderAreaCount-07858");
1366+
m_command_buffer.BeginRendering(rendering_info);
1367+
m_errorMonitor->VerifyFound();
1368+
1369+
multiview_pre_view.perViewRenderAreaCount = 1;
1370+
m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-pNext-07866");
1371+
m_command_buffer.BeginRendering(rendering_info);
1372+
m_errorMonitor->VerifyFound();
1373+
1374+
m_command_buffer.End();
1375+
}
1376+
12851377
TEST_F(NegativeMultiview, MeshShader) {
12861378
TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/issues/4194");
12871379
SetTargetApiVersion(VK_API_VERSION_1_2);

0 commit comments

Comments
 (0)