aboutsummaryrefslogtreecommitdiff
path: root/layers
diff options
context:
space:
mode:
authorJohn Zulauf <jzulauf@lunarg.com>2018-06-12 14:49:04 -0600
committerJohn Zulauf <32470354+jzulauf-lunarg@users.noreply.github.com>2018-06-15 09:04:59 -0600
commitdf851b15d547a9066b3a81679072b337868c7eef (patch)
treea430b156809db4ba686449cd84729af23bd9b44c /layers
parent7ec577ae780ad51d8f5f0cf93bcfff47d774f671 (diff)
downloadvulkan-validation-layers-df851b15d547a9066b3a81679072b337868c7eef.tar.gz
layers: Update barrier validation for self-depend
Add additional logic to support search for matching self-dependency when more than one are present in a sub-pass. Change-Id: I3defa94bb070f4a2869a0293e6bd4749282e9718
Diffstat (limited to 'layers')
-rw-r--r--layers/core_validation.cpp173
-rw-r--r--layers/core_validation_types.h3
-rw-r--r--layers/vk_layer_utils.h22
3 files changed, 131 insertions, 67 deletions
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 904454ca7..ac252abe1 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -7495,26 +7495,35 @@ static bool ValidateImageBarrierImage(layer_data *device_data, const char *funcN
// Validate image barriers within a renderPass
static bool ValidateRenderPassImageBarriers(layer_data *device_data, const char *funcName, GLOBAL_CB_NODE *cb_state,
uint32_t active_subpass, const safe_VkSubpassDescription &sub_desc, uint64_t rp_handle,
- VkAccessFlags sub_src_access_mask, VkAccessFlags sub_dst_access_mask,
+ const VkSubpassDependency *dependencies, const std::vector<uint32_t> &self_dependencies,
uint32_t image_mem_barrier_count, const VkImageMemoryBarrier *image_barriers) {
bool skip = false;
for (uint32_t i = 0; i < image_mem_barrier_count; ++i) {
const auto &img_barrier = image_barriers[i];
const auto &img_src_access_mask = img_barrier.srcAccessMask;
- if (img_src_access_mask != (sub_src_access_mask & img_src_access_mask)) {
+ const auto &img_dst_access_mask = img_barrier.dstAccessMask;
+ bool access_mask_match = false;
+ for (const auto self_dep_index : self_dependencies) {
+ const auto &sub_dep = dependencies[self_dep_index];
+ access_mask_match = (img_src_access_mask == (sub_dep.srcAccessMask & img_src_access_mask)) &&
+ (img_dst_access_mask == (sub_dep.dstAccessMask & img_dst_access_mask));
+ if (access_mask_match) break;
+ }
+ if (!access_mask_match) {
+ std::stringstream self_dep_ss;
+ stream_join(self_dep_ss, ", ", self_dependencies);
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-srcAccessMask-01175",
"%s: Barrier pImageMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency "
- "srcAccessMask(0x%X) of subpass %d of renderPass 0x%" PRIx64 ".",
- funcName, i, img_src_access_mask, sub_src_access_mask, active_subpass, rp_handle);
- }
- const auto &img_dst_access_mask = img_barrier.dstAccessMask;
- if (img_dst_access_mask != (sub_dst_access_mask & img_dst_access_mask)) {
+ "srcAccessMask of subpass %d of renderPass 0x%" PRIx64
+ ". Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, i, img_src_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-dstAccessMask-01176",
"%s: Barrier pImageMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency "
- "dstAccessMask(0x%X) of subpass %d of renderPass 0x%" PRIx64 ".",
- funcName, i, img_dst_access_mask, sub_dst_access_mask, active_subpass, rp_handle);
+ "dstAccessMask of subpass %d of renderPass 0x%" PRIx64
+ ". Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, i, img_dst_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
}
if (VK_QUEUE_FAMILY_IGNORED != img_barrier.srcQueueFamilyIndex ||
VK_QUEUE_FAMILY_IGNORED != img_barrier.dstQueueFamilyIndex) {
@@ -7549,74 +7558,108 @@ static bool ValidateRenderPassPipelineBarriers(layer_data *device_data, const ch
const VkBufferMemoryBarrier *buffer_mem_barriers, uint32_t image_mem_barrier_count,
const VkImageMemoryBarrier *image_barriers) {
bool skip = false;
- auto rp_state = cb_state->activeRenderPass;
+ const auto rp_state = cb_state->activeRenderPass;
const auto active_subpass = cb_state->activeSubpass;
auto rp_handle = HandleToUint64(rp_state->renderPass);
- if (!rp_state->hasSelfDependency[active_subpass]) {
+ const auto &self_dependencies = rp_state->self_dependencies[active_subpass];
+ const auto &dependencies = rp_state->createInfo.pDependencies;
+ if (self_dependencies.size() == 0) {
skip |=
log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
"VUID-vkCmdPipelineBarrier-pDependencies-01172",
"%s: Barriers cannot be set during subpass %d of renderPass 0x%" PRIx64 " with no self-dependency specified.",
funcName, active_subpass, rp_handle);
} else {
- assert(rp_state->subpass_to_dependency_index[cb_state->activeSubpass] != -1);
// Grab ref to current subpassDescription up-front for use below
const auto &sub_desc = rp_state->createInfo.pSubpasses[active_subpass];
- const auto &sub_dep = rp_state->createInfo.pDependencies[rp_state->subpass_to_dependency_index[active_subpass]];
- const auto &sub_src_stage_mask = ExpandPipelineStageFlags(sub_dep.srcStageMask);
- const auto &sub_dst_stage_mask = ExpandPipelineStageFlags(sub_dep.dstStageMask);
- if ((sub_src_stage_mask != VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) &&
- (src_stage_mask != (sub_src_stage_mask & src_stage_mask))) {
+ // Look for matching mask in any self-dependency
+ bool stage_mask_match = false;
+ for (const auto self_dep_index : self_dependencies) {
+ const auto &sub_dep = dependencies[self_dep_index];
+ const auto &sub_src_stage_mask = ExpandPipelineStageFlags(sub_dep.srcStageMask);
+ const auto &sub_dst_stage_mask = ExpandPipelineStageFlags(sub_dep.dstStageMask);
+ stage_mask_match = ((sub_src_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
+ (src_stage_mask == (sub_src_stage_mask & src_stage_mask))) &&
+ ((sub_dst_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
+ (dst_stage_mask == (sub_dst_stage_mask & dst_stage_mask)));
+ if (stage_mask_match) break;
+ }
+ if (!stage_mask_match) {
+ std::stringstream self_dep_ss;
+ stream_join(self_dep_ss, ", ", self_dependencies);
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-srcStageMask-01173",
- "%s: Barrier srcStageMask(0x%X) is not a subset of VkSubpassDependency srcStageMask(0x%X) of subpass "
- "%d of renderPass 0x%" PRIx64 ".",
- funcName, src_stage_mask, sub_src_stage_mask, active_subpass, rp_handle);
- }
- if ((sub_dst_stage_mask != VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) &&
- (dst_stage_mask != (sub_dst_stage_mask & dst_stage_mask))) {
+ "%s: Barrier srcStageMask(0x%X) is not a subset of VkSubpassDependency srcStageMask of any "
+ "self-dependency of subpass %d of renderPass 0x%" PRIx64
+ " for which dstStageMask is also a subset. "
+ "Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, src_stage_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-dstStageMask-01174",
- "%s: Barrier dstStageMask(0x%X) is not a subset of VkSubpassDependency dstStageMask(0x%X) of subpass "
- "%d of renderPass 0x%" PRIx64 ".",
- funcName, dst_stage_mask, sub_dst_stage_mask, active_subpass, rp_handle);
+ "%s: Barrier dstStageMask(0x%X) is not a subset of VkSubpassDependency dstStageMask of any "
+ "self-dependency of subpass %d of renderPass 0x%" PRIx64
+ " for which srcStageMask is also a subset. "
+ "Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, dst_stage_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
}
+
if (0 != buffer_mem_barrier_count) {
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-bufferMemoryBarrierCount-01178",
"%s: bufferMemoryBarrierCount is non-zero (%d) for subpass %d of renderPass 0x%" PRIx64 ".", funcName,
buffer_mem_barrier_count, active_subpass, rp_handle);
}
- const auto &sub_src_access_mask = sub_dep.srcAccessMask;
- const auto &sub_dst_access_mask = sub_dep.dstAccessMask;
for (uint32_t i = 0; i < mem_barrier_count; ++i) {
const auto &mb_src_access_mask = mem_barriers[i].srcAccessMask;
- if (mb_src_access_mask != (sub_src_access_mask & mb_src_access_mask)) {
- skip |=
- log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
- rp_handle, "VUID-vkCmdPipelineBarrier-srcAccessMask-01175",
- "%s: Barrier pMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency "
- "srcAccessMask(0x%X) of subpass %d of renderPass 0x%" PRIx64 ".",
- funcName, i, mb_src_access_mask, sub_src_access_mask, active_subpass, rp_handle);
- }
const auto &mb_dst_access_mask = mem_barriers[i].dstAccessMask;
- if (mb_dst_access_mask != (sub_dst_access_mask & mb_dst_access_mask)) {
- skip |=
- log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
- rp_handle, "VUID-vkCmdPipelineBarrier-dstAccessMask-01176",
- "%s: Barrier pMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency "
- "dstAccessMask(0x%X) of subpass %d of renderPass 0x%" PRIx64 ".",
- funcName, i, mb_dst_access_mask, sub_dst_access_mask, active_subpass, rp_handle);
+ bool access_mask_match = false;
+ for (const auto self_dep_index : self_dependencies) {
+ const auto &sub_dep = dependencies[self_dep_index];
+ access_mask_match = (mb_src_access_mask == (sub_dep.srcAccessMask & mb_src_access_mask)) &&
+ (mb_dst_access_mask == (sub_dep.dstAccessMask & mb_dst_access_mask));
+ if (access_mask_match) break;
+ }
+
+ if (!access_mask_match) {
+ std::stringstream self_dep_ss;
+ stream_join(self_dep_ss, ", ", self_dependencies);
+ skip |= log_msg(
+ device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
+ "VUID-vkCmdPipelineBarrier-srcAccessMask-01175",
+ "%s: Barrier pMemoryBarriers[%d].srcAccessMask(0x%X) is not a subset of VkSubpassDependency srcAccessMask "
+ "for any self-dependency of subpass %d of renderPass 0x%" PRIx64
+ " for which dstAccessMask is also a subset. "
+ "Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, i, mb_src_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
+ skip |= log_msg(
+ device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, rp_handle,
+ "VUID-vkCmdPipelineBarrier-dstAccessMask-01176",
+ "%s: Barrier pMemoryBarriers[%d].dstAccessMask(0x%X) is not a subset of VkSubpassDependency dstAccessMask "
+ "for any self-dependency of subpass %d of renderPass 0x%" PRIx64
+ " for which srcAccessMask is also a subset. "
+ "Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, i, mb_dst_access_mask, active_subpass, rp_handle, self_dep_ss.str().c_str());
}
}
- skip |= ValidateRenderPassImageBarriers(device_data, funcName, cb_state, active_subpass, sub_desc, rp_handle,
- sub_src_access_mask, sub_dst_access_mask, image_mem_barrier_count, image_barriers);
- if (sub_dep.dependencyFlags != dependency_flags) {
+
+ skip |= ValidateRenderPassImageBarriers(device_data, funcName, cb_state, active_subpass, sub_desc, rp_handle, dependencies,
+ self_dependencies, image_mem_barrier_count, image_barriers);
+
+ bool flag_match = false;
+ for (const auto self_dep_index : self_dependencies) {
+ const auto &sub_dep = dependencies[self_dep_index];
+ flag_match = sub_dep.dependencyFlags == dependency_flags;
+ if (flag_match) break;
+ }
+ if (!flag_match) {
+ std::stringstream self_dep_ss;
+ stream_join(self_dep_ss, ", ", self_dependencies);
skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
rp_handle, "VUID-vkCmdPipelineBarrier-dependencyFlags-01177",
- "%s: dependencyFlags param (0x%X) does not equal VkSubpassDependency dependencyFlags value (0x%X) for "
- "subpass %d of renderPass 0x%" PRIx64 ".",
- funcName, dependency_flags, sub_dep.dependencyFlags, cb_state->activeSubpass, rp_handle);
+ "%s: dependencyFlags param (0x%X) does not equal VkSubpassDependency dependencyFlags value for any "
+ "self-dependency of subpass %d of renderPass 0x%" PRIx64
+ ". Candidate VkSubpassDependency are pDependencies entries [%s].",
+ funcName, dependency_flags, cb_state->activeSubpass, rp_handle, self_dep_ss.str().c_str());
}
}
return skip;
@@ -9023,14 +9066,14 @@ static bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE c
static bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, RENDER_PASS_STATE *render_pass) {
// Shorthand...
auto &subpass_to_node = render_pass->subpassToNode;
- auto &has_self_dependency = render_pass->hasSelfDependency;
- auto &subpass_to_dep_index = render_pass->subpass_to_dependency_index;
+ subpass_to_node.resize(pCreateInfo->subpassCount);
+ auto &self_dependencies = render_pass->self_dependencies;
+ self_dependencies.resize(pCreateInfo->subpassCount);
bool skip = false;
for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
- DAGNode &subpass_node = subpass_to_node[i];
- subpass_node.pass = i;
- subpass_to_dep_index[i] = -1; // Default to no dependency and overwrite below as needed
+ subpass_to_node[i].pass = i;
+ self_dependencies[i].clear();
}
for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
@@ -9044,8 +9087,7 @@ static bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateIn
DRAWSTATE_INVALID_RENDERPASS,
"Dependency graph must be specified such that an earlier pass cannot depend on a later pass.");
} else if (dependency.srcSubpass == dependency.dstSubpass) {
- has_self_dependency[dependency.srcSubpass] = true;
- subpass_to_dep_index[dependency.srcSubpass] = i;
+ self_dependencies[dependency.srcSubpass].push_back(i);
} else {
subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
@@ -9295,9 +9337,6 @@ static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice
skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
render_pass->renderPass = VK_NULL_HANDLE;
- render_pass->hasSelfDependency.resize(pCreateInfo->subpassCount);
- render_pass->subpassToNode.resize(pCreateInfo->subpassCount);
- render_pass->subpass_to_dependency_index.resize(pCreateInfo->subpassCount);
skip |= CreatePassDAG(dev_data, pCreateInfo, render_pass);
for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
@@ -9329,11 +9368,14 @@ static bool PreCallValidateCreateRenderPass(const layer_data *dev_data, VkDevice
return skip;
}
-// Note: we are passing a shared_ptr by value -- but the caller is std::move'ing it to avoid ref count changes. (and it's also
-// clearer in the caller that we are relinquishing ownership to the share_ptr from the calling code)
+// Style note:
+// Use of rvalue reference exceeds reccommended usage of rvalue refs in google style guide, but intentionally forces caller to move
+// or copy. This is clearer than passing a pointer to shared_ptr and avoids the atomic increment/decrement of shared_ptr copy
+// construction or assignment.
static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo,
- VkRenderPass *pRenderPass, std::shared_ptr<RENDER_PASS_STATE> render_pass) {
- render_pass->renderPass = *pRenderPass;
+ const VkRenderPass render_pass_handle,
+ std::shared_ptr<RENDER_PASS_STATE> &&render_pass) {
+ render_pass->renderPass = render_pass_handle;
for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
@@ -9352,7 +9394,8 @@ static void PostCallRecordCreateRenderPass(layer_data *dev_data, const VkRenderP
}
}
- dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
+ // Even though render_pass is an rvalue-ref parameter, still must move s.t. move assignment is invoked.
+ dev_data->renderPassMap[render_pass_handle] = std::move(render_pass);
}
VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
@@ -9374,7 +9417,7 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderP
if (VK_SUCCESS == result) {
lock.lock();
- PostCallRecordCreateRenderPass(dev_data, pCreateInfo, pRenderPass, std::move(render_pass));
+ PostCallRecordCreateRenderPass(dev_data, pCreateInfo, *pRenderPass, std::move(render_pass));
}
return result;
}
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 93b22ac16..96bdf78d7 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -404,9 +404,8 @@ struct DAGNode {
struct RENDER_PASS_STATE : public BASE_NODE {
VkRenderPass renderPass;
safe_VkRenderPassCreateInfo createInfo;
- std::vector<bool> hasSelfDependency;
+ std::vector<std::vector<uint32_t>> self_dependencies;
std::vector<DAGNode> subpassToNode;
- std::vector<int32_t> subpass_to_dependency_index; // srcSubpass to dependency index of self dep, or -1 if none
std::unordered_map<uint32_t, bool> attachment_first_read;
RENDER_PASS_STATE(VkRenderPassCreateInfo const *pCreateInfo) : createInfo(pCreateInfo) {}
diff --git a/layers/vk_layer_utils.h b/layers/vk_layer_utils.h
index cfad81ce0..af129e254 100644
--- a/layers/vk_layer_utils.h
+++ b/layers/vk_layer_utils.h
@@ -85,6 +85,28 @@ static inline SepString string_join(const char *sep, const StringCollection &str
return string_join<SepString, StringCollection>(SepString(sep), strings);
}
+// Perl/Python style join operation for general types using stream semantics
+// Note: won't be as fast as string_join above, but simpler to use (and code)
+// Note: Modifiable reference doesn't match the google style but does match std style for stream handling and algorithms
+template <typename Stream, typename String, typename ForwardIt>
+Stream &stream_join(Stream &stream, const String &sep, ForwardIt first, ForwardIt last) {
+ if (first != last) {
+ stream << *first;
+ ++first;
+ while (first != last) {
+ stream << sep << *first;
+ ++first;
+ }
+ }
+ return stream;
+}
+
+// stream_join For whole collections with forward iterators
+template <typename Stream, typename String, typename Collection>
+Stream &stream_join(Stream &stream, const String &sep, const Collection &values) {
+ return stream_join(stream, sep, values.cbegin(), values.cend());
+}
+
extern "C" {
#endif