248 lines
12 KiB
C++
248 lines
12 KiB
C++
#include "renderer2D.hpp"
|
|
|
|
#include "exceptions.hpp"
|
|
#include "vk_enum_string.h"
|
|
|
|
#include <cstring>
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
|
|
namespace gz::vk {
|
|
|
|
Renderer2D::Renderer2D(VulkanInstance& instance) :
|
|
Renderer(instance),
|
|
rLog("renderer2D.log", true, false, "2D-Renderer", Color::BMAGENTA, true, 100) {
|
|
vk.createCommandBuffers(commandBuffers);
|
|
const size_t vertexCount = 500;
|
|
const size_t indexCount = 1000;
|
|
vk.createVertexBuffer<Vertex2D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize);
|
|
vk.createIndexBuffer<uint32_t>(indexCount, indexBuffer, indexBufferMemory, indexBufferSize);
|
|
createRenderPass();
|
|
createImages();
|
|
renderPassID = vk.createFramebuffers(imageViews, renderPass);
|
|
rLog("Created Renderer2D");
|
|
}
|
|
|
|
|
|
void Renderer2D::cleanup() {
|
|
cleanup_();
|
|
}
|
|
|
|
void Renderer2D::createImages() {
|
|
images.resize(vk.scImages.size());
|
|
imageMemory.resize(vk.scImages.size());
|
|
imageViews.resize(vk.scImages.size());
|
|
VkImageUsageFlags usage= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
for (size_t i = 0; i < images.size(); i++) {
|
|
vk.createImage(vk.scExtent.width, vk.scExtent.height, vk.scImageFormat, VK_IMAGE_TILING_OPTIMAL, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, images[i], imageMemory[i]);
|
|
vk.createImageView(vk.scImageFormat, images[i], imageViews[i], VK_IMAGE_ASPECT_COLOR_BIT);
|
|
}
|
|
|
|
}
|
|
|
|
void Renderer2D::createRenderPass() {
|
|
VkAttachmentDescription colorBlendAttachment{};
|
|
colorBlendAttachment.format = vk.scImageFormat;
|
|
colorBlendAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
colorBlendAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
colorBlendAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
colorBlendAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
colorBlendAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
colorBlendAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
colorBlendAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
|
|
|
VkAttachmentReference colorAttachmentRef{};
|
|
colorAttachmentRef.attachment = 0;
|
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
|
|
/* VkAttachmentDescription depthAttachment{}; */
|
|
/* depthAttachment.format = findDepthFormat(); */
|
|
/* depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; */
|
|
/* depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; */
|
|
/* depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */
|
|
/* depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; */
|
|
/* depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */
|
|
/* depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; */
|
|
/* depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */
|
|
|
|
/* VkAttachmentReference depthAttachmentRef{}; */
|
|
/* depthAttachmentRef.attachment = 1; */
|
|
/* depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */
|
|
|
|
VkSubpassDescription subpass{};
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
subpass.colorAttachmentCount = 1;
|
|
subpass.pColorAttachments = &colorAttachmentRef;
|
|
/* subpass.pDepthStencilAttachment = &depthAttachmentRef; */
|
|
|
|
VkSubpassDependency dependency{};
|
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
dependency.dstSubpass = 0;
|
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dependency.srcAccessMask = 0;
|
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
/* VkSubpassDependency dependency{}; */
|
|
/* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */
|
|
/* dependency.dstSubpass = 0; */
|
|
/* dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */
|
|
/* dependency.srcAccessMask = 0; */
|
|
/* dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */
|
|
/* dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; */
|
|
|
|
/* std::array<VkAttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */
|
|
std::vector<VkAttachmentDescription> attachments = { colorBlendAttachment };
|
|
VkRenderPassCreateInfo renderPassCI{};
|
|
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size());
|
|
renderPassCI.pAttachments = attachments.data();
|
|
renderPassCI.subpassCount = 1;
|
|
renderPassCI.pSubpasses = &subpass;
|
|
renderPassCI.dependencyCount = 1;
|
|
renderPassCI.pDependencies = &dependency;
|
|
/* renderPassCI.dependencyCount = 0; */
|
|
/* renderPassCI.pDependencies = nullptr; */
|
|
/* renderPassCI.correlatedViewMaskCount = 0; */
|
|
/* renderPassCI.pCorrelatedViewMasks = nullptr; */
|
|
VkResult result = vkCreateRenderPass(vk.device, &renderPassCI, nullptr, &renderPass);
|
|
if (result != VK_SUCCESS) {
|
|
throw getVkException(result, "Could not create render pass", "Renderer2D::createRenderPass");
|
|
}
|
|
rLog("createRenderPass: Created render pass.");
|
|
|
|
}
|
|
|
|
|
|
void Renderer2D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) {
|
|
VkCommandBufferBeginInfo commandBufferBI{};
|
|
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
/* commandBufferBI.flags = 0; */
|
|
/* commandBufferBI.pInheritanceInfo = nullptr; */
|
|
VkResult result = vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBI);
|
|
if (result != VK_SUCCESS) {
|
|
throw getVkException(result, "Failed to begin 2D command buffer", "Renderer2D::recordCommandBuffer");
|
|
}
|
|
|
|
VkRenderPassBeginInfo renderPassBI{};
|
|
renderPassBI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
renderPassBI.renderPass = renderPass;
|
|
renderPassBI.framebuffer = vk.getFramebuffers(renderPassID)[imageIndex];
|
|
renderPassBI.renderArea.offset = { 0, 0 };
|
|
renderPassBI.renderArea.extent = vk.scExtent;
|
|
// clear
|
|
std::array<VkClearValue, 2> clearValues{};
|
|
clearValues[0].color = {{1.0f, 0.0f, 0.0f, 1.0f}};
|
|
clearValues[1].depthStencil = {1.0f, 0};
|
|
renderPassBI.clearValueCount = static_cast<uint32_t>(clearValues.size());
|
|
renderPassBI.pClearValues = clearValues.data();
|
|
|
|
vkCmdBeginRenderPass(commandBuffers[currentFrame], &renderPassBI, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
vkCmdBindPipeline(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, vk.pipelines[PL_2D].pipeline);
|
|
VkBuffer vertexBuffers[] = { vertexBuffer };
|
|
VkDeviceSize offsets[] = {0};
|
|
uint32_t bindingCount = 1;
|
|
vkCmdBindVertexBuffers(commandBuffers[currentFrame], BINDING, bindingCount, vertexBuffers, offsets);
|
|
// TODO use correct index type!
|
|
vkCmdBindIndexBuffer(commandBuffers[currentFrame], indexBuffer, NO_OFFSET, VK_INDEX_TYPE_UINT32);
|
|
|
|
/* uint32_t descriptorCount = 1; */
|
|
/* uint32_t firstSet = 0; */
|
|
/* uint32_t dynamicOffsetCount = 0; */
|
|
/* uint32_t* dynamicOffsets = nullptr; */
|
|
/* vkCmdBindDescriptorSets(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_2D].layout, firstSet, descriptorCount, &descriptorSets[currentFrame], dynamicOffsetCount, dynamicOffsets); */
|
|
|
|
int instanceCount = 1;
|
|
int firstIndex = 0;
|
|
int firstInstance = 0;
|
|
vkCmdDrawIndexed(commandBuffers[currentFrame], static_cast<uint32_t>(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance);
|
|
|
|
vkCmdEndRenderPass(commandBuffers[currentFrame]);
|
|
vk.copyImageToImage(commandBuffers[currentFrame], images[imageIndex], vk.scImages[imageIndex], vk.scExtent.width, vk.scExtent.height);
|
|
result = vkEndCommandBuffer(commandBuffers[currentFrame]);
|
|
if (result != VK_SUCCESS) {
|
|
rLog.error("Failed to record 2D - command buffer", "VkResult:", STR_VK_RESULT(result));
|
|
throw getVkException(result, "Failed to record 2D - command buffer", "Renderer2D::recordCommandBuffer");
|
|
}
|
|
vk.commandBuffersToSubmitThisFrame.push_back(commandBuffers[currentFrame]);
|
|
}
|
|
|
|
|
|
void Renderer2D::fillVertexBufferWithShapes() {
|
|
rLog("fillVertexBufferWithShapes");
|
|
if (vertexBufferSize < shapesVerticesCount * sizeof(Vertex2D)) {
|
|
throw VkException("vertex buffer too small! vertexBufferSize: " + std::to_string(vertexBufferSize) + ", required size: " + std::to_string(shapesVerticesCount), "fillVertexBufferWithShapes");
|
|
}
|
|
|
|
// create staging buffer
|
|
VkBuffer stagingBuffer;
|
|
VkDeviceMemory stagingBufferMemory;
|
|
vk.createBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
|
|
|
// fill staging buffer
|
|
void* data;
|
|
vkMapMemory(vk.device, stagingBufferMemory, NO_OFFSET, vertexBufferSize, NO_FLAGS, &data);
|
|
Vertex2D* vdata = reinterpret_cast<Vertex2D*>(data);
|
|
size_t offset = 0;
|
|
for (auto it = shapes.begin(); it != shapes.end(); it++) {
|
|
rLog("fillVertexBufferWithShapes: copying vertex buffer nr", it - shapes.begin(), "-", it->getVertices(), "to address:", long(vdata + offset), " offset:", offset);
|
|
memcpy(vdata+offset, it->getVertices().data(), it->getVertices().size() * sizeof(Vertex2D));
|
|
offset += it->getVertices().size();
|
|
}
|
|
vkUnmapMemory(vk.device, stagingBufferMemory);
|
|
// fill vertex buffer
|
|
vk.copyBuffer(stagingBuffer, vertexBuffer, vertexBufferSize);
|
|
vkDestroyBuffer(vk.device, stagingBuffer, nullptr);
|
|
vkFreeMemory(vk.device, stagingBufferMemory, nullptr);
|
|
}
|
|
void Renderer2D::fillIndexBufferWithShapes() {
|
|
rLog("fillIndexBufferWithShapes");
|
|
if (indexBufferSize < shapesIndicesCount * sizeof(uint32_t)) {
|
|
throw VkException("index buffer too small! indexBufferSize: " + std::to_string(vertexBufferSize) + ", required size: " + std::to_string(shapesVerticesCount), "fillVertexBufferWithShapes");
|
|
}
|
|
|
|
// create staging buffer
|
|
VkBuffer stagingBuffer;
|
|
VkDeviceMemory stagingBufferMemory;
|
|
vk.createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
|
|
|
// fill staging buffer
|
|
void* data;
|
|
vkMapMemory(vk.device, stagingBufferMemory, NO_OFFSET, indexBufferSize, NO_FLAGS, &data);
|
|
uint32_t* idata = reinterpret_cast<uint32_t*>(data);
|
|
size_t offset = 0;
|
|
for (auto it = shapes.begin(); it != shapes.end(); it++) {
|
|
rLog("fillIndexBufferWithShapes: copying index buffer nr", it - shapes.begin(), "-", it->getIndices(), "to address:", long(idata + offset), " offset:", offset);
|
|
memcpy(idata+offset, it->getIndices().data(), it->getIndices().size() * sizeof(uint32_t));
|
|
offset += it->getIndices().size();
|
|
}
|
|
rLog("fillIndexBufferWithShapes: indices count:", shapesIndicesCount);
|
|
vkUnmapMemory(vk.device, stagingBufferMemory);
|
|
|
|
// fill index buffer
|
|
vk.copyBuffer(stagingBuffer, indexBuffer, indexBufferSize);
|
|
vkDestroyBuffer(vk.device, stagingBuffer, nullptr);
|
|
vkFreeMemory(vk.device, stagingBufferMemory, nullptr);
|
|
|
|
}
|
|
|
|
|
|
void Renderer2D::drawShape(const Shape& shape) {
|
|
shapes.emplace_back(shape);
|
|
// make indices valid
|
|
shapes.rbegin()->setIndexOffset(shapesVerticesCount);
|
|
shapes.rbegin()->setNormalize(vk.scExtent.width, vk.scExtent.height);
|
|
shapesVerticesCount += shape.getVertices().size();
|
|
shapesIndicesCount += shape.getIndices().size();
|
|
}
|
|
|
|
|
|
void Renderer2D::drawFrame(uint32_t imageIndex) {
|
|
vkResetCommandBuffer(commandBuffers[vk.currentFrame], NO_FLAGS);
|
|
recordCommandBuffer(imageIndex, vk.currentFrame);
|
|
|
|
}
|
|
|
|
|
|
} // namespace gz::vk
|