diff --git a/Makefile b/Makefile index 7eb6c29..e7f6500 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ OBJS = \ src/volk/volk.o \ src/file.o \ src/pack.o \ - src/dds_validate.o \ + src/dds/validate.o \ src/vulkan_helper.o \ src/collada/scene/vulkan.o \ src/collada/scene.o \ diff --git a/checker.dds b/checker.dds deleted file mode 100644 index 694ad56..0000000 Binary files a/checker.dds and /dev/null differ diff --git a/data/scenes/shadow_test/images/0_leaf_white.dds b/data/scenes/shadow_test/images/0_leaf_white.dds new file mode 100644 index 0000000..42954dc Binary files /dev/null and b/data/scenes/shadow_test/images/0_leaf_white.dds differ diff --git a/data/scenes/shadow_test/images/0_leaf_white.png b/data/scenes/shadow_test/images/0_leaf_white.png new file mode 100644 index 0000000..c9560a6 Binary files /dev/null and b/data/scenes/shadow_test/images/0_leaf_white.png differ diff --git a/data/scenes/shadow_test/shadow_test.DAE b/data/scenes/shadow_test/shadow_test.DAE index f8b505f..8fa7c72 100644 --- a/data/scenes/shadow_test/shadow_test.DAE +++ b/data/scenes/shadow_test/shadow_test.DAE @@ -6,14 +6,24 @@ OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68 file:///C:/Users/bilbo/Documents/wood/scenes/shadow_test.max - 2026-04-14T19:52:07 - 2026-04-14T19:52:07 + 2026-04-15T19:19:21 + 2026-04-15T19:19:21 Z_UP + + + leaf_white_png + + + + + leaf_white_png-surface + + @@ -23,7 +33,7 @@ 0.6627451 0.5882353 0.6196079 1 - 0.6627451 0.5882353 0.6196079 1 + 0 0 0 1 @@ -677,6 +687,11 @@ + + + ./images/0_leaf_white.png + + @@ -686,7 +701,9 @@ - + + + diff --git a/data/scenes/shadow_test/shadow_test.cpp b/data/scenes/shadow_test/shadow_test.cpp index d736a0f..a4811d5 100644 --- a/data/scenes/shadow_test/shadow_test.cpp +++ b/data/scenes/shadow_test/shadow_test.cpp @@ -1747,7 +1747,13 @@ channel const node_channel_node_camera001_matrix = { .target_attribute = target_attribute::ALL, }; +// leaf_white_png +image const image_leaf_white_png = { + .uri = "data/scenes/shadow_test/images/0_leaf_white.dds" +}; + image const * const images[] = { + &image_leaf_white_png, }; effect const effect_planematerial = { @@ -1762,8 +1768,8 @@ effect const effect_planematerial = { .color = {0.6627451f, 0.5882353f, 0.6196079f, 1.0f}, }, .diffuse = { - .type = color_or_texture_type::COLOR, - .color = {0.6627451f, 0.5882353f, 0.6196079f, 1.0f}, + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // leaf_white_png }, .specular = { .type = color_or_texture_type::COLOR, @@ -2215,7 +2221,7 @@ instance_material const instance_geometry_instance_materials_node_plane_0[] = { .emission = { .input_set = -1 }, .ambient = { .input_set = -1 }, - .diffuse = { .input_set = -1 }, + .diffuse = { .input_set = 0 }, .specular = { .input_set = -1 }, }, }; @@ -2283,8 +2289,8 @@ instance_light const instance_lights_node_camera001_target[] = { channel const * const node_channels_node_camera001_target[] = { &node_channel_node_camera001_target_translation_z, - &node_channel_node_camera001_target_translation_y, &node_channel_node_camera001_target_translation_x, + &node_channel_node_camera001_target_translation_y, }; node const node_node_camera001_target = { @@ -2570,9 +2576,9 @@ instance_light const instance_lights_node_lighthelper[] = { }; channel const * const node_channels_node_lighthelper[] = { - &node_channel_node_lighthelper_translation_z, - &node_channel_node_lighthelper_translation_y, &node_channel_node_lighthelper_translation_x, + &node_channel_node_lighthelper_translation_y, + &node_channel_node_lighthelper_translation_z, }; node const node_node_lighthelper = { @@ -2759,9 +2765,9 @@ instance_light const instance_lights_node_camerahelper[] = { }; channel const * const node_channels_node_camerahelper[] = { + &node_channel_node_camerahelper_translation_z, &node_channel_node_camerahelper_translation_x, &node_channel_node_camerahelper_translation_y, - &node_channel_node_camerahelper_translation_z, }; node const node_node_camerahelper = { diff --git a/filenames.txt b/filenames.txt index 9ec571d..9c62972 100644 --- a/filenames.txt +++ b/filenames.txt @@ -2,8 +2,7 @@ shader/triangle.spv shader/collada.spv data/scenes/shadow_test/shadow_test.vtx data/scenes/shadow_test/shadow_test.idx +data/scenes/shadow_test/images/0_leaf_white.dds checker.idx checker.vtx -checker.data -checker.dds sprite.data diff --git a/include/collada/scene/vulkan.h b/include/collada/scene/vulkan.h index 9da55a4..af05627 100644 --- a/include/collada/scene/vulkan.h +++ b/include/collada/scene/vulkan.h @@ -30,9 +30,17 @@ namespace collada::scene { }; struct vulkan { + static constexpr uint32_t maxFrames = 2; + static constexpr uint32_t perFrameDescriptorCount = 2; + static constexpr uint32_t constantDescriptorCount = 1; + static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount; + static constexpr uint32_t descriptorCount = uniformBufferDescriptorCount + 2; + // externally initialized, opaque handle VkInstance instance; VkDevice device; + VkQueue queue; + VkCommandPool commandPool; // externally initialized, structures VkPhysicalDeviceProperties physicalDeviceProperties; VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; @@ -56,16 +64,18 @@ namespace collada::scene { } vertexIndex; VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; - static constexpr uint32_t maxFrames = 2; - static constexpr uint32_t perFrameDescriptorCount = 2; - static constexpr uint32_t constantDescriptorCount = 1; - static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount; - static constexpr uint32_t descriptorCount = uniformBufferDescriptorCount + 2; VkDescriptorSetLayout descriptorSetLayouts[2]; // unrelated to maxFrames, unrelated to descriptorCount VkDescriptorSet descriptorSets0[maxFrames]; VkDescriptorSet descriptorSet1; + struct Image { + VkImage image; + VkDeviceMemory memory; + VkImageView imageView; + }; + Image * images; + struct { Scene scene; // global(?) Node * nodes; // per-scene @@ -106,6 +116,8 @@ namespace collada::scene { void initial_state(VkInstance instance, VkDevice device, + VkQueue queue, + VkCommandPool commandPool, VkPhysicalDeviceProperties const & physicalDeviceProperties, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkFormat colorFormat, @@ -134,6 +146,7 @@ namespace collada::scene { void create_descriptor_sets(); void write_descriptor_sets(collada::types::descriptor const * const descriptor); void load_material_constants(collada::types::descriptor const * const descriptor); + void load_images(collada::types::descriptor const * const descriptor); ////////////////////////////////////////////////////////////////////// // called by state::draw diff --git a/include/dds.h b/include/dds/dds.h similarity index 100% rename from include/dds.h rename to include/dds/dds.h diff --git a/include/dds/validate.h b/include/dds/validate.h new file mode 100644 index 0000000..31ea478 --- /dev/null +++ b/include/dds/validate.h @@ -0,0 +1,13 @@ +#pragma once + +#include "dds/dds.h" + +struct DDS_FILE { + unsigned int dwMagic; + DDS_HEADER header; + DDS_HEADER_DXT10 header10; +}; + +namespace dds { + DDS_FILE const * validate(void const * data, uint32_t size, uint32_t ** out_offsets, void ** out_data, uint32_t * out_size); +} diff --git a/include/dds/vulkan.h b/include/dds/vulkan.h new file mode 100644 index 0000000..0db558f --- /dev/null +++ b/include/dds/vulkan.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "dds/dds.h" +#include "volk/volk.h" + +namespace dds { + inline constexpr VkFormat dxgi_to_vulkan(DXGI_FORMAT dxgiFormat) + { + switch (dxgiFormat) { + case DXGI_FORMAT_BC1_UNORM: return VK_FORMAT_BC1_RGB_UNORM_BLOCK; + case DXGI_FORMAT_BC1_UNORM_SRGB: return VK_FORMAT_BC1_RGB_SRGB_BLOCK; + case DXGI_FORMAT_BC3_UNORM: return VK_FORMAT_BC3_UNORM_BLOCK; + case DXGI_FORMAT_BC3_UNORM_SRGB: return VK_FORMAT_BC3_SRGB_BLOCK; + case DXGI_FORMAT_BC7_UNORM: return VK_FORMAT_BC7_UNORM_BLOCK; + case DXGI_FORMAT_BC7_UNORM_SRGB: return VK_FORMAT_BC7_SRGB_BLOCK; + case DXGI_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; + case DXGI_FORMAT_R8G8B8A8_UINT: return VK_FORMAT_R8G8B8A8_UINT; + case DXGI_FORMAT_R8G8B8A8_SNORM: return VK_FORMAT_R8G8B8A8_SNORM; + case DXGI_FORMAT_R8G8B8A8_SINT: return VK_FORMAT_R8G8B8A8_SINT; + default: + assert(false); + } + } +} diff --git a/include/dds_validate.h b/include/dds_validate.h deleted file mode 100644 index 4c96346..0000000 --- a/include/dds_validate.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "dds.h" - -struct DDS_FILE { - unsigned int dwMagic; - DDS_HEADER header; - DDS_HEADER_DXT10 header10; -}; - -DDS_FILE const * dds_validate(void const * data, uint32_t size, uint32_t ** out_offsets, void ** out_data); diff --git a/include/minmax.h b/include/minmax.h new file mode 100644 index 0000000..27cf838 --- /dev/null +++ b/include/minmax.h @@ -0,0 +1,19 @@ +#pragma once + +template +inline static constexpr T min(T a, T b) +{ + return (a < b) ? a : b; +} + +template +inline static constexpr T max(T a, T b) +{ + return (a > b) ? a : b; +} + +template +inline static constexpr T clamp(T n, T minVal, T maxVal) +{ + return min(max(n, minVal), maxVal); +} diff --git a/include/vulkan_helper.h b/include/vulkan_helper.h index 41f1aaf..e3fac96 100644 --- a/include/vulkan_helper.h +++ b/include/vulkan_helper.h @@ -33,15 +33,17 @@ inline static constexpr void alignMappedMemoryRanges(uint32_t nonCoherentAtomSiz } VkDeviceSize allocateFromMemoryRequirements(VkDevice device, + VkDeviceSize nonCoherentAtomSize, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkMemoryRequirements const & memoryRequirements, VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryAllocateFlags memoryAllocateFlags, uint32_t count, - VkDeviceMemory * memory); + VkDeviceMemory * memory, + VkDeviceSize * stride); VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, - VkPhysicalDeviceProperties const & physicalDeviceProperties, + VkDeviceSize nonCoherentAtomSize, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryAllocateFlags memoryAllocateFlags, @@ -49,3 +51,14 @@ VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, VkMemoryRequirements const * memoryRequirements, VkDeviceMemory * memory, VkDeviceSize * offsets); + +void createImageFromFilenameDDS(VkDevice device, + VkQueue queue, + VkCommandBuffer commandBuffer, + VkFence fence, + VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + char const * const filename, + VkImage * outImage, + VkDeviceMemory * outMemory, + VkImageView * outImageView); diff --git a/src/collada/scene.cpp b/src/collada/scene.cpp index d8efa0a..6500f59 100644 --- a/src/collada/scene.cpp +++ b/src/collada/scene.cpp @@ -17,6 +17,7 @@ namespace collada::scene { vulkan.create_descriptor_sets(); vulkan.write_descriptor_sets(descriptor); vulkan.load_material_constants(descriptor); + vulkan.load_images(descriptor); vulkan.create_pipelines(descriptor); node_state.allocate_node_instances(descriptor->nodes, descriptor->nodes_count); diff --git a/src/collada/scene/vulkan.cpp b/src/collada/scene/vulkan.cpp index 0dc40a2..48781b7 100644 --- a/src/collada/scene/vulkan.cpp +++ b/src/collada/scene/vulkan.cpp @@ -9,7 +9,10 @@ #include "collada/inputs.h" #include "collada/scene/vulkan.h" +#include "minmax.h" #include "vulkan_helper.h" +#include "dds/validate.h" +#include "dds/vulkan.h" #include "check.h" #include "new.h" @@ -102,6 +105,8 @@ namespace collada::scene { void vulkan::initial_state(VkInstance instance, VkDevice device, + VkQueue queue, + VkCommandPool commandPool, VkPhysicalDeviceProperties const & physicalDeviceProperties, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkFormat colorFormat, @@ -111,6 +116,8 @@ namespace collada::scene { { this->instance = instance; this->device = device; + this->queue = queue; + this->commandPool = commandPool; this->physicalDeviceProperties = physicalDeviceProperties; this->physicalDeviceMemoryProperties = physicalDeviceMemoryProperties; @@ -155,14 +162,16 @@ namespace collada::scene { vkGetBufferMemoryRequirements(device, vertexIndex.buffer, &memoryRequirements); VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; VkMemoryAllocateFlags memoryAllocateFlags{}; - + VkDeviceSize stride; allocateFromMemoryRequirements(device, + physicalDeviceProperties.limits.nonCoherentAtomSize, physicalDeviceMemoryProperties, memoryRequirements, memoryPropertyFlags, memoryAllocateFlags, 1, - &vertexIndex.memory); + &vertexIndex.memory, + &stride); VK_CHECK(vkBindBufferMemory(device, vertexIndex.buffer, vertexIndex.memory, 0)); @@ -237,7 +246,7 @@ namespace collada::scene { VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; VkMemoryAllocateFlags memoryAllocateFlags{ }; shaderDataDevice.memorySize = allocateFromMemoryRequirements2(device, - physicalDeviceProperties, + physicalDeviceProperties.limits.nonCoherentAtomSize, physicalDeviceMemoryProperties, memoryPropertyFlags, memoryAllocateFlags, @@ -531,9 +540,52 @@ namespace collada::scene { alignMappedMemoryRanges(physicalDeviceProperties.limits.nonCoherentAtomSize, shaderDataDevice.memorySize, 1, mappedMemoryRanges); - //fprintf(stderr, "flush materials start %ld %ld %ld %ld : %ld\n", offset, size, alignedOffset, alignedSize, shaderDataDevice.memorySize); vkFlushMappedMemoryRanges(device, 1, mappedMemoryRanges); - //fprintf(stderr, "flush materials end\n"); + } + + ////////////////////////////////////////////////////////////////////// + // material textures + ////////////////////////////////////////////////////////////////////// + + void vulkan::load_images(collada::types::descriptor const * const descriptor) + { + VkCommandBuffer commandBuffer{}; + VkCommandBufferAllocateInfo commandBufferAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = commandPool, + .commandBufferCount = 1 + }; + VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, &commandBuffer)); + + VkFenceCreateInfo fenceCreateInfo{ + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO + }; + VkFence fence{}; + VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + + // images + images = NewM(descriptor->images_count); + + for (int i = 0; i < descriptor->images_count; i++) { + createImageFromFilenameDDS(device, + queue, + commandBuffer, + fence, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + descriptor->images[i]->uri, + &images[i].image, + &images[i].memory, + &images[i].imageView); + } + + // cleanup + + vkDestroyFence(device, fence, nullptr); + vkFreeCommandBuffers(device, + commandPool, + 1, + &commandBuffer); } ////////////////////////////////////////////////////////////////////// @@ -865,6 +917,13 @@ namespace collada::scene { void vulkan::destroy_all(collada::types::descriptor const * const descriptor) { + for (int i = 0; i < descriptor->images_count; i++) { + vkDestroyImage(device, images[i].image, nullptr); + vkDestroyImageView(device, images[i].imageView, nullptr); + vkFreeMemory(device, images[i].memory, nullptr); + } + free(images); + free(shaderData.nodes); free(shaderData.materialColors); diff --git a/src/dds_validate.cpp b/src/dds/validate.cpp similarity index 50% rename from src/dds_validate.cpp rename to src/dds/validate.cpp index 3e99edd..0a1d8c9 100644 --- a/src/dds_validate.cpp +++ b/src/dds/validate.cpp @@ -2,7 +2,7 @@ #include #include "new.h" -#include "dds_validate.h" +#include "dds/validate.h" static inline uint32_t max(uint32_t a, uint32_t b) { @@ -14,9 +14,9 @@ struct dds_size_levels { uint32_t const levels; }; -static inline uint32_t dim(uint32_t d) +static inline uint32_t bc(uint32_t d) { - return max(1, (d / 4)); + return max(4, d) / 4; } static inline uint32_t mip_size(DXGI_FORMAT dxgiFormat, uint32_t height, uint32_t width) @@ -25,7 +25,14 @@ static inline uint32_t mip_size(DXGI_FORMAT dxgiFormat, uint32_t height, uint32_ case DXGI_FORMAT_BC1_TYPELESS: [[fallthrough]]; case DXGI_FORMAT_BC1_UNORM: [[fallthrough]]; case DXGI_FORMAT_BC1_UNORM_SRGB: - return dim(height) * dim(width) * 8; + return bc(height) * bc(width) * 8; + case DXGI_FORMAT_BC3_TYPELESS: [[fallthrough]]; + case DXGI_FORMAT_BC3_UNORM: [[fallthrough]]; + case DXGI_FORMAT_BC3_UNORM_SRGB: [[fallthrough]]; + case DXGI_FORMAT_BC7_TYPELESS: [[fallthrough]]; + case DXGI_FORMAT_BC7_UNORM: [[fallthrough]]; + case DXGI_FORMAT_BC7_UNORM_SRGB: + return bc(height) * bc(width) * 16; case DXGI_FORMAT_R8G8B8A8_TYPELESS: [[fallthrough]]; case DXGI_FORMAT_R8G8B8A8_UNORM: [[fallthrough]]; case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: [[fallthrough]]; @@ -64,28 +71,31 @@ static inline dds_size_levels dds_mip_total_size(DXGI_FORMAT dxgiFormat, return {mip_total_size, mip_levels}; } -DDS_FILE const * dds_validate(void const * data, uint32_t size, uint32_t ** out_offsets, void ** out_data) -{ - DDS_FILE const * const dds = (DDS_FILE const *)data; - assert(dds->dwMagic == DDS_MAGIC); - assert(dds->header.dwSize == 124); - assert(dds->header.ddspf.dwSize == 32); - assert(dds->header.ddspf.dwFlags == DDS_FOURCC); - //assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','T','1')); - assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','1','0')); +namespace dds { + DDS_FILE const * validate(void const * data, uint32_t size, uint32_t ** out_offsets, void ** out_data, uint32_t * out_size) + { + DDS_FILE const * const dds = (DDS_FILE const *)data; + assert(dds->dwMagic == DDS_MAGIC); + assert(dds->header.dwSize == 124); + assert(dds->header.ddspf.dwSize == 32); + assert(dds->header.ddspf.dwFlags == DDS_FOURCC); + //assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','T','1')); + assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','1','0')); - uint32_t * offsets = NewM(dds->header.dwMipMapCount); + uint32_t * offsets = NewM(dds->header.dwMipMapCount); - uintptr_t image_data = ((uintptr_t)dds) + (sizeof (DDS_FILE)); - dds_size_levels ret = dds_mip_total_size(dds->header10.dxgiFormat, - dds->header.dwHeight, - dds->header.dwWidth, - dds->header.dwMipMapCount, - offsets); - assert(ret.size + (sizeof (DDS_FILE)) == size); - assert(ret.levels == dds->header.dwMipMapCount); + uintptr_t image_data = ((uintptr_t)dds) + (sizeof (DDS_FILE)); + dds_size_levels ret = dds_mip_total_size(dds->header10.dxgiFormat, + dds->header.dwHeight, + dds->header.dwWidth, + dds->header.dwMipMapCount, + offsets); + assert(ret.size + (sizeof (DDS_FILE)) == size); + assert(ret.levels == dds->header.dwMipMapCount); - *out_offsets = offsets; - *out_data = (void *)image_data; - return dds; + *out_offsets = offsets; + *out_data = (void *)image_data; + *out_size = ret.size; + return dds; + } } diff --git a/src/main.cpp b/src/main.cpp index e9afd2c..5d603b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,33 +10,16 @@ #include "check.h" #include "new.h" #include "file.h" -#include "dds_validate.h" +#include "dds/validate.h" #include "vulkan_helper.h" #include "shader_data.h" +#include "minmax.h" #include "collada/scene.h" #include "collada/scene/vulkan.h" #include "scenes/shadow_test/shadow_test.h" -template -inline static constexpr T min(T a, T b) -{ - return (a < b) ? a : b; -} - -template -inline static constexpr T max(T a, T b) -{ - return (a > b) ? a : b; -} - -template -inline static constexpr T clamp(T n, T minVal, T maxVal) -{ - return min(max(n, minVal), maxVal); -} - VkInstance instance{ VK_NULL_HANDLE }; VkDevice device{ VK_NULL_HANDLE }; VkQueue queue{ VK_NULL_HANDLE }; @@ -136,7 +119,8 @@ XMMATRIX currentModel() return XMMatrixTranslation(0, 0, 0.0) * XMMatrixRotationX(theta) * XMMatrixRotationZ(XM_PI * 0.5f); } -void createDepth(VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, +void createDepth(VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, uint32_t width, uint32_t height, VkFormat format, @@ -167,13 +151,16 @@ void createDepth(VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryPr vkGetImageMemoryRequirements(device, *image, &memoryRequirements); VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT }; VkMemoryAllocateFlags memoryAllocateFlags{ }; + VkDeviceSize stride; allocateFromMemoryRequirements(device, + nonCoherentAtomSize, physicalDeviceMemoryProperties, memoryRequirements, memoryPropertyFlags, memoryAllocateFlags, 1, - memory); + memory, + &stride); VK_CHECK(vkBindImageMemory(device, *image, *memory, 0)); VkImageViewCreateInfo imageViewCreateInfo{ @@ -190,7 +177,11 @@ void createDepth(VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryPr VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, imageView)); } -void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkSurfaceCapabilitiesKHR const & surfaceCapabilities) +void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, + VkFormat depthFormat, + VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + VkSurfaceCapabilitiesKHR const & surfaceCapabilities) { ////////////////////////////////////////////////////////////////////// // swapchain and images @@ -286,7 +277,8 @@ void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, V vkDestroyImageView(device, depthImageView, nullptr); } - createDepth(physicalDeviceMemoryProperties, + createDepth(nonCoherentAtomSize, + physicalDeviceMemoryProperties, imageExtent.width, imageExtent.height, depthFormat, @@ -495,13 +487,14 @@ int main() ASSERT(depthFormat != VK_FORMAT_UNDEFINED, "no depth format with VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"); printf("depthFormat: %s\n", string_VkFormat(depthFormat)); - recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceMemoryProperties, surfaceCapabilities); + recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceProperties.limits.nonCoherentAtomSize, physicalDeviceMemoryProperties, surfaceCapabilities); ////////////////////////////////////////////////////////////////////// // shadow ////////////////////////////////////////////////////////////////////// - createDepth(physicalDeviceMemoryProperties, + createDepth(physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, 1024, 1024, depthFormat, @@ -549,15 +542,16 @@ int main() vkGetBufferMemoryRequirements(device, vertexIndexBuffer, &memoryRequirements); VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; VkMemoryAllocateFlags memoryAllocateFlags{}; - + VkDeviceSize stride; allocateFromMemoryRequirements(device, + physicalDeviceProperties.limits.nonCoherentAtomSize, physicalDeviceMemoryProperties, memoryRequirements, memoryPropertyFlags, memoryAllocateFlags, 1, - &vertexIndexBufferMemory); - + &vertexIndexBufferMemory, + &stride); VK_CHECK(vkBindBufferMemory(device, vertexIndexBuffer, vertexIndexBufferMemory, 0)); void * vertexIndexMappedData; @@ -597,13 +591,15 @@ int main() VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; VkMemoryAllocateFlags memoryAllocateFlags{ }; - shaderDataDevice.stride = allocateFromMemoryRequirements(device, - physicalDeviceMemoryProperties, - memoryRequirements, - memoryPropertyFlags, - memoryAllocateFlags, - maxFramesInFlight, - &shaderDataDevice.memory); + allocateFromMemoryRequirements(device, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + memoryRequirements, + memoryPropertyFlags, + memoryAllocateFlags, + maxFramesInFlight, + &shaderDataDevice.memory, + &shaderDataDevice.stride); VkDeviceSize offset{ 0 }; VkDeviceSize size{ VK_WHOLE_SIZE }; @@ -652,188 +648,8 @@ int main() VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateCreateInfo, commandBuffers)); ////////////////////////////////////////////////////////////////////// - // texture - ////////////////////////////////////////////////////////////////////// - - uint32_t checkerSize; - void const * checkerStart = file::open("checker.dds", &checkerSize); - void * checkerData; - uint32_t * mipOffsets; - DDS_FILE const * ddsFile = dds_validate(checkerStart, checkerSize, &mipOffsets, &checkerData); - uint32_t checkerDataSize = checkerSize - (sizeof (DDS_FILE)); - - VkFormat textureFormat{ VK_FORMAT_B8G8R8A8_SRGB }; - - VkImageCreateInfo textureImageCreateInfo{ - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = textureFormat, - .extent = { - .width = ddsFile->header.dwWidth, - .height = ddsFile->header.dwHeight, - .depth = 1 - }, - .mipLevels = ddsFile->header.dwMipMapCount, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED - }; - VK_CHECK(vkCreateImage(device, &textureImageCreateInfo, nullptr, &textureImage)); - - VkMemoryRequirements textureImageMemoryRequirements; - vkGetImageMemoryRequirements(device, textureImage, &textureImageMemoryRequirements); - VkMemoryPropertyFlags textureImageMemoryPropertyFlags{ - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT - }; - VkMemoryAllocateFlags textureImageMemoryAllocateFlags{ }; - allocateFromMemoryRequirements(device, - physicalDeviceMemoryProperties, - textureImageMemoryRequirements, - textureImageMemoryPropertyFlags, - textureImageMemoryAllocateFlags, - 1, - &textureImageMemory); - VK_CHECK(vkBindImageMemory(device, textureImage, textureImageMemory, 0)); - - VkImageViewCreateInfo textureViewCreateInfo{ - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = textureImage, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = textureFormat, - .subresourceRange{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = ddsFile->header.dwMipMapCount, - .layerCount = 1 - } - }; - VK_CHECK(vkCreateImageView(device, &textureViewCreateInfo, nullptr, &textureImageView)); - - // texture transfer: source buffer - - VkBuffer textureSourceBuffer{}; - VkBufferCreateInfo textureSourceBufferCreateInfo{ - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = checkerDataSize, - .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT - }; - VK_CHECK(vkCreateBuffer(device, &textureSourceBufferCreateInfo, nullptr, &textureSourceBuffer)); - VkMemoryRequirements textureSourceBufferMemoryRequirements; - vkGetBufferMemoryRequirements(device, textureSourceBuffer, &textureSourceBufferMemoryRequirements); - VkMemoryPropertyFlags textureSourceBufferMemoryPropertyFlags{ - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - }; - VkMemoryAllocateFlags textureSourceBufferMemoryAllocateFlags{ }; - VkDeviceMemory textureSourceBufferMemory; - allocateFromMemoryRequirements(device, - physicalDeviceMemoryProperties, - textureSourceBufferMemoryRequirements, - textureSourceBufferMemoryPropertyFlags, - textureSourceBufferMemoryAllocateFlags, - 1, - &textureSourceBufferMemory); - VK_CHECK(vkBindBufferMemory(device, textureSourceBuffer, textureSourceBufferMemory, 0)); - - void * textureSourceMappedData; - VK_CHECK(vkMapMemory(device, textureSourceBufferMemory, 0, textureSourceBufferCreateInfo.size, 0, &textureSourceMappedData)); - memcpy((void *)(((ptrdiff_t)textureSourceMappedData) + 0), checkerData, checkerDataSize); - vkUnmapMemory(device, textureSourceBufferMemory); - - VkFenceCreateInfo textureFenceCreateInfo{ - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO - }; - VkFence textureFence{}; - VK_CHECK(vkCreateFence(device, &textureFenceCreateInfo, nullptr, &textureFence)); - - // texture transfer: command buffer - - VkCommandBuffer textureCommandBuffer{}; - VkCommandBufferAllocateInfo textureCommandBufferAllocateInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = commandPool, - .commandBufferCount = 1 - }; - VK_CHECK(vkAllocateCommandBuffers(device, &textureCommandBufferAllocateInfo, &textureCommandBuffer)); - - VkCommandBufferBeginInfo textureCommandBufferBeginInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT - }; - VK_CHECK(vkBeginCommandBuffer(textureCommandBuffer, &textureCommandBufferBeginInfo)); - VkImageMemoryBarrier2 barrierTextureImage{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .srcStageMask = VK_PIPELINE_STAGE_2_NONE, - .srcAccessMask = VK_ACCESS_2_NONE, - .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, - .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .image = textureImage, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = ddsFile->header.dwMipMapCount, - .layerCount = 1 - } - }; - VkDependencyInfo barrierTextureImageDependencyInfo{ - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .imageMemoryBarrierCount = 1, - .pImageMemoryBarriers = &barrierTextureImage - }; - vkCmdPipelineBarrier2(textureCommandBuffer, &barrierTextureImageDependencyInfo); - VkBufferImageCopy * copyRegions = NewM(ddsFile->header.dwMipMapCount); - for (uint32_t level = 0; level < ddsFile->header.dwMipMapCount; level++) { - copyRegions[level] = { - .bufferOffset = mipOffsets[level], - .imageSubresource{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = level, - .layerCount = 1 - }, - .imageExtent{ - .width = max(1u, ddsFile->header.dwWidth >> level), - .height = max(1u, ddsFile->header.dwHeight >> level), - .depth = 1 - }, - }; - } - vkCmdCopyBufferToImage(textureCommandBuffer, textureSourceBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, ddsFile->header.dwMipMapCount, copyRegions); - free(mipOffsets); - free(copyRegions); - - VkImageMemoryBarrier2 barrierTextureRead{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, - .image = textureImage, - .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = ddsFile->header.dwMipMapCount, .layerCount = 1 } - }; - VkDependencyInfo barrierTextureReadDependencyInfo{ - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .imageMemoryBarrierCount = 1, - .pImageMemoryBarriers = &barrierTextureRead - }; - vkCmdPipelineBarrier2(textureCommandBuffer, &barrierTextureReadDependencyInfo); - - VK_CHECK(vkEndCommandBuffer(textureCommandBuffer)); - - VkSubmitInfo textureSubmitInfo{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &textureCommandBuffer - }; - VK_CHECK(vkQueueSubmit(queue, 1, &textureSubmitInfo, textureFence)); - VK_CHECK(vkWaitForFences(device, 1, &textureFence, VK_TRUE, UINT64_MAX)); - vkDestroyFence(device, textureFence, nullptr); - vkDestroyBuffer(device, textureSourceBuffer, nullptr); - vkFreeMemory(device, textureSourceBufferMemory, nullptr); - // texture sampler + ////////////////////////////////////////////////////////////////////// VkSamplerCreateInfo samplerCreateInfo0{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, @@ -1237,6 +1053,8 @@ int main() collada_state.vulkan.initial_state(instance, device, + queue, + commandPool, physicalDeviceProperties, physicalDeviceMemoryProperties, surfaceFormat.format, @@ -1627,7 +1445,7 @@ int main() surfaceCapabilities.currentExtent.width = windowSize.x; surfaceCapabilities.currentExtent.height = windowSize.y; } - recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceMemoryProperties, surfaceCapabilities); + recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceProperties.limits.nonCoherentAtomSize, physicalDeviceMemoryProperties, surfaceCapabilities); } } diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index d50b17a..fc1dba0 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -1,12 +1,19 @@ #include #include #include +#include #include "volk/volk.h" #include "vulkan/vk_enum_string_helper.h" +#include "minmax.h" +#include "new.h" +#include "file.h" #include "check.h" +#include "dds/validate.h" +#include "dds/vulkan.h" + #include "vulkan_helper.h" inline static uint32_t findMemoryTypeIndex(VkPhysicalDeviceMemoryProperties const & memoryProperties, uint32_t memoryTypeBits, VkMemoryPropertyFlags propertyFlags) @@ -36,18 +43,21 @@ inline static uint32_t findMemoryTypeIndex(VkPhysicalDeviceMemoryProperties cons } VkDeviceSize allocateFromMemoryRequirements(VkDevice device, + VkDeviceSize nonCoherentAtomSize, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkMemoryRequirements const & memoryRequirements, VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryAllocateFlags memoryAllocateFlags, uint32_t count, - VkDeviceMemory * memory) + VkDeviceMemory * memory, + VkDeviceSize * outStride) { uint32_t memoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties, memoryRequirements.memoryTypeBits, memoryPropertyFlags); - VkDeviceSize stride = (count == 1) ? memoryRequirements.size : roundAlignment(memoryRequirements.size, memoryRequirements.alignment); + VkDeviceSize alignedSize = roundAlignment(memoryRequirements.size, memoryRequirements.alignment); + VkDeviceSize stride = (count == 1) ? memoryRequirements.size : alignedSize; VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, @@ -56,16 +66,17 @@ VkDeviceSize allocateFromMemoryRequirements(VkDevice device, VkMemoryAllocateInfo memoryAllocateInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = &memoryAllocateFlagsInfo, - .allocationSize = stride * count, + .allocationSize = roundAlignment(stride * count, nonCoherentAtomSize), .memoryTypeIndex = memoryTypeIndex, }; VK_CHECK(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, memory)); - return stride; + *outStride = stride; + return memoryAllocateInfo.allocationSize; } VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, - VkPhysicalDeviceProperties const & physicalDeviceProperties, + VkDeviceSize nonCoherentAtomSize, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryAllocateFlags memoryAllocateFlags, @@ -96,10 +107,201 @@ VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, VkMemoryAllocateInfo memoryAllocateInfo{ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = &memoryAllocateFlagsInfo, - .allocationSize = roundAlignment(offset, physicalDeviceProperties.limits.nonCoherentAtomSize), + .allocationSize = roundAlignment(offset, nonCoherentAtomSize), .memoryTypeIndex = memoryTypeIndex, }; VK_CHECK(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, memory)); return memoryAllocateInfo.allocationSize; } + +void createImageFromFilenameDDS(VkDevice device, + VkQueue queue, + VkCommandBuffer commandBuffer, + VkFence fence, + VkDeviceSize nonCoherentAtomSize, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + char const * const filename, + VkImage * outImage, + VkDeviceMemory * outMemory, + VkImageView * outImageView) +{ + uint32_t imageSize; + void const * imageStart = file::open(filename, &imageSize); + void * imageData; + uint32_t * mipOffsets; + uint32_t imageDataSize; + DDS_FILE const * ddsFile = dds::validate(imageStart, imageSize, &mipOffsets, &imageData, &imageDataSize); + + VkFormat format = dds::dxgi_to_vulkan(ddsFile->header10.dxgiFormat); + + // image + + VkImage image; + VkImageCreateInfo imageCreateInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = format, + .extent = { + .width = ddsFile->header.dwWidth, + .height = ddsFile->header.dwHeight, + .depth = 1 + }, + .mipLevels = ddsFile->header.dwMipMapCount, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED + }; + VK_CHECK(vkCreateImage(device, &imageCreateInfo, nullptr, &image)); + *outImage = image; + + // image view + + VkDeviceMemory imageMemory; + VkMemoryRequirements imageMemoryRequirements; + vkGetImageMemoryRequirements(device, image, &imageMemoryRequirements); + VkMemoryPropertyFlags imageMemoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT }; + VkMemoryAllocateFlags imageMemoryAllocateFlags{ }; + VkDeviceSize stride; + allocateFromMemoryRequirements(device, + nonCoherentAtomSize, + physicalDeviceMemoryProperties, + imageMemoryRequirements, + imageMemoryPropertyFlags, + imageMemoryAllocateFlags, + 1, + &imageMemory, + &stride); + *outMemory = imageMemory; + VK_CHECK(vkBindImageMemory(device, image, imageMemory, 0)); + + VkImageView imageView; + VkImageViewCreateInfo textureViewCreateInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = ddsFile->header.dwMipMapCount, + .layerCount = 1 + } + }; + VK_CHECK(vkCreateImageView(device, &textureViewCreateInfo, nullptr, &imageView)); + *outImageView = imageView; + + // texture transfer: source buffer + + VkBuffer sourceBuffer{}; + VkBufferCreateInfo sourceBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = imageDataSize, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT + }; + VK_CHECK(vkCreateBuffer(device, &sourceBufferCreateInfo, nullptr, &sourceBuffer)); + VkMemoryRequirements sourceBufferMemoryRequirements; + vkGetBufferMemoryRequirements(device, sourceBuffer, &sourceBufferMemoryRequirements); + VkMemoryPropertyFlags sourceBufferMemoryPropertyFlags{ + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + }; + VkMemoryAllocateFlags sourceBufferMemoryAllocateFlags{ }; + VkDeviceMemory sourceBufferMemory; + VkDeviceSize sourceBufferStride; + allocateFromMemoryRequirements(device, + nonCoherentAtomSize, + physicalDeviceMemoryProperties, + sourceBufferMemoryRequirements, + sourceBufferMemoryPropertyFlags, + sourceBufferMemoryAllocateFlags, + 1, + &sourceBufferMemory, + &sourceBufferStride); + VK_CHECK(vkBindBufferMemory(device, sourceBuffer, sourceBufferMemory, 0)); + + void * sourceMappedData; + VK_CHECK(vkMapMemory(device, sourceBufferMemory, 0, sourceBufferCreateInfo.size, 0, &sourceMappedData)); + memcpy((void *)(((ptrdiff_t)sourceMappedData) + 0), imageData, imageDataSize); + vkUnmapMemory(device, sourceBufferMemory); + + // transfer: command buffer + + VkCommandBufferBeginInfo commandBufferBeginInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + }; + VK_CHECK(vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo)); + VkImageMemoryBarrier2 imageBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_2_NONE, + .srcAccessMask = VK_ACCESS_2_NONE, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .image = image, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = ddsFile->header.dwMipMapCount, + .layerCount = 1 + } + }; + VkDependencyInfo imageDependencyInfo{ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &imageBarrier + }; + vkCmdPipelineBarrier2(commandBuffer, &imageDependencyInfo); + VkBufferImageCopy * copyRegions = NewM(ddsFile->header.dwMipMapCount); + for (uint32_t level = 0; level < ddsFile->header.dwMipMapCount; level++) { + copyRegions[level] = { + .bufferOffset = mipOffsets[level], + .imageSubresource{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = level, + .layerCount = 1 + }, + .imageExtent{ + .width = max(1u, ddsFile->header.dwWidth >> level), + .height = max(1u, ddsFile->header.dwHeight >> level), + .depth = 1 + }, + }; + } + vkCmdCopyBufferToImage(commandBuffer, sourceBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, ddsFile->header.dwMipMapCount, copyRegions); + free(mipOffsets); + free(copyRegions); + + VkImageMemoryBarrier2 readBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + .image = image, + .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = ddsFile->header.dwMipMapCount, .layerCount = 1 } + }; + VkDependencyInfo readDependencyInfo{ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &readBarrier + }; + vkCmdPipelineBarrier2(commandBuffer, &readDependencyInfo); + + VK_CHECK(vkEndCommandBuffer(commandBuffer)); + + vkResetFences(device, 1, &fence); + VkSubmitInfo submitInfo{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &commandBuffer + }; + VK_CHECK(vkQueueSubmit(queue, 1, &submitInfo, fence)); + VK_CHECK(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); + + vkDestroyBuffer(device, sourceBuffer, nullptr); + vkFreeMemory(device, sourceBufferMemory, nullptr); +}