From e9c0c9627cfe8b2fe2096a7a2e6627175e2921fe Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 15 Apr 2026 21:35:46 -0500 Subject: [PATCH] collada: load scene textures --- Makefile | 2 +- checker.dds | Bin 5592552 -> 0 bytes .../shadow_test/images/0_leaf_white.dds | Bin 0 -> 22020 bytes .../shadow_test/images/0_leaf_white.png | Bin 0 -> 1232 bytes data/scenes/shadow_test/shadow_test.DAE | 25 +- data/scenes/shadow_test/shadow_test.cpp | 20 +- filenames.txt | 3 +- include/collada/scene/vulkan.h | 23 +- include/{ => dds}/dds.h | 0 include/dds/validate.h | 13 + include/dds/vulkan.h | 27 ++ include/dds_validate.h | 11 - include/minmax.h | 19 ++ include/vulkan_helper.h | 17 +- src/collada/scene.cpp | 1 + src/collada/scene/vulkan.cpp | 69 ++++- src/{dds_validate.cpp => dds/validate.cpp} | 60 +++-- src/main.cpp | 252 +++--------------- src/vulkan_helper.cpp | 214 ++++++++++++++- 19 files changed, 471 insertions(+), 285 deletions(-) delete mode 100644 checker.dds create mode 100644 data/scenes/shadow_test/images/0_leaf_white.dds create mode 100644 data/scenes/shadow_test/images/0_leaf_white.png rename include/{ => dds}/dds.h (100%) create mode 100644 include/dds/validate.h create mode 100644 include/dds/vulkan.h delete mode 100644 include/dds_validate.h create mode 100644 include/minmax.h rename src/{dds_validate.cpp => dds/validate.cpp} (50%) 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 694ad568cff23de4578b47a2768a85c2f6026d1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5592552 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 PeEzS${`&j>`ak~#1F$Z3 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 0000000000000000000000000000000000000000..42954dcb3999f03fc63a53d730c70bab7123ab03 GIT binary patch literal 22020 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c9560a6de062ae76a43feb5a91004cd7eca555e7 GIT binary patch literal 1232 zcmV;>1TXuEP)I4t~5){0=$F%?e1YJo) zK~#9!?VZ7GTR{v&Ey5?Cqykicsz?bbBgoA_>ImSQkTO(4sz?DYz&iQ*bFvU9`m*+G z$sKZrfB`$O9ckxrmdoA!UQN?9Jt%0yGz0=bApjHtKp_AW0ze@E6aqj&6OYVq{?FI% zr_XnXy&Qm5{7YX803z|3Aux&04S`8~ZU{``b3{-v)g zIe|%htpaGpe>pxqyd0mXK{RDPw;PpO2Clc8(}#CmpeX<>(^?8Qxj<0|=oNFzzFVNm z27y(`{-p(=A`t+YGAq+-H4SM0X+RE8Jew-j0#-r%IYDj_>UsUX=x3`qLHbp|NFhG^ zzcaXiWzK$tEX?i%mQ{RDfqIIH?gExo{1%Z$XDKoSDQkeLeR+BSqB3Pf7ZBA2ESvb= z+0W)KCh_l!Yv%0$RTcmE`nE{?)}Qe@ zf~FeaPVu9sjMmqQ;sS=A{SjHuTsK&y?7!vvTbe)&5LlJ$_v#h&bQQ#DAZ;JunkXJc znI{M|0Q9W<(JJqyaEx{V-3uTO0noAbSn5h6T_6kq#ElS-ZQ*Q9Aw$ik%xm~e5R{n$ zKB{zY@vAKf%K%W}Ajb#@R0L`jz!f77fd~Kv>@*+%-`hSmU|y~%q-%y1}_=0wn_K|)>{qSPA0 z0r0ju^#>9-fag?@G5aHXC01q7yj`G|lc2#21Atd=pof5w;zxH%({%!SK+tj{xN7D@ z0&pw+QG*#R{)l}NI0tBfz!L-p@nNTcmcc+?A)t#7T?4d2aLZsv!IJ6G^3X+KYi3*< z_(<_R-(&AsP17`?Q`-BU{H0aE`4(|Y4X_k0gu^i@mVqM%>eeYGv-oKoz{3sBU108z zh{v6Nq+@aE8bQ&6_wQ54tBIcy0K`Ge{JPT~3e5%q>g!E?B;Pu~0000OpenCOLLADA 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); +}