collada: load scene textures
This commit is contained in:
parent
635e27b03f
commit
e9c0c9627c
2
Makefile
2
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 \
|
||||
|
||||
BIN
checker.dds
BIN
checker.dds
Binary file not shown.
BIN
data/scenes/shadow_test/images/0_leaf_white.dds
Normal file
BIN
data/scenes/shadow_test/images/0_leaf_white.dds
Normal file
Binary file not shown.
BIN
data/scenes/shadow_test/images/0_leaf_white.png
Normal file
BIN
data/scenes/shadow_test/images/0_leaf_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@ -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>
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
13
include/dds/validate.h
Normal 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
27
include/dds/vulkan.h
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
19
include/minmax.h
Normal 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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
252
src/main.cpp
252
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 <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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user