minecraft: send view and projection matrices to vertex shader
This commit is contained in:
parent
4cc844addf
commit
46924c8451
2
Makefile
2
Makefile
@ -25,7 +25,7 @@ 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)
|
||||
|
||||
@ -1,12 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "directxmath/directxmath.h"
|
||||
#include "volk/volk.h"
|
||||
|
||||
#include "minecraft/vulkan/per_world.h"
|
||||
|
||||
namespace minecraft::vulkan {
|
||||
|
||||
struct Scene {
|
||||
XMFLOAT4X4 projection;
|
||||
XMFLOAT4X4 view;
|
||||
XMFLOAT4X4 shadowProjection;
|
||||
XMFLOAT4X4 shadowView;
|
||||
XMFLOAT4 lightPosition;
|
||||
};
|
||||
|
||||
struct vulkan {
|
||||
static constexpr uint32_t maxFrames = 2;
|
||||
static constexpr uint32_t perFrameDescriptorCount = 1;
|
||||
static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount;
|
||||
static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 0;
|
||||
|
||||
static constexpr int perVertexSize = (3 + 3 + 2) * 2;
|
||||
static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2;
|
||||
|
||||
struct {
|
||||
VkDeviceSize jointWeightOffset;
|
||||
VkDeviceSize indexOffset;
|
||||
@ -35,8 +52,22 @@ namespace minecraft::vulkan {
|
||||
|
||||
per_world * worlds;
|
||||
|
||||
static constexpr int perVertexSize = (3 + 3 + 2) * 2;
|
||||
static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2;
|
||||
VkDescriptorPool descriptorPool{ VK_NULL_HANDLE };
|
||||
|
||||
VkDescriptorSetLayout descriptorSetLayouts[1]; // unrelated to maxFrames, unrelated to descriptorCount
|
||||
VkDescriptorSet descriptorSets0[maxFrames];
|
||||
|
||||
struct {
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize memorySize;
|
||||
void * mappedData;
|
||||
struct { // must match perFrameDescriptorCount
|
||||
VkBuffer sceneBuffer;
|
||||
VkDeviceAddress sceneOffset;
|
||||
VkDeviceAddress sceneSize;
|
||||
Scene * sceneMapped;
|
||||
} frame[maxFrames];
|
||||
} shaderDataDevice;
|
||||
|
||||
void initial_state(VkInstance instance,
|
||||
VkDevice device,
|
||||
@ -52,6 +83,14 @@ namespace minecraft::vulkan {
|
||||
void load_shader();
|
||||
void create_pipeline();
|
||||
void load_worlds();
|
||||
void draw(VkCommandBuffer commandBuffer);
|
||||
void create_uniform_buffers();
|
||||
void create_descriptor_sets();
|
||||
void write_descriptor_sets();
|
||||
void transfer_transforms(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
uint32_t frameIndex);
|
||||
|
||||
void draw(VkCommandBuffer commandBuffer,
|
||||
uint32_t frameIndex);
|
||||
};
|
||||
}
|
||||
|
||||
@ -16,11 +16,24 @@ struct VSOutput
|
||||
float4 Position : SV_POSITION;
|
||||
};
|
||||
|
||||
struct Scene
|
||||
{
|
||||
column_major float4x4 Projection;
|
||||
column_major float4x4 View;
|
||||
column_major float4x4 ShadowProjection;
|
||||
column_major float4x4 ShadowView;
|
||||
float4 LightPosition; // view space
|
||||
};
|
||||
|
||||
// set 0: per-frame
|
||||
[[vk::binding(0, 0)]] ConstantBuffer<Scene> Scene;
|
||||
|
||||
[shader("vertex")]
|
||||
VSOutput VSMain(VSInput input)
|
||||
{
|
||||
VSOutput output = (VSOutput)0;
|
||||
output.Position = float4(input.Position.xyz + input.BlockPosition, 1.0);
|
||||
float4 Position = float4(input.Position.xyz + input.BlockPosition, 1.0);
|
||||
output.Position = mul(Scene.Projection, mul(Scene.View, Position));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@ -722,6 +722,12 @@ int main()
|
||||
lightPositionWorld,
|
||||
collada_state.descriptor->nodes_count,
|
||||
collada_state.node_state.node_instances);
|
||||
|
||||
// minecraft
|
||||
|
||||
minecraft_state.transfer_transforms(projection,
|
||||
view,
|
||||
frameIndex);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -922,7 +928,7 @@ int main()
|
||||
//collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline
|
||||
//collada_state.draw();
|
||||
|
||||
minecraft_state.draw(commandBuffer);
|
||||
minecraft_state.draw(commandBuffer, frameIndex);
|
||||
|
||||
vkCmdEndRendering(commandBuffer);
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@ namespace minecraft::vulkan {
|
||||
{
|
||||
load_vertex_index_buffer("data/minecraft/per_vertex.vtx", "data/minecraft/configuration.idx");
|
||||
load_shader();
|
||||
create_uniform_buffers();
|
||||
create_descriptor_sets();
|
||||
write_descriptor_sets();
|
||||
create_pipeline();
|
||||
load_worlds();
|
||||
}
|
||||
@ -139,8 +142,8 @@ namespace minecraft::vulkan {
|
||||
{
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
//.setLayoutCount = 2,
|
||||
//.pSetLayouts = descriptorSetLayouts,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = descriptorSetLayouts,
|
||||
//.pushConstantRangeCount = 0,
|
||||
//.pPushConstantRanges = nullptr
|
||||
};
|
||||
@ -332,6 +335,150 @@ namespace minecraft::vulkan {
|
||||
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, pipelineCreateInfos, nullptr, &pipeline));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// uniform buffers
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::create_uniform_buffers()
|
||||
{
|
||||
VkMemoryRequirements memoryRequirements[uniformBufferDescriptorCount];
|
||||
VkDeviceSize offsets[uniformBufferDescriptorCount];
|
||||
|
||||
uint32_t memoryRequirementsIndex = 0;
|
||||
// per-frame
|
||||
for (uint32_t i = 0; i < maxFrames; i++) {
|
||||
VkBufferCreateInfo sceneBufferCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = (sizeof (Scene)),
|
||||
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
|
||||
VK_CHECK(vkCreateBuffer(device, &sceneBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].sceneBuffer));
|
||||
vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].sceneBuffer, &memoryRequirements[memoryRequirementsIndex++]);
|
||||
}
|
||||
|
||||
assert(memoryRequirementsIndex == uniformBufferDescriptorCount);
|
||||
|
||||
VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
|
||||
VkMemoryAllocateFlags memoryAllocateFlags{ };
|
||||
shaderDataDevice.memorySize = allocateFromMemoryRequirements2(device,
|
||||
physicalDeviceProperties.limits.nonCoherentAtomSize,
|
||||
physicalDeviceMemoryProperties,
|
||||
memoryPropertyFlags,
|
||||
memoryAllocateFlags,
|
||||
uniformBufferDescriptorCount,
|
||||
memoryRequirements,
|
||||
&shaderDataDevice.memory,
|
||||
offsets);
|
||||
|
||||
VkDeviceSize offset{ 0 };
|
||||
VkDeviceSize size{ VK_WHOLE_SIZE };
|
||||
VkMemoryMapFlags flags{ 0 };
|
||||
VK_CHECK(vkMapMemory(device, shaderDataDevice.memory, offset, size, flags, &shaderDataDevice.mappedData));
|
||||
|
||||
uint32_t offsetsIndex = 0;
|
||||
// this must match the same order as memoryRequirements
|
||||
for (uint32_t i = 0; i < maxFrames; i++) {
|
||||
shaderDataDevice.frame[i].sceneOffset = offsets[offsetsIndex];
|
||||
shaderDataDevice.frame[i].sceneSize = memoryRequirements[offsetsIndex++].size;
|
||||
shaderDataDevice.frame[i].sceneMapped = (Scene *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].sceneOffset);
|
||||
VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].sceneBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].sceneOffset));
|
||||
}
|
||||
assert(offsetsIndex == uniformBufferDescriptorCount);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// descriptor sets
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::create_descriptor_sets()
|
||||
{
|
||||
//
|
||||
// pool
|
||||
//
|
||||
constexpr int descriptorPoolSizesCount = 1;
|
||||
VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{
|
||||
{
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = (maxFrames * 1),
|
||||
},
|
||||
};
|
||||
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = maxFrames,
|
||||
.poolSizeCount = descriptorPoolSizesCount,
|
||||
.pPoolSizes = descriptorPoolSizes
|
||||
};
|
||||
VK_CHECK(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
||||
|
||||
//
|
||||
// uniform buffer descriptor set layout/allocation (set 0, per-frame)
|
||||
//
|
||||
{
|
||||
constexpr int bindingCount = 1;
|
||||
VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{
|
||||
{
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
|
||||
}
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = bindingCount,
|
||||
.pBindings = descriptorSetLayoutBindings
|
||||
};
|
||||
VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[0]));
|
||||
|
||||
VkDescriptorSetLayout setLayouts[maxFrames];
|
||||
for (uint32_t i = 0; i < maxFrames; i++) {
|
||||
setLayouts[i] = descriptorSetLayouts[0];
|
||||
};
|
||||
|
||||
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = descriptorPool,
|
||||
.descriptorSetCount = maxFrames,
|
||||
.pSetLayouts = setLayouts
|
||||
};
|
||||
VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, descriptorSets0));
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// descriptor set writes
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::write_descriptor_sets()
|
||||
{
|
||||
VkWriteDescriptorSet writeDescriptorSets[bindingCount];
|
||||
uint32_t writeIndex = 0;
|
||||
|
||||
VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames];
|
||||
|
||||
for (uint32_t i = 0; i < maxFrames; i++) {
|
||||
sceneDescriptorBufferInfos[i] = {
|
||||
.buffer = shaderDataDevice.frame[i].sceneBuffer,
|
||||
.offset = 0,
|
||||
.range = shaderDataDevice.frame[i].sceneSize,
|
||||
};
|
||||
writeDescriptorSets[writeIndex++] = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = descriptorSets0[i],
|
||||
.dstBinding = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.pBufferInfo = &sceneDescriptorBufferInfos[i]
|
||||
};
|
||||
}
|
||||
|
||||
assert(writeIndex == bindingCount);
|
||||
vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// load worlds
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -345,12 +492,50 @@ namespace minecraft::vulkan {
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// scene data
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::transfer_transforms(XMMATRIX const & projection,
|
||||
XMMATRIX const & view,
|
||||
uint32_t frameIndex)
|
||||
{
|
||||
XMStoreFloat4x4(&shaderDataDevice.frame[frameIndex].sceneMapped->projection, projection);
|
||||
XMStoreFloat4x4(&shaderDataDevice.frame[frameIndex].sceneMapped->view, view);
|
||||
|
||||
// flush
|
||||
constexpr int mappedMemoryRangesCount = 1;
|
||||
VkMappedMemoryRange mappedMemoryRanges[mappedMemoryRangesCount]{
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.memory = shaderDataDevice.memory,
|
||||
.offset = shaderDataDevice.frame[frameIndex].sceneOffset,
|
||||
.size = shaderDataDevice.frame[frameIndex].sceneSize,
|
||||
}
|
||||
};
|
||||
alignMappedMemoryRanges(physicalDeviceProperties.limits.nonCoherentAtomSize,
|
||||
shaderDataDevice.memorySize,
|
||||
mappedMemoryRangesCount,
|
||||
mappedMemoryRanges);
|
||||
vkFlushMappedMemoryRanges(device, mappedMemoryRangesCount, mappedMemoryRanges);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// draw
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void vulkan::draw(VkCommandBuffer commandBuffer)
|
||||
void vulkan::draw(VkCommandBuffer commandBuffer,
|
||||
uint32_t frameIndex)
|
||||
{
|
||||
VkDescriptorSet descriptorSets[2] = {
|
||||
descriptorSets0[frameIndex],
|
||||
};
|
||||
vkCmdBindDescriptorSets(commandBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipelineLayout,
|
||||
0, 1, descriptorSets,
|
||||
0, nullptr);
|
||||
|
||||
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16);
|
||||
VkBuffer vertexBuffers[2]{
|
||||
vertexIndex.buffer,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user