diff --git a/.idea/editor.xml b/.idea/editor.xml
index 8d0e15e..33921db 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -246,100 +246,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f5df2d3..dd73e75 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,8 +35,6 @@ target_include_directories(stb INTERFACE ${stb_SOURCE_DIR})
add_executable(v main.cpp
renderer/init.cpp
renderer/init.h
- renderer/swapchain.cpp
- renderer/swapchain.h
renderer/renderer.cpp
renderer/renderer.h
misc.cpp
diff --git a/main.cpp b/main.cpp
index 6aa8352..09900f3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -10,7 +10,6 @@
#include
#include "renderer/init.h"
-#include "renderer/swapchain.h"
#include "renderer/renderer.h"
#include "renderer/texture.h"
diff --git a/renderer/init.cpp b/renderer/init.cpp
index 7f52672..ef06c75 100644
--- a/renderer/init.cpp
+++ b/renderer/init.cpp
@@ -176,15 +176,15 @@ void createDevice() {
}
}
+ if (int r = glfwGetPhysicalDevicePresentationSupport(instance, physicalDevice, queueFamily) == GLFW_FALSE) {
+ return;
+ }
+
std::println("{}", queueFamily);
std::vector devExts = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
- VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
- VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME,
- VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME,
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME,
- VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
};
uint32_t extensionCount = 0;
@@ -208,41 +208,74 @@ void createDevice() {
.pQueuePriorities = &prio
};
- VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures{
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
+ VkPhysicalDeviceVulkan14Features enabledVk14Features{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES,
+ .pNext = nullptr,
+ .globalPriorityQuery = false,
+ .shaderSubgroupRotate = false,
+ .shaderSubgroupRotateClustered = false,
+ .shaderFloatControls2 = false,
+ .shaderExpectAssume = false,
+ .rectangularLines = false,
+ .bresenhamLines = false,
+ .smoothLines = false,
+ .stippledRectangularLines = false,
+ .stippledBresenhamLines = false,
+ .stippledSmoothLines = false,
+ .vertexAttributeInstanceRateDivisor = false,
+ .vertexAttributeInstanceRateZeroDivisor = false,
+ .indexTypeUint8 = false,
+ .dynamicRenderingLocalRead = false,
+ .maintenance5 = false,
+ .maintenance6 = false,
+ .pipelineProtectedAccess = false,
+ .pipelineRobustness = false,
+ .hostImageCopy = false,
+ .pushDescriptor = false,
+ };
+
+ VkPhysicalDeviceVulkan13Features enabledVk13Features{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
.pNext = nullptr,
- .shaderSampledImageArrayNonUniformIndexing = VK_TRUE,
- .descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
- .descriptorBindingPartiallyBound = VK_TRUE,
- .runtimeDescriptorArray = VK_TRUE
+ .robustImageAccess = false,
+ .inlineUniformBlock = false,
+ .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
+ .pipelineCreationCacheControl = false,
+ .privateData = false,
+ .shaderDemoteToHelperInvocation = false,
+ .shaderTerminateInvocation = false,
+ .subgroupSizeControl = false,
+ .computeFullSubgroups = false,
+ .synchronization2 = true,
+ .textureCompressionASTC_HDR = false,
+ .shaderZeroInitializeWorkgroupMemory = false,
+ .dynamicRendering = true,
+ .shaderIntegerDotProduct = false,
+ .maintenance4 = false
};
-
- VkPhysicalDeviceTimelineSemaphoreFeatures timeline{
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
- .pNext = &indexingFeatures,
- .timelineSemaphore = VK_TRUE
+ VkPhysicalDeviceVulkan12Features enabledVk12Features{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
+ .pNext = &enabledVk13Features,
+ .descriptorIndexing = true,
+ .shaderSampledImageArrayNonUniformIndexing = true,
+ .descriptorBindingSampledImageUpdateAfterBind = true,
+ .descriptorBindingPartiallyBound = true,
+ .descriptorBindingVariableDescriptorCount = true,
+ .runtimeDescriptorArray = true,
+ .bufferDeviceAddress = true,
};
-
- VkPhysicalDeviceSynchronization2Features sync2{
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
- .pNext = &timeline,
- .synchronization2 = VK_TRUE
+ const VkPhysicalDeviceFeatures enabledVk10Features{
+ .samplerAnisotropy = true,
};
- VkPhysicalDeviceDynamicRenderingFeatures dyn{
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
- .pNext = &sync2,
- .dynamicRendering = VK_TRUE
- };
-
-
const VkDeviceCreateInfo dci{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- .pNext = &dyn,
+ .pNext = &enabledVk12Features,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &qci,
.enabledExtensionCount = (uint32_t)devExts.size(),
.ppEnabledExtensionNames = devExts.data(),
+ .pEnabledFeatures = &enabledVk10Features,
};
vkCreateDevice(physicalDevice, &dci, nullptr, &device);
@@ -272,3 +305,83 @@ void createDevice() {
res = vmaCreateAllocator(&allocatorCreateInfo, &allocator);
}
+
+void createSwapchain(GLFWwindow* window) {
+ int fbWidth, fbHeight;
+ glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
+
+ swapchain_extent = {
+ static_cast(fbWidth),
+ static_cast(fbHeight)
+ };
+
+ VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo{
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
+ .pNext = nullptr,
+ .surface = surface,
+ };
+
+ VkSurfaceCapabilities2KHR surfCapabilities{
+ .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
+ };
+
+ vkGetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &surfaceInfo, &surfCapabilities);
+
+ const VkSwapchainCreateInfoKHR sci{
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ .surface = surface,
+ .minImageCount = surfCapabilities.surfaceCapabilities.minImageCount,
+ .imageFormat = swapchain_format.format,
+ .imageColorSpace = swapchain_format.colorSpace,
+ .imageExtent = swapchain_extent,
+ .imageArrayLayers = 1,
+ .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+ .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .presentMode = VK_PRESENT_MODE_FIFO_KHR,
+ .clipped = VK_TRUE
+ };
+
+ vkCreateSwapchainKHR(device, &sci, nullptr, &swapchain);
+
+ uint32_t imgCount;
+ vkGetSwapchainImagesKHR(device, swapchain, &imgCount, nullptr);
+ std::print("imgCount: {}", imgCount);
+ images = std::vector(imgCount);
+ vkGetSwapchainImagesKHR(device, swapchain, &imgCount, images.data());
+
+ imageLayouts = std::vector(
+ imgCount,
+ VK_IMAGE_LAYOUT_UNDEFINED
+ );
+
+ imageViews = std::vector(imgCount);
+
+ const VkSemaphoreCreateInfo seci{
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ };
+
+ renderFinished.resize(imgCount);
+
+ for (uint32_t i = 0; i < imgCount; i++) {
+ VkImageViewCreateInfo ivci{};
+ ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ ivci.image = images[i];
+ ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ ivci.format = swapchain_format.format; // must match swapchain format
+ ivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ ivci.subresourceRange.baseMipLevel = 0;
+ ivci.subresourceRange.levelCount = 1;
+ ivci.subresourceRange.baseArrayLayer = 0;
+ ivci.subresourceRange.layerCount = 1;
+
+ vkCreateImageView(device, &ivci, nullptr, &imageViews[i]);
+
+ vkCreateSemaphore(device, &seci, nullptr, &renderFinished[i]);
+ }
+}
diff --git a/renderer/init.h b/renderer/init.h
index 592a71c..7475a0f 100644
--- a/renderer/init.h
+++ b/renderer/init.h
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
inline VkInstance instance{};
inline VkPhysicalDevice physicalDevice{};
@@ -20,9 +21,23 @@ inline VkDebugUtilsMessengerEXT debugMessenger{};
inline VmaAllocator allocator{};
-inline uint32_t MAX_FRAMES_IN_FLIGHT = 2;
+inline constexpr uint32_t MAX_FRAMES_IN_FLIGHT = 2;
inline constexpr uint32_t MAX_VERTICES_PER_BATCH = 65536;
+inline VkSwapchainKHR swapchain;
+inline VkExtent2D swapchain_extent;
+inline VkSurfaceFormatKHR swapchain_format{
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
+};
+inline std::vector renderFinished;
+
+inline std::vector images;
+inline std::vector imageViews;
+inline std::vector imageLayouts;
+
+void createSwapchain(GLFWwindow* window);
+
int createInstance(GLFWwindow* window);
void createSurface(GLFWwindow* window);
void pickPhysicalDevice();
diff --git a/renderer/renderer.cpp b/renderer/renderer.cpp
index d30deb6..c1d2f33 100644
--- a/renderer/renderer.cpp
+++ b/renderer/renderer.cpp
@@ -5,7 +5,7 @@
#include "renderer.h"
#include "init.h"
#include "sprite.h"
-#include "swapchain.h"
+#include
bool SortKey::operator<(const SortKey& b) const {
if (depth != b.depth) return depth < b.depth;
@@ -174,6 +174,7 @@ void Renderer::createFrameResources() {
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
Frame &frame = frames[i];
+
vkCreateSemaphore(device, &seci, nullptr, &frame.imageAvailable);
vkCreateFence(device, &fenceInfo, nullptr, &frame.in_flight_fence);
@@ -189,42 +190,101 @@ void Renderer::createFrameResources() {
};
vkAllocateCommandBuffers(device, &cbai, &frame.command_buffer);
+
+ VkBufferCreateInfo bufferInfo = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = 1024 * 1024 * 4,
+ .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ };
+
+ VmaAllocationCreateInfo allocCreateInfo = {};
+ allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
+ allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
+ VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
+ VMA_ALLOCATION_CREATE_MAPPED_BIT;
+
+ vmaCreateBuffer(
+ allocator,
+ &bufferInfo,
+ &allocCreateInfo,
+ &frame.vertexBuffer.buffer,
+ &frame.vertexBuffer.allocation,
+ &frame.vertexBuffer.info);
}
-
-
-
- VkBufferCreateInfo bufferInfo = {
- .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
- .size = 1024 * 1024 * 4,
- .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
- };
-
- VmaAllocationCreateInfo allocInfo = {
- .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT,
- .usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
- };
-
- vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &vertexBuffer, &vertexAllocation, &vertexAllocInfo);
-
- VkDescriptorBufferInfo vertexBufferInfo{
- .buffer = vertexBuffer,
- .offset = 0,
- .range = VK_WHOLE_SIZE
- };
-
- VkWriteDescriptorSet bufferWrite{
- .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
- .dstSet = set,
- .dstBinding = 1,
- .dstArrayElement = 0,
- .descriptorCount = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .pBufferInfo = &vertexBufferInfo
- };
-
- vkUpdateDescriptorSets(device, 1, &bufferWrite, 0, nullptr);
}
+AllocatedBuffer Renderer::create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage) {
+ // allocate buffer
+ VkBufferCreateInfo bufferInfo = {.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
+ bufferInfo.pNext = nullptr;
+ bufferInfo.size = allocSize;
+
+ bufferInfo.usage = usage;
+
+ VmaAllocationCreateInfo vmaallocInfo = {};
+ vmaallocInfo.usage = memoryUsage;
+ vmaallocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
+ AllocatedBuffer newBuffer{};
+
+ // allocate the buffer
+ vmaCreateBuffer(allocator, &bufferInfo, &vmaallocInfo, &newBuffer.buffer, &newBuffer.allocation, &newBuffer.info);
+
+ return newBuffer;
+}
+
+void Renderer::destroy_buffer(const AllocatedBuffer& buffer) {
+ vmaDestroyBuffer(allocator, buffer.buffer, buffer.allocation);
+}
+
+// GPUMeshBuffers Renderer::uploadMesh(std::span indices, std::span vertices) {
+// const size_t vertexBufferSize = vertices.size() * sizeof(vertex_p2_st2_col4_a1_u32);
+// const size_t indexBufferSize = indices.size() * sizeof(uint32_t);
+//
+// GPUMeshBuffers newSurface;
+//
+// //create vertex buffer
+// newSurface.vertexBuffer = create_buffer(vertexBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+// VMA_MEMORY_USAGE_GPU_ONLY);
+//
+// //find the adress of the vertex buffer
+// VkBufferDeviceAddressInfo deviceAdressInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,.buffer = newSurface.vertexBuffer.buffer };
+// newSurface.vertexBufferAddress = vkGetBufferDeviceAddress(device, &deviceAdressInfo);
+//
+// //create index buffer
+// newSurface.indexBuffer = create_buffer(indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+// VMA_MEMORY_USAGE_GPU_ONLY);
+//
+// AllocatedBuffer staging = create_buffer(vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
+//
+// void* data = staging.allocation->GetMappedData();
+//
+// // copy vertex buffer
+// memcpy(data, vertices.data(), vertexBufferSize);
+// // copy index buffer
+// memcpy((char*)data + vertexBufferSize, indices.data(), indexBufferSize);
+//
+// immediate_submit([&](VkCommandBuffer cmd) {
+// VkBufferCopy vertexCopy{ 0 };
+// vertexCopy.dstOffset = 0;
+// vertexCopy.srcOffset = 0;
+// vertexCopy.size = vertexBufferSize;
+//
+// vkCmdCopyBuffer(cmd, staging.buffer, newSurface.vertexBuffer.buffer, 1, &vertexCopy);
+//
+// VkBufferCopy indexCopy{ 0 };
+// indexCopy.dstOffset = 0;
+// indexCopy.srcOffset = vertexBufferSize;
+// indexCopy.size = indexBufferSize;
+//
+// vkCmdCopyBuffer(cmd, staging.buffer, newSurface.indexBuffer.buffer, 1, &indexCopy);
+// });
+//
+// destroy_buffer(staging);
+//
+// return newSurface;
+//
+// }
+
void Renderer::end_frame() {
Frame &frame = frames[currentFrame];
@@ -232,40 +292,24 @@ void Renderer::end_frame() {
vkWaitForFences(device, 1, &frame.in_flight_fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &frame.in_flight_fence);
+ uint32_t imageIndex;
+ vkAcquireNextImageKHR(
+ device,
+ swapchain,
+ UINT64_MAX,
+ frame.imageAvailable,
+ VK_NULL_HANDLE,
+ &imageIndex
+ );
+
commands = counting_sort_descending(commands, [](const RenderCommand &cmd){
return cmd.key.depth;
});
- VkMemoryPropertyFlags memPropFlags;
- vmaGetAllocationMemoryProperties(allocator, vertexAllocation, &memPropFlags);
+ std::vector vertices;
- if(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
- // The Allocation ended up in a mappable memory.
- // Calling vmaCopyMemoryToAllocation() does vmaMapMemory(), memcpy(), vmaUnmapMemory(), and vmaFlushAllocation().
- VkResult result = vmaCopyMemoryToAllocation(allocator, myData, alloc, 0, myDataSize);
- // Check result...
-
- VkBufferMemoryBarrier bufMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
- bufMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
- bufMemBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
- bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- bufMemBarrier.buffer = buf;
- bufMemBarrier.offset = 0;
- bufMemBarrier.size = VK_WHOLE_SIZE;
-
- // It's important to insert a buffer memory barrier here to ensure writing to the buffer has finished.
- vkCmdPipelineBarrier(c, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
- 0, 0, nullptr, 1, &bufMemBarrier, 0, nullptr);
- }
-
- vertex_p2_st2_col4_a1_u32 *vPtr = (vertex_p2_st2_col4_a1_u32 *) vertexAllocInfo.pMappedData;
- vertex_p2_st2_col4_a1_u32 *currentFrameStart = vPtr + (currentFrame * MAX_VERTICES_PER_BATCH);
-
- uint32_t totalVertices = 0;
for (auto& cmd : commands) {
- vPtr = currentFrameStart + totalVertices;
switch (cmd.pipeline) {
case PipelineType::ColoredQuad: {
@@ -295,34 +339,22 @@ void Renderer::end_frame() {
// vertex_p2_st2_col4_a1_u32 vBR = { {x1, y1}, {u1, v1}, q.color, 1, q.textureID };
// --- Triangle 1 (TL, TR, BL) ---
- vPtr[0] = vTL;
- vPtr[1] = vTR;
- vPtr[2] = vBL;
+ vertices.push_back(vTL);
+ vertices.push_back(vTR);
+ vertices.push_back(vBL);
// --- Triangle 2 (TR, BR, BL) ---
- vPtr[3] = vTR;
- vPtr[4] = vBR;
- vPtr[5] = vBL;
+ vertices.push_back(vTR);
+ vertices.push_back(vBR);
+ vertices.push_back(vBL);
break;
}
default:
break;
}
-
- totalVertices += 6;
}
- uint32_t imageIndex;
- vkAcquireNextImageKHR(
- device,
- swapchain,
- UINT64_MAX,
- frame.imageAvailable,
- VK_NULL_HANDLE,
- &imageIndex
- );
-
VkCommandBuffer command_buffer = frame.command_buffer;
vkResetCommandBuffer(command_buffer, 0);
@@ -331,7 +363,9 @@ void Renderer::end_frame() {
images[imageIndex],
imageViews[imageIndex],
swapchain_extent,
- imageLayouts[imageIndex]
+ imageLayouts[imageIndex],
+ frame,
+ vertices
);
imageLayouts[imageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -379,15 +413,46 @@ void Renderer::end_frame() {
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
+void Renderer::upload_vertex_buffer(
+ VkCommandBuffer cmd,
+ const Frame &frame,
+ std::span vertices) const {
+ VkMemoryPropertyFlags memPropFlags;
+ vmaGetAllocationMemoryProperties(allocator, frame.vertexBuffer.allocation, &memPropFlags);
+
+ if(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ // The Allocation ended up in a mappable memory.
+ // Calling vmaCopyMemoryToAllocation() does vmaMapMemory(), memcpy(), vmaUnmapMemory(), and vmaFlushAllocation().
+ VkResult result = vmaCopyMemoryToAllocation(allocator, vertices.data(), frame.vertexBuffer.allocation, 0, vertices.size() * sizeof(vertex_p2_st2_col4_a1_u32));
+ // Check result...
+
+ VkBufferMemoryBarrier bufMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
+ bufMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
+ bufMemBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
+ bufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ bufMemBarrier.buffer = frame.vertexBuffer.buffer;
+ bufMemBarrier.offset = 0;
+ bufMemBarrier.size = VK_WHOLE_SIZE;
+
+ // It's important to insert a buffer memory barrier here to ensure writing to the buffer has finished.
+ vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
+ 0, 0, nullptr, 1, &bufMemBarrier, 0, nullptr);
+ }
+}
+
void Renderer::recordCommandBuffer(
- VkCommandBuffer command_buffer,
+ VkCommandBuffer cmd,
VkImage image,
VkImageView imageView,
VkExtent2D extent,
- VkImageLayout oldLayout) const
+ VkImageLayout oldLayout,
+ const Frame &frame,
+ const std::vector &vertices) const
{
+
VkCommandBufferBeginInfo begin{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
- vkBeginCommandBuffer(command_buffer, &begin);
+ vkBeginCommandBuffer(cmd, &begin);
{
VkImageMemoryBarrier2 toColor{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
@@ -404,7 +469,7 @@ void Renderer::recordCommandBuffer(
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &toColor
};
- vkCmdPipelineBarrier2(command_buffer, &dep);
+ vkCmdPipelineBarrier2(cmd, &dep);
}
VkClearValue clearColor = {{{0.1f, 0.1f, 0.2f, 1.0f}}};
@@ -425,31 +490,35 @@ void Renderer::recordCommandBuffer(
.pColorAttachments = &colorAttach
};
- vkCmdBeginRendering(command_buffer, &ri);
+ upload_vertex_buffer(cmd, frame, vertices);
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr);
+ vkCmdBeginRendering(cmd, &ri);
VkViewport vp{0.0f, 0.0f, (float)extent.width, (float)extent.height, 0.0f, 1.0f};
VkRect2D sc{{0, 0}, extent};
- vkCmdSetViewport(command_buffer, 0, 1, &vp);
- vkCmdSetScissor(command_buffer, 0, 1, &sc);
+ vkCmdSetViewport(cmd, 0, 1, &vp);
+ vkCmdSetScissor(cmd, 0, 1, &sc);
+
+ vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr);
+ VkDeviceSize vOffset{ 0 };
+ vkCmdBindVertexBuffers(cmd, 0, 1, &frame.vertexBuffer.buffer, &vOffset);
PipelineType lastPipeline = PipelineType::None; // Track current state
uint32_t vertexOffset = currentFrame * MAX_VERTICES_PER_BATCH;
uint32_t currentBatchVertices = 0;
- for (const auto & cmd : commands) {
+ for (const auto & render_command : commands) {
// Only switch pipelines if we have to
- if (cmd.pipeline != lastPipeline) {
+ if (render_command.pipeline != lastPipeline) {
// If we were mid-batch, draw what we have before switching
if (currentBatchVertices > 0) {
- vkCmdDraw(command_buffer, currentBatchVertices, 1, vertexOffset, 0);
+ vkCmdDraw(cmd, currentBatchVertices, 1, vertexOffset, 0);
vertexOffset += currentBatchVertices;
currentBatchVertices = 0;
}
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, get_pipeline(cmd.pipeline));
- lastPipeline = cmd.pipeline;
+ vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, get_pipeline(render_command.pipeline));
+ lastPipeline = render_command.pipeline;
}
currentBatchVertices += 6;
@@ -457,10 +526,10 @@ void Renderer::recordCommandBuffer(
// Draw the final batch
if (currentBatchVertices > 0) {
- vkCmdDraw(command_buffer, currentBatchVertices, 1, vertexOffset, 0);
+ vkCmdDraw(cmd, currentBatchVertices, 1, vertexOffset, 0);
}
- vkCmdEndRendering(command_buffer);
+ vkCmdEndRendering(cmd);
// 3. Transition back to Present
{
@@ -474,10 +543,10 @@ void Renderer::recordCommandBuffer(
toPresent.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
VkDependencyInfo dep{ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &toPresent };
- vkCmdPipelineBarrier2(command_buffer, &dep);
+ vkCmdPipelineBarrier2(cmd, &dep);
}
- vkEndCommandBuffer(command_buffer);
+ vkEndCommandBuffer(cmd);
}
VkPipeline Renderer::get_pipeline(PipelineType type) const {
diff --git a/renderer/renderer.h b/renderer/renderer.h
index ff7228f..15bc2c3 100644
--- a/renderer/renderer.h
+++ b/renderer/renderer.h
@@ -13,6 +13,8 @@
#include "sprite.h"
#include "texture.h"
#include
+#include
+#include
enum class PROJECTION_TYPE : uint8_t {
NONE,
@@ -34,13 +36,15 @@ struct vertex_p2_st2_col4_a1_u32 {
return {0, sizeof(vertex_p2_st2_col4_a1_u32), VK_VERTEX_INPUT_RATE_VERTEX};
}
- static std::vector getAttributeDescriptions() {
+ static std::array getAttributeDescriptions() {
return {
- {0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, pos)},
- {1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, st)},
- {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, col)},
- {3, 0, VK_FORMAT_R32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, alpha)},
- {4, 0, VK_FORMAT_R32_UINT, offsetof(vertex_p2_st2_col4_a1_u32, textureID)},
+ {
+ {0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, pos)},
+ {1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, st)},
+ {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, col)},
+ {3, 0, VK_FORMAT_R32_SFLOAT, offsetof(vertex_p2_st2_col4_a1_u32, alpha)},
+ {4, 0, VK_FORMAT_R32_UINT, offsetof(vertex_p2_st2_col4_a1_u32, textureID)},
+ }
};
}
};
@@ -114,30 +118,21 @@ struct RenderCommand {
////////////////////////////////////////////////////////////////////////////////////////////////
+struct AllocatedBuffer {
+ VkBuffer buffer;
+ VmaAllocation allocation;
+ VmaAllocationInfo info;
+};
+
+struct GPUMeshBuffers {
+ AllocatedBuffer indexBuffer;
+ AllocatedBuffer vertexBuffer;
+ VkDeviceAddress vertexBufferAddress;
+};
+
struct Renderer {
std::vector commands{};
- void begin_frame();
- void end_frame();
- void flush();
-
- void submit_sprite(glm::vec2 pos, const sprite_t &sprite);
- void submit_quad();
-
- explicit Renderer(GLFWwindow *window);
- void create_pipeline_layout();
- void createFrameResources();
- void create_default_sampler();
- void recordCommandBuffer(
- VkCommandBuffer cmd,
- VkImage image,
- VkImageView imageView,
- VkExtent2D extent,
- VkImageLayout oldLayout) const;
- void immediate_submit(std::function&& func) const;
- void transition_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) const;
- VkImageView create_image_view(VkImage image, VkFormat format) const;
-
VkDescriptorSetLayout descriptor_set_layout{};
VkPipelineLayout pipelineLayout{};
VkPipeline textured_quad_pipeline{};
@@ -157,18 +152,46 @@ struct Renderer {
VkSemaphore imageAvailable{};
VkFence in_flight_fence{};
+
+ AllocatedBuffer vertexBuffer{};
};
std::vector frames;
uint32_t currentFrame = 0;
- VkBuffer vertexBuffer{};
- VmaAllocation vertexAllocation{};
- VmaAllocationInfo vertexAllocInfo{};
-
VkDescriptorPool descriptorPool{};
std::vector textureSets{};
+ void begin_frame();
+ void end_frame();
+ void flush();
+
+ void submit_sprite(glm::vec2 pos, const sprite_t &sprite);
+ void submit_quad();
+
+ explicit Renderer(GLFWwindow *window);
+ void create_pipeline_layout();
+ void createFrameResources();
+ void create_default_sampler();
+ void recordCommandBuffer(
+ VkCommandBuffer cmd,
+ VkImage image,
+ VkImageView imageView,
+ VkExtent2D extent,
+ VkImageLayout oldLayout,
+ const Frame &frame,
+ const std::vector &vertices) const;
+ void immediate_submit(std::function&& func) const;
+ void transition_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) const;
+ VkImageView create_image_view(VkImage image, VkFormat format) const;
+ AllocatedBuffer create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage);
+ void destroy_buffer(const AllocatedBuffer& buffer);
+ // GPUMeshBuffers uploadMesh(std::span indices, std::span vertices);
+ void upload_vertex_buffer(
+ VkCommandBuffer cmd,
+ const Frame &frame,
+ std::span vertices) const;
+
VkPipeline get_pipeline(PipelineType type) const;
// void bind_material(VkCommandBuffer cmd, uint16_t materialID);
void create_descriptor_pool();
@@ -232,10 +255,10 @@ struct Renderer {
// --- Vertex Input (Matching our vertex_p2_st2_col4 struct) ---
VkPipelineVertexInputStateCreateInfo vi{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .vertexBindingDescriptionCount = 0,
- .pVertexBindingDescriptions = nullptr,
- .vertexAttributeDescriptionCount = 0,
- .pVertexAttributeDescriptions = nullptr,
+ .vertexBindingDescriptionCount = 1,
+ .pVertexBindingDescriptions = &binding,
+ .vertexAttributeDescriptionCount = attrs.size(),
+ .pVertexAttributeDescriptions = attrs.data(),
};
// --- Input Assembly (Changes based on Topology parameter) ---
diff --git a/renderer/swapchain.cpp b/renderer/swapchain.cpp
deleted file mode 100644
index 1c7b929..0000000
--- a/renderer/swapchain.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Created by Vicente Ferrari Smith on 13.02.26.
-//
-
-#include "swapchain.h"
-#include
-
-void createSwapchain(GLFWwindow* window) {
- int fbWidth, fbHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
-
- swapchain_extent = {
- static_cast(fbWidth),
- static_cast(fbHeight)
- };
-
- VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo{
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
- .pNext = nullptr,
- .surface = surface,
- };
-
- VkSurfaceCapabilities2KHR surfCapabilities{
- .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
- };
-
- vkGetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &surfaceInfo, &surfCapabilities);
-
- MAX_FRAMES_IN_FLIGHT = std::min(surfCapabilities.surfaceCapabilities.minImageCount + 1, surfCapabilities.surfaceCapabilities.maxImageCount);
-
- const VkSwapchainCreateInfoKHR sci{
- .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
- .surface = surface,
- .minImageCount = MAX_FRAMES_IN_FLIGHT,
- .imageFormat = swapchain_format.format,
- .imageColorSpace = swapchain_format.colorSpace,
- .imageExtent = swapchain_extent,
- .imageArrayLayers = 1,
- .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
- .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
- .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
- .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- .presentMode = VK_PRESENT_MODE_FIFO_KHR,
- .clipped = VK_TRUE
- };
-
- vkCreateSwapchainKHR(device, &sci, nullptr, &swapchain);
-
- uint32_t imgCount;
- vkGetSwapchainImagesKHR(device, swapchain, &imgCount, nullptr);
- std::print("imgCount: {}", imgCount);
- images = std::vector(imgCount);
- vkGetSwapchainImagesKHR(device, swapchain, &imgCount, images.data());
-
- imageLayouts = std::vector(
- imgCount,
- VK_IMAGE_LAYOUT_UNDEFINED
- );
-
- imageViews = std::vector(imgCount);
-
- const VkSemaphoreCreateInfo seci{
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
- };
-
- renderFinished.resize(imgCount);
-
- for (uint32_t i = 0; i < imgCount; i++) {
- VkImageViewCreateInfo ivci{};
- ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- ivci.image = images[i];
- ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
- ivci.format = swapchain_format.format; // must match swapchain format
- ivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- ivci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- ivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- ivci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
- ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- ivci.subresourceRange.baseMipLevel = 0;
- ivci.subresourceRange.levelCount = 1;
- ivci.subresourceRange.baseArrayLayer = 0;
- ivci.subresourceRange.layerCount = 1;
-
- vkCreateImageView(device, &ivci, nullptr, &imageViews[i]);
-
- vkCreateSemaphore(device, &seci, nullptr, &renderFinished[i]);
- }
-}
diff --git a/renderer/swapchain.h b/renderer/swapchain.h
deleted file mode 100644
index 224bd14..0000000
--- a/renderer/swapchain.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Created by Vicente Ferrari Smith on 13.02.26.
-//
-
-#ifndef V_SWAPCHAIN_H
-#define V_SWAPCHAIN_H
-
-#include "init.h"
-#include
-
-inline VkSwapchainKHR swapchain;
-inline VkExtent2D swapchain_extent;
-inline VkSurfaceFormatKHR swapchain_format{
- VK_FORMAT_B8G8R8A8_UNORM,
- VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
-};
-inline std::vector renderFinished;
-
-inline std::vector images;
-inline std::vector imageViews;
-inline std::vector imageLayouts;
-
-void createSwapchain(GLFWwindow* window);
-
-#endif //V_SWAPCHAIN_H
\ No newline at end of file
diff --git a/shaders/triangle.frag b/shaders/triangle.frag
index 05c2395..3d9e39c 100644
--- a/shaders/triangle.frag
+++ b/shaders/triangle.frag
@@ -5,7 +5,8 @@ layout(set = 0, binding = 0) uniform sampler2D texSamplers[];
layout(location = 0) in vec2 uv;
layout(location = 1) in vec4 color;
-layout(location = 2) in flat uint tex_id;
+layout(location = 2) in float alpha;
+layout(location = 3) in flat uint tex_id;
layout(location = 0) out vec4 out_color;
diff --git a/shaders/triangle.frag.spv b/shaders/triangle.frag.spv
index 8c5544c..5d95baa 100644
Binary files a/shaders/triangle.frag.spv and b/shaders/triangle.frag.spv differ
diff --git a/shaders/triangle.vert b/shaders/triangle.vert
index 062c031..df2ee4f 100644
--- a/shaders/triangle.vert
+++ b/shaders/triangle.vert
@@ -1,5 +1,5 @@
#version 460
-#extension GL_EXT_nonuniform_qualifier : require
+#extension GL_EXT_buffer_reference : require
struct Vertex {
vec2 pos;
@@ -9,20 +9,36 @@ struct Vertex {
uint textureID;
};
-layout(std430, set = 0, binding = 1) readonly buffer VertexBuffer {
- Vertex vertices[];
-} vBuf;
+layout(location = 0) in vec2 inPos; // Matches VK_FORMAT_R32G32_SFLOAT
+layout(location = 1) in vec2 inTexCoord; // Matches VK_FORMAT_R32G32_SFLOAT
+layout(location = 2) in vec4 inColor; // Matches VK_FORMAT_R32G32B32A32_SFLOAT
+layout(location = 3) in float inAlpha; // Matches VK_FORMAT_R32_SFLOAT
+layout(location = 4) in uint inTextureID; // Matches VK_FORMAT_R32_UINT
+
+//layout(std430, set = 0, binding = 1) readonly buffer VertexBuffer {
+// Vertex vertices[];
+//} vBuf;
+
+//layout(buffer_reference, std430) readonly buffer VertexBuffer{
+// Vertex vertices[];
+//};
+
+//push constants block
+//layout(push_constant) uniform constants {
+// mat4 render_matrix;
+// VertexBuffer vertexBuffer;
+//} PushConstants;
layout(location = 0) out vec2 uv;
layout(location = 1) out vec4 color;
-layout(location = 2) out flat uint tex_id;
+layout(location = 2) out float alpha;
+layout(location = 3) out flat uint tex_id;
void main() {
- Vertex v = vBuf.vertices[gl_VertexIndex];
-
- uv = v.uv;
- color = v.color;
- tex_id = v.textureID;
- gl_Position = vec4(v.pos, 0.0, 1.0);
+ uv = inTexCoord;
+ color = inColor;
+ alpha = inAlpha;
+ tex_id = inTextureID;
+ gl_Position = vec4(inPos, 0.0, 1.0);
}
diff --git a/shaders/triangle.vert.spv b/shaders/triangle.vert.spv
index 94e0639..6de9cef 100644
Binary files a/shaders/triangle.vert.spv and b/shaders/triangle.vert.spv differ