diff options
author | Tony-LunarG <tony@lunarg.com> | 2018-09-21 13:47:06 -0600 |
---|---|---|
committer | Tony Barbour <tony@lunarg.com> | 2018-09-24 13:29:17 -0600 |
commit | bc9fc056ea7b181725cfb8a4eda03ed9da85c17f (patch) | |
tree | a7d4dbd0bee9c38df16828f74298e3cd4099a694 | |
parent | 267a7288e96e097b7ee538d13f24fd6acc29047a (diff) | |
download | Vulkan-Tools-bc9fc056ea7b181725cfb8a4eda03ed9da85c17f.tar.gz Vulkan-Tools-bc9fc056ea7b181725cfb8a4eda03ed9da85c17f.tar.bz2 Vulkan-Tools-bc9fc056ea7b181725cfb8a4eda03ed9da85c17f.zip |
cube: Use staging buffer instead of staging image
There is no guarantee that linear images are supported
Change-Id: Ie59f3bf7bfc1d77e17f1d06ffc524e886dca46a6
-rw-r--r-- | cube/cube.c | 95 | ||||
-rw-r--r-- | cube/cube.cpp | 87 |
2 files changed, 144 insertions, 38 deletions
diff --git a/cube/cube.c b/cube/cube.c index ea9517e8..fb239361 100644 --- a/cube/cube.c +++ b/cube/cube.c @@ -161,6 +161,7 @@ struct texture_object { VkSampler sampler; VkImage image; + VkBuffer buffer; VkImageLayout imageLayout; VkMemoryAllocateInfo mem_alloc; @@ -1488,6 +1489,65 @@ bool loadTexture(const char *filename, uint8_t *rgba_data, VkSubresourceLayout * return true; } +static void demo_prepare_texture_buffer(struct demo *demo, const char *filename, struct texture_object *tex_obj) { + int32_t tex_width; + int32_t tex_height; + VkResult U_ASSERT_ONLY err; + bool U_ASSERT_ONLY pass; + + if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) { + ERR_EXIT("Failed to load textures", "Load Texture Failure"); + } + + tex_obj->tex_width = tex_width; + tex_obj->tex_height = tex_height; + + const VkBufferCreateInfo buffer_create_info = {.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .size = tex_width * tex_height * 4, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL}; + + err = vkCreateBuffer(demo->device, &buffer_create_info, NULL, &tex_obj->buffer); + assert(!err); + + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements(demo->device, tex_obj->buffer, &mem_reqs); + + tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + tex_obj->mem_alloc.pNext = NULL; + tex_obj->mem_alloc.allocationSize = mem_reqs.size; + tex_obj->mem_alloc.memoryTypeIndex = 0; + + VkFlags requirements = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, requirements, &tex_obj->mem_alloc.memoryTypeIndex); + assert(pass); + + err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL, &(tex_obj->mem)); + assert(!err); + + /* bind memory */ + err = vkBindBufferMemory(demo->device, tex_obj->buffer, tex_obj->mem, 0); + assert(!err); + + VkSubresourceLayout layout; + memset(&layout, 0, sizeof(layout)); + layout.rowPitch = tex_width * 4; + + void *data; + err = vkMapMemory(demo->device, tex_obj->mem, 0, tex_obj->mem_alloc.allocationSize, 0, &data); + assert(!err); + + if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) { + fprintf(stderr, "Error loading texture: %s\n", filename); + } + + vkUnmapMemory(demo->device, tex_obj->mem); +} + static void demo_prepare_texture_image(struct demo *demo, const char *filename, struct texture_object *tex_obj, VkImageTiling tiling, VkImageUsageFlags usage, VkFlags required_props) { const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; @@ -1565,10 +1625,11 @@ static void demo_prepare_texture_image(struct demo *demo, const char *filename, tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } -static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_objs) { +static void demo_destroy_texture(struct demo *demo, struct texture_object *tex_objs) { /* clean up staging resources */ vkFreeMemory(demo->device, tex_objs->mem, NULL); - vkDestroyImage(demo->device, tex_objs->image, NULL); + if (tex_objs->image) vkDestroyImage(demo->device, tex_objs->image, NULL); + if (tex_objs->buffer) vkDestroyBuffer(demo->device, tex_objs->buffer, NULL); } static void demo_prepare_textures(struct demo *demo) { @@ -1595,31 +1656,27 @@ static void demo_prepare_textures(struct demo *demo) { /* Must use staging buffer to copy linear texture to optimized */ memset(&demo->staging_texture, 0, sizeof(demo->staging_texture)); - demo_prepare_texture_image(demo, tex_files[i], &demo->staging_texture, VK_IMAGE_TILING_LINEAR, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + demo_prepare_texture_buffer(demo, tex_files[i], &demo->staging_texture); demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL, (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - demo_set_image_layout(demo, demo->staging_texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT); - demo_set_image_layout(demo, demo->textures[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageCopy copy_region = { - .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, - .srcOffset = {0, 0, 0}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, - .dstOffset = {0, 0, 0}, - .extent = {demo->staging_texture.tex_width, demo->staging_texture.tex_height, 1}, + VkBufferImageCopy copy_region = { + .bufferOffset = 0, + .bufferRowLength = demo->staging_texture.tex_width, + .bufferImageHeight = demo->staging_texture.tex_height, + .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + .imageOffset = {0, 0, 0}, + .imageExtent = {demo->staging_texture.tex_width, demo->staging_texture.tex_height, 1}, }; - vkCmdCopyImage(demo->cmd, demo->staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); + + vkCmdCopyBufferToImage(demo->cmd, demo->staging_texture.buffer, demo->textures[i].image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); demo_set_image_layout(demo, demo->textures[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, demo->textures[i].imageLayout, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -2186,8 +2243,8 @@ static void demo_prepare(struct demo *demo) { * that need to be flushed before beginning the render loop. */ demo_flush_init_cmd(demo); - if (demo->staging_texture.image) { - demo_destroy_texture_image(demo, &demo->staging_texture); + if (demo->staging_texture.buffer) { + demo_destroy_texture(demo, &demo->staging_texture); } demo->current_buffer = 0; diff --git a/cube/cube.cpp b/cube/cube.cpp index 6ff11900..5c68442c 100644 --- a/cube/cube.cpp +++ b/cube/cube.cpp @@ -78,6 +78,7 @@ struct texture_object { vk::Sampler sampler; vk::Image image; + vk::Buffer buffer; vk::ImageLayout imageLayout{vk::ImageLayout::eUndefined}; vk::MemoryAllocateInfo mem_alloc; @@ -216,7 +217,7 @@ struct Demo { vk::Bool32 check_layers(uint32_t, const char *const *, uint32_t, vk::LayerProperties *); void cleanup(); void create_device(); - void destroy_texture_image(texture_object *); + void destroy_texture(texture_object *); void draw(); void draw_build_cmd(vk::CommandBuffer); void flush_init_cmd(); @@ -238,6 +239,7 @@ struct Demo { void prepare_pipeline(); void prepare_render_pass(); void prepare_texture_image(const char *, texture_object *, vk::ImageTiling, vk::ImageUsageFlags, vk::MemoryPropertyFlags); + void prepare_texture_buffer(const char *, texture_object *); void prepare_textures(); void resize(); @@ -710,10 +712,11 @@ void Demo::create_device() { VERIFY(result == vk::Result::eSuccess); } -void Demo::destroy_texture_image(texture_object *tex_objs) { +void Demo::destroy_texture(texture_object *tex_objs) { // clean up staging resources device.freeMemory(tex_objs->mem, nullptr); - device.destroyImage(tex_objs->image, nullptr); + if (tex_objs->image) device.destroyImage(tex_objs->image, nullptr); + if (tex_objs->buffer) device.destroyBuffer(tex_objs->buffer, nullptr); } void Demo::draw() { @@ -1499,8 +1502,8 @@ void Demo::prepare() { * that need to be flushed before beginning the render loop. */ flush_init_cmd(); - if (staging_texture.image) { - destroy_texture_image(&staging_texture); + if (staging_texture.buffer) { + destroy_texture(&staging_texture); } current_buffer = 0; @@ -2016,6 +2019,56 @@ vk::ShaderModule Demo::prepare_shader_module(const uint32_t *code, size_t size) return module; } +void Demo::prepare_texture_buffer(const char *filename, texture_object *tex_obj) { + int32_t tex_width; + int32_t tex_height; + + if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) { + ERR_EXIT("Failed to load textures", "Load Texture Failure"); + } + + tex_obj->tex_width = tex_width; + tex_obj->tex_height = tex_height; + + auto const buffer_create_info = vk::BufferCreateInfo() + .setSize(tex_width * tex_height * 4) + .setUsage(vk::BufferUsageFlagBits::eTransferSrc) + .setSharingMode(vk::SharingMode::eExclusive) + .setQueueFamilyIndexCount(0) + .setPQueueFamilyIndices(nullptr); + + auto result = device.createBuffer(&buffer_create_info, nullptr, &tex_obj->buffer); + VERIFY(result == vk::Result::eSuccess); + + vk::MemoryRequirements mem_reqs; + device.getBufferMemoryRequirements(tex_obj->buffer, &mem_reqs); + + tex_obj->mem_alloc.setAllocationSize(mem_reqs.size); + tex_obj->mem_alloc.setMemoryTypeIndex(0); + + vk::MemoryPropertyFlags requirements = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + auto pass = memory_type_from_properties(mem_reqs.memoryTypeBits, requirements, &tex_obj->mem_alloc.memoryTypeIndex); + VERIFY(pass == true); + + result = device.allocateMemory(&tex_obj->mem_alloc, nullptr, &(tex_obj->mem)); + VERIFY(result == vk::Result::eSuccess); + + result = device.bindBufferMemory(tex_obj->buffer, tex_obj->mem, 0); + VERIFY(result == vk::Result::eSuccess); + + vk::SubresourceLayout layout; + memset(&layout, 0, sizeof(layout)); + layout.rowPitch = tex_width * 4; + auto data = device.mapMemory(tex_obj->mem, 0, tex_obj->mem_alloc.allocationSize); + VERIFY(data.result == vk::Result::eSuccess); + + if (!loadTexture(filename, (uint8_t *)data.value, &layout, &tex_width, &tex_height)) { + fprintf(stderr, "Error loading texture: %s\n", filename); + } + + device.unmapMemory(tex_obj->mem); +} + void Demo::prepare_texture_image(const char *filename, texture_object *tex_obj, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags required_props) { int32_t tex_width; @@ -2096,17 +2149,12 @@ void Demo::prepare_textures() { } else if (props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) { /* Must use staging buffer to copy linear texture to optimized */ - prepare_texture_image(tex_files[i], &staging_texture, vk::ImageTiling::eLinear, vk::ImageUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + prepare_texture_buffer(tex_files[i], &staging_texture); prepare_texture_image(tex_files[i], &textures[i], vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal); - set_image_layout(staging_texture.image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::ePreinitialized, - vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits(), vk::PipelineStageFlagBits::eTopOfPipe, - vk::PipelineStageFlagBits::eTransfer); - set_image_layout(textures[i].image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits(), vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer); @@ -2117,15 +2165,16 @@ void Demo::prepare_textures() { .setBaseArrayLayer(0) .setLayerCount(1); - auto const copy_region = vk::ImageCopy() - .setSrcSubresource(subresource) - .setSrcOffset({0, 0, 0}) - .setDstSubresource(subresource) - .setDstOffset({0, 0, 0}) - .setExtent({(uint32_t)staging_texture.tex_width, (uint32_t)staging_texture.tex_height, 1}); + auto const copy_region = + vk::BufferImageCopy() + .setBufferOffset(0) + .setBufferRowLength(staging_texture.tex_width) + .setBufferImageHeight(staging_texture.tex_height) + .setImageSubresource(subresource) + .setImageOffset({0, 0, 0}) + .setImageExtent({(uint32_t)staging_texture.tex_width, (uint32_t)staging_texture.tex_height, 1}); - cmd.copyImage(staging_texture.image, vk::ImageLayout::eTransferSrcOptimal, textures[i].image, - vk::ImageLayout::eTransferDstOptimal, 1, ©_region); + cmd.copyBufferToImage(staging_texture.buffer, textures[i].image, vk::ImageLayout::eTransferDstOptimal, 1, ©_region); set_image_layout(textures[i].image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eTransferDstOptimal, textures[i].imageLayout, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eTransfer, |