提问人:StarFox 提问时间:8/3/2023 最后编辑:genpfaultStarFox 更新时间:8/9/2023 访问量:70
vkCmdPipelineBarrier 抱怨未启用镶嵌着色器功能,但甚至没有使用
vkCmdPipelineBarrier complains about tessellationShader feature not being enabled, but its not even used
问:
我正在努力在我的 Vulkan 渲染器中为每个对象添加 1 个或更多。我遵循了对其他人效果很好的无绑定资源指南,并尝试在我的 LoadImage 类的帮助下上传纹理,我上传了一个图像和一个法线贴图:
class LoadImage
{
private:
int m_width;
int m_height;
int m_channel;
stbi_uc* m_ppixels;
bool m_loaded = false;
bool m_uploaded = false;
VkImage m_image;
VkDeviceMemory m_imageMemory;
VkImageView m_imageView;
VkImageLayout m_imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkDevice m_device;
VkSampler m_sampler;
uint32_t mipLevels;
public:
LoadImage() {
m_loaded = false;
}
LoadImage(const char* path, VkPhysicalDevice physicalDevice) {
load(path, physicalDevice);
}
~LoadImage() {
//destroy();
}
void load(const char* path, VkPhysicalDevice physicalDevice) {
if (m_loaded) {
throw std::logic_error("Image was already loaded!");
}
m_ppixels = stbi_load(path, &m_width, &m_height, &m_channel, STBI_rgb_alpha);
m_loaded = true;
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(m_width, m_height)))) + 1;
if (m_ppixels == nullptr) {
throw std::invalid_argument("Failed to load Image!");
}
}
void createColorResources(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat colorFormat, VkSampleCountFlagBits msaaSamples, uint32_t width, uint32_t height) {
createImage(device, physicalDevice, width, height, 1, msaaSamples, colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_image, m_imageMemory);
m_imageView = createImageView(device, m_image, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
m_loaded = true;
}
void upload(const VkDevice& device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue) {
if (m_uploaded) {
throw std::logic_error("Image was already uploaded!");
}
this->m_device = device;
VkDeviceSize imageSize = getSizeInBytes();
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(device, physicalDevice, imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, stagingBuffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBufferMemory);
void* data;
vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
memcpy(data, getRaw(), imageSize);
vkUnmapMemory(device, stagingBufferMemory);
createImage(device, physicalDevice, getWidth(), getHeight(), mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_image, m_imageMemory);
changeLayout(device, commandPool, queue, m_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);
writeBufferToImage(device, commandPool, queue, stagingBuffer);
generateMipmaps(device, physicalDevice, commandPool, queue, m_image, VK_FORMAT_R8G8B8A8_SRGB, m_width, m_height, mipLevels);
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
m_imageView = createImageView(m_device, m_image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);
VkSamplerCreateInfo samplerCreateInfo;
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCreateInfo.pNext = nullptr;
samplerCreateInfo.flags = 0;
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerCreateInfo.mipLodBias = 0.0f;
samplerCreateInfo.anisotropyEnable = VK_TRUE; //THIS RIGHT HERE
samplerCreateInfo.maxAnisotropy = 16; //MAX 16
samplerCreateInfo.compareEnable = VK_FALSE;
samplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = static_cast<float>(mipLevels);
samplerCreateInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerCreateInfo.unnormalizedCoordinates = VK_FALSE;
VkResult result = vkCreateSampler(device, &samplerCreateInfo, nullptr, &m_sampler);
ASSERT_VULKAN(result);
stbi_image_free(m_ppixels);
m_uploaded = true;
}
void changeLayout(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) {
changeImageLayout(device, commandPool, queue, m_image, VK_FORMAT_R8G8B8A8_UNORM, this->m_imageLayout, newLayout, mipLevels);
this->m_imageLayout = newLayout;
}
void writeBufferToImage(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkBuffer buffer) {
VkCommandBuffer commandBuffer = startSingleTimeCommandBuffer(device, commandPool);
VkBufferImageCopy bufferImageCopy;
bufferImageCopy.bufferOffset = 0;
bufferImageCopy.bufferRowLength = 0;
bufferImageCopy.bufferImageHeight = 0;
bufferImageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferImageCopy.imageSubresource.mipLevel = 0;
bufferImageCopy.imageSubresource.baseArrayLayer = 0;
bufferImageCopy.imageSubresource.layerCount = 1;
bufferImageCopy.imageOffset = { 0, 0, 0 };
bufferImageCopy.imageExtent = { (uint32_t)getWidth(), (uint32_t)getHeight(), 1 };
vkCmdCopyBufferToImage(commandBuffer, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferImageCopy);
endSingleTimeCommandBuffer(device, queue, commandPool, commandBuffer);
}
void generateMipmaps(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels) {
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(physicalDevice, imageFormat, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
throw std::runtime_error("texture image format does not support linear blitting!");
}
VkCommandBuffer commandBuffer = startSingleTimeCommandBuffer(device , commandPool);
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.subresourceRange.levelCount = 1;
int32_t mipWidth = texWidth;
int32_t mipHeight = texHeight;
for (uint32_t i = 1; i < mipLevels; i++) {
barrier.subresourceRange.baseMipLevel = i - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
VkImageBlit blit{};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
vkCmdBlitImage(commandBuffer,
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR);
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
if (mipWidth > 1) mipWidth /= 2;
if (mipHeight > 1) mipHeight /= 2;
}
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
endSingleTimeCommandBuffer(device, queue, commandPool, commandBuffer);
}
void clearImage() {
if (m_loaded) {
stbi_image_free(m_ppixels);
m_loaded = false;
}
}
LoadImage(const LoadImage&) = delete;
LoadImage(LoadImage&&) = delete;
LoadImage& operator =(const LoadImage&) = delete;
LoadImage& operator =(LoadImage&&) = delete;
void destroy() {
if (m_loaded) {
stbi_image_free(m_ppixels);
m_loaded = false;
}
if (m_uploaded) {
vkDestroySampler(m_device, m_sampler, nullptr);
vkDestroyImageView(m_device, m_imageView, nullptr);
vkDestroyImage(m_device, m_image, nullptr);
vkFreeMemory(m_device, m_imageMemory, nullptr);
m_uploaded = false;
}
}
int getHeight() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return m_height;
}
int getWidth() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return m_width;
}
int getChannels() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return 4;
}
int getSizeInBytes() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return getWidth() * getHeight() * getChannels();
}
stbi_uc* getRaw() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return m_ppixels;
}
VkSampler getSampler() {
if (!m_loaded) {
throw std::logic_error("LoadImage wasnt loaded!");
}
return m_sampler;
}
VkImageView getImageView() {
return m_imageView;
}
};
我知道它不是写得最好的。 为了更好地理解:
LoadImage image;
LoadImage normal;
std::vector<LoadImage> v_image;
std::vector<LoadImage> v_normal;
int TextureElement = 0;
const uint32_t TextureArraySize = 2;
这就是我使用 Loadimage 类加载/上传图像的方式:
void loadTexture(const std::string& Tex, const std::string& Norm) {
image.load(Tex.c_str(), physicalDevices[0]);
image.upload(device, physicalDevices[0], commandPool, queue);
normal.load(Norm.c_str(), physicalDevices[0]);
normal.upload(device, physicalDevices[0], commandPool, queue);
v_image.push_back(image);
v_normal.push_back(normal);
image.clearImage();
normal.clearImage();
}
void createDescriptorSet() {
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{};
descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocateInfo.pNext = nullptr;
descriptorSetAllocateInfo.descriptorPool = descriptorPool;
descriptorSetAllocateInfo.descriptorSetCount = 1;
descriptorSetAllocateInfo.pSetLayouts = &descriptorSetLayout;
VkResult result = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet);
ASSERT_VULKAN(result);
VkDescriptorBufferInfo descriptorBufferInfo{};
descriptorBufferInfo.buffer = ShaderStorageBuffer;
descriptorBufferInfo.offset = 0;
descriptorBufferInfo.range =sizeof(ssbo);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.pNext = nullptr;
descriptorWrite.dstSet = descriptorSet;
descriptorWrite.dstBinding = StorageBinding;
descriptorWrite.dstArrayElement = TextureElement * 2;
descriptorWrite.descriptorCount = 1;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptorWrite.pImageInfo = nullptr;
descriptorWrite.pBufferInfo = &descriptorBufferInfo;
descriptorWrite.pTexelBufferView = nullptr;
VkDescriptorImageInfo descriptorImageInfo[TextureArraySize];
VkDescriptorImageInfo descriptorImageNormalInfo[TextureArraySize];
for (uint32_t i = 0; i < TextureArraySize; i++) {
descriptorImageInfo[i] = {};
descriptorImageInfo[i].sampler = v_image[i].getSampler();
descriptorImageInfo[i].imageView = v_image[i].getImageView();
descriptorImageInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
descriptorImageNormalInfo[i] = {};
descriptorImageNormalInfo[i].sampler = v_normal[i].getSampler();
descriptorImageNormalInfo[i].imageView = v_normal[i].getImageView();
descriptorImageNormalInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
std::vector<VkDescriptorImageInfo> descriptorImageInfos = { descriptorImageInfo, descriptorImageNormalInfo };
VkWriteDescriptorSet descriptorSampler{};
descriptorSampler.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorSampler.pNext = nullptr;
descriptorSampler.dstSet = descriptorSet;
descriptorSampler.dstBinding = 1;
descriptorSampler.dstArrayElement = TextureElement * 2;
descriptorSampler.descriptorCount = descriptorImageInfos.size();
descriptorSampler.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorSampler.pImageInfo = descriptorImageInfos.data();
descriptorSampler.pBufferInfo = nullptr;
descriptorSampler.pTexelBufferView = nullptr;
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
writeDescriptorSets.push_back(descriptorWrite);
writeDescriptorSets.push_back(descriptorSampler);
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, nullptr);
}
我知道这是一个很长的问题,也有一些改进建议会很好,就像一年前一样,我开始使用 c++ 编码作为业余爱好,并使用 Vulkan API 大约半年。
我已经试过了:
- 设置断点 (dint help)
- 使用了调用堆栈
- 阅读文档
- 实现更好的 debugMessenger
编辑:还有更多错误消息
VUID-vkCmdPipelineBarrier-srcStageMask-04091(ERROR / SPEC): msgNum: 2143709137 - Validation Error: [ VUID-vkCmdPipelineBarrier-srcStageMask-04091 ] Object 0: handle = 0x26c9336abf0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x7fc667d1 | vkCmdPipelineBarrier(): .srcStageMask includes VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT when the device does not have tessellationShader feature enabled. The Vulkan spec states: If the tessellationShader feature is not enabled, pname:srcStageMask must not contain VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-vkCmdPipelineBarrier-srcStageMask-04091)
Objects: 1
[0] 0x26c9336abf0, type: 6, name: NULL
VUID-vkCmdPipelineBarrier-dstStageMask-04091(ERROR / SPEC): msgNum: -28584298 - Validation Error: [ VUID-vkCmdPipelineBarrier-dstStageMask-04091 ] Object 0: handle = 0x26c9336abf0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0xfe4bd696 | vkCmdPipelineBarrier(): .dstStageMask includes VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT when the device does not have tessellationShader feature enabled. The Vulkan spec states: If the tessellationShader feature is not enabled, pname:dstStageMask must not contain VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT (https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-vkCmdPipelineBarrier-dstStageMask-04091)
Objects: 1
[0] 0x26c9336abf0, type: 6, name: NULL
答:
2赞
Sascha Willems
8/4/2023
#1
代码中的障碍看起来是正确的。但是在您的评论中,您提到您使用 MSI Afterburner。此类工具会安装隐式 Vulkan 层,如果您运行 Vulkan 应用程序,这些层将始终处于启用状态。这意味着他们可以注入自己的 Vulkan 代码,例如用于显示叠加层。众所周知,MSI Afterburner 的 Vulkan 层会导致问题,这些问题也可能导致验证层消息错误,然后看起来像是由您的应用程序引起的。
如果您使用 Vulkan 进行开发,最好禁用这些隐式层。你可以通过删除MSI Afterburner,将其在注册表中的层值更改为1(在Windows上,请参阅Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ImplicitLayers),使用LunarG SDK中的vkconfig或设置环境变量来做到这一点
评论
0赞
StarFox
8/4/2023
我在编码时默认关闭了 msi Afterburner,但我认为添加它可能会提供更多内部内容。我还认为我搞砸了调试消息传递器的部分
0赞
StarFox
8/4/2023
我删除了 Loadimage scince 中的 clearImage 功能,它被清除了两次
评论