VK_NV_scissor_exclusive
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index e9d0ccc..dad6cdd 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -1779,6 +1779,7 @@
// Exclude KHX (if not already present) { CMD_SETDEVICEMASKKHX, "VUID-vkCmdSetDeviceMask-commandBuffer-recording" },
{CMD_SETDISCARDRECTANGLEEXT, "VUID-vkCmdSetDiscardRectangleEXT-commandBuffer-recording"},
{CMD_SETEVENT, "VUID-vkCmdSetEvent-commandBuffer-recording"},
+ {CMD_SETEXCLUSIVESCISSOR, "VUID-vkCmdSetExclusiveScissorNV-commandBuffer-recording"},
{CMD_SETLINEWIDTH, "VUID-vkCmdSetLineWidth-commandBuffer-recording"},
{CMD_SETSAMPLELOCATIONSEXT, "VUID-vkCmdSetSampleLocationsEXT-commandBuffer-recording"},
{CMD_SETSCISSOR, "VUID-vkCmdSetScissor-commandBuffer-recording"},
@@ -2010,6 +2011,9 @@
case VK_DYNAMIC_STATE_VIEWPORT:
flags &= ~CBSTATUS_VIEWPORT_SET;
break;
+ case VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV:
+ flags &= ~CBSTATUS_EXCLUSIVE_SCISSOR_SET;
+ break;
default:
break;
}
@@ -2289,6 +2293,11 @@
device_data->enabled_features.eight_bit_storage = *eight_bit_storage_features;
}
+ const auto *exclusive_scissor_features = lvl_find_in_chain<VkPhysicalDeviceExclusiveScissorFeaturesNV>(pCreateInfo->pNext);
+ if (exclusive_scissor_features) {
+ device_data->enabled_features.exclusive_scissor = *exclusive_scissor_features;
+ }
+
// Store physical device properties and physical device mem limits into device layer_data structs
instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
@@ -6329,6 +6338,47 @@
if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
}
+static bool PreCallValidateCmdSetExclusiveScissorNV(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
+ bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetExclusiveScissorNV()", VK_QUEUE_GRAPHICS_BIT,
+ "VUID-vkCmdSetExclusiveScissorNV-commandBuffer-cmdpool");
+ skip |= ValidateCmd(dev_data, cb_state, CMD_SETEXCLUSIVESCISSOR, "vkCmdSetExclusiveScissorNV()");
+ if (cb_state->static_status & CBSTATUS_EXCLUSIVE_SCISSOR_SET) {
+ skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-None-02032",
+ "vkCmdSetExclusiveScissorNV(): pipeline was created without VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV flag.");
+ }
+
+ if (!GetEnabledFeatures(dev_data)->exclusive_scissor.exclusiveScissor) {
+ skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-None-02031",
+ "vkCmdSetExclusiveScissorNV: The exclusiveScissor feature is disabled.");
+ }
+
+ return skip;
+}
+
+static void PreCallRecordCmdSetExclusiveScissorNV(GLOBAL_CB_NODE *cb_state, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount) {
+ // XXX TODO: We don't have VUIDs for validating that all exclusive scissors have been set.
+ // cb_state->exclusiveScissorMask |= ((1u << exclusiveScissorCount) - 1u) << firstExclusiveScissor;
+ cb_state->status |= CBSTATUS_EXCLUSIVE_SCISSOR_SET;
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount,
+ const VkRect2D *pExclusiveScissors) {
+ bool skip = false;
+ layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+ unique_lock_t lock(global_lock);
+ GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
+ if (pCB) {
+ skip |= PreCallValidateCmdSetExclusiveScissorNV(dev_data, pCB, commandBuffer);
+ if (!skip) {
+ PreCallRecordCmdSetExclusiveScissorNV(pCB, firstExclusiveScissor, exclusiveScissorCount);
+ }
+ }
+ lock.unlock();
+ if (!skip) dev_data->dispatch_table.CmdSetExclusiveScissorNV(commandBuffer, firstExclusiveScissor, exclusiveScissorCount, pExclusiveScissors);
+}
+
static bool PreCallValidateCmdSetLineWidth(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer) {
bool skip = ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT,
"VUID-vkCmdSetLineWidth-commandBuffer-cmdpool");
@@ -13847,6 +13897,7 @@
{"vkSubmitDebugUtilsMessageEXT", (void *)SubmitDebugUtilsMessageEXT},
{"vkCmdDrawIndirectCountKHR", (void *)CmdDrawIndirectCountKHR},
{"vkCmdDrawIndexedIndirectCountKHR", (void *)CmdDrawIndexedIndirectCountKHR},
+ {"vkCmdSetExclusiveScissorNV", (void *)CmdSetExclusiveScissorNV},
};
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index e6f4317..29d5ee4 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -478,6 +478,7 @@
CMD_SETDEVICEMASKKHX,
CMD_SETDISCARDRECTANGLEEXT,
CMD_SETEVENT,
+ CMD_SETEXCLUSIVESCISSOR,
CMD_SETLINEWIDTH,
CMD_SETSAMPLELOCATIONSEXT,
CMD_SETSCISSOR,
@@ -514,7 +515,8 @@
CBSTATUS_VIEWPORT_SET = 0x00000080,
CBSTATUS_SCISSOR_SET = 0x00000100,
CBSTATUS_INDEX_BUFFER_BOUND = 0x00000200, // Index buffer has been set
- CBSTATUS_ALL_STATE_SET = 0x000001FF, // All state set (intentionally exclude index buffer)
+ CBSTATUS_EXCLUSIVE_SCISSOR_SET = 0x00000400,
+ CBSTATUS_ALL_STATE_SET = 0x000005FF, // All state set (intentionally exclude index buffer)
// clang-format on
};
@@ -1048,6 +1050,7 @@
VkPhysicalDeviceFeatures core;
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing;
VkPhysicalDevice8BitStorageFeaturesKHR eight_bit_storage;
+ VkPhysicalDeviceExclusiveScissorFeaturesNV exclusive_scissor;
};
// Fwd declarations of layer_data and helpers to look-up/validate state from layer_data maps
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index 5037343..7f5be9a 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -1319,6 +1319,7 @@
bool has_dynamic_viewport_w_scaling_nv = false;
bool has_dynamic_discard_rectangle_ext = false;
bool has_dynamic_sample_locations_ext = false;
+ bool has_dynamic_exclusive_scissor_nv = false;
if (pCreateInfos[i].pDynamicState != nullptr) {
const auto &dynamic_state_info = *pCreateInfos[i].pDynamicState;
for (uint32_t state_index = 0; state_index < dynamic_state_info.dynamicStateCount; ++state_index) {
@@ -1329,6 +1330,7 @@
if (dynamic_state == VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV) has_dynamic_viewport_w_scaling_nv = true;
if (dynamic_state == VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT) has_dynamic_discard_rectangle_ext = true;
if (dynamic_state == VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT) has_dynamic_sample_locations_ext = true;
+ if (dynamic_state == VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV) has_dynamic_exclusive_scissor_nv = true;
}
}
@@ -1524,11 +1526,13 @@
const VkStructureType allowed_structs_VkPipelineViewportStateCreateInfo[] = {
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV,
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV};
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV,
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV,
+ };
skip |= validate_struct_pnext(
report_data, "vkCreateGraphicsPipelines",
ParameterName("pCreateInfos[%i].pViewportState->pNext", ParameterName::IndexVector{i}),
- "VkPipelineViewportSwizzleStateCreateInfoNV, VkPipelineViewportWScalingStateCreateInfoNV",
+ "VkPipelineViewportSwizzleStateCreateInfoNV, VkPipelineViewportWScalingStateCreateInfoNV, VkPipelineViewportExclusiveScissorStateCreateInfoNV",
viewport_state.pNext, ARRAY_SIZE(allowed_structs_VkPipelineViewportStateCreateInfo),
allowed_structs_VkPipelineViewportStateCreateInfo, 65,
"VUID-VkPipelineViewportStateCreateInfo-pNext-pNext");
@@ -1538,6 +1542,8 @@
ParameterName("pCreateInfos[%i].pViewportState->flags", ParameterName::IndexVector{i}),
viewport_state.flags, "VUID-VkPipelineViewportStateCreateInfo-flags-zerobitmask");
+ auto exclusive_scissor_struct = lvl_find_in_chain<VkPipelineViewportExclusiveScissorStateCreateInfoNV>(pCreateInfos[i].pViewportState->pNext);
+
if (!device_data->physical_device_features.multiViewport) {
if (viewport_state.viewportCount != 1) {
skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
@@ -1556,6 +1562,18 @@
") is not 1.",
i, viewport_state.scissorCount);
}
+
+ if (exclusive_scissor_struct &&
+ (exclusive_scissor_struct->exclusiveScissorCount != 0 && exclusive_scissor_struct->exclusiveScissorCount != 1)) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+ VK_NULL_HANDLE, "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02027",
+ "vkCreateGraphicsPipelines: The VkPhysicalDeviceFeatures::multiViewport feature is "
+ "disabled, but pCreateInfos[%" PRIu32 "] exclusiveScissorCount (=%" PRIu32
+ ") is not 1.",
+ i, exclusive_scissor_struct->exclusiveScissorCount);
+
+ }
+
} else { // multiViewport enabled
if (viewport_state.viewportCount == 0) {
skip |= log_msg(
@@ -1586,6 +1604,16 @@
}
}
+ if (exclusive_scissor_struct &&
+ exclusive_scissor_struct->exclusiveScissorCount > device_data->device_limits.maxViewports) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+ VK_NULL_HANDLE, "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02028",
+ "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
+ "] exclusiveScissorCount (=%" PRIu32
+ ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
+ i, exclusive_scissor_struct->exclusiveScissorCount, device_data->device_limits.maxViewports);
+ }
+
if (viewport_state.scissorCount != viewport_state.viewportCount) {
skip |=
log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
@@ -1595,6 +1623,17 @@
i, viewport_state.scissorCount, i, viewport_state.viewportCount);
}
+ if (exclusive_scissor_struct &&
+ exclusive_scissor_struct->exclusiveScissorCount != 0 &&
+ exclusive_scissor_struct->exclusiveScissorCount != viewport_state.viewportCount) {
+ skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+ VK_NULL_HANDLE, "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02029",
+ "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32 "] exclusiveScissorCount (=%" PRIu32
+ ") must be zero or identical to pCreateInfos[%" PRIu32 "].pViewportState->viewportCount (=%" PRIu32 ").",
+ i, exclusive_scissor_struct->exclusiveScissorCount, i, viewport_state.viewportCount);
+ }
+
if (!has_dynamic_viewport && viewport_state.viewportCount > 0 && viewport_state.pViewports == nullptr) {
skip |= log_msg(
report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, VK_NULL_HANDLE,
@@ -1615,6 +1654,17 @@
i, i);
}
+ if (!has_dynamic_exclusive_scissor_nv && exclusive_scissor_struct &&
+ exclusive_scissor_struct->exclusiveScissorCount > 0 && exclusive_scissor_struct->pExclusiveScissors == nullptr) {
+ skip |= log_msg(
+ report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, VK_NULL_HANDLE,
+ "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-pDynamicStates-02030",
+ "vkCreateGraphicsPipelines: The exclusive scissor state is static (pCreateInfos[%" PRIu32
+ "].pDynamicState->pDynamicStates does not contain VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV), but pCreateInfos[%" PRIu32
+ "] pExclusiveScissors (=NULL) is an invalid pointer.",
+ i, i);
+ }
+
// validate the VkViewports
if (!has_dynamic_viewport && viewport_state.pViewports) {
for (uint32_t viewport_i = 0; viewport_i < viewport_state.viewportCount; ++viewport_i) {
@@ -1653,6 +1703,15 @@
"VK_EXT_sample_locations extension is not enabled.",
i);
}
+
+ if (has_dynamic_exclusive_scissor_nv && !device_data->extensions.vk_nv_scissor_exclusive) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
+ VK_NULL_HANDLE, kVUID_PVError_ExtensionNotEnabled,
+ "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
+ "].pDynamicState->pDynamicStates contains VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV, but "
+ "VK_NV_scissor_exclusive extension is not enabled.",
+ i);
+ }
}
if (pCreateInfos[i].pMultisampleState == nullptr) {
@@ -3040,6 +3099,89 @@
return skip;
}
+bool pv_vkCmdSetExclusiveScissorNV(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstExclusiveScissor,
+ uint32_t exclusiveScissorCount,
+ const VkRect2D* pExclusiveScissors)
+{
+ bool skip = false;
+
+ layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+ debug_report_data *report_data = device_data->report_data;
+
+ if (!device_data->physical_device_features.multiViewport) {
+ if (firstExclusiveScissor != 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035",
+ "vkCmdSetExclusiveScissorNV: The multiViewport feature is disabled, but firstExclusiveScissor (=%" PRIu32 ") is not 0.",
+ firstExclusiveScissor);
+ }
+ if (exclusiveScissorCount > 1) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036",
+ "vkCmdSetExclusiveScissorNV: The multiViewport feature is disabled, but exclusiveScissorCount (=%" PRIu32 ") is not 1.",
+ exclusiveScissorCount);
+ }
+ } else { // multiViewport enabled
+ const uint64_t sum = static_cast<uint64_t>(firstExclusiveScissor) + static_cast<uint64_t>(exclusiveScissorCount);
+ if (sum > device_data->device_limits.maxViewports) {
+ skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02034",
+ "vkCmdSetExclusiveScissorNV: firstExclusiveScissor + exclusiveScissorCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
+ ") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
+ firstExclusiveScissor, exclusiveScissorCount, sum, device_data->device_limits.maxViewports);
+ }
+ }
+
+ if (firstExclusiveScissor >= device_data->device_limits.maxViewports) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02033",
+ "vkCmdSetExclusiveScissorNV: firstExclusiveScissor (=%" PRIu32 ") must be less than maxViewports (=%" PRIu32 ").",
+ firstExclusiveScissor, device_data->device_limits.maxViewports);
+ }
+
+ if (pExclusiveScissors) {
+ for (uint32_t scissor_i = 0; scissor_i < exclusiveScissorCount; ++scissor_i) {
+ const auto &scissor = pExclusiveScissors[scissor_i]; // will crash on invalid ptr
+
+ if (scissor.offset.x < 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-x-02037",
+ "vkCmdSetExclusiveScissorNV: pScissors[%" PRIu32 "].offset.x (=%" PRIi32 ") is negative.", scissor_i,
+ scissor.offset.x);
+ }
+
+ if (scissor.offset.y < 0) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-x-02037",
+ "vkCmdSetExclusiveScissorNV: pScissors[%" PRIu32 "].offset.y (=%" PRIi32 ") is negative.", scissor_i,
+ scissor.offset.y);
+ }
+
+ const int64_t x_sum = static_cast<int64_t>(scissor.offset.x) + static_cast<int64_t>(scissor.extent.width);
+ if (x_sum > INT32_MAX) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-offset-02038",
+ "vkCmdSetExclusiveScissorNV: offset.x + extent.width (=%" PRIi32 " + %" PRIu32 " = %" PRIi64
+ ") of pScissors[%" PRIu32 "] will overflow int32_t.",
+ scissor.offset.x, scissor.extent.width, x_sum, scissor_i);
+ }
+
+ const int64_t y_sum = static_cast<int64_t>(scissor.offset.y) + static_cast<int64_t>(scissor.extent.height);
+ if (y_sum > INT32_MAX) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+ HandleToUint64(commandBuffer), "VUID-vkCmdSetExclusiveScissorNV-offset-02039",
+ "vkCmdSetExclusiveScissorNV: offset.y + extent.height (=%" PRIi32 " + %" PRIu32 " = %" PRIi64
+ ") of pScissors[%" PRIu32 "] will overflow int32_t.",
+ scissor.offset.y, scissor.extent.height, y_sum, scissor_i);
+ }
+ }
+ }
+
+ return skip;
+}
+
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *funcName) {
layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
if (!ApiParentExtensionEnabled(funcName, device_data->extensions.device_extension_set)) {
@@ -3106,6 +3248,7 @@
custom_functions["vkCreateDescriptorPool"] = (void *)pv_vkCreateDescriptorPool;
custom_functions["vkCmdDispatch"] = (void *)pv_vkCmdDispatch;
custom_functions["vkCmdDispatchBaseKHR"] = (void *)pv_vkCmdDispatchBaseKHR;
+ custom_functions["vkCmdSetExclusiveScissorNV"] = (void *)pv_vkCmdSetExclusiveScissorNV;
}
} // namespace parameter_validation
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index c6771ef..eed967c 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -31691,6 +31691,167 @@
vkFreeMemory(m_device->device(), index_buffer_memory, 0);
}
+TEST_F(VkLayerTest, ExclusiveScissorNV) {
+ TEST_DESCRIPTION("Test VK_NV_scissor_exclusive with multiViewport disabled.");
+
+ if (InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ } else {
+ printf("%s Did not find required instance extension %s; skipped.\n", kSkipPrefix,
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ return;
+ }
+ ASSERT_NO_FATAL_FAILURE(InitFramework(myDbgFunc, m_errorMonitor));
+ std::array<const char *, 1> required_device_extensions = {
+ {VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME}};
+ for (auto device_extension : required_device_extensions) {
+ if (DeviceExtensionSupported(gpu(), nullptr, device_extension)) {
+ m_device_extension_names.push_back(device_extension);
+ } else {
+ printf("%s %s Extension not supported, skipping tests\n", kSkipPrefix, device_extension);
+ return;
+ }
+ }
+
+ PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR =
+ (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR");
+ ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
+
+ // Create a device that enables exclusive scissor but disables multiViewport
+ auto exclusive_scissor_features = lvl_init_struct<VkPhysicalDeviceExclusiveScissorFeaturesNV>();
+ auto features2 = lvl_init_struct<VkPhysicalDeviceFeatures2KHR>(&exclusive_scissor_features);
+ vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
+
+ features2.features.multiViewport = VK_FALSE;
+
+ ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
+ ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+ // Based on PSOViewportStateTests
+ {
+ VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
+ VkViewport viewports[] = {viewport, viewport};
+ VkRect2D scissor = {{0, 0}, {64, 64}};
+ VkRect2D scissors[100] = {scissor, scissor};
+
+ using std::vector;
+ struct TestCase {
+ uint32_t viewport_count;
+ VkViewport *viewports;
+ uint32_t scissor_count;
+ VkRect2D *scissors;
+ uint32_t exclusive_scissor_count;
+ VkRect2D *exclusive_scissors;
+
+ vector<std::string> vuids;
+ };
+
+ vector<TestCase> test_cases = {
+ {1,
+ viewports,
+ 1,
+ scissors,
+ 2,
+ scissors,
+ {"VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02027",
+ "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02029"}},
+ {1,
+ viewports,
+ 1,
+ scissors,
+ 100,
+ scissors,
+ {"VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02027",
+ "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02028",
+ "VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-exclusiveScissorCount-02029"}},
+ {1,
+ viewports,
+ 1,
+ scissors,
+ 1,
+ nullptr,
+ {"VUID-VkPipelineViewportExclusiveScissorStateCreateInfoNV-pDynamicStates-02030"}},
+ };
+
+ for (const auto &test_case : test_cases) {
+
+ VkPipelineViewportExclusiveScissorStateCreateInfoNV exc = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV };
+
+ const auto break_vp = [&test_case, &exc](CreatePipelineHelper &helper) {
+ helper.vp_state_ci_.viewportCount = test_case.viewport_count;
+ helper.vp_state_ci_.pViewports = test_case.viewports;
+ helper.vp_state_ci_.scissorCount = test_case.scissor_count;
+ helper.vp_state_ci_.pScissors = test_case.scissors;
+ helper.vp_state_ci_.pNext = &exc;
+
+ exc.exclusiveScissorCount = test_case.exclusive_scissor_count;
+ exc.pExclusiveScissors = test_case.exclusive_scissors;
+ };
+ CreatePipelineHelper::OneshotTest(*this, break_vp, VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuids);
+ }
+ }
+
+ // Based on SetDynScissorParamTests
+ {
+ auto vkCmdSetExclusiveScissorNV =
+ (PFN_vkCmdSetExclusiveScissorNV)vkGetDeviceProcAddr(m_device->device(), "vkCmdSetExclusiveScissorNV");
+
+ const VkRect2D scissor = {{0, 0}, {16, 16}};
+ const VkRect2D scissors[] = {scissor, scissor};
+
+ m_commandBuffer->begin();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 1, scissors);
+ m_errorMonitor->VerifyFound();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 0, nullptr);
+ m_errorMonitor->VerifyFound();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 2, scissors);
+ m_errorMonitor->VerifyFound();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: parameter exclusiveScissorCount must be greater than 0");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 0, scissors);
+ m_errorMonitor->VerifyFound();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 1, 2, scissors);
+ m_errorMonitor->VerifyFound();
+
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdSetExclusiveScissorNV: required parameter pExclusiveScissors specified as NULL");
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 1, nullptr);
+ m_errorMonitor->VerifyFound();
+
+ struct TestCase {
+ VkRect2D scissor;
+ std::string vuid;
+ };
+
+ std::vector<TestCase> test_cases = {{{{-1, 0}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
+ {{{0, -1}, {16, 16}}, "VUID-vkCmdSetExclusiveScissorNV-x-02037"},
+ {{{1, 0}, {INT32_MAX, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+ {{{INT32_MAX, 0}, {1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+ {{{0, 0}, {uint32_t{INT32_MAX} + 1, 16}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02038"},
+ {{{0, 1}, {16, INT32_MAX}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
+ {{{0, INT32_MAX}, {16, 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"},
+ {{{0, 0}, {16, uint32_t{INT32_MAX} + 1}}, "VUID-vkCmdSetExclusiveScissorNV-offset-02039"}};
+
+ for (const auto &test_case : test_cases) {
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, test_case.vuid);
+ vkCmdSetExclusiveScissorNV(m_commandBuffer->handle(), 0, 1, &test_case.scissor);
+ m_errorMonitor->VerifyFound();
+ }
+
+ m_commandBuffer->end();
+ }
+}
+
+
#if defined(ANDROID) && defined(VALIDATION_APK)
const char *appTag = "VulkanLayerValidationTests";
static bool initialized = false;