diff --git a/Makefile b/Makefile index a801336..e3cc623 100644 --- a/Makefile +++ b/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) diff --git a/data/minecraft/terrain2.dds b/data/minecraft/terrain2.dds new file mode 100644 index 0000000..796b727 Binary files /dev/null and b/data/minecraft/terrain2.dds differ diff --git a/data/minecraft/terrain2.png b/data/minecraft/terrain2.png new file mode 100644 index 0000000..ece5596 Binary files /dev/null and b/data/minecraft/terrain2.png differ diff --git a/filenames.txt b/filenames.txt index 923aef2..fb4c619 100644 --- a/filenames.txt +++ b/filenames.txt @@ -33,3 +33,5 @@ data/minecraft/midnightmeadow/region.0.-1.instance.cfg data/minecraft/midnightmeadow/region.-1.-1.instance.cfg data/minecraft/midnightmeadow/global.dump data/minecraft/midnightmeadow/global.lights.vtx + +data/minecraft/terrain2.dds diff --git a/include/minecraft/vulkan.h b/include/minecraft/vulkan.h index e2a1b95..772221a 100644 --- a/include/minecraft/vulkan.h +++ b/include/minecraft/vulkan.h @@ -19,7 +19,7 @@ namespace minecraft::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 uint32_t bindingCount = uniformBufferDescriptorCount + 3; static constexpr int perVertexSize = (3 + 3 + 2) * 2; static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2; @@ -43,6 +43,9 @@ namespace minecraft::vulkan { VkFormat colorFormat; VkFormat depthFormat; + VkSampler linearSampler; + VkImageView shadowDepthImageView; + // // method initialized // @@ -54,8 +57,16 @@ namespace minecraft::vulkan { VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; - VkDescriptorSetLayout descriptorSetLayouts[1]; // unrelated to maxFrames, unrelated to descriptorCount + VkDescriptorSetLayout descriptorSetLayouts[2]; // unrelated to maxFrames, unrelated to descriptorCount VkDescriptorSet descriptorSets0[maxFrames]; + VkDescriptorSet descriptorSet1; + + struct Image { + VkImage image; + VkDeviceMemory memory; + VkImageView imageView; + }; + Image terrainImage; struct { VkDeviceMemory memory; @@ -76,7 +87,9 @@ namespace minecraft::vulkan { VkPhysicalDeviceProperties physicalDeviceProperties, VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, VkFormat colorFormat, - VkFormat depthFormat); + VkFormat depthFormat, + VkSampler linearSampler, + VkImageView shadowDepthImageView); void init(); void load_vertex_index_buffer(char const * vertex_filename, char const * index_filename); @@ -89,6 +102,8 @@ namespace minecraft::vulkan { void transfer_transforms(XMMATRIX const & projection, XMMATRIX const & view, uint32_t frameIndex); + void load_image(char const * filename, + Image & image); void draw(VkCommandBuffer commandBuffer, uint32_t frameIndex); diff --git a/shader/minecraft.hlsl b/shader/minecraft.hlsl index 7f2cb4f..924020b 100644 --- a/shader/minecraft.hlsl +++ b/shader/minecraft.hlsl @@ -14,6 +14,7 @@ struct VSInput struct VSOutput { float4 Position : SV_POSITION; + float4 Texture : TEXCOORD0; }; struct Scene @@ -28,17 +29,33 @@ struct Scene // set 0: per-frame [[vk::binding(0, 0)]] ConstantBuffer Scene; +// set 1: constant +[[vk::binding(0, 1)]] SamplerState LinearSampler; +[[vk::binding(1, 1)]] Texture2DArray ShadowTexture; +[[vk::binding(2, 1)]] Texture2D TerrainTexture; + +float2 yf(float2 v, float scale) +{ + return float2(v.x, 1.0 - v.y) * scale; +} + [shader("vertex")] VSOutput VSMain(VSInput input) { VSOutput output = (VSOutput)0; float4 Position = float4(input.Position.xyz + input.BlockPosition, 1.0); output.Position = mul(Scene.Projection, mul(Scene.View, Position)); + + float2 textureOffset = float2(input.TextureID % 8, input.TextureID / 8) * 16; + output.Texture = float4(yf(input.Texture.xy, 16), textureOffset); return output; } [shader("pixel")] float4 PSMain(VSOutput input) : SV_TARGET { - return float4(1, 0, 0, 1); + float2 texture = input.Texture.xy + input.Texture.zw; + float4 color = TerrainTexture.Load(int3(texture, 0)).xyzw; + + return float4(color.xyz, 1); } diff --git a/src/main.cpp b/src/main.cpp index a93791f..a9ea530 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -609,7 +609,9 @@ int main() physicalDeviceProperties, physicalDeviceMemoryProperties, surfaceFormat.format, - depthFormat); + depthFormat, + textureSamplers[0], + shadowDepthImageViewDepth); minecraft_state.init(); ////////////////////////////////////////////////////////////////////// diff --git a/src/minecraft/vulkan.cpp b/src/minecraft/vulkan.cpp index 90d5b43..cc97b0b 100644 --- a/src/minecraft/vulkan.cpp +++ b/src/minecraft/vulkan.cpp @@ -29,7 +29,9 @@ namespace minecraft::vulkan { VkPhysicalDeviceProperties physicalDeviceProperties, VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, VkFormat colorFormat, - VkFormat depthFormat) + VkFormat depthFormat, + VkSampler linearSampler, + VkImageView shadowDepthImageView) { this->instance = instance; this->device = device; @@ -41,12 +43,16 @@ namespace minecraft::vulkan { this->colorFormat = colorFormat; this->depthFormat = depthFormat; + + this->linearSampler = linearSampler; + this->shadowDepthImageView = shadowDepthImageView; } void vulkan::init() { load_vertex_index_buffer("data/minecraft/per_vertex.vtx", "data/minecraft/configuration.idx"); load_shader(); + load_image("data/minecraft/terrain2.dds", terrainImage); create_uniform_buffers(); create_descriptor_sets(); write_descriptor_sets(); @@ -142,7 +148,7 @@ namespace minecraft::vulkan { { VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 1, + .setLayoutCount = 2, .pSetLayouts = descriptorSetLayouts, //.pushConstantRangeCount = 0, //.pPushConstantRanges = nullptr @@ -388,6 +394,49 @@ namespace minecraft::vulkan { assert(offsetsIndex == uniformBufferDescriptorCount); } + ////////////////////////////////////////////////////////////////////// + // images + ////////////////////////////////////////////////////////////////////// + + void vulkan::load_image(char const * filename, + Image & image) + { + 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)); + + // load + + createImageFromFilenameDDS(device, + queue, + commandBuffer, + fence, + physicalDeviceProperties.limits.nonCoherentAtomSize, + physicalDeviceMemoryProperties, + filename, + &image.image, + &image.memory, + &image.imageView); + + // cleanup + + vkDestroyFence(device, fence, nullptr); + vkFreeCommandBuffers(device, + commandPool, + 1, + &commandBuffer); + } + ////////////////////////////////////////////////////////////////////// // descriptor sets ////////////////////////////////////////////////////////////////////// @@ -397,16 +446,24 @@ namespace minecraft::vulkan { // // pool // - constexpr int descriptorPoolSizesCount = 1; + constexpr int descriptorPoolSizesCount = 3; VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{ { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = (maxFrames * 1), }, + { // linear sampler + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1 + 1, // +1 for shadow sampler + } }; VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = maxFrames, + .maxSets = maxFrames + 1, .poolSizeCount = descriptorPoolSizesCount, .pPoolSizes = descriptorPoolSizes }; @@ -446,6 +503,48 @@ namespace minecraft::vulkan { }; VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, descriptorSets0)); } + + // + // uniform buffer descriptor set layout/allocation (set 1, constant) + // + { + constexpr int bindingCount = 3; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, + { // shadow sampled image + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, + { // terrain sampled image + .binding = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + } + }; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = bindingCount, + .pBindings = descriptorSetLayoutBindings + }; + VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[1])); + + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &descriptorSetLayouts[1] + }; + VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet1)); + } } ////////////////////////////////////////////////////////////////////// @@ -459,6 +558,7 @@ namespace minecraft::vulkan { VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames]; + // set0 bindings for (uint32_t i = 0; i < maxFrames; i++) { sceneDescriptorBufferInfos[i] = { .buffer = shaderDataDevice.frame[i].sceneBuffer, @@ -475,6 +575,43 @@ namespace minecraft::vulkan { }; } + // set1 bindings + VkDescriptorImageInfo samplerDescriptorImageInfo = { + .sampler = linearSampler, + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet1, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .pImageInfo = &samplerDescriptorImageInfo + }; + VkDescriptorImageInfo shadowDepthDescriptorImageInfo = { + .imageView = shadowDepthImageView, + .imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet1, + .dstBinding = 1, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = &shadowDepthDescriptorImageInfo + }; + VkDescriptorImageInfo terrainDescriptorImageInfo = { + .imageView = terrainImage.imageView, + .imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet1, + .dstBinding = 2, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = &terrainDescriptorImageInfo + }; + assert(writeIndex == bindingCount); vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr); } @@ -529,11 +666,12 @@ namespace minecraft::vulkan { { VkDescriptorSet descriptorSets[2] = { descriptorSets0[frameIndex], + descriptorSet1, }; vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, - 0, 1, descriptorSets, + 0, 2, descriptorSets, 0, nullptr); vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16);