render collada scene
This commit is contained in:
parent
1456e04200
commit
0a33f58f04
14
Makefile
14
Makefile
@ -21,10 +21,11 @@ CFLAGS += -Wno-error=array-bounds
|
||||
CFLAGS += -Wno-unknown-pragmas
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -I./include
|
||||
CFLAGS += -I./data
|
||||
CFLAGS += -I../SDL3-dist/include
|
||||
CFLAGS += -fpic
|
||||
|
||||
FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address
|
||||
#FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address
|
||||
|
||||
LDFLAGS += -lm
|
||||
ifeq ($(UNAME),Linux)
|
||||
@ -40,7 +41,14 @@ 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 \
|
||||
src/collada/node_state.o
|
||||
|
||||
SCENES = \
|
||||
data/scenes/shadow_test/shadow_test.o
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
LIBS = \
|
||||
@ -61,7 +69,7 @@ all: main
|
||||
%.o: %.s
|
||||
$(AS) $< -o $@
|
||||
|
||||
main: $(OBJS) $(LIBS) $(BINS) $(SHADERS)
|
||||
main: $(OBJS) $(LIBS) $(SCENES)
|
||||
$(CC) $(ARCH) $(LDFLAGS) $(FLAGS) $(OPT) $(DEBUG) $^ -o $@
|
||||
|
||||
%.spv: %.hlsl
|
||||
|
||||
999
data/scenes/shadow_test/shadow_test.DAE
Normal file
999
data/scenes/shadow_test/shadow_test.DAE
Normal file
File diff suppressed because one or more lines are too long
2282
data/scenes/shadow_test/shadow_test.cpp
Normal file
2282
data/scenes/shadow_test/shadow_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
data/scenes/shadow_test/shadow_test.h
Normal file
3
data/scenes/shadow_test/shadow_test.h
Normal file
@ -0,0 +1,3 @@
|
||||
namespace shadow_test {
|
||||
extern collada::types::descriptor const descriptor;
|
||||
}
|
||||
BIN
data/scenes/shadow_test/shadow_test.idx
Normal file
BIN
data/scenes/shadow_test/shadow_test.idx
Normal file
Binary file not shown.
0
data/scenes/shadow_test/shadow_test.vjw
Normal file
0
data/scenes/shadow_test/shadow_test.vjw
Normal file
BIN
data/scenes/shadow_test/shadow_test.vtx
Normal file
BIN
data/scenes/shadow_test/shadow_test.vtx
Normal file
Binary file not shown.
@ -1,4 +1,7 @@
|
||||
shader/triangle.spv
|
||||
shader/collada.spv
|
||||
data/scenes/shadow_test/shadow_test.vtx
|
||||
data/scenes/shadow_test/shadow_test.idx
|
||||
checker.idx
|
||||
checker.vtx
|
||||
checker.data
|
||||
|
||||
54
include/check.h
Normal file
54
include/check.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#define SDL_CHECK(f) \
|
||||
{ \
|
||||
bool result = (f); \
|
||||
if (result != true) { \
|
||||
fprintf(stderr, "SDL: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, SDL_GetError()); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SDL_CHECK_NONNULL(f) \
|
||||
{ \
|
||||
void * ptr = (void *)(f); \
|
||||
if (ptr == nullptr) { \
|
||||
fprintf(stderr, "SDL: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, SDL_GetError()); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VK_CHECK(f) \
|
||||
{ \
|
||||
VkResult result = (f); \
|
||||
if (result != VK_SUCCESS) { \
|
||||
fprintf(stderr, "VK: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, string_VkResult(result)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VK_CHECK_SWAPCHAIN(f) \
|
||||
{ \
|
||||
VkResult result = (f); \
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { \
|
||||
updateSwapchain = true; \
|
||||
} else if (result != VK_SUCCESS) { \
|
||||
fprintf(stderr, "VK: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, string_VkResult(result)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ASSERT(expr, msg) \
|
||||
{ \
|
||||
bool result = (expr); \
|
||||
if (result != true) { \
|
||||
fprintf(stderr, "%s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, msg); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||
#define UNREACHABLE() __assume(false);
|
||||
#else // GCC, Clang
|
||||
#define UNREACHABLE() __builtin_unreachable();
|
||||
#endif
|
||||
38
include/collada/inputs.h
Normal file
38
include/collada/inputs.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "collada/types.h"
|
||||
|
||||
namespace collada::inputs {
|
||||
inline static uint32_t format_size(types::input_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case types::input_format::FLOAT1: return 1 * 4;
|
||||
case types::input_format::FLOAT2: return 2 * 4;
|
||||
case types::input_format::FLOAT3: return 3 * 4;
|
||||
case types::input_format::FLOAT4: return 4 * 4;
|
||||
case types::input_format::INT1: return 1 * 4;
|
||||
case types::input_format::INT2: return 2 * 4;
|
||||
case types::input_format::INT3: return 3 * 4;
|
||||
case types::input_format::INT4: return 4 * 4;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static types::input_element const input_elements_blendindices_0_4_blendweight_0_4[] = {
|
||||
{
|
||||
.semantic = "BLENDINDICES",
|
||||
.semantic_index = 0,
|
||||
.format = types::input_format::INT4,
|
||||
},
|
||||
{
|
||||
.semantic = "BLENDWEIGHT",
|
||||
.semantic_index = 0,
|
||||
.format = types::input_format::FLOAT4,
|
||||
},
|
||||
};
|
||||
|
||||
static types::inputs const skin_inputs = {
|
||||
.elements = input_elements_blendindices_0_4_blendweight_0_4,
|
||||
.elements_count = 2,
|
||||
};
|
||||
}
|
||||
32
include/collada/instance_types.h
Normal file
32
include/collada/instance_types.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "directxmath/directxmath.h"
|
||||
|
||||
#include "collada/types.h"
|
||||
|
||||
namespace collada::instance_types {
|
||||
|
||||
struct XM_ALIGNED_DATA(16) lookat {
|
||||
XMVECTOR eye;
|
||||
XMVECTOR at;
|
||||
XMVECTOR up;
|
||||
};
|
||||
|
||||
struct XM_ALIGNED_DATA(16) transform {
|
||||
union {
|
||||
instance_types::lookat lookat;
|
||||
XMMATRIX matrix;
|
||||
XMVECTOR vector;
|
||||
};
|
||||
types::transform_type type;
|
||||
};
|
||||
|
||||
struct node {
|
||||
// immutable state
|
||||
types::node const * node;
|
||||
|
||||
// mutable state
|
||||
transform * transforms;
|
||||
XMMATRIX world;
|
||||
};
|
||||
}
|
||||
13
include/collada/node_state.h
Normal file
13
include/collada/node_state.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "collada/types.h"
|
||||
#include "collada/instance_types.h"
|
||||
|
||||
namespace collada::node_state {
|
||||
struct state {
|
||||
instance_types::node * node_instances;
|
||||
|
||||
void allocate_node_instances(types::node const * const * const nodes, int nodes_count);
|
||||
void update_node_world_transform(instance_types::node & node_instance);
|
||||
};
|
||||
};
|
||||
23
include/collada/scene.h
Normal file
23
include/collada/scene.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "collada/types.h"
|
||||
#include "collada/instance_types.h"
|
||||
#include "collada/node_state.h"
|
||||
|
||||
#include "collada/scene/vulkan.h"
|
||||
|
||||
namespace collada::scene {
|
||||
struct state {
|
||||
types::descriptor const * descriptor;
|
||||
node_state::state node_state;
|
||||
|
||||
collada::scene::vulkan vulkan;
|
||||
|
||||
void load_scene(types::descriptor const * const descriptor);
|
||||
void draw();
|
||||
|
||||
void update(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
float t);
|
||||
};
|
||||
}
|
||||
96
include/collada/scene/vulkan.h
Normal file
96
include/collada/scene/vulkan.h
Normal file
@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "volk/volk.h"
|
||||
|
||||
#include "collada/types.h"
|
||||
#include "collada/instance_types.h"
|
||||
#include "collada/scene/vulkan.h"
|
||||
|
||||
#include "shader_data.h"
|
||||
|
||||
namespace collada::scene {
|
||||
struct vulkan {
|
||||
// externally initialized, opaque handle
|
||||
VkInstance instance;
|
||||
VkDevice device;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
// externally initialized, structures
|
||||
VkPhysicalDeviceProperties physicalDeviceProperties;
|
||||
VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties;
|
||||
// externally initialized, enum
|
||||
VkFormat colorFormat;
|
||||
VkFormat depthFormat;
|
||||
// externally initialized, pointers
|
||||
ShaderData * shaderData;
|
||||
ShaderDataDevice const * shaderDataDevice;
|
||||
|
||||
// method initialized
|
||||
VkShaderModule shaderModule;
|
||||
VkPipeline * pipelines;
|
||||
struct {
|
||||
VkDeviceSize indexOffset;
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
} vertexIndex;
|
||||
|
||||
// per-frame
|
||||
VkCommandBuffer commandBuffer;
|
||||
uint32_t frameIndex;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// called directly
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initial_state(VkInstance instance,
|
||||
VkDevice device,
|
||||
VkPipelineLayout pipelineLayout,
|
||||
VkDescriptorSetLayout descriptorSetLayout,
|
||||
VkPhysicalDeviceProperties const & physicalDeviceProperties,
|
||||
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties,
|
||||
VkFormat colorFormat,
|
||||
VkFormat depthFormat,
|
||||
ShaderData * shaderData,
|
||||
ShaderDataDevice const * shaderDataDevice);
|
||||
|
||||
void per_frame_state(uint32_t frameIndex);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// called by initial_state
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void load_shader();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// called by state::load_scene
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void load_vertex_index_buffer(char const * vertex_filename,
|
||||
char const * index_filename);
|
||||
void create_pipelines(collada::types::descriptor const * const descriptor);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// called by state::draw
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void draw_geometry(types::geometry const & geometry,
|
||||
types::instance_material const * const instance_materials,
|
||||
int const instance_materials_count);
|
||||
|
||||
void draw_instance_geometries(types::instance_geometry const * const instance_geometries,
|
||||
int const instance_geometries_count);
|
||||
|
||||
void draw_node(int32_t node_index,
|
||||
types::node const & node,
|
||||
instance_types::node const & node_instance);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// called by state::update
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void transfer_transforms(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
int nodes_count,
|
||||
instance_types::node const * const node_instances);
|
||||
};
|
||||
}
|
||||
410
include/collada/types.h
Normal file
410
include/collada/types.h
Normal file
@ -0,0 +1,410 @@
|
||||
#pragma once
|
||||
|
||||
namespace collada::types {
|
||||
|
||||
struct float2 {
|
||||
float const x;
|
||||
float const y;
|
||||
};
|
||||
|
||||
struct float3 {
|
||||
float const x;
|
||||
float const y;
|
||||
float const z;
|
||||
};
|
||||
|
||||
struct float4 {
|
||||
float const x;
|
||||
float const y;
|
||||
float const z;
|
||||
float const w;
|
||||
};
|
||||
|
||||
struct float7 {
|
||||
float const a;
|
||||
float const b;
|
||||
float const c;
|
||||
float const d;
|
||||
float const e;
|
||||
float const f;
|
||||
float const g;
|
||||
};
|
||||
|
||||
struct matrix {
|
||||
float const _11, _12, _13, _14;
|
||||
float const _21, _22, _23, _24;
|
||||
float const _31, _32, _33, _34;
|
||||
float const _41, _42, _43, _44;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// geometry
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class input_format {
|
||||
FLOAT1,
|
||||
FLOAT2,
|
||||
FLOAT3,
|
||||
FLOAT4,
|
||||
INT1,
|
||||
INT2,
|
||||
INT3,
|
||||
INT4,
|
||||
};
|
||||
|
||||
struct input_element {
|
||||
char const * const semantic;
|
||||
int const semantic_index;
|
||||
enum input_format const format;
|
||||
};
|
||||
|
||||
// inputs uniqueness is by evaluted pointer
|
||||
struct inputs {
|
||||
input_element const * const elements;
|
||||
int const elements_count;
|
||||
};
|
||||
|
||||
struct triangles {
|
||||
int const count;
|
||||
int const index_offset;
|
||||
int const inputs_index;
|
||||
};
|
||||
|
||||
struct mesh {
|
||||
// `triangles` must become a union if non-triangles are implemented.
|
||||
// instance_geometry is an index into this array.
|
||||
types::triangles const * triangles;
|
||||
int const triangles_count;
|
||||
|
||||
int const vertex_buffer_offset;
|
||||
int const vertex_buffer_size;
|
||||
|
||||
int const index_buffer_offset;
|
||||
int const index_buffer_size;
|
||||
};
|
||||
|
||||
struct geometry {
|
||||
types::mesh mesh;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// light
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class light_type {
|
||||
AMBIENT,
|
||||
DIRECTIONAL,
|
||||
POINT,
|
||||
SPOT,
|
||||
};
|
||||
|
||||
struct light {
|
||||
light_type type;
|
||||
float3 color;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// image
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct image {
|
||||
const char * uri;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// effect
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class color_or_texture_type {
|
||||
COLOR,
|
||||
TEXTURE,
|
||||
};
|
||||
|
||||
struct texture {
|
||||
int const image_index; // index in to images
|
||||
};
|
||||
|
||||
struct color_or_texture {
|
||||
color_or_texture_type type;
|
||||
union {
|
||||
float4 color;
|
||||
types::texture texture;
|
||||
};
|
||||
};
|
||||
|
||||
struct blinn {
|
||||
color_or_texture const emission;
|
||||
color_or_texture const ambient;
|
||||
color_or_texture const diffuse;
|
||||
color_or_texture const specular;
|
||||
float const shininess;
|
||||
color_or_texture const reflective;
|
||||
float const reflectivity;
|
||||
color_or_texture const transparent;
|
||||
float const transparency;
|
||||
float const index_of_refraction;
|
||||
};
|
||||
|
||||
struct lambert {
|
||||
color_or_texture const emission;
|
||||
color_or_texture const ambient;
|
||||
color_or_texture const diffuse;
|
||||
color_or_texture const reflective;
|
||||
float const reflectivity;
|
||||
color_or_texture const transparent;
|
||||
float const transparency;
|
||||
float const index_of_refraction;
|
||||
};
|
||||
|
||||
struct phong {
|
||||
color_or_texture const emission;
|
||||
color_or_texture const ambient;
|
||||
color_or_texture const diffuse;
|
||||
color_or_texture const specular;
|
||||
float const shininess;
|
||||
color_or_texture const reflective;
|
||||
float const reflectivity;
|
||||
color_or_texture const transparent;
|
||||
float const transparency;
|
||||
float const index_of_refraction;
|
||||
};
|
||||
|
||||
struct constant {
|
||||
float4 const color;
|
||||
color_or_texture const reflective;
|
||||
float const reflectivity;
|
||||
color_or_texture const transparent;
|
||||
float const transparency;
|
||||
float const index_of_refraction;
|
||||
};
|
||||
|
||||
enum class effect_type {
|
||||
BLINN,
|
||||
LAMBERT,
|
||||
PHONG,
|
||||
CONSTANT,
|
||||
};
|
||||
|
||||
struct effect {
|
||||
effect_type const type;
|
||||
union {
|
||||
types::blinn const blinn;
|
||||
types::lambert const lambert;
|
||||
types::phong const phong;
|
||||
types::constant const constant;
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// node
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct lookat {
|
||||
float3 const eye;
|
||||
float3 const at;
|
||||
float3 const up;
|
||||
};
|
||||
|
||||
enum class transform_type {
|
||||
LOOKAT,
|
||||
MATRIX,
|
||||
ROTATE,
|
||||
SCALE,
|
||||
SKEW,
|
||||
TRANSLATE,
|
||||
};
|
||||
|
||||
struct transform {
|
||||
transform_type const type;
|
||||
union {
|
||||
types::lookat const lookat;
|
||||
types::matrix const matrix;
|
||||
float4 const rotate;
|
||||
float3 const scale;
|
||||
float7 const skew;
|
||||
float3 const translate;
|
||||
};
|
||||
};
|
||||
|
||||
enum class node_type {
|
||||
JOINT,
|
||||
NODE,
|
||||
};
|
||||
|
||||
struct material {
|
||||
types::effect const * const effect;
|
||||
};
|
||||
|
||||
struct bind_vertex_input {
|
||||
int input_set; // TEXCOORD semantic input slot
|
||||
};
|
||||
|
||||
struct instance_material {
|
||||
int const element_index; // an index into mesh.triangles
|
||||
types::material const * const material;
|
||||
|
||||
// heavily simplified from collada data model
|
||||
bind_vertex_input const emission;
|
||||
bind_vertex_input const ambient;
|
||||
bind_vertex_input const diffuse;
|
||||
bind_vertex_input const specular;
|
||||
};
|
||||
|
||||
struct instance_geometry {
|
||||
types::geometry const * const geometry;
|
||||
|
||||
instance_material const * const instance_materials;
|
||||
int const instance_materials_count;
|
||||
};
|
||||
|
||||
struct skin {
|
||||
types::geometry const * const geometry; // source
|
||||
|
||||
matrix const bind_shape_matrix; // one per skin
|
||||
matrix const * const inverse_bind_matrices; // one per joint
|
||||
|
||||
int const vertex_buffer_offset;
|
||||
int const vertex_buffer_size;
|
||||
};
|
||||
|
||||
struct controller {
|
||||
types::skin skin;
|
||||
};
|
||||
|
||||
struct instance_controller {
|
||||
types::controller const * const controller;
|
||||
|
||||
//node const * const skeleton; // a reference to the root of the joint heirarchy
|
||||
|
||||
int const * const joint_node_indices; // one per joint
|
||||
int const joint_count;
|
||||
|
||||
instance_material const * const instance_materials;
|
||||
int const instance_materials_count;
|
||||
};
|
||||
|
||||
struct instance_light {
|
||||
types::light const * const light;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// animation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class interpolation {
|
||||
LINEAR,
|
||||
BEZIER,
|
||||
};
|
||||
|
||||
struct source {
|
||||
union {
|
||||
float const * const float_array;
|
||||
enum interpolation const * const interpolation_array;
|
||||
};
|
||||
int const count;
|
||||
int const stride;
|
||||
};
|
||||
|
||||
struct sampler {
|
||||
source const input;
|
||||
source const output;
|
||||
source const in_tangent;
|
||||
source const out_tangent;
|
||||
source const interpolation;
|
||||
};
|
||||
|
||||
enum class target_attribute {
|
||||
A, // alpha color component
|
||||
ANGLE, // euler angle
|
||||
B, // blue color component
|
||||
G, // green color component
|
||||
P, // third texture component
|
||||
Q, // fourth texture component
|
||||
R, // red color component
|
||||
S, // first texture coordinate
|
||||
T, // second texture coordinate
|
||||
TIME, // time in seconds
|
||||
U, // first generic parameter
|
||||
V, // second generic parameter
|
||||
W, // fourth cartesian coordinate
|
||||
X, // first cartesian coordinate
|
||||
Y, // second cartesian coordinate
|
||||
Z, // third cartesian coordinate
|
||||
ALL,
|
||||
};
|
||||
|
||||
struct channel {
|
||||
sampler const * const source_sampler;
|
||||
int const target_node_index; // an index into the nodes array
|
||||
int const target_transform_index;
|
||||
types::target_attribute const target_attribute;
|
||||
};
|
||||
|
||||
/*
|
||||
struct animation {
|
||||
animation const * const animations; // nested animations
|
||||
int const animations_count;
|
||||
|
||||
channels const * const channels;
|
||||
int const channels_count;
|
||||
};
|
||||
*/
|
||||
|
||||
struct camera {
|
||||
float xfov;
|
||||
float yfov;
|
||||
float znear;
|
||||
float zfar;
|
||||
float aspect_ratio;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// scene
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct node {
|
||||
char const * name;
|
||||
|
||||
int const parent_index;
|
||||
|
||||
node_type const type;
|
||||
|
||||
transform const * const transforms;
|
||||
int const transforms_count;
|
||||
|
||||
instance_geometry const * const instance_geometries;
|
||||
int const instance_geometries_count;
|
||||
|
||||
instance_controller const * const instance_controllers;
|
||||
int const instance_controllers_count;
|
||||
|
||||
instance_light const * const instance_lights;
|
||||
int const instance_lights_count;
|
||||
|
||||
channel const * const * const channels;
|
||||
int const channels_count;
|
||||
|
||||
//node const * const * const nodes;
|
||||
//int const nodes_count;
|
||||
};
|
||||
|
||||
struct descriptor {
|
||||
// these are only the top-level nodes; nodes may have children
|
||||
node const * const * const nodes;
|
||||
int const nodes_count;
|
||||
|
||||
inputs const * const inputs_list;
|
||||
int const inputs_list_count;
|
||||
|
||||
image const * const * const images;
|
||||
int const images_count;
|
||||
|
||||
//animation const * const animations;
|
||||
//int const animations_count;
|
||||
|
||||
// hmm, this part is not really platform-agnostic:
|
||||
char const * const position_normal_texture_buffer;
|
||||
char const * const joint_weight_buffer;
|
||||
char const * const index_buffer;
|
||||
};
|
||||
}
|
||||
21
include/shader_data.h
Normal file
21
include/shader_data.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "directxmath/directxmath.h"
|
||||
|
||||
constexpr uint32_t maxFramesInFlight{ 2 };
|
||||
|
||||
struct ShaderData {
|
||||
XMFLOAT4X4 projection;
|
||||
XMFLOAT4X4 modelView[16];
|
||||
XMFLOAT4 lightPosition;
|
||||
};
|
||||
|
||||
struct ShaderDataDevice {
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceAddress stride;
|
||||
void * mappedData;
|
||||
struct {
|
||||
VkBuffer buffer{ VK_NULL_HANDLE };
|
||||
VkDeviceAddress deviceAddress{};
|
||||
} frame[maxFramesInFlight];
|
||||
};
|
||||
18
include/vulkan_helper.h
Normal file
18
include/vulkan_helper.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
inline static constexpr VkDeviceSize roundAlignment(VkDeviceSize offset, VkDeviceSize alignment)
|
||||
{
|
||||
// must be a power of two
|
||||
assert(alignment && ((alignment & (alignment - 1)) == 0));
|
||||
return (offset + (alignment - 1)) & (-alignment);
|
||||
}
|
||||
|
||||
VkDeviceSize allocateFromMemoryRequirements(VkDevice device,
|
||||
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties,
|
||||
VkMemoryRequirements const & memoryRequirements,
|
||||
VkMemoryPropertyFlags memoryPropertyFlags,
|
||||
VkMemoryAllocateFlags memoryAllocateFlags,
|
||||
uint32_t count,
|
||||
VkDeviceMemory * memory);
|
||||
66
shader/collada.hlsl
Normal file
66
shader/collada.hlsl
Normal file
@ -0,0 +1,66 @@
|
||||
struct VSInput
|
||||
{
|
||||
float3 Position : POSITION0;
|
||||
float3 Normal : NORMAL0;
|
||||
float3 Texture : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float3 Normal : NORMAL0;
|
||||
float2 Texture : TEXCOORD0;
|
||||
float3 LightDirection : NORMAL1;
|
||||
float3 ViewDirection : NORMAL2;
|
||||
};
|
||||
|
||||
struct ShaderData
|
||||
{
|
||||
column_major float4x4 Projection;
|
||||
column_major float4x4 ModelView[16];
|
||||
float4 LightPosition; // view space
|
||||
};
|
||||
|
||||
[[vk::binding(0, 0)]] ConstantBuffer<ShaderData> data;
|
||||
|
||||
struct PushConstant {
|
||||
int ModelViewIndex;
|
||||
};
|
||||
|
||||
[[vk::push_constant]]
|
||||
struct PushConstant constants;
|
||||
|
||||
[shader("vertex")]
|
||||
VSOutput VSMain(VSInput input)
|
||||
{
|
||||
float4x4 modelView = data.ModelView[constants.ModelViewIndex];
|
||||
|
||||
VSOutput output = (VSOutput)0;
|
||||
output.Position = mul(data.Projection, mul(modelView, float4(input.Position.xyz, 1.0))) * float4(-1, -1, 1, 1);
|
||||
output.Normal = mul((float3x3)modelView, input.Normal);
|
||||
output.Texture = input.Texture.xy * 1.0;
|
||||
|
||||
float4 viewPosition = mul(modelView, float4(input.Position.xyz, 1.0));
|
||||
output.LightDirection = (data.LightPosition - viewPosition).xyz;
|
||||
output.ViewDirection = -viewPosition.xyz;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
[shader("pixel")]
|
||||
float4 PSMain(VSOutput input) : SV_TARGET
|
||||
{
|
||||
//float3 color = texture.Sample(samplers[0], input.Texture).bgr;
|
||||
|
||||
float3 N = normalize(input.Normal);
|
||||
float3 L = normalize(input.LightDirection);
|
||||
float3 V = normalize(input.ViewDirection);
|
||||
float3 R = reflect(-L, N);
|
||||
|
||||
const float a = 16.0;
|
||||
const float specularIntensity = 0.8;
|
||||
float3 specular = pow(max(dot(R, V), 0), a) * specularIntensity;
|
||||
float3 diffuse = max(dot(N, L), 0.001);
|
||||
|
||||
return float4(diffuse + specular, 1.0);
|
||||
}
|
||||
117
src/collada/node_state.cpp
Normal file
117
src/collada/node_state.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "directxmath/directxmath.h"
|
||||
|
||||
#include "new.h"
|
||||
|
||||
#include "collada/node_state.h"
|
||||
|
||||
namespace collada::node_state {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// transforms
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline static void load_transform(types::transform const & transform,
|
||||
instance_types::transform * instance_transform)
|
||||
{
|
||||
switch (transform.type) {
|
||||
case types::transform_type::LOOKAT:
|
||||
instance_transform->lookat.eye = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.eye);
|
||||
instance_transform->lookat.at = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.at);
|
||||
instance_transform->lookat.up = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.up);
|
||||
break;
|
||||
case types::transform_type::MATRIX:
|
||||
instance_transform->matrix = XMMatrixTranspose(XMLoadFloat4x4((XMFLOAT4X4 *)&transform.matrix));
|
||||
break;
|
||||
case types::transform_type::ROTATE:
|
||||
instance_transform->vector = XMLoadFloat4((XMFLOAT4 *)&transform.rotate);
|
||||
break;
|
||||
case types::transform_type::SCALE:
|
||||
instance_transform->vector = XMLoadFloat3((XMFLOAT3*)&transform.scale);
|
||||
break;
|
||||
case types::transform_type::TRANSLATE:
|
||||
instance_transform->vector = XMLoadFloat3((XMFLOAT3*)&transform.translate);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
instance_transform->type = transform.type;
|
||||
}
|
||||
|
||||
inline static void initialize_node_transforms(instance_types::node & node_instance)
|
||||
{
|
||||
for (int i = 0; i < node_instance.node->transforms_count; i++) {
|
||||
load_transform(node_instance.node->transforms[i], &node_instance.transforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void allocate_node_instance(instance_types::node & node_instance,
|
||||
types::node const * const node)
|
||||
{
|
||||
node_instance.node = node;
|
||||
node_instance.transforms = NewM<instance_types::transform>(node->transforms_count);
|
||||
|
||||
initialize_node_transforms(node_instance);
|
||||
}
|
||||
|
||||
void state::allocate_node_instances(types::node const * const * const nodes, int nodes_count)
|
||||
{
|
||||
node_instances = NewM<instance_types::node>(nodes_count);
|
||||
for (int i = 0; i < nodes_count; i++) {
|
||||
allocate_node_instance(node_instances[i], nodes[i]);
|
||||
}
|
||||
for (int i = 0; i < nodes_count; i++) {
|
||||
update_node_world_transform(node_instances[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// world matrix
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline static bool vector_equal(XMVECTOR V1, XMVECTOR V2)
|
||||
{
|
||||
uint32_t CR;
|
||||
XMVectorEqualR(&CR, V1, V2);
|
||||
return XMComparisonAllTrue(CR);
|
||||
}
|
||||
|
||||
inline static XMMATRIX transform_matrix(instance_types::transform const& transform)
|
||||
{
|
||||
switch (transform.type) {
|
||||
case types::transform_type::TRANSLATE:
|
||||
return XMMatrixTranslationFromVector(transform.vector);
|
||||
case types::transform_type::ROTATE:
|
||||
//assert(!vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero()));
|
||||
if (vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero()))
|
||||
return XMMatrixIdentity();
|
||||
return XMMatrixRotationNormal(transform.vector,
|
||||
XMConvertToRadians(XMVectorGetW(transform.vector)));
|
||||
case types::transform_type::SCALE:
|
||||
return XMMatrixScalingFromVector(transform.vector);
|
||||
case types::transform_type::MATRIX:
|
||||
return transform.matrix;
|
||||
default:
|
||||
fprintf(stderr, "unknown transform type %d\n", (int)transform.type);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void state::update_node_world_transform(instance_types::node & node_instance)
|
||||
{
|
||||
XMMATRIX world;
|
||||
|
||||
if (node_instance.node->parent_index >= 0)
|
||||
world = node_instances[node_instance.node->parent_index].world;
|
||||
else
|
||||
world = XMMatrixIdentity();
|
||||
|
||||
for (int i = 0; i < node_instance.node->transforms_count; i++) {
|
||||
world = transform_matrix(node_instance.transforms[i]) * world;
|
||||
}
|
||||
|
||||
node_instance.world = world;
|
||||
}
|
||||
}
|
||||
50
src/collada/scene.cpp
Normal file
50
src/collada/scene.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "collada/scene.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace collada::scene {
|
||||
|
||||
void state::load_scene(types::descriptor const * const descriptor)
|
||||
{
|
||||
this->descriptor = descriptor;
|
||||
|
||||
vulkan.create_pipelines(descriptor);
|
||||
vulkan.load_vertex_index_buffer(descriptor->position_normal_texture_buffer,
|
||||
descriptor->index_buffer);
|
||||
|
||||
node_state.allocate_node_instances(descriptor->nodes, descriptor->nodes_count);
|
||||
}
|
||||
|
||||
void state::draw()
|
||||
{
|
||||
for (int i = 0; i < descriptor->nodes_count; i++) {
|
||||
types::node const & node = *descriptor->nodes[i];
|
||||
instance_types::node const & node_instance = node_state.node_instances[i];
|
||||
|
||||
if (node.instance_geometries_count <= 0)
|
||||
continue;
|
||||
|
||||
vulkan.draw_node(i,
|
||||
node,
|
||||
node_instance);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void state::update(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
float t)
|
||||
{
|
||||
//t = animate::loop(t / 1.0f, 1.0f);
|
||||
|
||||
for (int i = 0; i < descriptor->nodes_count; i++) {
|
||||
//animate::animate_node(node_state.node_instances[i], t);
|
||||
node_state.update_node_world_transform(node_state.node_instances[i]);
|
||||
}
|
||||
|
||||
vulkan.transfer_transforms(projection,
|
||||
view,
|
||||
descriptor->nodes_count,
|
||||
node_state.node_instances);
|
||||
}
|
||||
}
|
||||
426
src/collada/scene/vulkan.cpp
Normal file
426
src/collada/scene/vulkan.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "volk/volk.h"
|
||||
#include "vulkan/vk_enum_string_helper.h"
|
||||
|
||||
#include "collada/inputs.h"
|
||||
#include "collada/scene/vulkan.h"
|
||||
|
||||
#include "vulkan_helper.h"
|
||||
|
||||
#include "check.h"
|
||||
#include "new.h"
|
||||
#include "file.h"
|
||||
|
||||
inline static uint32_t vulkan_semantic_location(char const * const semantic, int semantic_index)
|
||||
{
|
||||
if (strcmp(semantic, "POSITION") == 0 && semantic_index == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(semantic, "NORMAL") == 0 && semantic_index == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(semantic, "TEXCOORD") == 0 && semantic_index == 0) {
|
||||
return 2;
|
||||
}
|
||||
if (strcmp(semantic, "BLENDINDICES") == 0 && semantic_index == 0) {
|
||||
return 3;
|
||||
}
|
||||
if (strcmp(semantic, "BLENDWEIGHT") == 0 && semantic_index == 0) {
|
||||
return 4;
|
||||
}
|
||||
fprintf(stderr, "unknown semantic %s index %d\n", semantic, semantic_index);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
inline static VkFormat vulkan_format(collada::types::input_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case collada::types::input_format::FLOAT1: return VK_FORMAT_R32_SFLOAT;
|
||||
case collada::types::input_format::FLOAT2: return VK_FORMAT_R32G32_SFLOAT;
|
||||
case collada::types::input_format::FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT;
|
||||
case collada::types::input_format::FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case collada::types::input_format::INT1: return VK_FORMAT_R32_SINT;
|
||||
case collada::types::input_format::INT2: return VK_FORMAT_R32G32_SINT;
|
||||
case collada::types::input_format::INT3: return VK_FORMAT_R32G32B32_SINT;
|
||||
case collada::types::input_format::INT4: return VK_FORMAT_R32G32B32A32_SINT;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline static uint32_t vulkan_load_layout(collada::types::inputs const & inputs,
|
||||
uint32_t binding,
|
||||
uint32_t start_offset,
|
||||
VkVertexInputAttributeDescription * vertexAttributeDescriptions)
|
||||
{
|
||||
uint32_t offset = start_offset;
|
||||
for (int i = 0; i < inputs.elements_count; i++) {
|
||||
uint32_t location = vulkan_semantic_location(inputs.elements[i].semantic, inputs.elements[i].semantic_index);
|
||||
VkFormat format = vulkan_format(inputs.elements[i].format);
|
||||
vertexAttributeDescriptions[i].location = location;
|
||||
vertexAttributeDescriptions[i].binding = binding;
|
||||
vertexAttributeDescriptions[i].format = format;
|
||||
vertexAttributeDescriptions[i].offset = offset;
|
||||
offset += collada::inputs::format_size(inputs.elements[i].format);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
inline static void vulkan_vertex_input_states(collada::types::descriptor const * const descriptor,
|
||||
VkPipelineVertexInputStateCreateInfo * vertexInputStates,
|
||||
VkVertexInputBindingDescription * vertexBindingDescriptions)
|
||||
{
|
||||
for (int i = 0; i < descriptor->inputs_list_count; i++) {
|
||||
collada::types::inputs const & inputs = descriptor->inputs_list[i];
|
||||
VkVertexInputAttributeDescription * vertexAttributeDescriptions = NewM<VkVertexInputAttributeDescription>(inputs.elements_count);
|
||||
uint32_t stride = vulkan_load_layout(inputs,
|
||||
0, // binding
|
||||
0, // start_offset
|
||||
vertexAttributeDescriptions);
|
||||
|
||||
vertexBindingDescriptions[i] = {
|
||||
.binding = 0,
|
||||
.stride = stride,
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
};
|
||||
|
||||
vertexInputStates[i] = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &vertexBindingDescriptions[i],
|
||||
.vertexAttributeDescriptionCount = (uint32_t)inputs.elements_count,
|
||||
.pVertexAttributeDescriptions = vertexAttributeDescriptions,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace collada::scene {
|
||||
|
||||
void vulkan::initial_state(VkInstance instance,
|
||||
VkDevice device,
|
||||
VkPipelineLayout pipelineLayout,
|
||||
VkDescriptorSetLayout descriptorSetLayout,
|
||||
VkPhysicalDeviceProperties const & physicalDeviceProperties,
|
||||
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties,
|
||||
VkFormat colorFormat,
|
||||
VkFormat depthFormat,
|
||||
ShaderData * shaderData,
|
||||
ShaderDataDevice const * shaderDataDevice)
|
||||
{
|
||||
this->instance = instance;
|
||||
this->device = device;
|
||||
this->pipelineLayout = pipelineLayout;
|
||||
this->descriptorSetLayout = descriptorSetLayout;
|
||||
|
||||
this->physicalDeviceProperties = physicalDeviceProperties;
|
||||
this->physicalDeviceMemoryProperties = physicalDeviceMemoryProperties;
|
||||
|
||||
this->colorFormat = colorFormat;
|
||||
this->depthFormat = depthFormat;
|
||||
|
||||
this->shaderData = shaderData;
|
||||
this->shaderDataDevice = shaderDataDevice;
|
||||
|
||||
load_shader();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// vertex index buffer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::load_vertex_index_buffer(char const * vertex_filename,
|
||||
char const * index_filename)
|
||||
{
|
||||
uint32_t vertexSize;
|
||||
void const * vertexStart = file::open(vertex_filename, &vertexSize);
|
||||
uint32_t indexSize;
|
||||
void const * indexStart = file::open(index_filename, &indexSize);
|
||||
|
||||
vertexIndex.indexOffset = vertexSize; // + vertexJWStart;
|
||||
|
||||
// create buffer
|
||||
|
||||
VkDeviceSize bufferSize{ vertexSize + indexSize };
|
||||
VkBufferCreateInfo vertexIndexBufferCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = bufferSize,
|
||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
VK_CHECK(vkCreateBuffer(device, &vertexIndexBufferCreateInfo, nullptr, &vertexIndex.buffer));
|
||||
|
||||
// allocate memory
|
||||
|
||||
VkMemoryRequirements memoryRequirements;
|
||||
vkGetBufferMemoryRequirements(device, vertexIndex.buffer, &memoryRequirements);
|
||||
VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
|
||||
VkMemoryAllocateFlags memoryAllocateFlags{};
|
||||
|
||||
allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
memoryRequirements,
|
||||
memoryPropertyFlags,
|
||||
memoryAllocateFlags,
|
||||
1,
|
||||
&vertexIndex.memory);
|
||||
|
||||
VK_CHECK(vkBindBufferMemory(device, vertexIndex.buffer, vertexIndex.memory, 0));
|
||||
|
||||
// copy data
|
||||
|
||||
void * vertexIndexMappedData;
|
||||
VK_CHECK(vkMapMemory(device, vertexIndex.memory, 0, vertexIndexBufferCreateInfo.size, 0, &vertexIndexMappedData));
|
||||
memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + 0), vertexStart, vertexSize);
|
||||
memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize), indexStart, indexSize);
|
||||
|
||||
VkMappedMemoryRange mappedMemoryRange{
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.memory = vertexIndex.memory,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
};
|
||||
vkFlushMappedMemoryRanges(device, 1, &mappedMemoryRange);
|
||||
|
||||
vkUnmapMemory(device, vertexIndex.memory);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// shader
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::load_shader()
|
||||
{
|
||||
uint32_t shaderSize;
|
||||
void const * shaderStart = file::open("shader/collada.spv", &shaderSize);
|
||||
|
||||
VkShaderModuleCreateInfo shaderModuleCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = shaderSize,
|
||||
.pCode = (uint32_t *)shaderStart
|
||||
};
|
||||
VK_CHECK(vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &shaderModule));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// pipeline
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::create_pipelines(collada::types::descriptor const * const descriptor)
|
||||
{
|
||||
VkPushConstantRange pushConstantRange{
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.size = (sizeof (int32_t))
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &descriptorSetLayout,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pushConstantRange
|
||||
};
|
||||
VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2]{
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = shaderModule,
|
||||
.pName = "VSMain"
|
||||
},
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = shaderModule,
|
||||
.pName = "PSMain"
|
||||
}
|
||||
};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1
|
||||
};
|
||||
|
||||
constexpr uint32_t dynamicStateCount = 2;
|
||||
VkDynamicState dynamicStates[dynamicStateCount]{
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamicState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = dynamicStateCount,
|
||||
.pDynamicStates = dynamicStates
|
||||
};
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.depthTestEnable = VK_TRUE,
|
||||
.depthWriteEnable = VK_TRUE,
|
||||
.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
|
||||
.stencilTestEnable = VK_TRUE,
|
||||
.front = {
|
||||
.failOp = VK_STENCIL_OP_REPLACE,
|
||||
.passOp = VK_STENCIL_OP_REPLACE,
|
||||
.depthFailOp = VK_STENCIL_OP_REPLACE,
|
||||
.compareOp = VK_COMPARE_OP_ALWAYS,
|
||||
.compareMask = 0x01,
|
||||
.writeMask = 0x01,
|
||||
.reference = 1,
|
||||
},
|
||||
};
|
||||
|
||||
VkPipelineRenderingCreateInfo renderingCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachmentFormats = &colorFormat,
|
||||
.depthAttachmentFormat = depthFormat,
|
||||
.stencilAttachmentFormat = depthFormat
|
||||
};
|
||||
|
||||
VkPipelineColorBlendAttachmentState blendAttachment{
|
||||
.colorWriteMask = 0xF
|
||||
};
|
||||
VkPipelineColorBlendStateCreateInfo colorBlendState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &blendAttachment
|
||||
};
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
//.cullMode = VK_CULL_MODE_NONE,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
.lineWidth = 1.0f
|
||||
};
|
||||
VkPipelineMultisampleStateCreateInfo multisampleState{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo * vertexInputStates = NewM<VkPipelineVertexInputStateCreateInfo>(descriptor->inputs_list_count);
|
||||
VkVertexInputBindingDescription * vertexBindingDescriptions = NewM<VkVertexInputBindingDescription>(descriptor->inputs_list_count);
|
||||
vulkan_vertex_input_states(descriptor,
|
||||
vertexInputStates,
|
||||
vertexBindingDescriptions);
|
||||
|
||||
VkGraphicsPipelineCreateInfo * pipelineCreateInfos = NewM<VkGraphicsPipelineCreateInfo>(descriptor->inputs_list_count);
|
||||
|
||||
for (int i = 0; i < descriptor->inputs_list_count; i++) {
|
||||
pipelineCreateInfos[i] = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = &renderingCreateInfo,
|
||||
.stageCount = 2,
|
||||
.pStages = shaderStages,
|
||||
.pVertexInputState = &vertexInputStates[i],
|
||||
.pInputAssemblyState = &inputAssemblyState,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizationState,
|
||||
.pMultisampleState = &multisampleState,
|
||||
.pDepthStencilState = &depthStencilState,
|
||||
.pColorBlendState = &colorBlendState,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = pipelineLayout
|
||||
};
|
||||
};
|
||||
|
||||
pipelines = NewM<VkPipeline>(descriptor->inputs_list_count);
|
||||
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, descriptor->inputs_list_count, pipelineCreateInfos, nullptr, pipelines));
|
||||
|
||||
free(vertexBindingDescriptions);
|
||||
for (int i = 0; i < descriptor->inputs_list_count; i++) {
|
||||
free((void *)vertexInputStates[i].pVertexAttributeDescriptions);
|
||||
}
|
||||
free(vertexInputStates);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// draw
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::draw_geometry(types::geometry const & geometry,
|
||||
types::instance_material const * const instance_materials,
|
||||
int const instance_materials_count)
|
||||
{
|
||||
types::mesh const& mesh = geometry.mesh;
|
||||
|
||||
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset + mesh.index_buffer_offset, VK_INDEX_TYPE_UINT32);
|
||||
|
||||
for (int j = 0; j < instance_materials_count; j++) {
|
||||
types::instance_material const& instance_material = instance_materials[j];
|
||||
types::triangles const& triangles = mesh.triangles[instance_material.element_index];
|
||||
|
||||
//set_instance_material(instance_material);
|
||||
|
||||
VkDeviceSize vertexOffset{ (VkDeviceSize)mesh.vertex_buffer_offset };
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndex.buffer, &vertexOffset);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[triangles.inputs_index]);
|
||||
|
||||
uint32_t indexCount = triangles.count * 3;
|
||||
vkCmdDrawIndexed(commandBuffer, indexCount, 1, triangles.index_offset, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan::draw_instance_geometries(types::instance_geometry const * const instance_geometries,
|
||||
int const instance_geometries_count)
|
||||
{
|
||||
for (int i = 0; i < instance_geometries_count; i++) {
|
||||
types::instance_geometry const &instance_geometry = instance_geometries[i];
|
||||
draw_geometry(*instance_geometry.geometry,
|
||||
instance_geometry.instance_materials,
|
||||
instance_geometry.instance_materials_count);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan::transfer_transforms(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
int nodes_count,
|
||||
instance_types::node const * const node_instances)
|
||||
{
|
||||
// store
|
||||
XMStoreFloat4x4(&shaderData->projection, projection);
|
||||
XMVECTOR lightPosition = XMVector3Transform(XMVectorSet(-42, -40, 156, 0), view);
|
||||
XMStoreFloat4(&shaderData->lightPosition, lightPosition);
|
||||
|
||||
for (int i = 0; i < nodes_count; i++) {
|
||||
XMMATRIX model_view = node_instances[i].world * view;
|
||||
XMStoreFloat4x4(&shaderData->modelView[i], model_view);
|
||||
}
|
||||
|
||||
// copy
|
||||
|
||||
size_t frameOffset = shaderDataDevice->stride * frameIndex;
|
||||
void * frameData = (void *)(((VkDeviceSize)shaderDataDevice->mappedData) + frameOffset);
|
||||
VkDeviceSize frameSize{ (sizeof (ShaderData)) };
|
||||
memcpy(frameData, &shaderData->projection, frameSize);
|
||||
|
||||
// flush
|
||||
|
||||
VkDeviceSize flushSize{ roundAlignment(frameSize, physicalDeviceProperties.limits.nonCoherentAtomSize) };
|
||||
VkMappedMemoryRange shaderDataMemoryRange{
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.memory = shaderDataDevice->memory,
|
||||
.offset = frameOffset,
|
||||
.size = flushSize,
|
||||
};
|
||||
vkFlushMappedMemoryRanges(device, 1, &shaderDataMemoryRange);
|
||||
}
|
||||
|
||||
void vulkan::draw_node(int32_t node_index,
|
||||
types::node const & node,
|
||||
instance_types::node const & node_instance)
|
||||
{
|
||||
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (sizeof (int32_t)), &node_index);
|
||||
|
||||
draw_instance_geometries(node.instance_geometries, node.instance_geometries_count);
|
||||
}
|
||||
}
|
||||
275
src/main.cpp
275
src/main.cpp
@ -7,9 +7,17 @@
|
||||
#include "SDL3/SDL_vulkan.h"
|
||||
#include "directxmath/directxmath.h"
|
||||
|
||||
#include "check.h"
|
||||
#include "new.h"
|
||||
#include "file.h"
|
||||
#include "dds_validate.h"
|
||||
#include "vulkan_helper.h"
|
||||
#include "shader_data.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)
|
||||
@ -29,61 +37,6 @@ inline static constexpr T clamp(T n, T minVal, T maxVal)
|
||||
return min(max(n, minVal), maxVal);
|
||||
}
|
||||
|
||||
#define SDL_CHECK(f) \
|
||||
{ \
|
||||
bool result = (f); \
|
||||
if (result != true) { \
|
||||
fprintf(stderr, "SDL: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, SDL_GetError()); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SDL_CHECK_NONNULL(f) \
|
||||
{ \
|
||||
void * ptr = (void *)(f); \
|
||||
if (ptr == nullptr) { \
|
||||
fprintf(stderr, "SDL: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, SDL_GetError()); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VK_CHECK(f) \
|
||||
{ \
|
||||
VkResult result = (f); \
|
||||
if (result != VK_SUCCESS) { \
|
||||
fprintf(stderr, "VK: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, string_VkResult(result)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VK_CHECK_SWAPCHAIN(f) \
|
||||
{ \
|
||||
VkResult result = (f); \
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { \
|
||||
updateSwapchain = true; \
|
||||
} else if (result != VK_SUCCESS) { \
|
||||
fprintf(stderr, "VK: %s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, string_VkResult(result)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ASSERT(expr, msg) \
|
||||
{ \
|
||||
bool result = (expr); \
|
||||
if (result != true) { \
|
||||
fprintf(stderr, "%s %s L%d error: `%s`\n", __FILE__, __func__, __LINE__, msg); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||
#define UNREACHABLE() __assume(false);
|
||||
#else // GCC, Clang
|
||||
#define UNREACHABLE() __builtin_unreachable();
|
||||
#endif
|
||||
|
||||
constexpr uint32_t maxFramesInFlight{ 2 };
|
||||
|
||||
VkInstance instance{ VK_NULL_HANDLE };
|
||||
VkDevice device{ VK_NULL_HANDLE };
|
||||
VkQueue queue{ VK_NULL_HANDLE };
|
||||
@ -131,25 +84,7 @@ VkDescriptorSet textureDescriptorSet{ VK_NULL_HANDLE };
|
||||
|
||||
XMINT2 windowSize{};
|
||||
|
||||
struct ShaderData {
|
||||
XMFLOAT4X4 transform;
|
||||
XMFLOAT4X4 modelView;
|
||||
XMFLOAT4 lightPosition;
|
||||
uint32_t selected;
|
||||
};
|
||||
|
||||
ShaderData shaderData{};
|
||||
|
||||
struct ShaderDataDevice {
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceAddress stride;
|
||||
void * mappedData;
|
||||
struct {
|
||||
VkBuffer buffer{ VK_NULL_HANDLE };
|
||||
VkDeviceAddress deviceAddress{};
|
||||
} frame[maxFramesInFlight];
|
||||
};
|
||||
|
||||
ShaderDataDevice shaderDataDevice{};
|
||||
|
||||
void print_memoryPropertyFlags(VkMemoryPropertyFlags propertyFlags)
|
||||
@ -167,48 +102,22 @@ void print_memoryPropertyFlags(VkMemoryPropertyFlags propertyFlags)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
uint32_t findMemoryTypeIndex(VkPhysicalDeviceMemoryProperties const & memoryProperties, uint32_t memoryTypeBits, VkMemoryPropertyFlags propertyFlags)
|
||||
{
|
||||
// find an exact match
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
if (!(memoryTypeBits & (1u << i)))
|
||||
continue;
|
||||
|
||||
if (memoryProperties.memoryTypes[i].propertyFlags == propertyFlags) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// find a partial match
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
if (!(memoryTypeBits & (1u << i)))
|
||||
continue;
|
||||
|
||||
if ((memoryProperties.memoryTypes[i].propertyFlags & propertyFlags) == propertyFlags) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(false, "no memory type index matching memoryTypeBits and propertyFlags");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
XMMATRIX currentProjection()
|
||||
{
|
||||
float fov_angle_y = XMConvertToRadians(45 * 1.0);
|
||||
float aspect_ratio = (float)windowSize.x / (float)windowSize.y;
|
||||
float near_z = 0.1;
|
||||
float far_z = 100.0;
|
||||
XMMATRIX projection = XMMatrixPerspectiveFovRH(fov_angle_y, aspect_ratio, near_z, far_z);
|
||||
float far_z = 1000.0;
|
||||
XMMATRIX projection = XMMatrixPerspectiveFovLH(fov_angle_y, aspect_ratio, near_z, far_z);
|
||||
return projection;
|
||||
}
|
||||
|
||||
XMMATRIX currentView()
|
||||
{
|
||||
XMVECTOR eye = XMVectorSet(0, -3, 0, 0);
|
||||
XMVECTOR eye = XMVectorSet(-57, 159, 269, 0);
|
||||
XMVECTOR at = XMVectorSet(0, 0, 0, 0);
|
||||
XMVECTOR up = XMVectorSet(0, 0, 1, 0);
|
||||
XMMATRIX view = XMMatrixLookAtRH(eye, at, up);
|
||||
XMMATRIX view = XMMatrixLookAtLH(eye, at, up);
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -220,7 +129,7 @@ XMMATRIX currentModel()
|
||||
return XMMatrixTranslation(0, 0, 0.0) * XMMatrixRotationX(theta) * XMMatrixRotationZ(XM_PI * 0.5f);
|
||||
}
|
||||
|
||||
void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, VkPhysicalDeviceMemoryProperties const & memoryProperties, VkSurfaceCapabilitiesKHR const & surfaceCapabilities)
|
||||
void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkSurfaceCapabilitiesKHR const & surfaceCapabilities)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// swapchain and images
|
||||
@ -339,14 +248,14 @@ void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, V
|
||||
VkMemoryPropertyFlags depthImageMemoryPropertyFlags{
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
};
|
||||
uint32_t depthImageMemoryTypeIndex = findMemoryTypeIndex(memoryProperties, depthImageMemoryRequirements.memoryTypeBits, depthImageMemoryPropertyFlags);
|
||||
VkMemoryAllocateInfo depthImageAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = depthImageMemoryRequirements.size,
|
||||
.memoryTypeIndex = depthImageMemoryTypeIndex,
|
||||
};
|
||||
|
||||
VK_CHECK(vkAllocateMemory(device, &depthImageAllocateInfo, nullptr, &depthImageMemory));
|
||||
VkMemoryAllocateFlags depthImageMemoryAllocateFlags{ };
|
||||
allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
depthImageMemoryRequirements,
|
||||
depthImageMemoryPropertyFlags,
|
||||
depthImageMemoryAllocateFlags,
|
||||
1,
|
||||
&depthImageMemory);
|
||||
VK_CHECK(vkBindImageMemory(device, depthImage, depthImageMemory, 0));
|
||||
|
||||
VkImageViewCreateInfo depthViewCreateInfo{
|
||||
@ -363,41 +272,6 @@ void recreateSwapchain(VkSurfaceFormatKHR surfaceFormat, VkFormat depthFormat, V
|
||||
VK_CHECK(vkCreateImageView(device, &depthViewCreateInfo, nullptr, &depthImageView));
|
||||
}
|
||||
|
||||
inline static constexpr VkDeviceSize roundAlignment(VkDeviceSize offset, VkDeviceSize alignment)
|
||||
{
|
||||
// must be a power of two
|
||||
assert(alignment && ((alignment & (alignment - 1)) == 0));
|
||||
return (offset + (alignment - 1)) & (-alignment);
|
||||
}
|
||||
|
||||
VkDeviceSize allocateFromMemoryRequirements(VkPhysicalDeviceMemoryProperties2 const & physicalDeviceMemoryProperties,
|
||||
VkMemoryRequirements const & memoryRequirements,
|
||||
VkMemoryPropertyFlags memoryPropertyFlags,
|
||||
VkMemoryAllocateFlags memoryAllocateFlags,
|
||||
uint32_t count,
|
||||
VkDeviceMemory * memory)
|
||||
{
|
||||
uint32_t memoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties.memoryProperties,
|
||||
memoryRequirements.memoryTypeBits,
|
||||
memoryPropertyFlags);
|
||||
|
||||
VkDeviceSize stride = (count == 1) ? memoryRequirements.size : roundAlignment(memoryRequirements.size, memoryRequirements.alignment);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
|
||||
.flags = memoryAllocateFlags,
|
||||
};
|
||||
VkMemoryAllocateInfo memoryAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &memoryAllocateFlagsInfo,
|
||||
.allocationSize = stride * count,
|
||||
.memoryTypeIndex = memoryTypeIndex,
|
||||
};
|
||||
VK_CHECK(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, memory));
|
||||
|
||||
return stride;
|
||||
}
|
||||
|
||||
inline static int positive_modulo(int i, unsigned int n) {
|
||||
return (i % n + n) % n;
|
||||
}
|
||||
@ -484,21 +358,21 @@ int main()
|
||||
// memory
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkPhysicalDeviceMemoryProperties2 physicalDeviceMemoryProperties{
|
||||
VkPhysicalDeviceMemoryProperties2 physicalDeviceMemoryProperties2{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2,
|
||||
.pNext = nullptr
|
||||
};
|
||||
vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &physicalDeviceMemoryProperties);
|
||||
vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &physicalDeviceMemoryProperties2);
|
||||
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties = physicalDeviceMemoryProperties2.memoryProperties;
|
||||
if constexpr (true) {
|
||||
VkPhysicalDeviceMemoryProperties const & memoryProperties = physicalDeviceMemoryProperties.memoryProperties;
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
for (uint32_t i = 0; i < physicalDeviceMemoryProperties.memoryTypeCount; i++) {
|
||||
printf("memoryTypes[%u].propertyFlags: ", i);
|
||||
print_memoryPropertyFlags(memoryProperties.memoryTypes[i].propertyFlags);
|
||||
printf("memoryTypes[%u].heapIndex: %u\n", i, memoryProperties.memoryTypes[i].heapIndex);
|
||||
print_memoryPropertyFlags(physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags);
|
||||
printf("memoryTypes[%u].heapIndex: %u\n", i, physicalDeviceMemoryProperties.memoryTypes[i].heapIndex);
|
||||
}
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; i++) {
|
||||
printf("memoryHeaps[%u].size %lu\n", i, memoryProperties.memoryHeaps[i].size);
|
||||
printf("memoryHeaps[%u].flags %08x\n", i, memoryProperties.memoryHeaps[i].flags);
|
||||
for (uint32_t i = 0; i < physicalDeviceMemoryProperties.memoryHeapCount; i++) {
|
||||
printf("memoryHeaps[%u].size %lu\n", i, physicalDeviceMemoryProperties.memoryHeaps[i].size);
|
||||
printf("memoryHeaps[%u].flags %08x\n", i, physicalDeviceMemoryProperties.memoryHeaps[i].flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,7 +459,7 @@ 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.memoryProperties, surfaceCapabilities);
|
||||
recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceMemoryProperties, surfaceCapabilities);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// mesh
|
||||
@ -613,7 +487,8 @@ int main()
|
||||
VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
|
||||
VkMemoryAllocateFlags memoryAllocateFlags{};
|
||||
|
||||
allocateFromMemoryRequirements(physicalDeviceMemoryProperties,
|
||||
allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
memoryRequirements,
|
||||
memoryPropertyFlags,
|
||||
memoryAllocateFlags,
|
||||
@ -659,7 +534,8 @@ int main()
|
||||
|
||||
VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
|
||||
VkMemoryAllocateFlags memoryAllocateFlags{ };
|
||||
shaderDataDevice.stride = allocateFromMemoryRequirements(physicalDeviceMemoryProperties,
|
||||
shaderDataDevice.stride = allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
memoryRequirements,
|
||||
memoryPropertyFlags,
|
||||
memoryAllocateFlags,
|
||||
@ -748,15 +624,14 @@ int main()
|
||||
VkMemoryPropertyFlags textureImageMemoryPropertyFlags{
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
};
|
||||
uint32_t textureImageMemoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties.memoryProperties, textureImageMemoryRequirements.memoryTypeBits, textureImageMemoryPropertyFlags);
|
||||
|
||||
VkMemoryAllocateInfo textureImageAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = textureImageMemoryRequirements.size,
|
||||
.memoryTypeIndex = textureImageMemoryTypeIndex,
|
||||
};
|
||||
|
||||
VK_CHECK(vkAllocateMemory(device, &textureImageAllocateInfo, nullptr, &textureImageMemory));
|
||||
VkMemoryAllocateFlags textureImageMemoryAllocateFlags{ };
|
||||
allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
textureImageMemoryRequirements,
|
||||
textureImageMemoryPropertyFlags,
|
||||
textureImageMemoryAllocateFlags,
|
||||
1,
|
||||
&textureImageMemory);
|
||||
VK_CHECK(vkBindImageMemory(device, textureImage, textureImageMemory, 0));
|
||||
|
||||
VkImageViewCreateInfo textureViewCreateInfo{
|
||||
@ -786,14 +661,15 @@ int main()
|
||||
VkMemoryPropertyFlags textureSourceBufferMemoryPropertyFlags{
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
};
|
||||
uint32_t textureSourceBufferMemoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties.memoryProperties, textureSourceBufferMemoryRequirements.memoryTypeBits, textureSourceBufferMemoryPropertyFlags);
|
||||
VkMemoryAllocateInfo textureSourceBufferAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = textureSourceBufferMemoryRequirements.size,
|
||||
.memoryTypeIndex = textureSourceBufferMemoryTypeIndex,
|
||||
};
|
||||
VkMemoryAllocateFlags textureSourceBufferMemoryAllocateFlags{ };
|
||||
VkDeviceMemory textureSourceBufferMemory;
|
||||
VK_CHECK(vkAllocateMemory(device, &textureSourceBufferAllocateInfo, nullptr, &textureSourceBufferMemory));
|
||||
allocateFromMemoryRequirements(device,
|
||||
physicalDeviceMemoryProperties,
|
||||
textureSourceBufferMemoryRequirements,
|
||||
textureSourceBufferMemoryPropertyFlags,
|
||||
textureSourceBufferMemoryAllocateFlags,
|
||||
1,
|
||||
&textureSourceBufferMemory);
|
||||
VK_CHECK(vkBindBufferMemory(device, textureSourceBuffer, textureSourceBufferMemory, 0));
|
||||
|
||||
void * textureSourceMappedData;
|
||||
@ -1290,6 +1166,25 @@ int main()
|
||||
};
|
||||
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 2, pipelineCreateInfos, nullptr, pipelines));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// initialize collada
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
collada::scene::state collada_state;
|
||||
|
||||
collada_state.vulkan.initial_state(instance,
|
||||
device,
|
||||
pipelineLayout,
|
||||
uniformBufferDescriptorSetLayout,
|
||||
physicalDeviceProperties,
|
||||
physicalDeviceMemoryProperties,
|
||||
surfaceFormat.format,
|
||||
depthFormat,
|
||||
&shaderData,
|
||||
&shaderDataDevice);
|
||||
|
||||
collada_state.load_scene(&shadow_test::descriptor);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// loop
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -1330,6 +1225,8 @@ int main()
|
||||
}
|
||||
|
||||
// shader data
|
||||
|
||||
/*
|
||||
XMMATRIX model = currentModel();
|
||||
XMMATRIX view = currentView();
|
||||
XMMATRIX modelView = model * view;
|
||||
@ -1351,7 +1248,7 @@ int main()
|
||||
.size = flushSize,
|
||||
};
|
||||
vkFlushMappedMemoryRanges(device, 1, &shaderDataMemoryRange);
|
||||
|
||||
*/
|
||||
|
||||
// wait for fence
|
||||
VK_CHECK(vkWaitForFences(device, 1, &fences[frameIndex], true, UINT64_MAX));
|
||||
@ -1437,6 +1334,8 @@ int main()
|
||||
vkCmdBeginRendering(commandBuffer, &renderingInfo);
|
||||
|
||||
VkViewport viewport{
|
||||
.x = 0,
|
||||
.y = 0,//static_cast<float>(windowSize.y),
|
||||
.width = static_cast<float>(windowSize.x),
|
||||
.height = static_cast<float>(windowSize.y),
|
||||
.minDepth = 0.0f,
|
||||
@ -1446,12 +1345,13 @@ int main()
|
||||
VkRect2D scissor{ .extent{ .width = (uint32_t)windowSize.x, .height = (uint32_t)windowSize.y } };
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
VkDeviceSize vertexOffset{ 0 };
|
||||
/*
|
||||
VkDescriptorSet descriptorSets[2] = {
|
||||
uniformBufferDescriptorSets[frameIndex],
|
||||
textureDescriptorSet,
|
||||
};
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, descriptorSets, 0, nullptr);
|
||||
VkDeviceSize vertexOffset{ 0 };
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexIndexBuffer, &vertexOffset);
|
||||
VkDeviceSize indexOffset{ vertexBufferSize };
|
||||
vkCmdBindIndexBuffer(commandBuffer, vertexIndexBuffer, indexOffset, VK_INDEX_TYPE_UINT32);
|
||||
@ -1459,10 +1359,25 @@ int main()
|
||||
VkDeviceSize indexCount{ 2400 };
|
||||
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[MAIN_PIPELINE]);
|
||||
vkCmdDrawIndexed(commandBuffer, indexCount, 3, 0, 0, 0);
|
||||
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||
|
||||
//vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[OUTLINE_PIPELINE]);
|
||||
//vkCmdDrawIndexed(commandBuffer, indexCount, 3, 0, 0, 0);
|
||||
//vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||
*/
|
||||
|
||||
collada_state.vulkan.commandBuffer = commandBuffer;
|
||||
collada_state.vulkan.frameIndex = frameIndex;
|
||||
|
||||
XMMATRIX projection = currentProjection();
|
||||
XMMATRIX view = currentView();
|
||||
collada_state.update(projection, view, 0);
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
collada_state.vulkan.pipelineLayout,
|
||||
0, 1, &uniformBufferDescriptorSets[frameIndex],
|
||||
0, nullptr);
|
||||
|
||||
collada_state.draw();
|
||||
|
||||
vkCmdEndRendering(commandBuffer);
|
||||
|
||||
@ -1520,7 +1435,7 @@ int main()
|
||||
updateSwapchain = false;
|
||||
VK_CHECK(vkDeviceWaitIdle(device));
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCapabilities));
|
||||
recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceMemoryProperties.memoryProperties, surfaceCapabilities);
|
||||
recreateSwapchain(surfaceFormat, depthFormat, physicalDeviceMemoryProperties, surfaceCapabilities);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
64
src/vulkan_helper.cpp
Normal file
64
src/vulkan_helper.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "volk/volk.h"
|
||||
#include "vulkan/vk_enum_string_helper.h"
|
||||
|
||||
#include "check.h"
|
||||
|
||||
#include "vulkan_helper.h"
|
||||
|
||||
inline static uint32_t findMemoryTypeIndex(VkPhysicalDeviceMemoryProperties const & memoryProperties, uint32_t memoryTypeBits, VkMemoryPropertyFlags propertyFlags)
|
||||
{
|
||||
// find an exact match
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
if (!(memoryTypeBits & (1u << i)))
|
||||
continue;
|
||||
|
||||
if (memoryProperties.memoryTypes[i].propertyFlags == propertyFlags) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// find a partial match
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
||||
if (!(memoryTypeBits & (1u << i)))
|
||||
continue;
|
||||
|
||||
if ((memoryProperties.memoryTypes[i].propertyFlags & propertyFlags) == propertyFlags) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(false, "no memory type index matching memoryTypeBits and propertyFlags");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
VkDeviceSize allocateFromMemoryRequirements(VkDevice device,
|
||||
VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties,
|
||||
VkMemoryRequirements const & memoryRequirements,
|
||||
VkMemoryPropertyFlags memoryPropertyFlags,
|
||||
VkMemoryAllocateFlags memoryAllocateFlags,
|
||||
uint32_t count,
|
||||
VkDeviceMemory * memory)
|
||||
{
|
||||
uint32_t memoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties,
|
||||
memoryRequirements.memoryTypeBits,
|
||||
memoryPropertyFlags);
|
||||
|
||||
VkDeviceSize stride = (count == 1) ? memoryRequirements.size : roundAlignment(memoryRequirements.size, memoryRequirements.alignment);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
|
||||
.flags = memoryAllocateFlags,
|
||||
};
|
||||
VkMemoryAllocateInfo memoryAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &memoryAllocateFlagsInfo,
|
||||
.allocationSize = stride * count,
|
||||
.memoryTypeIndex = memoryTypeIndex,
|
||||
};
|
||||
VK_CHECK(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, memory));
|
||||
|
||||
return stride;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user