vkCmdPipelineBarrier 抱怨 tessellationShader 功能未启用,但它甚至没有被使用

问题描述 投票:0回答:1

我正在努力在我的 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 大约半年。

我已经尝试过:

  1. 设置断点(无帮助)
  2. 使用了调用堆栈
  3. 阅读文档
  4. 实现更好的 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
c++ textures vulkan
1个回答
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 或设置 环境变量 来实现此目的

© www.soinside.com 2019 - 2024. All rights reserved.