PacktPublishing / Vulkan-Cookbook

Code repository for Vulkan Cookbook by Packt
MIT License
816 stars 109 forks source link

Cube Image generation error #3

Closed cylof22 closed 6 years ago

cylof22 commented 7 years ago

I have following the method to generate the cube image by using the staging buffer. However, I copy all the image by using a single vkCmdCopyBufferToImage. The result image is wrong. Please see the following code:

// Use stagging buffer to copy the skybox image struct { VkBuffer buffer; VkDeviceMemory memory; } staging_res;

VkBufferCreateInfo buffer_info = {
    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0,
    1024 * 1024 * 4 * 6,
    VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, NULL
};
VK_VALIDATION_RESULT(vkCreateBuffer(s_gpu_device, &buffer_info, VK_ALLOC_CALLBACK, &staging_res.buffer));

VkMemoryRequirements mreq_buffer = { 0 };
vkGetBufferMemoryRequirements(s_gpu_device, staging_res.buffer, &mreq_buffer);

VkMemoryAllocateInfo alloc_info_buffer = {
    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, mreq_buffer.size,
    get_mem_type_index(s_gpu, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
};
VK_VALIDATION_RESULT(vkAllocateMemory(s_gpu_device, &alloc_info_buffer, VK_ALLOC_CALLBACK, &staging_res.memory));
VK_VALIDATION_RESULT(vkBindBufferMemory(s_gpu_device, staging_res.buffer, staging_res.memory, 0));

uint8_t *ptr;
VK_VALIDATION_RESULT(vkMapMemory(s_gpu_device, staging_res.memory, 0, VK_WHOLE_SIZE, 0, (void **)&ptr));

const char *name[6] = {
    "Texture/Skybox_right1.png", "Texture/Skybox_left2.png",
    "Texture/Skybox_top3.png", "Texture/Skybox_bottom4.png",
    "Texture/Skybox_front5.png", "Texture/Skybox_back6.png"
};

VkDeviceSize offset = 0;
std::array<VkBufferImageCopy, 6> buffer_copy_regions;
for (int i = 0; i < 6; ++i) {
    int w, h, comp;
    stbi_uc* data = load_image(s_app->activity->assetManager, name[i], &w, &h, &comp, 4);
    if (!data)
        continue;

    size_t size = w * h * comp;
    memcpy(ptr + offset, data, size);

    buffer_copy_regions[i].bufferRowLength = 0;
    buffer_copy_regions[i].bufferImageHeight = 0;
    buffer_copy_regions[i].bufferOffset = offset;
    buffer_copy_regions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    buffer_copy_regions[i].imageSubresource.baseArrayLayer = i;
    buffer_copy_regions[i].imageSubresource.layerCount = 1;
    buffer_copy_regions[i].imageSubresource.mipLevel = 0;
    buffer_copy_regions[i].imageExtent.width = w;
    buffer_copy_regions[i].imageExtent.height = h;
    buffer_copy_regions[i].imageExtent.depth = 1;
    buffer_copy_regions[i].imageOffset.x = 0;
    buffer_copy_regions[i].imageOffset.y = 0;
    buffer_copy_regions[i].imageOffset.z = 0;

    offset += size;
    stbi_image_free(data);
}
vkUnmapMemory(s_gpu_device, staging_res.memory);

// update the stagging buffer into the cubebox image
VkCommandBufferAllocateInfo staggingCmdInfo;
staggingCmdInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
staggingCmdInfo.pNext = NULL;
staggingCmdInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
staggingCmdInfo.commandPool = s_command_pool;
staggingCmdInfo.commandBufferCount = 1;

VkCommandBuffer staggingCmd;
vkAllocateCommandBuffers(s_gpu_device, &staggingCmdInfo, &staggingCmd);

VkCommandBufferBeginInfo staggingBeginInfo = {};
staggingBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
staggingBeginInfo.pNext = NULL;
staggingBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
staggingBeginInfo.pInheritanceInfo = NULL;

VkImageSubresourceRange skybox_subresource_range;
skybox_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
skybox_subresource_range.baseMipLevel = 0;
skybox_subresource_range.levelCount = 1;
skybox_subresource_range.baseArrayLayer = 0;
skybox_subresource_range.layerCount = 6;

vkBeginCommandBuffer(staggingCmd, &staggingBeginInfo);

setImageLayout(staggingCmd, s_skybox_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 
     skybox_subresource_range, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);

vkCmdCopyBufferToImage(staggingCmd, staging_res.buffer, s_skybox_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, buffer_copy_regions.size(), buffer_copy_regions.data());

setImageLayout(staggingCmd, s_skybox_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
    skybox_subresource_range, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);

vkEndCommandBuffer(staggingCmd);

VkFence skyboxFence;
VkFenceCreateInfo skyboxFenceInfo;
skyboxFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
skyboxFenceInfo.pNext = NULL;
skyboxFenceInfo.flags = 0;
vkCreateFence(s_gpu_device, &skyboxFenceInfo, VK_ALLOC_CALLBACK, &skyboxFence);

VkPipelineStageFlags skyboxPipelineStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkSubmitInfo skyboxSubmitInfo = {};
skyboxSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
skyboxSubmitInfo.pNext = NULL;
skyboxSubmitInfo.commandBufferCount = 1;
skyboxSubmitInfo.pCommandBuffers = &staggingCmd;

vkQueueSubmit(s_gpu_queue, 1, &skyboxSubmitInfo, skyboxFence);

vkWaitForFences(s_gpu_device, 1, &skyboxFence, true, UINT64_MAX);
Ekzuzy commented 7 years ago

I will look into it during the working week and I'll get back to You.

cylof22 commented 7 years ago

The staging method is right. The error is related to the skybox geometry generation method. Thanks for your reply.

Ekzuzy commented 7 years ago

Hi. I've checked Your code, copied it to my own project and executed. The resulting image indeed looks strange. But when I added one small modification, it started working fine:

int w, h, comp;
stbi_uc* data = load_image(s_app->activity->assetManager, name[i], &w, &h, &comp, 4);
if (!data)
    continue;
comp = 4;
size_t size = w * h * comp;

I only added the line: "comp=4;". As far as I remember, stbi_image library always converts loaded image data so it has 4 components. But it also stores the original number of components in the provided variable (comp - in my case it was 3). After adding the mentioned line the resulting image started looking as it should. Does it help? If not, could You post more information about the problem You are facing? Some screenshots, or maybe a full source code?

cylof22 commented 7 years ago

Thanks for your reply. I will try it. I am just porting the intel's stardust demo to the android platform. The demo demonstrates the power of Vulkan's multithread rendering. The repository is https://github.com/cylof22/Stardust. The original respository is https://github.com/GameTechDev/stardust_vulkan.

Ekzuzy commented 7 years ago

Send me a message with information if this helped You or not. But don't forget to change image format according to the number of components that were read from the file.