collada: load scene textures

This commit is contained in:
Zack Buhman 2026-04-15 21:35:46 -05:00
parent 635e27b03f
commit e9c0c9627c
19 changed files with 471 additions and 285 deletions

View File

@ -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 \

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -6,14 +6,24 @@
<authoring_tool>OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68</authoring_tool>
<source_data>file:///C:/Users/bilbo/Documents/wood/scenes/shadow_test.max</source_data>
</contributor>
<created>2026-04-14T19:52:07</created>
<modified>2026-04-14T19:52:07</modified>
<created>2026-04-15T19:19:21</created>
<modified>2026-04-15T19:19:21</modified>
<unit name="inch" meter="0.0254"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_effects>
<effect id="PlaneMaterial">
<profile_COMMON>
<newparam sid="leaf_white_png-surface">
<surface type="2D">
<init_from>leaf_white_png</init_from>
</surface>
</newparam>
<newparam sid="leaf_white_png-sampler">
<sampler2D>
<source>leaf_white_png-surface</source>
</sampler2D>
</newparam>
<technique sid="common">
<blinn>
<emission>
@ -23,7 +33,7 @@
<color>0.6627451 0.5882353 0.6196079 1</color>
</ambient>
<diffuse>
<color>0.6627451 0.5882353 0.6196079 1</color>
<texture texture="leaf_white_png-sampler" texcoord="CHANNEL1"/>
</diffuse>
<specular>
<color>0 0 0 1</color>
@ -677,6 +687,11 @@
</extra>
</light>
</library_lights>
<library_images>
<image id="leaf_white_png">
<init_from>./images/0_leaf_white.png</init_from>
</image>
</library_images>
<library_visual_scenes>
<visual_scene id="MaxScene">
<node name="EnvironmentAmbientLight">
@ -686,7 +701,9 @@
<instance_geometry url="#geom-Plane">
<bind_material>
<technique_common>
<instance_material symbol="PlaneMaterial" target="#PlaneMaterial-material"/>
<instance_material symbol="PlaneMaterial" target="#PlaneMaterial-material">
<bind_vertex_input semantic="CHANNEL1" input_semantic="TEXCOORD" input_set="0"/>
</instance_material>
</technique_common>
</bind_material>
</instance_geometry>

View File

@ -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 = {

View File

@ -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

View File

@ -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

13
include/dds/validate.h Normal file
View File

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

27
include/dds/vulkan.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <assert.h>
#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);
}
}
}

View File

@ -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);

19
include/minmax.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
template <typename T>
inline static constexpr T min(T a, T b)
{
return (a < b) ? a : b;
}
template <typename T>
inline static constexpr T max(T a, T b)
{
return (a > b) ? a : b;
}
template <typename T>
inline static constexpr T clamp(T n, T minVal, T maxVal)
{
return min(max(n, minVal), maxVal);
}

View File

@ -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);

View File

@ -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);

View File

@ -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<Image>(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);

View File

@ -2,7 +2,7 @@
#include <stdint.h>
#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<uint32_t>(dds->header.dwMipMapCount);
uint32_t * offsets = NewM<uint32_t>(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;
}
}

View File

@ -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 <typename T>
inline static constexpr T min(T a, T b)
{
return (a < b) ? a : b;
}
template <typename T>
inline static constexpr T max(T a, T b)
{
return (a > b) ? a : b;
}
template <typename T>
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<VkBufferImageCopy>(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);
}
}

View File

@ -1,12 +1,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#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<VkBufferImageCopy>(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);
}