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);
+}