diff --git a/src/editor/shaders/triangle.vert b/src/editor/shaders/triangle.vert index 9f0c10e..e690b76 100644 --- a/src/editor/shaders/triangle.vert +++ b/src/editor/shaders/triangle.vert @@ -5,14 +5,13 @@ layout(location = 1) in vec3 color; layout(location = 0) out vec3 vertColor; -//layout(binding = 0) uniform ModelViewProjection { -// mat4 model; -// mat4 view; -// mat4 projection; -//} mvp; +layout(binding = 0) uniform ModelViewProjection { + mat4 model; + mat4 view; + mat4 projection; +} mvp; void main() { -// gl_Position = mvp.projection * mvp.view * mvp.model * vec4(position, 1.0); - gl_Position = vec4(position, 1.0); + gl_Position = mvp.projection * mvp.view * mvp.model * vec4(position, 1.0); vertColor = color; -} +} \ No newline at end of file diff --git a/src/engine/Buffer.cpp b/src/engine/Buffer.cpp index ddcefcb..d994c16 100644 --- a/src/engine/Buffer.cpp +++ b/src/engine/Buffer.cpp @@ -1,7 +1,7 @@ #include "Buffer.h" namespace Vixen { - Buffer::Buffer(Usage bufferUsage, const size_t &size) + Buffer::Buffer(const Usage bufferUsage, const std::size_t &size) : bufferUsage(bufferUsage), size(size) {} @@ -9,7 +9,7 @@ namespace Vixen { return bufferUsage; } - size_t Buffer::getSize() const { + std::size_t Buffer::getSize() const { return size; } } diff --git a/src/engine/Buffer.h b/src/engine/Buffer.h index 12841fe..382e543 100644 --- a/src/engine/Buffer.h +++ b/src/engine/Buffer.h @@ -1,8 +1,6 @@ #pragma once -#include #include -#include namespace Vixen { /** @@ -18,7 +16,9 @@ namespace Vixen { TRANSFER_SRC = 1 << 4, }; - virtual char *map() = 0; + virtual ~Buffer() = default; + + virtual char* map() = 0; virtual void unmap() = 0; @@ -28,9 +28,9 @@ namespace Vixen { * @param dataSize The size of the data. * @param offset The offset within this buffer to start writing from. */ - virtual void write(const char *data, size_t dataSize, size_t offset) = 0; + virtual void write(const char* data, std::size_t dataSize, std::size_t offset) = 0; - [[nodiscard]] size_t getSize() const; + [[nodiscard]] std::size_t getSize() const; [[nodiscard]] Usage getBufferUsage() const; @@ -43,9 +43,8 @@ namespace Vixen { * Create a new buffer. Where the allocation is made is determined by the allocation usage. * @param bufferUsage Specifies how the buffer will be used and what data it will hold. * @param size The size of this buffer measured in bytes. - * @param allocationUsage Specifies how this buffer's allocated memory will be used. */ - Buffer(Usage bufferUsage, const std::size_t &size); + Buffer(Usage bufferUsage, const std::size_t& size); }; inline Buffer::Usage operator|(Buffer::Usage a, Buffer::Usage b) { diff --git a/src/engine/Camera.cpp b/src/engine/Camera.cpp index c7232bb..da60b2e 100644 --- a/src/engine/Camera.cpp +++ b/src/engine/Camera.cpp @@ -1,8 +1,8 @@ #include "Camera.h" namespace Vixen { - Camera::Camera(float fieldOfView, float nearPlane, float farPlane, glm::vec3 clearColor) - : position(0, 0, 0), + Camera::Camera(const glm::vec3 position, const float fieldOfView, const float nearPlane, const float farPlane, const glm::vec3 clearColor) + : position(position), // rotation(glm::quat{}), rotation({}), fieldOfView(fieldOfView), @@ -16,19 +16,30 @@ namespace Vixen { // glm::mat4 translation = glm::translate({1.0}, -position); // // return rot * translation; + // return glm::lookAt( + // position, + // position + rotation, + // {0.0f, 1.0f, 0.0f} + // ); return glm::lookAt( - position, - position + rotation, - {0.0f, 1.0f, 0.0f} + glm::vec3{2.0f, 2.0f, 2.0f}, + glm::vec3{0.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 0.0f, 1.0f} ); } - glm::mat4 Camera::perspective(float aspectRatio) const { + glm::mat4 Camera::perspective(const float aspectRatio) const { + // return glm::perspective( + // glm::radians(fieldOfView), + // aspectRatio, + // nearPlane, + // farPlane + // ); return glm::perspective( - glm::radians(fieldOfView), - aspectRatio, - nearPlane, - farPlane + glm::radians(45.0f), + 1.7f, + 0.1f, + 10.0f ); } diff --git a/src/engine/Camera.h b/src/engine/Camera.h index 8fa03a7..413c309 100644 --- a/src/engine/Camera.h +++ b/src/engine/Camera.h @@ -3,25 +3,25 @@ #include #include #include -#include namespace Vixen { class Camera { + public: explicit Camera( - float fieldOfView = 114.0f, - float nearPlane = 0.01f, - float farPlane = 1000.0f, - glm::vec3 clearColor = {0.0f, 0.0f, 0.0f} + glm::vec3 position = {}, + float fieldOfView = 114.0f, + float nearPlane = 0.1f, + float farPlane = 1000.0f, + glm::vec3 clearColor = {0.0f, 0.0f, 0.0f} ); [[nodiscard]] glm::mat4 view() const; [[nodiscard]] glm::mat4 perspective(float aspectRatio) const; - public: - [[nodiscard]] const glm::vec3 &getPosition() const; + [[nodiscard]] const glm::vec3& getPosition() const; -// [[nodiscard]] const glm::quat &getRotation() const; + // [[nodiscard]] const glm::quat &getRotation() const; [[nodiscard]] glm::vec3 getEulerRotation() const; @@ -29,7 +29,7 @@ namespace Vixen { [[nodiscard]] float getFarPlane() const; - [[nodiscard]] const glm::vec3 &getClearColor() const; + [[nodiscard]] const glm::vec3& getClearColor() const; private: glm::vec3 position; diff --git a/src/engine/ShaderModule.h b/src/engine/ShaderModule.h index c5dba63..88ca58a 100644 --- a/src/engine/ShaderModule.h +++ b/src/engine/ShaderModule.h @@ -44,29 +44,35 @@ namespace Vixen { public: ShaderModule( - Stage stage, - std::string entrypoint, - const std::vector &bindings, - const std::vector &inputs + const Stage stage, + std::string entrypoint, + const std::vector& bindings, + const std::vector& inputs, + const std::vector& uniformBuffers ) : stage(stage), entrypoint(std::move(entrypoint)), bindings(bindings), - inputs(inputs) {} + inputs(inputs), + uniformBuffers(uniformBuffers) {} [[nodiscard]] Stage getStage() const { return stage; } - [[nodiscard]] const std::string &getEntrypoint() const { + [[nodiscard]] const std::string& getEntrypoint() const { return entrypoint; } - [[nodiscard]] const std::vector &getBindings() const { + [[nodiscard]] const std::vector& getBindings() const { return bindings; } - [[nodiscard]] const std::vector &getInputs() const { + [[nodiscard]] const std::vector& getInputs() const { return inputs; } + + [[nodiscard]] std::vector getUniformBuffers() const { + return uniformBuffers; + } }; } diff --git a/src/engine/vk/CMakeLists.txt b/src/engine/vk/CMakeLists.txt index 59d7f9f..ca5d0ce 100644 --- a/src/engine/vk/CMakeLists.txt +++ b/src/engine/vk/CMakeLists.txt @@ -57,6 +57,8 @@ add_library( VkDescriptorPool.h VkDescriptorSetLayout.cpp VkDescriptorSetLayout.h + VkDescriptorSet.cpp + VkDescriptorSet.h ) target_link_libraries( VkVixen diff --git a/src/engine/vk/VkBuffer.cpp b/src/engine/vk/VkBuffer.cpp index 0479cfe..fb43938 100644 --- a/src/engine/vk/VkBuffer.cpp +++ b/src/engine/vk/VkBuffer.cpp @@ -1,12 +1,12 @@ #include "VkBuffer.h" namespace Vixen::Vk { - VkBuffer::VkBuffer(const std::shared_ptr &device, Usage bufferUsage, const size_t &size) - : Buffer(bufferUsage, size), - device(device), - allocation(VK_NULL_HANDLE), - buffer(VK_NULL_HANDLE) { - VkBufferUsageFlags bufferUsageFlags; + VkBuffer::VkBuffer(const std::shared_ptr& device, const Usage bufferUsage, const size_t& size) + : Buffer(bufferUsage, size), + device(device), + allocation(VK_NULL_HANDLE), + buffer(VK_NULL_HANDLE) { + VkBufferUsageFlags bufferUsageFlags = 0; if (bufferUsage & Usage::VERTEX) bufferUsageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; if (bufferUsage & Usage::INDEX) @@ -18,57 +18,63 @@ namespace Vixen::Vk { if (bufferUsage & Usage::UNIFORM) bufferUsageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - VkBufferCreateInfo bufferCreateInfo = {}; - bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCreateInfo.size = size; - bufferCreateInfo.usage = bufferUsageFlags; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + const VkBufferCreateInfo bufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = size, + .usage = bufferUsageFlags, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr + }; - VmaAllocationCreateInfo allocationCreateInfo = { - // TODO: Only add this flag if necessary (e.g. staging buffer) - .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, - .usage = VMA_MEMORY_USAGE_AUTO + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + // TODO: Only add this flag if necessary (e.g. staging buffer) + .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + .requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT }; checkVulkanResult( - vmaCreateBuffer( - device->getAllocator(), - &bufferCreateInfo, - &allocationCreateInfo, - &buffer, - &allocation, - nullptr - ), - "Failed to create Vk buffer" + vmaCreateBuffer( + device->getAllocator(), + &bufferCreateInfo, + &allocationCreateInfo, + &buffer, + &allocation, + nullptr + ), + "Failed to create Vk buffer" ); } - VkBuffer::VkBuffer(VkBuffer &&o) noexcept - : Buffer(o.bufferUsage, o.size), - allocation(std::exchange(o.allocation, nullptr)), - buffer(std::exchange(o.buffer, nullptr)) {} + VkBuffer::VkBuffer(VkBuffer&& o) noexcept + : Buffer(o.bufferUsage, o.size), + allocation(std::exchange(o.allocation, nullptr)), + buffer(std::exchange(o.buffer, nullptr)) {} VkBuffer::~VkBuffer() { vmaDestroyBuffer(device->getAllocator(), buffer, allocation); } - void VkBuffer::write(const char *data, size_t dataSize, size_t offset) { + void VkBuffer::write(const char* data, const size_t dataSize, const size_t offset) { if (offset + dataSize > size) throw std::runtime_error("Buffer overflow"); - void *d = map(); - memcpy(static_cast(d) + offset, data, dataSize); + void* d = map(); + memcpy(static_cast(d) + offset, data, dataSize); unmap(); } - char *VkBuffer::map() { - void *data; + char* VkBuffer::map() { + void* data; checkVulkanResult( - vmaMapMemory(device->getAllocator(), allocation, &data), - "Failed to map buffer" + vmaMapMemory(device->getAllocator(), allocation, &data), + "Failed to map buffer" ); - return static_cast(data); + return static_cast(data); } void VkBuffer::unmap() { @@ -80,31 +86,31 @@ namespace Vixen::Vk { } void VkBuffer::transfer( - VkBuffer &destination, - size_t destinationOffset + VkBuffer& destination, + size_t destinationOffset ) { device->getTransferCommandPool() - ->allocateCommandBuffer(VkCommandBuffer::Level::PRIMARY) - .record( - VkCommandBuffer::Usage::SINGLE, - [this, &destination, &destinationOffset](auto commandBuffer) { - VkBufferCopy region{ - .srcOffset = 0, - .dstOffset = destinationOffset, - .size = size, - }; - - vkCmdCopyBuffer(commandBuffer, buffer, destination.getBuffer(), 1, ®ion); - } - ) - .submit(device->getTransferQueue(), {}, {}, {}); + ->allocateCommandBuffer(VkCommandBuffer::Level::PRIMARY) + .record( + VkCommandBuffer::Usage::SINGLE, + [this, &destination, &destinationOffset](auto commandBuffer) { + VkBufferCopy region{ + .srcOffset = 0, + .dstOffset = destinationOffset, + .size = size, + }; + + vkCmdCopyBuffer(commandBuffer, buffer, destination.getBuffer(), 1, ®ion); + } + ) + .submit(device->getTransferQueue(), {}, {}, {}); } VkBuffer VkBuffer::stage( - const std::shared_ptr &device, - Usage usage, - size_t size, - const char *data + const std::shared_ptr& device, + const Usage usage, + const size_t size, + const char* data ) { auto source = VkBuffer(device, usage | Usage::TRANSFER_SRC, size); auto destination = VkBuffer(device, usage | Usage::TRANSFER_DST, size); diff --git a/src/engine/vk/VkBuffer.h b/src/engine/vk/VkBuffer.h index 17b2491..6918aa9 100644 --- a/src/engine/vk/VkBuffer.h +++ b/src/engine/vk/VkBuffer.h @@ -6,7 +6,7 @@ #include "Device.h" namespace Vixen::Vk { - class VkBuffer : public Buffer { + class VkBuffer final : public Buffer { std::shared_ptr device; VmaAllocation allocation; @@ -22,7 +22,7 @@ namespace Vixen::Vk { VkBuffer(VkBuffer &&o) noexcept; - ~VkBuffer(); + ~VkBuffer() override; char *map() override; @@ -52,8 +52,8 @@ namespace Vixen::Vk { template static VkBuffer stage( const std::shared_ptr &device, - Usage usage, - size_t size, + const Usage usage, + const size_t size, F lambda ) { auto source = VkBuffer(device, usage | Usage::TRANSFER_SRC, size); diff --git a/src/engine/vk/VkDescriptorPool.cpp b/src/engine/vk/VkDescriptorPool.cpp index fef2d66..589c618 100644 --- a/src/engine/vk/VkDescriptorPool.cpp +++ b/src/engine/vk/VkDescriptorPool.cpp @@ -22,7 +22,45 @@ namespace Vixen::Vk { ); } + VkDescriptorPool::VkDescriptorPool(VkDescriptorPool&& fp) noexcept + : pool(std::exchange(fp.pool, nullptr)), + device(std::move(fp.device)) {} + + VkDescriptorPool const& VkDescriptorPool::operator=(VkDescriptorPool&& fp) noexcept { + std::swap(fp.pool, pool); + std::swap(fp.device, device); + + return *this; + } + VkDescriptorPool::~VkDescriptorPool() { vkDestroyDescriptorPool(device->getDevice(), pool, nullptr); } + + VkDescriptorSet VkDescriptorPool::allocate(const VkDescriptorSetLayout &layout) const { + const auto &l = layout.getLayout(); + const VkDescriptorSetAllocateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = pool, + .descriptorSetCount = 1, + .pSetLayouts = &l + }; + + VkDescriptorSet set; + checkVulkanResult( + vkAllocateDescriptorSets(device->getDevice(), &info, &set), + "Failed to allocate descriptor set" + ); + + return set; + } + + std::shared_ptr VkDescriptorPool::getDevice() const { + return device; + } + + ::VkDescriptorPool VkDescriptorPool::getPool() const { + return pool; + } } diff --git a/src/engine/vk/VkDescriptorPool.h b/src/engine/vk/VkDescriptorPool.h index 33ead08..da5f21a 100644 --- a/src/engine/vk/VkDescriptorPool.h +++ b/src/engine/vk/VkDescriptorPool.h @@ -1,6 +1,6 @@ #pragma once -#include "Device.h" +#include "VkDescriptorSetLayout.h" namespace Vixen::Vk { class VkDescriptorPool { @@ -15,12 +15,20 @@ namespace Vixen::Vk { uint32_t maxSets ); - VkDescriptorPool(const VkDescriptorPool& other) = delete; + VkDescriptorPool(VkDescriptorPool& other) = delete; - VkDescriptorPool(VkDescriptorPool&& other) noexcept = delete; + VkDescriptorPool& operator=(const VkDescriptorPool& other) = delete; - VkDescriptorPool& operator=(VkDescriptorPool other) = delete; + VkDescriptorPool(VkDescriptorPool&& fp) noexcept; + + VkDescriptorPool const& operator=(VkDescriptorPool&& fp) noexcept; ~VkDescriptorPool(); + + [[nodiscard]] ::VkDescriptorSet allocate(const VkDescriptorSetLayout &layout) const; + + [[nodiscard]] std::shared_ptr getDevice() const; + + [[nodiscard]] ::VkDescriptorPool getPool() const; }; } diff --git a/src/engine/vk/VkDescriptorSet.cpp b/src/engine/vk/VkDescriptorSet.cpp new file mode 100644 index 0000000..1086e07 --- /dev/null +++ b/src/engine/vk/VkDescriptorSet.cpp @@ -0,0 +1,71 @@ +#include "VkDescriptorSet.h" + +namespace Vixen::Vk { + VkDescriptorSet::VkDescriptorSet( + const std::shared_ptr& device, + const std::shared_ptr& pool, + const VkDescriptorSetLayout& layout + ) : set(VK_NULL_HANDLE), + device(device), + pool(pool) { + const auto& l = layout.getLayout(); + const VkDescriptorSetAllocateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = pool->getPool(), + .descriptorSetCount = 1, + .pSetLayouts = &l + }; + + checkVulkanResult( + vkAllocateDescriptorSets(device->getDevice(), &info, &set), + "Failed to allocate descriptor set" + ); + } + + VkDescriptorSet::VkDescriptorSet(VkDescriptorSet&& fp) noexcept + : set(std::exchange(fp.set, nullptr)), + device(std::move(device)), + pool(std::move(pool)) {} + + VkDescriptorSet const& VkDescriptorSet::operator=(VkDescriptorSet&& fp) noexcept { + std::swap(fp.set, set); + std::swap(fp.device, device); + std::swap(fp.pool, pool); + + return *this; + } + + VkDescriptorSet::~VkDescriptorSet() { + vkFreeDescriptorSets(device->getDevice(), pool->getPool(), 1, &set); + } + + void VkDescriptorSet::updateUniformBuffer(const uint32_t binding, const VkBuffer& buffer) const { + const VkDescriptorBufferInfo bufferInfo{ + .buffer = buffer.getBuffer(), + // TODO: This can't be hardcoded in the future to deal with buffers storing + // multiple descriptors (or other things), will need a better solution + .offset = 0, + .range = buffer.getSize() + }; + + const VkWriteDescriptorSet write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = set, + .dstBinding = binding, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pImageInfo = nullptr, + .pBufferInfo = &bufferInfo, + .pTexelBufferView = nullptr + }; + + vkUpdateDescriptorSets(device->getDevice(), 1, &write, 0, nullptr); + } + + ::VkDescriptorSet VkDescriptorSet::getSet() const { + return set; + } +} diff --git a/src/engine/vk/VkDescriptorSet.h b/src/engine/vk/VkDescriptorSet.h new file mode 100644 index 0000000..78d2f42 --- /dev/null +++ b/src/engine/vk/VkDescriptorSet.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Device.h" +#include "VkDescriptorPool.h" +#include "VkBuffer.h" + +namespace Vixen::Vk { + class VkDescriptorSet { + ::VkDescriptorSet set; + + std::shared_ptr device; + + std::shared_ptr pool; + + public: + VkDescriptorSet( + const std::shared_ptr& device, + const std::shared_ptr& pool, + const VkDescriptorSetLayout& layout + ); + + VkDescriptorSet(VkDescriptorSet& other) = delete; + + VkDescriptorSet& operator=(const VkDescriptorSet& other) = delete; + + VkDescriptorSet(VkDescriptorSet&& fp) noexcept; + + VkDescriptorSet const& operator=(VkDescriptorSet&& fp) noexcept; + + ~VkDescriptorSet(); + + void updateUniformBuffer( + uint32_t binding, + const VkBuffer &buffer + ) const; + + [[nodiscard]] ::VkDescriptorSet getSet() const; + }; +} diff --git a/src/engine/vk/VkDescriptorSetLayout.cpp b/src/engine/vk/VkDescriptorSetLayout.cpp index 03e169f..a7a188c 100644 --- a/src/engine/vk/VkDescriptorSetLayout.cpp +++ b/src/engine/vk/VkDescriptorSetLayout.cpp @@ -1,5 +1,39 @@ #include "VkDescriptorSetLayout.h" namespace Vixen::Vk { + VkDescriptorSetLayout::VkDescriptorSetLayout( + const std::shared_ptr& device, + const std::vector& bindings + ) : layout(VK_NULL_HANDLE) { + const VkDescriptorSetLayoutCreateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = static_cast(bindings.size()), + .pBindings = bindings.data() + }; + checkVulkanResult( + vkCreateDescriptorSetLayout(device->getDevice(), &info, nullptr, &layout), + "Failed to create descriptor set layout" + ); + } + + VkDescriptorSetLayout::VkDescriptorSetLayout(VkDescriptorSetLayout&& fp) noexcept + : layout(std::exchange(fp.layout, nullptr)), + device(std::move(fp.device)) {} + + VkDescriptorSetLayout const& VkDescriptorSetLayout::operator=(VkDescriptorSetLayout&& fp) noexcept { + std::swap(fp.layout, layout); + + return *this; + } + + VkDescriptorSetLayout::~VkDescriptorSetLayout() { + vkDestroyDescriptorSetLayout(device->getDevice(), layout, nullptr); + } + + ::VkDescriptorSetLayout VkDescriptorSetLayout::getLayout() const { + return layout; + } } diff --git a/src/engine/vk/VkDescriptorSetLayout.h b/src/engine/vk/VkDescriptorSetLayout.h index 62e5042..4c6ae91 100644 --- a/src/engine/vk/VkDescriptorSetLayout.h +++ b/src/engine/vk/VkDescriptorSetLayout.h @@ -4,7 +4,26 @@ namespace Vixen::Vk { class VkDescriptorSetLayout { + ::VkDescriptorSetLayout layout; + + std::shared_ptr device; + public: + VkDescriptorSetLayout( + const std::shared_ptr& device, + const std::vector& bindings + ); + + VkDescriptorSetLayout(VkDescriptorSetLayout& other) = delete; + + VkDescriptorSetLayout& operator=(const VkDescriptorSetLayout& other) = delete; + + VkDescriptorSetLayout(VkDescriptorSetLayout&& fp) noexcept; + + VkDescriptorSetLayout const& operator=(VkDescriptorSetLayout&& fp) noexcept; + + ~VkDescriptorSetLayout(); + [[nodiscard]] ::VkDescriptorSetLayout getLayout() const; }; } diff --git a/src/engine/vk/VkPipeline.cpp b/src/engine/vk/VkPipeline.cpp index c235136..5e47c62 100644 --- a/src/engine/vk/VkPipeline.cpp +++ b/src/engine/vk/VkPipeline.cpp @@ -2,10 +2,10 @@ namespace Vixen::Vk { VkPipeline::VkPipeline( - const std::shared_ptr &device, - const Swapchain &swapchain, - const VkShaderProgram &program, - const Config &config + const std::shared_ptr& device, + const Swapchain& swapchain, + const VkShaderProgram& program, + const Config& config ) : device(device), program(program), config(config), @@ -15,108 +15,110 @@ namespace Vixen::Vk { stages.emplace_back(program.getVertex()->createInfo()); stages.emplace_back(program.getFragment()->createInfo()); - std::vector dynamicStates{ - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR + constexpr std::array dynamicStates{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamicStateInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = static_cast(dynamicStates.size()), - .pDynamicStates = dynamicStates.data() + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = static_cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data() }; - const auto &vertexModule = program.getVertex(); + const auto& vertexModule = program.getVertex(); std::vector vertexBindings{}; - for (const auto &binding: vertexModule->getBindings()) { - VkVertexInputRate rate; - switch (binding.rate) { - case ShaderModule::Rate::VERTEX: - rate = VK_VERTEX_INPUT_RATE_VERTEX; - break; - case ShaderModule::Rate::INSTANCE: - rate = VK_VERTEX_INPUT_RATE_INSTANCE; - break; + for (const auto& [binding, stride, rate] : vertexModule->getBindings()) { + VkVertexInputRate r; + switch (rate) { + case ShaderModule::Rate::VERTEX: + r = VK_VERTEX_INPUT_RATE_VERTEX; + break; + case ShaderModule::Rate::INSTANCE: + r = VK_VERTEX_INPUT_RATE_INSTANCE; + break; + default: + throw std::runtime_error("Not implemented input rate"); } vertexBindings.push_back( - { - .binding = binding.binding, - .stride = static_cast(binding.stride), - // TODO: Allow specification of input rate - .inputRate = rate - } + { + .binding = binding, + .stride = static_cast(stride), + // TODO: Allow specification of input rate + .inputRate = r + } ); } std::vector vertexAttributes{}; - for (const auto &input: vertexModule->getInputs()) { + for (const auto& input : vertexModule->getInputs()) { vertexAttributes.push_back( - { - .location = input.location.value_or(0), - .binding = input.binding.value_or(0), - // TODO: Automatically determine the format and offset - .format = VK_FORMAT_R32G32B32_SFLOAT, - .offset = static_cast(input.offset) - } + { + .location = input.location.value_or(0), + .binding = input.binding.value_or(0), + // TODO: Automatically determine the format and offset + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = static_cast(input.offset) + } ); } VkPipelineVertexInputStateCreateInfo vertexInputInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = static_cast(vertexBindings.size()), - .pVertexBindingDescriptions = vertexBindings.data(), - .vertexAttributeDescriptionCount = static_cast(vertexAttributes.size()), - .pVertexAttributeDescriptions = vertexAttributes.data(), + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = static_cast(vertexBindings.size()), + .pVertexBindingDescriptions = vertexBindings.data(), + .vertexAttributeDescriptionCount = static_cast(vertexAttributes.size()), + .pVertexAttributeDescriptions = vertexAttributes.data(), }; VkPipelineViewportStateCreateInfo viewportInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .viewportCount = 1, - .pViewports = &config.viewport, - .scissorCount = 1, - .pScissors = &config.scissor + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &config.viewport, + .scissorCount = 1, + .pScissors = &config.scissor }; VkPipelineColorBlendStateCreateInfo colorBlendInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .logicOpEnable = VK_FALSE, - .logicOp = VK_LOGIC_OP_COPY, - .attachmentCount = 1, - .pAttachments = &config.colorBlendAttachment, - .blendConstants = { - 0.0f, - 0.0f, - 0.0f, - 0.0f - } + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &config.colorBlendAttachment, + .blendConstants = { + 0.0f, + 0.0f, + 0.0f, + 0.0f + } }; VkGraphicsPipelineCreateInfo pipelineInfo{ - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = static_cast(stages.size()), - .pStages = stages.data(), - .pVertexInputState = &vertexInputInfo, - .pInputAssemblyState = &config.inputAssemblyInfo, - .pViewportState = &viewportInfo, - .pRasterizationState = &config.rasterizationInfo, - .pMultisampleState = &config.multisampleInfo, - .pDepthStencilState= &config.depthStencilInfo, - .pColorBlendState = &colorBlendInfo, - .pDynamicState = &dynamicStateInfo, - - .layout = pipelineLayout.getLayout(), - .renderPass = renderPass.getRenderPass(), - .subpass = config.subpass, - - .basePipelineHandle = VK_NULL_HANDLE, - .basePipelineIndex = -1, + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = static_cast(stages.size()), + .pStages = stages.data(), + .pVertexInputState = &vertexInputInfo, + .pInputAssemblyState = &config.inputAssemblyInfo, + .pViewportState = &viewportInfo, + .pRasterizationState = &config.rasterizationInfo, + .pMultisampleState = &config.multisampleInfo, + .pDepthStencilState = &config.depthStencilInfo, + .pColorBlendState = &colorBlendInfo, + .pDynamicState = &dynamicStateInfo, + + .layout = pipelineLayout.getLayout(), + .renderPass = renderPass.getRenderPass(), + .subpass = config.subpass, + + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1, }; checkVulkanResult( - vkCreateGraphicsPipelines(device->getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline), - "Failed to create Vulkan pipeline" + vkCreateGraphicsPipelines(device->getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline), + "Failed to create Vulkan pipeline" ); } @@ -140,15 +142,15 @@ namespace Vixen::Vk { bind(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR); } - const VkShaderProgram &VkPipeline::getProgram() const { + const VkShaderProgram& VkPipeline::getProgram() const { return program; } - const VkRenderPass &VkPipeline::getRenderPass() const { + const VkRenderPass& VkPipeline::getRenderPass() const { return renderPass; } - const VkPipeline::Config &VkPipeline::getConfig() const { + const VkPipeline::Config& VkPipeline::getConfig() const { return config; } } diff --git a/src/engine/vk/VkPipeline.h b/src/engine/vk/VkPipeline.h index 8f384ae..9bf3178 100644 --- a/src/engine/vk/VkPipeline.h +++ b/src/engine/vk/VkPipeline.h @@ -83,7 +83,7 @@ namespace Vixen::Vk { .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, + .cullMode = VK_CULL_MODE_BACK_BIT, .frontFace = VK_FRONT_FACE_CLOCKWISE, .depthBiasEnable = VK_FALSE, .depthBiasConstantFactor = 0.0f, @@ -132,7 +132,8 @@ namespace Vixen::Vk { } Builder &setHeight(uint32_t h) { - config.viewport.height = static_cast(h); + config.viewport.height = static_cast(-h); + config.viewport.y = static_cast(h); config.scissor.extent.height = h; return *this; } diff --git a/src/engine/vk/VkPipelineLayout.cpp b/src/engine/vk/VkPipelineLayout.cpp index a15394f..19b7fc4 100644 --- a/src/engine/vk/VkPipelineLayout.cpp +++ b/src/engine/vk/VkPipelineLayout.cpp @@ -1,20 +1,22 @@ #include "VkPipelineLayout.h" namespace Vixen::Vk { - - VkPipelineLayout::VkPipelineLayout(const std::shared_ptr &device, const VkShaderProgram &program) - : device(device) { - VkPipelineLayoutCreateInfo pipelineLayoutInfo{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 0, - .pSetLayouts = nullptr, - .pushConstantRangeCount = 0, - .pPushConstantRanges = nullptr, + VkPipelineLayout::VkPipelineLayout(const std::shared_ptr& device, const VkShaderProgram& program) + : device(device) { + const auto& l = program.getVertex()->getDescriptorSetLayout().getLayout(); + const VkPipelineLayoutCreateInfo pipelineLayoutInfo{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = &l, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr }; - Vk::checkVulkanResult( - vkCreatePipelineLayout(device->getDevice(), &pipelineLayoutInfo, nullptr, &layout), - "Failed to create pipeline layout" + checkVulkanResult( + vkCreatePipelineLayout(device->getDevice(), &pipelineLayoutInfo, nullptr, &layout), + "Failed to create pipeline layout" ); } diff --git a/src/engine/vk/VkRenderer.cpp b/src/engine/vk/VkRenderer.cpp index 7be24d7..a708c29 100644 --- a/src/engine/vk/VkRenderer.cpp +++ b/src/engine/vk/VkRenderer.cpp @@ -2,24 +2,24 @@ namespace Vixen::Vk { VkRenderer::VkRenderer( - const std::shared_ptr &device, - Swapchain &swapchain, - const std::shared_ptr &pipeline + const std::shared_ptr& device, + Swapchain& swapchain, + const std::shared_ptr& pipeline ) : device(device), swapchain(swapchain), pipeline(pipeline), pipelineLayout(std::make_unique(device, pipeline->getProgram())), renderCommandPool(std::make_shared( - device->getDevice(), - device->getGraphicsQueueFamily().index, - VkCommandPool::Usage::GRAPHICS, - true + device->getDevice(), + device->getGraphicsQueueFamily().index, + VkCommandPool::Usage::GRAPHICS, + true )), renderCommandBuffers( - renderCommandPool->allocateCommandBuffers( - VkCommandBuffer::Level::PRIMARY, - swapchain.getImageCount() - ) + renderCommandPool->allocateCommandBuffers( + VkCommandBuffer::Level::PRIMARY, + swapchain.getImageCount() + ) ) { const auto imageCount = swapchain.getImageCount(); renderFinishedSemaphores.reserve(imageCount); @@ -33,31 +33,37 @@ namespace Vixen::Vk { device->waitIdle(); } - void VkRenderer::render(const VkBuffer &buffer, uint32_t vertexCount, uint32_t indexCount) { + void VkRenderer::render( + const VkBuffer& buffer, + uint32_t vertexCount, + uint32_t indexCount, + const VkDescriptorSet& set + ) { auto state = swapchain.acquireImage( - std::numeric_limits::max(), - [this, &buffer, &vertexCount, &indexCount]( - const auto ¤tFrame, - const auto &imageIndex, - const auto &imageAvailableSemaphore - ) { - auto &commandBuffer = renderCommandBuffers[currentFrame]; - - prepare(commandBuffer, framebuffers[imageIndex], buffer, vertexCount, indexCount); - - std::vector<::VkSemaphore> waitSemaphores = {imageAvailableSemaphore.getSemaphore()}; - std::vector<::VkSemaphore> signalSemaphores = { - renderFinishedSemaphores[currentFrame].getSemaphore()}; - - commandBuffer.submit( - device->getGraphicsQueue(), - waitSemaphores, - {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}, - signalSemaphores - ); - - swapchain.present(imageIndex, signalSemaphores); - } + std::numeric_limits::max(), + [this, &buffer, &vertexCount, &indexCount, &set]( + const auto& currentFrame, + const auto& imageIndex, + const auto& imageAvailableSemaphore + ) { + auto& commandBuffer = renderCommandBuffers[currentFrame]; + + prepare(commandBuffer, framebuffers[imageIndex], buffer, vertexCount, indexCount, set); + + std::vector<::VkSemaphore> waitSemaphores = {imageAvailableSemaphore.getSemaphore()}; + std::vector<::VkSemaphore> signalSemaphores = { + renderFinishedSemaphores[currentFrame].getSemaphore() + }; + + commandBuffer.submit( + device->getGraphicsQueue(), + waitSemaphores, + {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}, + signalSemaphores + ); + + swapchain.present(imageIndex, signalSemaphores); + } ); if (state == Swapchain::State::OUT_OF_DATE) { @@ -74,127 +80,140 @@ namespace Vixen::Vk { } void VkRenderer::prepare( - VkCommandBuffer &commandBuffer, - VkFramebuffer &framebuffer, - const VkBuffer &buffer, - uint32_t vertexCount, - uint32_t indexCount - ) { + VkCommandBuffer& commandBuffer, + VkFramebuffer& framebuffer, + const VkBuffer& buffer, + uint32_t vertexCount, + uint32_t indexCount, + const VkDescriptorSet& set + ) const { commandBuffer.record( - VkCommandBuffer::Usage::SIMULTANEOUS, - [this, &framebuffer, &buffer, &vertexCount, &indexCount](::VkCommandBuffer commandBuffer) { - std::vector clearValues{ - { - .color = { - 0.0f, - 0.0f, - 0.0f, - 1.0f - } - }, - { - .depthStencil = { - 1.0f, - 0 - } - } - }; - - VkRenderPassBeginInfo renderPassInfo{ - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = pipeline->getRenderPass().getRenderPass(), - .framebuffer = framebuffer.getFramebuffer(), - .renderArea = { - .offset = { - .x = 0, - .y = 0 - }, - .extent = swapchain.getExtent(), - }, - .clearValueCount = static_cast(clearValues.size()), - .pClearValues = clearValues.data() - }; - - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - pipeline->bindGraphics(commandBuffer); - - VkViewport viewport{ - .x = 0.0f, - .y = 0.0f, - .width = static_cast(swapchain.getExtent().width), - .height = static_cast(swapchain.getExtent().height), - .minDepth = 0.0f, - .maxDepth = 1.0f, - }; - vkCmdSetViewport(commandBuffer, 0, 1, &viewport); - - VkRect2D scissor{ - .offset = {0, 0}, - .extent = swapchain.getExtent(), - }; - vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - - ::VkBuffer vertexBuffers[1]{buffer.getBuffer()}; - // TODO: Hardcoded buffer offset should probably automatically be determined somehow - ::VkDeviceSize offsets[] = {0}; - - vkCmdBindVertexBuffers( - commandBuffer, - 0, - 1, - vertexBuffers, - offsets - ); - - vkCmdBindIndexBuffer( - commandBuffer, - buffer.getBuffer(), - vertexCount * 24, - VK_INDEX_TYPE_UINT32 - ); - - // TODO: Hardcoded buffer offset should probably automatically be determined somehow - vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0); - - vkCmdEndRenderPass(commandBuffer); - } + VkCommandBuffer::Usage::SIMULTANEOUS, + [this, &framebuffer, &buffer, &vertexCount, &indexCount, &set](::VkCommandBuffer commandBuffer) { + std::vector clearValues{ + { + .color = { + 0.0f, + 0.0f, + 0.0f, + 1.0f + } + }, + { + .depthStencil = { + 1.0f, + 0 + } + } + }; + + const VkRenderPassBeginInfo renderPassInfo{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = pipeline->getRenderPass().getRenderPass(), + .framebuffer = framebuffer.getFramebuffer(), + .renderArea = { + .offset = { + .x = 0, + .y = 0 + }, + .extent = swapchain.getExtent(), + }, + .clearValueCount = static_cast(clearValues.size()), + .pClearValues = clearValues.data() + }; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + pipeline->bindGraphics(commandBuffer); + + const VkViewport viewport{ + .x = 0.0f, + .y = 0.0f, + .width = static_cast(swapchain.getExtent().width), + .height = static_cast(swapchain.getExtent().height), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + const VkRect2D scissor{ + .offset = {0, 0}, + .extent = swapchain.getExtent(), + }; + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + const ::VkBuffer vertexBuffers[1]{buffer.getBuffer()}; + // TODO: Hardcoded buffer offset should probably automatically be determined somehow + constexpr VkDeviceSize offsets[] = {0}; + + vkCmdBindVertexBuffers( + commandBuffer, + 0, + 1, + vertexBuffers, + offsets + ); + + vkCmdBindIndexBuffer( + commandBuffer, + buffer.getBuffer(), + vertexCount * 24, + VK_INDEX_TYPE_UINT32 + ); + + const auto& s = set.getSet(); + vkCmdBindDescriptorSets( + commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout->getLayout(), + 0, + 1, + &s, + 0, + nullptr + ); + + // TODO: Hardcoded buffer offset should probably automatically be determined somehow + vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0); + + vkCmdEndRenderPass(commandBuffer); + } ); } void VkRenderer::createFramebuffers() { - const auto &imageCount = swapchain.getImageCount(); + const auto& imageCount = swapchain.getImageCount(); depthImages.reserve(imageCount); depthImageViews.reserve(imageCount); framebuffers.reserve(imageCount); for (size_t i = 0; i < imageCount; i++) { depthImages.emplace_back( - device, - swapchain.getExtent().width, - swapchain.getExtent().height, - VK_SAMPLE_COUNT_1_BIT, - VK_FORMAT_D32_SFLOAT, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + device, + swapchain.getExtent().width, + swapchain.getExtent().height, + VK_SAMPLE_COUNT_1_BIT, + VK_FORMAT_D32_SFLOAT, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); depthImageViews.emplace_back( - std::make_unique( - depthImages[i], - VK_IMAGE_ASPECT_DEPTH_BIT - ) + std::make_unique( + depthImages[i], + VK_IMAGE_ASPECT_DEPTH_BIT + ) ); framebuffers.emplace_back( - device, - pipeline->getRenderPass(), - swapchain.getExtent().width, - swapchain.getExtent().height, - std::vector<::VkImageView>{ - swapchain.getImageViews()[i], - depthImageViews[i]->getImageView() - } + device, + pipeline->getRenderPass(), + swapchain.getExtent().width, + swapchain.getExtent().height, + std::vector{ + swapchain.getImageViews()[i], + depthImageViews[i]->getImageView() + } ); } } diff --git a/src/engine/vk/VkRenderer.h b/src/engine/vk/VkRenderer.h index b39ea9d..5cff7f6 100644 --- a/src/engine/vk/VkRenderer.h +++ b/src/engine/vk/VkRenderer.h @@ -6,12 +6,13 @@ #include "VkFramebuffer.h" #include "VkSemaphore.h" #include "VkBuffer.h" +#include "VkDescriptorSet.h" namespace Vixen::Vk { class VkRenderer { std::shared_ptr device; - Swapchain &swapchain; + Swapchain& swapchain; std::unique_ptr pipelineLayout; @@ -31,28 +32,34 @@ namespace Vixen::Vk { public: VkRenderer( - const std::shared_ptr &device, - Swapchain &swapchain, - const std::shared_ptr &pipeline + const std::shared_ptr& device, + Swapchain& swapchain, + const std::shared_ptr& pipeline ); - VkRenderer(const VkRenderer &) = delete; + VkRenderer(const VkRenderer&) = delete; - VkRenderer &operator=(const VkRenderer &) = delete; + VkRenderer& operator=(const VkRenderer&) = delete; ~VkRenderer(); - void render(const VkBuffer &buffer, uint32_t vertexCount, uint32_t indexCount); + void render( + const VkBuffer& buffer, + uint32_t vertexCount, + uint32_t indexCount, + const VkDescriptorSet& set + ); private: void createFramebuffers(); void prepare( - VkCommandBuffer &commandBuffer, - VkFramebuffer &framebuffer, - const VkBuffer &buffer, - uint32_t vertexCount, - uint32_t indexCount - ); + VkCommandBuffer& commandBuffer, + VkFramebuffer& framebuffer, + const VkBuffer& buffer, + uint32_t vertexCount, + uint32_t indexCount, + const VkDescriptorSet& set + ) const; }; } diff --git a/src/engine/vk/VkShaderModule.cpp b/src/engine/vk/VkShaderModule.cpp index 50b80f1..5989961 100644 --- a/src/engine/vk/VkShaderModule.cpp +++ b/src/engine/vk/VkShaderModule.cpp @@ -7,10 +7,12 @@ namespace Vixen::Vk { const std::vector& binary, const std::vector& bindings, const std::vector& inputs, + const std::vector& uniformBuffers, const std::string& entrypoint - ) : ShaderModule(stage, entrypoint, bindings, inputs), + ) : ShaderModule(stage, entrypoint, bindings, inputs, uniformBuffers), device(device), - module(VK_NULL_HANDLE) { + module(VK_NULL_HANDLE), + descriptorSetLayout(device, createBindings()) { const VkShaderModuleCreateInfo info{ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .codeSize = binary.size() * sizeof(uint32_t), @@ -40,15 +42,16 @@ namespace Vixen::Vk { } std::vector VkShaderModule::createBindings() const { - const auto& bindings = getBindings(); + const VkShaderStageFlags& stage = getVulkanShaderStage(getStage()); + const auto& uniformBuffers = getUniformBuffers(); - std::vector b{bindings.size()}; - for (const auto& [binding, stride, rate] : bindings) { - const VkShaderStageFlags& stage = getVulkanShaderStage(getStage()); - - b.push_back( + std::vector b{}; + b.reserve(uniformBuffers.size()); + for (const auto& [binding, location, size, offset] : uniformBuffers) { + b.emplace_back( VkDescriptorSetLayoutBinding{ - .binding = binding, + .binding = binding.value_or(0), + // TODO: Remove hardcoded descriptor type .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // TODO: This count value is used for array bindings .descriptorCount = 1, @@ -60,4 +63,8 @@ namespace Vixen::Vk { return b; } + + const VkDescriptorSetLayout& VkShaderModule::getDescriptorSetLayout() { + return descriptorSetLayout; + } } diff --git a/src/engine/vk/VkShaderModule.h b/src/engine/vk/VkShaderModule.h index 60c2d8d..78edce9 100644 --- a/src/engine/vk/VkShaderModule.h +++ b/src/engine/vk/VkShaderModule.h @@ -17,6 +17,7 @@ #include "../ShaderModule.h" #include "Vulkan.h" #include "Device.h" +#include "VkDescriptorSetLayout.h" #define VIXEN_VK_SPIRV_VERSION 130 @@ -26,6 +27,8 @@ namespace Vixen::Vk { std::shared_ptr device; + VkDescriptorSetLayout descriptorSetLayout; + public: VkShaderModule( const std::shared_ptr& device, @@ -33,6 +36,7 @@ namespace Vixen::Vk { const std::vector& binary, const std::vector& bindings, const std::vector& inputs, + const std::vector& uniformBuffers, const std::string& entrypoint = "main" ); @@ -46,6 +50,8 @@ namespace Vixen::Vk { [[nodiscard]] std::vector createBindings() const; + [[nodiscard]] const VkDescriptorSetLayout& getDescriptorSetLayout(); + class Builder { // TODO: This builder has slightly confusing API, you can compile before setting the stage meaning its possible to mistakenly have the wrong stage set at compile time Stage stage; @@ -180,7 +186,7 @@ namespace Vixen::Vk { glslang::FinalizeProcess(); - return std::make_shared(d, stage, binary, bindings, inputs, entrypoint); + return std::make_shared(d, stage, binary, bindings, inputs, uniformBuffers, entrypoint); } std::shared_ptr compile(const std::shared_ptr& d, const std::string& source) { diff --git a/src/engine/vk/VkVixen.cpp b/src/engine/vk/VkVixen.cpp index c3c6354..b96f115 100644 --- a/src/engine/vk/VkVixen.cpp +++ b/src/engine/vk/VkVixen.cpp @@ -14,7 +14,6 @@ namespace Vixen::Vk { )), swapchain(device, 3) { window.center(); - window.maximize(); window.setVisible(true); } } diff --git a/src/engine/vk/test/main.cpp b/src/engine/vk/test/main.cpp index a98937e..3f1fcc2 100644 --- a/src/engine/vk/test/main.cpp +++ b/src/engine/vk/test/main.cpp @@ -10,12 +10,20 @@ #include "VkPipeline.h" #include "VkRenderer.h" #include "VkDescriptorPool.h" +#include "VkDescriptorSet.h" +#include "../../Camera.h" struct Vertex { glm::vec3 position; glm::vec3 color; }; +struct UniformBufferObject { + glm::mat4 model; + glm::mat4 view; + glm::mat4 projection; +}; + int main() { #ifdef _WIN32 system(("chcp " + std::to_string(CP_UTF8)).c_str()); @@ -45,7 +53,7 @@ int main() { }) .compileFromFile(vixen.device, "../../src/editor/shaders/triangle.vert"); const auto fragment = Vixen::Vk::VkShaderModule::Builder(Vixen::ShaderModule::Stage::FRAGMENT) - .compileFromFile(vixen.device, "../../src/editor/shaders/triangle.frag"); + .compileFromFile(vixen.device, "../../src/editor/shaders/triangle.frag"); const auto program = Vixen::Vk::VkShaderProgram(vertex, fragment); int width; @@ -92,13 +100,31 @@ int main() { } ); + auto camera = Vixen::Camera({0.0f, 0.0f, -5.0f}); + const std::vector sizes{ { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1 } }; - const auto pool = Vixen::Vk::VkDescriptorPool(vixen.device, sizes, 1); + + auto uniformBuffer = Vixen::Vk::VkBuffer( + vixen.device, + Vixen::Buffer::Usage::UNIFORM, + sizeof(UniformBufferObject) + ); + + UniformBufferObject ubo{ + glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)), + camera.view(), + camera.perspective(static_cast(width) / static_cast(height)) + }; + uniformBuffer.write(reinterpret_cast(&ubo), sizeof(UniformBufferObject), 0); + + auto descriptorPool = std::make_shared(vixen.device, sizes, 1); + auto descriptorSet = Vixen::Vk::VkDescriptorSet(vixen.device, descriptorPool, vertex->getDescriptorSetLayout()); + descriptorSet.updateUniformBuffer(0, uniformBuffer); double old = glfwGetTime(); uint32_t fps = 0; @@ -109,7 +135,7 @@ int main() { renderer = std::make_unique(vixen.device, vixen.swapchain, pipeline); } - renderer->render(buffer, vertices.size(), indices.size()); + renderer->render(buffer, vertices.size(), indices.size(), descriptorSet); fps++; if (const double& now = glfwGetTime(); now - old >= 1) {