layers: GH934 Bounds checking on SetViewport
Add viewport bounds checking.
Change-Id: I8ec8a663c5ce3d90447f8f6228ce3ed8fcbb4454
diff --git a/layers/parameter_validation.cpp b/layers/parameter_validation.cpp
index bf7db2e..443d3bf 100644
--- a/layers/parameter_validation.cpp
+++ b/layers/parameter_validation.cpp
@@ -75,6 +75,7 @@
bool swapchain_enabled = false;
bool display_swapchain_enabled = false;
+ bool amd_negative_viewport_height_enabled = false;
};
static std::unordered_map<void *, struct instance_extension_enables> instance_extension_map;
@@ -1614,6 +1615,7 @@
layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
device_data->swapchain_enabled = false;
device_data->display_swapchain_enabled = false;
+ device_data->amd_negative_viewport_height_enabled = false;
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
@@ -1622,6 +1624,9 @@
if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
device_data->display_swapchain_enabled = true;
}
+ if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0) {
+ device_data->amd_negative_viewport_height_enabled = true;
+ }
}
}
@@ -3949,9 +3954,70 @@
}
}
-bool preCmdSetViewport(debug_report_data *report_data, uint32_t viewport_count, const VkViewport *viewports) {
+bool preCmdSetViewport(layer_data *my_data, uint32_t viewport_count, const VkViewport *viewports) {
+ debug_report_data *report_data = my_data->report_data;
+
bool skip =
validate_array(report_data, "vkCmdSetViewport", "viewportCount", "pViewports", viewport_count, viewports, true, true);
+
+ if (viewport_count > 0 && viewports != nullptr) {
+ const VkPhysicalDeviceLimits &limits = my_data->device_limits;
+ for (uint32_t viewportIndex = 0; viewportIndex < viewport_count; ++viewportIndex) {
+ const VkViewport &viewport = viewports[viewportIndex];
+
+ if (viewport.width <= 0 || viewport.width > limits.maxViewportDimensions[0]) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01448, LayerName,
+ "vkCmdSetViewport %d: width (%f) exceeds permitted bounds (0,%u). %s", viewportIndex,
+ viewport.width, limits.maxViewportDimensions[0], validation_error_map[VALIDATION_ERROR_01448]);
+ }
+
+ bool invalid_height = (viewport.height <= 0 || viewport.height > limits.maxViewportDimensions[1]);
+ if (my_data->amd_negative_viewport_height_enabled && (viewport.height < 0)) {
+ // VALIDATION_ERROR_01790
+ invalid_height = false;
+ }
+ if (invalid_height) {
+ skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01449, LayerName,
+ "vkCmdSetViewport %d: height (%f) exceeds permitted bounds (0,%u). %s", viewportIndex,
+ viewport.height, limits.maxViewportDimensions[1], validation_error_map[VALIDATION_ERROR_01449]);
+ }
+
+ if (viewport.x < limits.viewportBoundsRange[0] || viewport.x > limits.viewportBoundsRange[1]) {
+ skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01450, LayerName, "vkCmdSetViewport %d: x (%f) exceeds permitted bounds (%f,%f). %s",
+ viewportIndex, viewport.x, limits.viewportBoundsRange[0], limits.viewportBoundsRange[1],
+ validation_error_map[VALIDATION_ERROR_01450]);
+ }
+
+ if (viewport.y < limits.viewportBoundsRange[0] || viewport.y > limits.viewportBoundsRange[1]) {
+ skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01450, LayerName, "vkCmdSetViewport %d: y (%f) exceeds permitted bounds (%f,%f). %s",
+ viewportIndex, viewport.y, limits.viewportBoundsRange[0], limits.viewportBoundsRange[1],
+ validation_error_map[VALIDATION_ERROR_01450]);
+ }
+
+ if (viewport.x + viewport.width > limits.viewportBoundsRange[1]) {
+ skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01451, LayerName,
+ "vkCmdSetViewport %d: x (%f) + width (%f) exceeds permitted bound (%f). %s", viewportIndex, viewport.x,
+ viewport.width, limits.viewportBoundsRange[1], validation_error_map[VALIDATION_ERROR_01451]);
+ }
+
+ if (viewport.y + viewport.height > limits.viewportBoundsRange[1]) {
+ skip |=
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+ VALIDATION_ERROR_01452, LayerName,
+ "vkCmdSetViewport %d: y (%f) + height (%f) exceeds permitted bound (%f). %s", viewportIndex, viewport.y,
+ viewport.height, limits.viewportBoundsRange[1], validation_error_map[VALIDATION_ERROR_01452]);
+ }
+ }
+ }
+
return skip;
}
@@ -3961,7 +4027,7 @@
layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
assert(my_data != NULL);
- skip |= preCmdSetViewport(my_data->report_data, viewportCount, pViewports);
+ skip |= preCmdSetViewport(my_data, viewportCount, pViewports);
if (!skip) {
get_dispatch_table(pc_device_table_map, commandBuffer)