From a3d9a157f354627241e0dc10723211c0801976d7 Mon Sep 17 00:00:00 2001 From: Shu Date: Thu, 1 Oct 2020 19:54:02 +0200 Subject: [PATCH] Vulkan first texture --- resource/content/shaders/Tris.fs.spv | 4 +- resource/content/shaders/Tris.vs.spv | 4 +- resource/shaders-src/Tris.frag | 5 +- resource/shaders-src/Tris.vert | 3 + src/client/render/UI.cpp | 2 +- src/client/render/vk/Allocator.cpp | 168 +++++++++++++++++--- src/client/render/vk/Allocator.hpp | 18 ++- src/client/render/vk/CommandCenter.cpp | 132 ++++++++++++--- src/client/render/vk/CommandCenter.hpp | 5 + src/client/render/vk/PhysicalDeviceInfo.hpp | 8 +- src/client/render/vk/Pipeline.cpp | 12 +- src/client/render/vk/Renderer.cpp | 25 ++- src/client/render/vk/buffer/VertexData.hpp | 17 +- src/client/render/vk/texture.cpp | 75 +++++++++ src/client/render/vk/texture.hpp | 16 ++ 15 files changed, 422 insertions(+), 72 deletions(-) create mode 100644 src/client/render/vk/texture.cpp create mode 100644 src/client/render/vk/texture.hpp diff --git a/resource/content/shaders/Tris.fs.spv b/resource/content/shaders/Tris.fs.spv index e223b25..a103cb7 100644 --- a/resource/content/shaders/Tris.fs.spv +++ b/resource/content/shaders/Tris.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71d966265a11ee35ec6f5b58769526362c0369ab876154cbb7245a1e076252b1 -size 608 +oid sha256:4b32ce588c35a63f6b6ff88860385d1afca26ba07270ce602b0fd55db589e619 +size 764 diff --git a/resource/content/shaders/Tris.vs.spv b/resource/content/shaders/Tris.vs.spv index 4421d80..ba8ebf7 100644 --- a/resource/content/shaders/Tris.vs.spv +++ b/resource/content/shaders/Tris.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38fcf9482521a5e4f20cc3c02fbf69c4e238512578e0e39c79cffe290218d9c7 -size 1712 +oid sha256:2ec9a7ac1fde5472e4d1e1136e2adcd8b19ce9b51c3224f38a6458e4ec5dad09 +size 1872 diff --git a/resource/shaders-src/Tris.frag b/resource/shaders-src/Tris.frag index 84daf5e..c456c89 100644 --- a/resource/shaders-src/Tris.frag +++ b/resource/shaders-src/Tris.frag @@ -1,10 +1,13 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +layout(binding = 1) uniform sampler2D texSampler; + layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; void main() { - outColor = vec4(fragColor, 1.0); + outColor = texture(texSampler, fragTexCoord); } diff --git a/resource/shaders-src/Tris.vert b/resource/shaders-src/Tris.vert index f758886..5aa7b41 100644 --- a/resource/shaders-src/Tris.vert +++ b/resource/shaders-src/Tris.vert @@ -9,10 +9,13 @@ layout(binding = 0) uniform UniformBufferObject { layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTexCoord; layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoord; void main() { gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; + fragTexCoord = inTexCoord; } \ No newline at end of file diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 1d27322..0c42033 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -72,7 +72,7 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons ImGui::SameLine(); changeRenderer |= ImGui::Checkbox("Stochastic", &options.renderer.voxel.stochastic); if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Hide textures tilling\nMay cause visible inconsistances on chunk borders"); + ImGui::SetTooltip("Hide textures tiling\nMay cause visible inconsistances on chunk borders"); changeRenderer |= ImGui::Checkbox("Geometry", &options.renderer.voxel.geometry); ImGui::SameLine(); diff --git a/src/client/render/vk/Allocator.cpp b/src/client/render/vk/Allocator.cpp index 0f3c460..42433cf 100644 --- a/src/client/render/vk/Allocator.cpp +++ b/src/client/render/vk/Allocator.cpp @@ -22,9 +22,9 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD } updateProperties(); - { + { // Transfer if (!info.queueIndices.transferFamily.has_value()) { - LOG_W("No transfer queue family. Using graphics one"); + LOG_W("No transfer queue family. Fallback to graphics one"); } const auto family = info.queueIndices.transferFamily.value_or(info.queueIndices.graphicsFamily.value()); @@ -37,8 +37,7 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD if (vkCreateCommandPool(device, &poolInfo, ALLOC, &transferPool) != VK_SUCCESS) { FATAL("Failed to create transfer pool!"); } - } - { + VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; @@ -48,12 +47,33 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD vkAllocateCommandBuffers(device, &allocInfo, &transferBuffer); tracyCtx = TracyVkContext(info.device, device, transferQueue, transferBuffer); } + { // Graphics + vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue); + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value(); + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) { + FATAL("Failed to create graphics pool!"); + } + + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = graphicsPool; + allocInfo.commandBufferCount = 1; + + vkAllocateCommandBuffers(device, &allocInfo, &graphicsBuffer); + } } Allocator::~Allocator() { TracyVkDestroy(tracyCtx); vkFreeCommandBuffers(device, transferPool, 1, &transferBuffer); + vkFreeCommandBuffers(device, graphicsPool, 1, &graphicsBuffer); vkDestroyCommandPool(device, transferPool, ALLOC); + vkDestroyCommandPool(device, graphicsPool, ALLOC); //NOTE: all allocations are delete by ~vector } @@ -189,6 +209,39 @@ Allocator::memory_ptr Allocator::createBuffers(const std::vectorref, memory->offset) != VK_SUCCESS) { + LOG_E("Failed to allocate image memory"); + return GetNull(); + } + + if (data_size != 0 && data != nullptr) { + Allocator::buffer_info stagingBuffer; + if(auto stagingMemory = createBuffer({data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) { + stagingMemory->write(data, data_size, data_offset); + transitionImageLayout(out.image, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + copyBufferToImage(stagingBuffer, out, info.extent.width, info.extent.height); + transitionImageLayout(out.image, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, finalLayout); + vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor + } else { + FATAL("Cannot allocate staging memory"); + return GetNull(); + } + } + return memory; +} void Allocator::updateProperties() { if (hasBudget()) { @@ -203,12 +256,12 @@ void Allocator::updateProperties() { vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); } } -Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties) { +Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) { // Search in existing allocations for (auto& alloc: allocations) { if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) && (getProperties().memoryTypes[alloc->memoryType].propertyFlags & properties) == properties && - alloc->size > requirements.size + alloc->size > requirements.size && alloc->optimalTiling == optimalTiling ) { VkDeviceSize start = 0; auto aligned = [&](VkDeviceSize offset) { @@ -261,20 +314,36 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr); } - auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, ptr)).get(); + auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, optimalTiling, ptr)).get(); allocation->areas.push_back({requirements.size, 0}); return memory_ptr(new memory_area{memory, requirements.size, 0, ptr}, allocation->deleter); } -void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) { - //FIXME: assert no out of range - +void beginCmd(VkCommandBuffer buffer) { VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(transferBuffer, &beginInfo); + vkBeginCommandBuffer(buffer, &beginInfo); +} +void submitCmd(VkCommandBuffer buffer, VkQueue queue) { + vkEndCommandBuffer(buffer); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &buffer; + + vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); + //TODO: parallelize + vkQueueWaitIdle(queue); //MAYBE: use fences + vkResetCommandBuffer(buffer, 0); +} +void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) { + //FIXME: assert no out of range + + beginCmd(transferBuffer); VkBufferCopy copyRegion{}; copyRegion.srcOffset = 0; @@ -282,17 +351,70 @@ void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) copyRegion.size = size; vkCmdCopyBuffer(transferBuffer, src.buffer, dst.buffer, 1, ©Region); - vkEndCommandBuffer(transferBuffer); - - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &transferBuffer; - - vkQueueSubmit(transferQueue, 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(transferQueue); //MAYBE: use fences - vkResetCommandBuffer(transferBuffer, 0); + submitCmd(transferBuffer, transferQueue); } +void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) { + beginCmd(graphicsBuffer); + + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + barrier.image = image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + VkPipelineStageFlags sourceStage; + VkPipelineStageFlags destinationStage; + + if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + FATAL("Unsupported layout transition!"); + } + + vkCmdPipelineBarrier(graphicsBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); + + submitCmd(graphicsBuffer, graphicsQueue); +} +void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t width, uint32_t height) { + beginCmd(transferBuffer); + + VkBufferImageCopy region{}; + region.bufferOffset = src.offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + + region.imageOffset = {0, 0, 0}; + region.imageExtent = {width, height, 1}; + + vkCmdCopyBufferToImage(transferBuffer, src.buffer, dest.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + submitCmd(transferBuffer, transferQueue); +} + std::optional Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) { updateProperties(); @@ -350,8 +472,8 @@ void Allocator::MemoryDeleter::operator()(memory_area* area) { LOG_E("Allocation area not found"); delete area; } -Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, void *ptr): - device(device), memory(memory), size(size), memoryType(memoryType), ptr(ptr), deleter(this) { } +Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr): + device(device), memory(memory), size(size), memoryType(memoryType), optimalTiling(optimalTiling), ptr(ptr), deleter(this) { } Allocator::Allocation::~Allocation() { if(!areas.empty()) LOG_E("Freeing " << areas.size() << " floating buffers"); diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp index ec35783..9432027 100644 --- a/src/client/render/vk/Allocator.hpp +++ b/src/client/render/vk/Allocator.hpp @@ -38,7 +38,7 @@ public: using memory_ptr = std::unique_ptr; - memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags); + memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false); bool deallocate(const memory_area&); struct buffer_info { @@ -55,7 +55,17 @@ public: memory_ptr createBuffer(const buffer_requirement&, VkMemoryPropertyFlags, buffer_info&); memory_ptr createBuffers(const std::vector &, VkMemoryPropertyFlags, std::vector &); + struct image_info { + VkImage image = nullptr; + VkDeviceSize offset = 0; + }; + memory_ptr createImage(const VkImageCreateInfo&, VkMemoryPropertyFlags, image_info&, + const void *data = nullptr, VkDeviceSize data_size = 0, VkDeviceSize data_offset = 0, + VkImageLayout finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size); + void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); + void copyBufferToImage(buffer_info buffer, image_info image, uint32_t width, uint32_t height); void setTracyZone(const char* name); @@ -68,13 +78,14 @@ private: void updateProperties(); struct Allocation { - Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, void *ptr); + Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr); ~Allocation(); const VkDevice device; const VkDeviceMemory memory; const VkDeviceSize size; const uint32_t memoryType; + const bool optimalTiling; void *const ptr = nullptr; const MemoryDeleter deleter; @@ -92,6 +103,9 @@ private: VkCommandPool transferPool; VkCommandBuffer transferBuffer; // MAYBE: parallel upload TracyVkCtx tracyCtx; + VkQueue graphicsQueue; + VkCommandPool graphicsPool; + VkCommandBuffer graphicsBuffer; std::vector> allocations; }; diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index f56cc42..4adf814 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -4,12 +4,18 @@ #include "Pipeline.hpp" #include "../Renderer.hpp" #include "buffer/VertexData.hpp" +#include "texture.hpp" using namespace render::vk; +#define CONTENT_DIR "content/" +#define TEXTURES_DIR CONTENT_DIR "textures/" + CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vector &views, - const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt): -device(device), indexedBufferMemory(Allocator::GetNull()), uniformBuffersMemory(Allocator::GetNull()) { + const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device), + indexedBufferMemory(Allocator::GetNull()), sampleImageMemory(Allocator::GetNull()), + uniformBuffersMemory(Allocator::GetNull()) +{ { // Graphics command pool vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue); VkCommandPoolCreateInfo poolInfo{}; @@ -34,6 +40,80 @@ device(device), indexedBufferMemory(Allocator::GetNull()), uniformBuffersMemory( FATAL("Cannot create vertex buffer"); } } + { // Texture sampler (const) + std::vector data; + dds::header_info header; + if (dds::readDDS(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", data, header)) { + FATAL("Cannot read texture"); + } + + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = header.width; + imageInfo.extent.height = header.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = header.mipMapCount; //TODO: + imageInfo.arrayLayers = 1; + imageInfo.format = header.format; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.flags = 0; + + sampleImageMemory = alloc.createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, sampleImage, data.data(), data.size()); + if(!sampleImageMemory) { + FATAL("Cannot create texture image"); + } + + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = sampleImage.image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = header.format; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + if (vkCreateImageView(device, &viewInfo, nullptr, &sampleImageView) != VK_SUCCESS) { + FATAL("Failed to create texture image view!"); + } + + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + if (info.features.samplerAnisotropy && opt.anisotropy > 0) { + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = 1 << (opt.anisotropy-1); + } else { + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.f; + } + + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; //TODO: + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + + if (vkCreateSampler(device, &samplerInfo, nullptr, &sampleSampler) != VK_SUCCESS) { + FATAL("Failed to create texture sampler!"); + } + } allocate(alloc, views, pipe, info.swapDetails.capabilities.currentExtent, opt); } @@ -45,6 +125,11 @@ CommandCenter::~CommandCenter() { vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC); indexedBufferMemory.reset(); + vkDestroySampler(device, sampleSampler, ALLOC); + vkDestroyImageView(device, sampleImageView, ALLOC); + vkDestroyImage(device, sampleImage.image, ALLOC); + sampleImageMemory.reset(); + vkDestroyCommandPool(device, graphicsPool, ALLOC); } #include @@ -83,14 +168,16 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v } } { // Descriptor pool - VkDescriptorPoolSize poolSize{}; - poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSize.descriptorCount = framebuffers.size(); + std::array poolSizes{}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = framebuffers.size(); + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = framebuffers.size(); VkDescriptorPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = 1; - poolInfo.pPoolSizes = &poolSize; + poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = framebuffers.size(); poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT @@ -117,20 +204,29 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v bufferInfo.offset = 0; bufferInfo.range = sizeof(buffer::vk::UniformBufferObject); - VkWriteDescriptorSet descriptorWrite{}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSets[i]; - descriptorWrite.dstBinding = 0; - descriptorWrite.dstArrayElement = 0; + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = sampleImageView; + imageInfo.sampler = sampleSampler; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrite.descriptorCount = 1; + std::array descriptorWrites{}; + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[0].dstSet = descriptorSets[i]; + descriptorWrites[0].dstBinding = 0; + descriptorWrites[0].dstArrayElement = 0; + descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrites[0].descriptorCount = 1; + descriptorWrites[0].pBufferInfo = &bufferInfo; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.pImageInfo = nullptr; - descriptorWrite.pTexelBufferView = nullptr; + descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[1].dstSet = descriptorSets[i]; + descriptorWrites[1].dstBinding = 1; + descriptorWrites[1].dstArrayElement = 0; + descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[1].descriptorCount = 1; + descriptorWrites[1].pImageInfo = &imageInfo; - vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); } } diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index 207a07c..4a0a35b 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -36,6 +36,11 @@ private: Allocator::buffer_info indexBuffer; Allocator::memory_ptr indexedBufferMemory; + Allocator::image_info sampleImage; + VkImageView sampleImageView; + VkSampler sampleSampler; + Allocator::memory_ptr sampleImageMemory; + glm::mat4 proj; std::vector uniformBuffers; Allocator::memory_ptr uniformBuffersMemory; diff --git a/src/client/render/vk/PhysicalDeviceInfo.hpp b/src/client/render/vk/PhysicalDeviceInfo.hpp index 6c2eb1e..f678ac0 100644 --- a/src/client/render/vk/PhysicalDeviceInfo.hpp +++ b/src/client/render/vk/PhysicalDeviceInfo.hpp @@ -26,7 +26,11 @@ struct PhysicalDeviceInfo { PhysicalDeviceInfo() {} PhysicalDeviceInfo(GLFWwindow *window, VkPhysicalDevice device, VkSurfaceKHR surface): window(window), device(device), surface(surface), - swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface)) { } + swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface)) + { + vkGetPhysicalDeviceProperties(device, &properties); + vkGetPhysicalDeviceFeatures(device, &features); + } VkSurfaceFormatKHR getFormat() const; bool hasMemoryBudget() const; @@ -36,6 +40,8 @@ struct PhysicalDeviceInfo { VkSurfaceKHR surface; SwapChainSupportDetails swapDetails; QueueFamilyIndices queueIndices; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; std::vector optionalExtensions; }; } \ No newline at end of file diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index b88b547..a5521d0 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -7,7 +7,6 @@ #define CONTENT_DIR "content/" #define SHADER_DIR CONTENT_DIR "shaders/" -#define TEXTURES_DIR CONTENT_DIR "textures/" constexpr auto BLENDING = true; @@ -58,10 +57,17 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render } } { + VkDescriptorSetLayoutBinding samplerLayoutBinding{}; + samplerLayoutBinding.binding = 1; + samplerLayoutBinding.descriptorCount = 1; + samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + samplerLayoutBinding.pImmutableSamplers = nullptr; + samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + std::vector bindings = {buffer::vk::UniformBufferObject::getLayoutBinding(), samplerLayoutBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo{}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = 1; - std::vector bindings = {buffer::vk::UniformBufferObject::getLayoutBinding()}; + layoutInfo.bindingCount = bindings.size(); layoutInfo.pBindings = bindings.data(); if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &descriptorSetLayout) != VK_SUCCESS) { diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index 95300bd..36db369 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -289,15 +289,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { uint bestScore = 0; for(const auto& device: devices) { uint score = 1; - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDeviceFeatures deviceFeatures; - vkGetPhysicalDeviceProperties(device, &deviceProperties); - vkGetPhysicalDeviceFeatures(device, &deviceFeatures); - auto infos = PhysicalDeviceInfo(window.getPtr(), device, surface); - //FIXME: if (!deviceFeatures.geometryShader) continue; - { uint32_t availableExtensionsCount; vkEnumerateDeviceExtensionProperties(device, nullptr, &availableExtensionsCount, nullptr); @@ -324,10 +317,17 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { } } - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + if (infos.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += 10000; - score += deviceProperties.limits.maxImageDimension2D; + score += infos.properties.limits.maxImageDimension2D; + + if (infos.features.geometryShader) + score += 2000; + + if (infos.features.samplerAnisotropy) + score += 1000; + //TODO: check others limits if (!infos.queueIndices.isComplete()) @@ -347,9 +347,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { LOG_E("Any GPU matching requirements"); return false; } - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(physicalInfo.device, &deviceProperties); - LOG_D("Using " << deviceProperties.deviceName); + LOG_D("Using " << physicalInfo.properties.deviceName); } VkDevice device; @@ -371,7 +369,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { } VkPhysicalDeviceFeatures deviceFeatures{}; - //TODO: + deviceFeatures.geometryShader = physicalInfo.features.geometryShader; + deviceFeatures.samplerAnisotropy = physicalInfo.features.samplerAnisotropy; std::vector extensions(requiredExtensions); extensions.insert(extensions.end(), physicalInfo.optionalExtensions.begin(), physicalInfo.optionalExtensions.end()); diff --git a/src/client/render/vk/buffer/VertexData.hpp b/src/client/render/vk/buffer/VertexData.hpp index c34d4c6..fa2d305 100644 --- a/src/client/render/vk/buffer/VertexData.hpp +++ b/src/client/render/vk/buffer/VertexData.hpp @@ -10,6 +10,7 @@ namespace buffer::vk { struct VertexData { glm::vec2 pos; glm::vec3 color; + glm::vec2 uv; static VkVertexInputBindingDescription getBindingDescription() { VkVertexInputBindingDescription description{}; @@ -18,8 +19,8 @@ struct VertexData { description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return description; } - static std::array getAttributeDescriptions() { - std::array attributeDescriptions{}; + static std::array getAttributeDescriptions() { + std::array attributeDescriptions{}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; @@ -28,15 +29,19 @@ struct VertexData { attributeDescriptions[1].location = 1; attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[1].offset = offsetof(VertexData, color); + attributeDescriptions[2].binding = 0; + attributeDescriptions[2].location = 2; + attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[2].offset = offsetof(VertexData, uv); return attributeDescriptions; } }; const std::vector vertices = { - {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, - {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, - {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, - {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}} + {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, + {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}} }; const std::vector indices = { 0, 1, 2, 2, 3, 0 diff --git a/src/client/render/vk/texture.cpp b/src/client/render/vk/texture.cpp new file mode 100644 index 0000000..7189c8a --- /dev/null +++ b/src/client/render/vk/texture.cpp @@ -0,0 +1,75 @@ +#include "texture.hpp" +#include +#include +#include +#include +#include +#include +#include + +#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII +#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII +#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII + +VkResult render::vk::dds::readDDS(const std::string& imagepath, std::vector& data, header_info& info) { + + unsigned char header[124]; + + FILE *fp; + + /* try to open the file */ + fp = fopen(imagepath.c_str(), "rb"); + if (fp == NULL){ + printf("%s could not be opened.\n", imagepath.c_str()); getchar(); + return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT; + } + + /* verify the type of file */ + char filecode[4]; + fread(filecode, 1, 4, fp); + if (strncmp(filecode, "DDS ", 4) != 0) { + fclose(fp); + return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT; + } + + /* get the surface desc */ + fread(&header, 124, 1, fp); + + info.height = *(unsigned int*)&(header[8 ]); + info.width = *(unsigned int*)&(header[12]); + unsigned int linearSize = *(unsigned int*)&(header[16]); + info.mipMapCount = *(unsigned int*)&(header[24]); + unsigned int fourCC = *(unsigned int*)&(header[80]); + + + /* how big is it going to be including all mipmaps? */ + unsigned int bufsize = info.mipMapCount > 1 ? linearSize * 2 : linearSize; + data.resize(bufsize); + fread(data.data(), 1, bufsize, fp); + /* close the file pointer */ + fclose(fp); + + switch(fourCC) + { + case FOURCC_DXT1: + info.format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + break; + case FOURCC_DXT3: + info.format = VK_FORMAT_BC2_SRGB_BLOCK; + break; + case FOURCC_DXT5: + info.format = VK_FORMAT_BC3_SRGB_BLOCK; + break; + //MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK + default: + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + +#if FALSE + glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); + glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST); + + TODO: glGenerateTextureMipmap(textureID); +#endif + return VK_SUCCESS; +} \ No newline at end of file diff --git a/src/client/render/vk/texture.hpp b/src/client/render/vk/texture.hpp new file mode 100644 index 0000000..56ca58d --- /dev/null +++ b/src/client/render/vk/texture.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include +#include + +namespace render::vk::dds { +struct header_info { + unsigned int height; + unsigned int width; + unsigned int mipMapCount; + VkFormat format; +}; +VkResult readDDS(const std::string& imagepath, std::vector& data, header_info& info); +} \ No newline at end of file