progress. But we still have to correctly send the vertex data.
This commit is contained in:
1 parent
34789e806b
commit
19f2acc2ec
15 files changed
+294
-202
No files matched your search
+36
-11
@@ -56,17 +56,27 @@ int createInstance(GLFWwindow *window) {
|
||||
uint32_t extensions_count;
|
||||
const char** extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
|
||||
std::vector<const char*> instance_exts;
|
||||
instance_exts.reserve(extensions_count + 1);
|
||||
// Copy GLFW-required extensions
|
||||
|
||||
for (uint32_t i = 0; i < extensions_count; i++) {
|
||||
instance_exts.push_back(extensions[i]);
|
||||
}
|
||||
// Append portability enumeration (MANDATORY on macOS)
|
||||
instance_exts.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
instance_exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
instance_exts.push_back(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
|
||||
|
||||
for (auto& ext : instance_exts) {
|
||||
std::print("extension {}\n", ext);
|
||||
uint32_t availableCount = 0;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &availableCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> available(availableCount);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &availableCount, available.data());
|
||||
|
||||
bool has_portability_extension = false;
|
||||
|
||||
for (const VkExtensionProperties &property : available) {
|
||||
if (strcmp(property.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) {
|
||||
has_portability_extension = true;
|
||||
instance_exts.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr VkApplicationInfo app{
|
||||
@@ -90,10 +100,9 @@ int createInstance(GLFWwindow *window) {
|
||||
dbg.pfnUserCallback = debugCallback;
|
||||
|
||||
|
||||
const VkInstanceCreateInfo ici{
|
||||
VkInstanceCreateInfo ici{
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = &dbg,
|
||||
.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR,
|
||||
.pApplicationInfo = &app,
|
||||
.enabledLayerCount = 1,
|
||||
.ppEnabledLayerNames = layers,
|
||||
@@ -101,6 +110,10 @@ int createInstance(GLFWwindow *window) {
|
||||
.ppEnabledExtensionNames = instance_exts.data(),
|
||||
};
|
||||
|
||||
if (has_portability_extension) {
|
||||
ici.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||
}
|
||||
|
||||
VkResult res = vkCreateInstance(&ici, nullptr, &instance);
|
||||
if (res != VK_SUCCESS) {
|
||||
printf("vkCreateInstance failed: %d\n", res);
|
||||
@@ -165,16 +178,28 @@ void createDevice() {
|
||||
|
||||
std::println("{}", queueFamily);
|
||||
|
||||
const char* devExts[] = {
|
||||
std::vector<const char*> 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,
|
||||
"VK_KHR_portability_subset"
|
||||
};
|
||||
|
||||
uint32_t extensionCount = 0;
|
||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data());
|
||||
|
||||
for (const auto& ext : availableExtensions) {
|
||||
if (strcmp(ext.extensionName, "VK_KHR_portability_subset") == 0) {
|
||||
devExts.push_back("VK_KHR_portability_subset");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float prio = 1.0f;
|
||||
VkDeviceQueueCreateInfo qci{
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
@@ -216,8 +241,8 @@ void createDevice() {
|
||||
.pNext = &dyn,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &qci,
|
||||
.enabledExtensionCount = 7,
|
||||
.ppEnabledExtensionNames = devExts
|
||||
.enabledExtensionCount = (uint32_t)devExts.size(),
|
||||
.ppEnabledExtensionNames = devExts.data(),
|
||||
};
|
||||
|
||||
vkCreateDevice(physicalDevice, &dci, nullptr, &device);
|
||||
|
||||
+11
-8
@@ -9,16 +9,19 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
|
||||
inline VkInstance instance;
|
||||
inline VkPhysicalDevice physicalDevice;
|
||||
inline VkDevice device;
|
||||
inline VkQueue graphics_queue;
|
||||
inline uint32_t queueFamily;
|
||||
inline VkInstance instance{};
|
||||
inline VkPhysicalDevice physicalDevice{};
|
||||
inline VkDevice device{};
|
||||
inline VkQueue graphics_queue{};
|
||||
inline uint32_t queueFamily{};
|
||||
|
||||
inline VkSurfaceKHR surface;
|
||||
inline VkDebugUtilsMessengerEXT debugMessenger;
|
||||
inline VkSurfaceKHR surface{};
|
||||
inline VkDebugUtilsMessengerEXT debugMessenger{};
|
||||
|
||||
inline VmaAllocator allocator;
|
||||
inline VmaAllocator allocator{};
|
||||
|
||||
inline uint32_t MAX_FRAMES_IN_FLIGHT = 2;
|
||||
inline constexpr uint32_t MAX_VERTICES_PER_BATCH = 65536;
|
||||
|
||||
int createInstance(GLFWwindow* window);
|
||||
void createSurface(GLFWwindow* window);
|
||||
|
||||
+113
-109
@@ -15,14 +15,6 @@ bool SortKey::operator<(const SortKey& b) const {
|
||||
|
||||
Renderer::Renderer(GLFWwindow *window) {
|
||||
|
||||
VkCommandPoolCreateInfo cpci{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = queueFamily
|
||||
};
|
||||
|
||||
vkCreateCommandPool(device, &cpci, nullptr, &commandPool);
|
||||
|
||||
create_pipeline_layout();
|
||||
colored_quad_pipeline = create_graphics_pipeline<vertex_p2_st2_col4_a1_u32>(
|
||||
device,
|
||||
@@ -37,20 +29,7 @@ Renderer::Renderer(GLFWwindow *window) {
|
||||
}
|
||||
|
||||
void Renderer::begin_frame() {
|
||||
uint64_t waitValue = 0;
|
||||
|
||||
if (frameValue >= MAX_FRAMES_IN_FLIGHT) {
|
||||
waitValue = frameValue - MAX_FRAMES_IN_FLIGHT + 1;
|
||||
|
||||
VkSemaphoreWaitInfo waitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
|
||||
.semaphoreCount = 1,
|
||||
.pSemaphores = &timelineSemaphore,
|
||||
.pValues = &waitValue
|
||||
};
|
||||
|
||||
vkWaitSemaphores(device, &waitInfo, UINT64_MAX);
|
||||
}
|
||||
commands.clear();
|
||||
}
|
||||
|
||||
void Renderer::flush() {
|
||||
@@ -122,7 +101,7 @@ void Renderer::create_pipeline_layout() {
|
||||
bindings[0] = VkDescriptorSetLayoutBinding{
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1000,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
};
|
||||
|
||||
@@ -130,7 +109,7 @@ void Renderer::create_pipeline_layout() {
|
||||
.binding = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT // The vertex shader "pulls" from here
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
|
||||
};
|
||||
|
||||
VkDescriptorBindingFlags flags[2] = {
|
||||
@@ -146,7 +125,7 @@ void Renderer::create_pipeline_layout() {
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo dslci{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.pNext = &layoutFlags, // Attach the flags
|
||||
.pNext = &layoutFlags,
|
||||
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
|
||||
.bindingCount = 2,
|
||||
.pBindings = bindings
|
||||
@@ -175,44 +154,55 @@ void Renderer::create_pipeline_layout() {
|
||||
}
|
||||
|
||||
void Renderer::createFrameResources() {
|
||||
VkSemaphoreTypeCreateInfo typeInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
|
||||
.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
|
||||
.initialValue = 0
|
||||
};
|
||||
|
||||
const VkSemaphoreCreateInfo semaphoreci{
|
||||
const VkSemaphoreCreateInfo seci{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = &typeInfo
|
||||
};
|
||||
|
||||
vkCreateSemaphore(device, &semaphoreci, nullptr, &timelineSemaphore);
|
||||
VkFenceCreateInfo fenceInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
|
||||
const VkSemaphoreCreateInfo seci{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
VkCommandPoolCreateInfo cpci{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = queueFamily
|
||||
};
|
||||
|
||||
for (auto & frame : frames) {
|
||||
frames.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
|
||||
Frame &frame = frames[i];
|
||||
vkCreateSemaphore(device, &seci, nullptr, &frame.imageAvailable);
|
||||
vkCreateSemaphore(device, &seci, nullptr, &frame.renderFinished);
|
||||
}
|
||||
|
||||
const VkCommandBufferAllocateInfo cbai{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1
|
||||
};
|
||||
vkCreateFence(device, &fenceInfo, nullptr, &frame.in_flight_fence);
|
||||
|
||||
|
||||
vkCreateCommandPool(device, &cpci, nullptr, &frame.commandPool);
|
||||
|
||||
const VkCommandBufferAllocateInfo cbai{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = frame.commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1
|
||||
};
|
||||
|
||||
for (auto &frame : frames) {
|
||||
vkAllocateCommandBuffers(device, &cbai, &frame.command_buffer);
|
||||
}
|
||||
|
||||
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bufferInfo.size = 1024 * 1024 * 4;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
|
||||
allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
|
||||
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);
|
||||
|
||||
@@ -237,12 +227,40 @@ void Renderer::createFrameResources() {
|
||||
|
||||
void Renderer::end_frame() {
|
||||
|
||||
Frame &frame = frames[currentFrame];
|
||||
|
||||
vkWaitForFences(device, 1, &frame.in_flight_fence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(device, 1, &frame.in_flight_fence);
|
||||
|
||||
commands = counting_sort_descending(commands, [](const RenderCommand &cmd){
|
||||
return cmd.key.depth;
|
||||
});
|
||||
|
||||
VkMemoryPropertyFlags memPropFlags;
|
||||
vmaGetAllocationMemoryProperties(allocator, vertexAllocation, &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, 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_FRAME);
|
||||
vertex_p2_st2_col4_a1_u32 *currentFrameStart = vPtr + (currentFrame * MAX_VERTICES_PER_BATCH);
|
||||
|
||||
uint32_t totalVertices = 0;
|
||||
for (auto& cmd : commands) {
|
||||
@@ -251,7 +269,7 @@ void Renderer::end_frame() {
|
||||
|
||||
switch (cmd.pipeline) {
|
||||
case PipelineType::ColoredQuad: {
|
||||
const auto &q = cmd.textured_quad;
|
||||
const auto &q = cmd.colored_quad;
|
||||
|
||||
// Calculate spatial corners
|
||||
float x0 = q.position.x;
|
||||
@@ -260,16 +278,21 @@ void Renderer::end_frame() {
|
||||
float y1 = q.position.y + q.size.y;
|
||||
|
||||
// Calculate UV corners
|
||||
float u0 = q.uvMin.x;
|
||||
float v0 = q.uvMin.y;
|
||||
float u1 = q.uvMax.x;
|
||||
float v1 = q.uvMax.y;
|
||||
// float u0 = q.uvMin.x;
|
||||
// float v0 = q.uvMin.y;
|
||||
// float u1 = q.uvMax.x;
|
||||
// float v1 = q.uvMax.y;
|
||||
|
||||
// Define the 4 corners of the quad
|
||||
vertex_p2_st2_col4_a1_u32 vTL = { {x0, y0}, {u0, v0}, q.color, 1, q.textureID };
|
||||
vertex_p2_st2_col4_a1_u32 vTR = { {x1, y0}, {u1, v0}, q.color, 1, q.textureID };
|
||||
vertex_p2_st2_col4_a1_u32 vBL = { {x0, y1}, {u0, v1}, q.color, 1, q.textureID };
|
||||
vertex_p2_st2_col4_a1_u32 vBR = { {x1, y1}, {u1, v1}, q.color, 1, q.textureID };
|
||||
vertex_p2_st2_col4_a1_u32 vTL = { {x0, y0}, {0, 0}, q.color, 1, 0 };
|
||||
vertex_p2_st2_col4_a1_u32 vTR = { {x1, y0}, {0, 0}, q.color, 1, 0 };
|
||||
vertex_p2_st2_col4_a1_u32 vBL = { {x0, y1}, {0, 0}, q.color, 1, 0 };
|
||||
vertex_p2_st2_col4_a1_u32 vBR = { {x1, y1}, {0, 0}, q.color, 1, 0 };
|
||||
|
||||
// vertex_p2_st2_col4_a1_u32 vTL = { {x0, y0}, {u0, v0}, q.color, 1, q.textureID };
|
||||
// vertex_p2_st2_col4_a1_u32 vTR = { {x1, y0}, {u1, v0}, q.color, 1, q.textureID };
|
||||
// vertex_p2_st2_col4_a1_u32 vBL = { {x0, y1}, {u0, v1}, q.color, 1, q.textureID };
|
||||
// vertex_p2_st2_col4_a1_u32 vBR = { {x1, y1}, {u1, v1}, q.color, 1, q.textureID };
|
||||
|
||||
// --- Triangle 1 (TL, TR, BL) ---
|
||||
vPtr[0] = vTL;
|
||||
@@ -295,12 +318,12 @@ void Renderer::end_frame() {
|
||||
device,
|
||||
swapchain,
|
||||
UINT64_MAX,
|
||||
frames[currentFrame].imageAvailable,
|
||||
frame.imageAvailable,
|
||||
VK_NULL_HANDLE,
|
||||
&imageIndex
|
||||
);
|
||||
|
||||
VkCommandBuffer command_buffer = frames[currentFrame].command_buffer;
|
||||
VkCommandBuffer command_buffer = frame.command_buffer;
|
||||
vkResetCommandBuffer(command_buffer, 0);
|
||||
|
||||
recordCommandBuffer(
|
||||
@@ -311,33 +334,20 @@ void Renderer::end_frame() {
|
||||
imageLayouts[imageIndex]
|
||||
);
|
||||
|
||||
commands.clear();
|
||||
|
||||
imageLayouts[imageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
frameValue++;
|
||||
|
||||
VkSemaphoreSubmitInfo waitBinary{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
||||
.semaphore = frames[currentFrame].imageAvailable,
|
||||
.semaphore = frame.imageAvailable,
|
||||
.stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT
|
||||
};
|
||||
|
||||
VkSemaphoreSubmitInfo signalBinary{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
||||
.semaphore = frames[currentFrame].renderFinished,
|
||||
.semaphore = renderFinished[imageIndex],
|
||||
.stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT
|
||||
};
|
||||
|
||||
VkSemaphoreSubmitInfo signalTimeline{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
|
||||
.semaphore = timelineSemaphore,
|
||||
.value = frameValue,
|
||||
.stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT
|
||||
};
|
||||
|
||||
VkSemaphoreSubmitInfo signals[] = { signalBinary, signalTimeline };
|
||||
|
||||
VkCommandBufferSubmitInfo cmdInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
|
||||
.commandBuffer = command_buffer,
|
||||
@@ -349,16 +359,16 @@ void Renderer::end_frame() {
|
||||
.pWaitSemaphoreInfos = &waitBinary,
|
||||
.commandBufferInfoCount = 1,
|
||||
.pCommandBufferInfos = &cmdInfo,
|
||||
.signalSemaphoreInfoCount = 2,
|
||||
.pSignalSemaphoreInfos = signals,
|
||||
.signalSemaphoreInfoCount = 1,
|
||||
.pSignalSemaphoreInfos = &signalBinary,
|
||||
};
|
||||
|
||||
vkQueueSubmit2(graphics_queue, 1, &submit, VK_NULL_HANDLE);
|
||||
vkQueueSubmit2(graphics_queue, 1, &submit, frame.in_flight_fence);
|
||||
|
||||
VkPresentInfoKHR present{
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &frames[currentFrame].renderFinished,
|
||||
.pWaitSemaphores = &renderFinished[imageIndex],
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &imageIndex,
|
||||
@@ -425,7 +435,7 @@ void Renderer::recordCommandBuffer(
|
||||
vkCmdSetScissor(command_buffer, 0, 1, &sc);
|
||||
|
||||
PipelineType lastPipeline = PipelineType::None; // Track current state
|
||||
uint32_t vertexOffset = currentFrame * MAX_VERTICES_PER_FRAME;
|
||||
uint32_t vertexOffset = currentFrame * MAX_VERTICES_PER_BATCH;
|
||||
uint32_t currentBatchVertices = 0;
|
||||
|
||||
for (const auto & cmd : commands) {
|
||||
@@ -479,31 +489,31 @@ VkPipeline Renderer::get_pipeline(PipelineType type) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::bind_material(VkCommandBuffer cmd, uint16_t materialID) {
|
||||
// In a real app, you'd have an array/map: std::vector<VkDescriptorSet> textureSets;
|
||||
VkDescriptorSet set = textureSets[materialID];
|
||||
|
||||
vkCmdBindDescriptorSets(
|
||||
cmd,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipelineLayout, // Our shared layout
|
||||
0, // Starting at Set 0
|
||||
1, // Binding 1 set
|
||||
&set,
|
||||
0, nullptr
|
||||
);
|
||||
}
|
||||
// void Renderer::bind_material(VkCommandBuffer cmd, uint16_t materialID) {
|
||||
// // In a real app, you'd have an array/map: std::vector<VkDescriptorSet> textureSets;
|
||||
// VkDescriptorSet set = textureSets[materialID];
|
||||
//
|
||||
// vkCmdBindDescriptorSets(
|
||||
// cmd,
|
||||
// VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
// pipelineLayout, // Our shared layout
|
||||
// 0, // Starting at Set 0
|
||||
// 1, // Binding 1 set
|
||||
// &set,
|
||||
// 0, nullptr
|
||||
// );
|
||||
// }
|
||||
|
||||
void Renderer::create_descriptor_pool() {
|
||||
VkDescriptorPoolSize pool_sizes[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 10 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 },
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
|
||||
.maxSets = 1000,
|
||||
.maxSets = 1,
|
||||
.poolSizeCount = 2,
|
||||
.pPoolSizes = pool_sizes
|
||||
};
|
||||
@@ -517,9 +527,7 @@ void Renderer::create_descriptor_pool() {
|
||||
.pSetLayouts = &descriptor_set_layout
|
||||
};
|
||||
|
||||
if (vkAllocateDescriptorSets(device, &alloc_info, &set) != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to allocate bindless descriptor set!");
|
||||
}
|
||||
vkAllocateDescriptorSets(device, &alloc_info, &set);
|
||||
}
|
||||
|
||||
void Renderer::update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) {
|
||||
@@ -618,7 +626,7 @@ Texture Renderer::upload_texture(int w, int h, void* pixels) {
|
||||
|
||||
void Renderer::immediate_submit(std::function<void(VkCommandBuffer)>&& func) const {
|
||||
VkCommandBufferAllocateInfo allocInfo{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
allocInfo.commandPool = commandPool; // Use a pool created with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||
allocInfo.commandPool = frames[currentFrame].commandPool; // Use a pool created with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
@@ -643,7 +651,7 @@ void Renderer::immediate_submit(std::function<void(VkCommandBuffer)>&& func) con
|
||||
vkQueueSubmit(graphics_queue, 1, &submit, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(graphics_queue);
|
||||
|
||||
vkFreeCommandBuffers(device, commandPool, 1, &cmd);
|
||||
vkFreeCommandBuffers(device, frames[currentFrame].commandPool, 1, &cmd);
|
||||
}
|
||||
|
||||
void Renderer::transition_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) const {
|
||||
@@ -690,9 +698,7 @@ VkImageView Renderer::create_image_view(VkImage image, VkFormat format) const {
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageView view;
|
||||
if (vkCreateImageView(device, &viewInfo, nullptr, &view) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image view!");
|
||||
}
|
||||
vkCreateImageView(device, &viewInfo, nullptr, &view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -717,7 +723,5 @@ void Renderer::create_default_sampler() {
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
|
||||
if (vkCreateSampler(device, &samplerInfo, nullptr, &defaultSampler) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create texture sampler!");
|
||||
}
|
||||
vkCreateSampler(device, &samplerInfo, nullptr, &defaultSampler);
|
||||
}
|
||||
+21
-53
@@ -5,6 +5,7 @@
|
||||
#ifndef V_RENDERER_H
|
||||
#define V_RENDERER_H
|
||||
|
||||
#include "init.h"
|
||||
#include <volk/volk.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -22,17 +23,6 @@ enum class PROJECTION_TYPE : uint8_t {
|
||||
COUNT,
|
||||
};
|
||||
|
||||
struct vertex_p2_col4 {
|
||||
glm::vec2 pos;
|
||||
glm::vec4 col;
|
||||
};
|
||||
|
||||
struct vertex_p2_st2_col4 {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 st;
|
||||
glm::vec4 col;
|
||||
};
|
||||
|
||||
struct vertex_p2_st2_col4_a1_u32 {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 st;
|
||||
@@ -55,21 +45,6 @@ struct vertex_p2_st2_col4_a1_u32 {
|
||||
}
|
||||
};
|
||||
|
||||
struct vertex_st2 {
|
||||
glm::vec2 st;
|
||||
};
|
||||
|
||||
struct vertex_p2_scale2_rot1_st2 {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 scale;
|
||||
float rot;
|
||||
glm::vec2 st;
|
||||
};
|
||||
|
||||
typedef vertex_st2 quad_st2[6];
|
||||
|
||||
typedef vertex_p2_scale2_rot1_st2 quad_pos2_scale2_rot1_st2[6];
|
||||
|
||||
// commands
|
||||
|
||||
enum class PipelineType : uint8_t {
|
||||
@@ -140,7 +115,7 @@ struct RenderCommand {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Renderer {
|
||||
std::vector<RenderCommand> commands;
|
||||
std::vector<RenderCommand> commands{};
|
||||
|
||||
void begin_frame();
|
||||
void end_frame();
|
||||
@@ -163,47 +138,40 @@ struct Renderer {
|
||||
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;
|
||||
VkPipeline colored_quad_pipeline;
|
||||
VkPipeline line_pipeline;
|
||||
VkPipeline text_pipeline;
|
||||
VkPipeline chunk_pipeline;
|
||||
VkDescriptorSet set;
|
||||
VkDescriptorSetLayout descriptor_set_layout{};
|
||||
VkPipelineLayout pipelineLayout{};
|
||||
VkPipeline textured_quad_pipeline{};
|
||||
VkPipeline colored_quad_pipeline{};
|
||||
VkPipeline line_pipeline{};
|
||||
VkPipeline text_pipeline{};
|
||||
VkPipeline chunk_pipeline{};
|
||||
VkDescriptorSet set{};
|
||||
|
||||
VkSampler defaultSampler;
|
||||
VkSampler defaultSampler{};
|
||||
|
||||
uint32_t nextTextureSlot = 0;
|
||||
|
||||
VkCommandPool commandPool;
|
||||
|
||||
static constexpr uint32_t MAX_FRAMES_IN_FLIGHT = 2;
|
||||
static constexpr uint32_t MAX_VERTICES_PER_FRAME = 65536;
|
||||
|
||||
struct Frame {
|
||||
VkCommandPool commandPool{};
|
||||
VkCommandBuffer command_buffer{};
|
||||
|
||||
VkSemaphore imageAvailable{};
|
||||
VkSemaphore renderFinished{};
|
||||
VkFence in_flight_fence{};
|
||||
};
|
||||
|
||||
Frame frames[MAX_FRAMES_IN_FLIGHT];
|
||||
std::vector<Frame> frames;
|
||||
uint32_t currentFrame = 0;
|
||||
|
||||
VkSemaphore timelineSemaphore{};
|
||||
uint64_t frameValue = 0;
|
||||
VkBuffer vertexBuffer{};
|
||||
VmaAllocation vertexAllocation{};
|
||||
VmaAllocationInfo vertexAllocInfo{};
|
||||
|
||||
VkBuffer vertexBuffer;
|
||||
VmaAllocation vertexAllocation;
|
||||
VmaAllocationInfo vertexAllocInfo;
|
||||
|
||||
VkDescriptorPool descriptorPool;
|
||||
std::vector<VkDescriptorSet> textureSets;
|
||||
VkDescriptorPool descriptorPool{};
|
||||
std::vector<VkDescriptorSet> textureSets{};
|
||||
|
||||
VkPipeline get_pipeline(PipelineType type) const;
|
||||
void bind_material(VkCommandBuffer cmd, uint16_t materialID);
|
||||
// void bind_material(VkCommandBuffer cmd, uint16_t materialID);
|
||||
void create_descriptor_pool();
|
||||
VkDescriptorSet create_texture_descriptor(VkImageView imageView, VkSampler sampler);
|
||||
void update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler);
|
||||
|
||||
// Returns the resource info so the Manager can store it
|
||||
|
||||
+25
-1
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "swapchain.h"
|
||||
#include <print>
|
||||
|
||||
void createSwapchain(GLFWwindow* window) {
|
||||
int fbWidth, fbHeight;
|
||||
@@ -13,10 +14,24 @@ void createSwapchain(GLFWwindow* window) {
|
||||
static_cast<uint32_t>(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 = 2,
|
||||
.minImageCount = MAX_FRAMES_IN_FLIGHT,
|
||||
.imageFormat = swapchain_format.format,
|
||||
.imageColorSpace = swapchain_format.colorSpace,
|
||||
.imageExtent = swapchain_extent,
|
||||
@@ -33,6 +48,7 @@ void createSwapchain(GLFWwindow* window) {
|
||||
|
||||
uint32_t imgCount;
|
||||
vkGetSwapchainImagesKHR(device, swapchain, &imgCount, nullptr);
|
||||
std::print("imgCount: {}", imgCount);
|
||||
images = std::vector<VkImage>(imgCount);
|
||||
vkGetSwapchainImagesKHR(device, swapchain, &imgCount, images.data());
|
||||
|
||||
@@ -43,6 +59,12 @@ void createSwapchain(GLFWwindow* window) {
|
||||
|
||||
imageViews = std::vector<VkImageView>(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;
|
||||
@@ -60,5 +82,7 @@ void createSwapchain(GLFWwindow* window) {
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCreateImageView(device, &ivci, nullptr, &imageViews[i]);
|
||||
|
||||
vkCreateSemaphore(device, &seci, nullptr, &renderFinished[i]);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ inline VkSurfaceFormatKHR swapchain_format{
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
|
||||
};
|
||||
inline std::vector<VkSemaphore> renderFinished;
|
||||
|
||||
inline std::vector<VkImage> images;
|
||||
inline std::vector<VkImageView> imageViews;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
constexpr std::string TEXTURE_SHEETS_PATH = "data/texture_sheets";
|
||||
inline const std::string TEXTURE_SHEETS_PATH = "data/texture_sheets";
|
||||
|
||||
typedef std::string texture_cell_id;
|
||||
typedef std::string texture_sheet_id;
|
||||
|
||||
Reference in new issue
Block a user