简体   繁体   中英

How do I pass a 3D VkImage to a compute shader without the data changing?

I'm trying to pass a randomized 3D image of voxels to a compute shader, but when I run the shader the entire shader results in this: 计算着色器输出

As you can see, this does not look anything like randomly generated voxels, except for the first and half of the second voxels. I honestly have absolutely no clue as to what is happening to the data. I know its not a problem with my compute shader output to the swapchain images because I checked if other compute shaders (like just a screen of noise etc.) would work, and they did. I've narrowed down the location of the bug to the copying of data from my std::vector<std::vector<std::vector<glm::vec4>>> to the voxelImage or it could be in the passing of the voxelImage to the compute shader.

Also I have checked that the generation of the voxels is not just generating what is seen on the screen. The vector of vec4s is indeed randomized, I guarantee the error is in either of the two places I have narrowed it down to.

I will only post the code for the voxelImage and voxelImageView creation, as well as the descriptors as that is likely where the bug is occuring. (posting the rest of the code would be unnecessarily excessive and it would be far too long)

Voxel Image Creation:

void createVoxelImage() {

        VkDeviceSize imageSize = voxelDataInit.size();



        VkBuffer stagingBuffer;
        VkDeviceMemory stagingBufferMemory;
        VmaAllocation stagingAllocation;
        createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_GPU_ONLY, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, stagingBuffer, stagingAllocation, stagingBufferMemory);

        void* data;
        vmaMapMemory(allocator, stagingAllocation, &data);
        memcpy(data, &voxelDataInit, imageSize);
        vmaUnmapMemory(allocator, stagingAllocation);

        
        
       
        VkDeviceMemory temp; 
        createImage(voxWidth, voxHeight, voxDepth, VK_IMAGE_TYPE_3D, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, voxelImage, voxelAllocation, VMA_MEMORY_USAGE_GPU_ONLY, temp, 5);
        //vkFreeMemory(device, temp, NULL);

        //VkDeviceMemory temp;
        //createImage(voxWidth, voxHeight, voxDepth, VK_IMAGE_TYPE_3D, VK_FORMAT_B8G8R8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, voxelImage, voxelAllocation, VMA_MEMORY_USAGE_CPU_TO_GPU, temp, 5);

        transitionImageLayout(voxelImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
        copyBufferToImage(stagingBuffer, voxelImage, static_cast<uint32_t>(voxWidth), static_cast<uint32_t>(voxHeight), static_cast<uint32_t>(voxDepth));
        transitionImageLayout(voxelImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);

        vmaDestroyBuffer(allocator, stagingBuffer, stagingAllocation);

    }

Voxel Image View Creation:

void createVoxelImageView() {
        VkImageViewCreateInfo viewInfo{};
        viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        viewInfo.image = voxelImage;
        viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
        viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
        //viewInfo.flags = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
        viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        viewInfo.subresourceRange.baseMipLevel = 0;
        viewInfo.subresourceRange.levelCount = 1;
        viewInfo.subresourceRange.baseArrayLayer = 0;
        viewInfo.subresourceRange.layerCount = 1;

        
        
        if (vkCreateImageView(device, &viewInfo, nullptr, &voxelImageView) != VK_SUCCESS) {
            throw std::runtime_error("Failed to create image view! (voxel)");
        }
    }

Input of Data Into Shader

layout(binding = 4, rgba8) uniform image3D voxels;

Def of createImage :

void createImage(uint32_t width, uint32_t height, uint32_t depth, VkImageType imgType, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkImageLayout layout, VkMemoryPropertyFlags properties, VkImage& image, VmaAllocation& allocation, VmaMemoryUsage memUsage, VkDeviceMemory& imageMemory, int callNum) {
        VkImageCreateInfo imageInfo{};
        imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
        imageInfo.imageType = imgType;
        imageInfo.extent.width = width;
        imageInfo.extent.height = height;
        imageInfo.extent.depth = depth;
        imageInfo.mipLevels = 1;
        
        imageInfo.arrayLayers = 1;
        imageInfo.format = format;
        imageInfo.tiling = tiling;
        imageInfo.initialLayout = layout;
        imageInfo.usage = usage;
        imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
        imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        imageInfo.flags = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;

        VmaAllocationCreateInfo vmaAllocInfo = {};
        vmaAllocInfo.usage = memUsage;
        vmaAllocInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;


        if (vmaCreateImage(allocator, &imageInfo, &vmaAllocInfo, &image, &allocation, nullptr) != VK_SUCCESS) {
            throw std::runtime_error(std::to_string(callNum));
            throw std::runtime_error("failed to create image!");
        }
    }

Def of transitionImageLayout :

void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlagBits srcAccess, VkAccessFlagBits dstAccess, VkPipelineStageFlagBits srcStage, VkPipelineStageFlagBits dstStage) {
        VkCommandBuffer commandBuffer = beginSingleTimeCommands();

        VkImageMemoryBarrier barrier{};
        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        barrier.oldLayout = oldLayout;
        barrier.newLayout = newLayout;
        barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
        barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
        barrier.image = image;
        barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        barrier.subresourceRange.baseMipLevel = 0;
        barrier.subresourceRange.levelCount = 1;
        barrier.subresourceRange.baseArrayLayer = 0;
        barrier.subresourceRange.layerCount = 1;
        

        VkPipelineStageFlags sourceStage;
        VkPipelineStageFlags destinationStage;

        if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
            barrier.srcAccessMask = 0;
            barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;

            sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
            destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
        }
        
        else {
            if (srcStage == VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) {
                barrier.srcAccessMask = 0;
            }
            else {
                barrier.srcAccessMask = srcAccess;
            }
            barrier.dstAccessMask = dstAccess;

            sourceStage = srcStage;
            destinationStage = dstStage;
            //throw std::runtime_error("Unsupported layout transition.");
        }

        vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);

        endSingleTimeCommands(commandBuffer);
    }

Def of copyBufferToImage :

void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, uint32_t depth){
    VkCommandBuffer commandBuffer = beginSingleTimeCommands();

    VkBufferImageCopy region{};
    region.bufferOffset = 0;
    region.bufferRowLength = 0;
    region.bufferImageHeight = 0;
    
    region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    region.imageSubresource.mipLevel = 0;
    region.imageSubresource.baseArrayLayer = 0;
    region.imageSubresource.layerCount = 1;

    region.imageOffset = { 0, 0, 0 };
    region.imageExtent = {
        width,
        height,
        depth
    };

    

    vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);

    endSingleTimeCommands(commandBuffer);
}

If voxelDataInit truly is a variable of type std::vector<std::vector<std::vector<glm::vec4>>> , then memcpy(data, &voxelDataInit, imageSize); is never going to work. &voxelDataInit is a pointer to a vector . And pointers to vector<T> s are always the same size (ignoring the allocator itself): the size of 3 pointers.

Remember: a vector<T> is a pointer to an array of T s. Or rather, it's 3 pointers into that array. But regardless, a vector<T> is not itself an array of T s; it merely owns one. As such, copying the bytes of a vector will not copy the array itself.

Also, the size of the vector is just the number of elements, not the number of bytes in the array.

The best way to copy such a data structure is to stop using such a data structure. If you want a 3D array, then what you want is a one-dimensional array of size length width height. You can index any particular X,Y,Z component of the array by using the length,width,height to convert the 3D coordinate into a 1D coordinate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM