diff --git a/include/application.hpp b/include/application.hpp index d00e0a6..11315e2 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -31,10 +31,16 @@ namespace engine { const gfx::DescriptorSetLayout* setZeroLayout; const gfx::DescriptorSet* setZero; struct SetZeroBuffer { - glm::mat4 view; glm::mat4 proj; }; gfx::DescriptorBuffer* setZeroBuffer; + /* uniforms for per-frame data */ + const gfx::DescriptorSetLayout* setOneLayout; + const gfx::DescriptorSet* setOne; + struct SetOneBuffer { + glm::mat4 view; + }; + gfx::DescriptorBuffer* setOneBuffer; }; class Application { diff --git a/res/engine/shaders/skybox.vert b/res/engine/shaders/skybox.vert index 2e0f9b3..53870c4 100644 --- a/res/engine/shaders/skybox.vert +++ b/res/engine/shaders/skybox.vert @@ -5,17 +5,20 @@ layout( push_constant ) uniform Constants { } constants; layout(set = 0, binding = 0) uniform SetZeroBuffer { - mat4 view; mat4 proj; } setZeroBuffer; +layout(set = 1, binding = 0) uniform SetOneBuffer { + mat4 view; +} setOneBuffer; + layout(location = 0) in vec3 inPosition; layout(location = 2) in vec2 inUV; layout(location = 0) out vec2 fragUV; void main() { - mat4 myView = setZeroBuffer.view; + mat4 myView = setOneBuffer.view; myView[3] = vec4(0.0, 0.0, 0.0, 1.0); vec4 pos = setZeroBuffer.proj * myView * constants.model * vec4(inPosition, 1.0); gl_Position = pos; diff --git a/res/engine/shaders/standard.vert b/res/engine/shaders/standard.vert index e113334..6eedeb6 100644 --- a/res/engine/shaders/standard.vert +++ b/res/engine/shaders/standard.vert @@ -5,10 +5,13 @@ layout( push_constant ) uniform Constants { } constants; layout(set = 0, binding = 0) uniform SetZeroBuffer { - mat4 view; mat4 proj; } setZeroBuffer; +layout(set = 1, binding = 0) uniform SetOneBuffer { + mat4 view; +} setOneBuffer; + layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; layout(location = 2) in vec2 inUV; @@ -19,12 +22,12 @@ layout(location = 2) out vec2 fragUV; layout(location = 3) out vec3 fragLightPos; void main() { - gl_Position = setZeroBuffer.proj * setZeroBuffer.view * constants.model * vec4(inPosition, 1.0); + gl_Position = setZeroBuffer.proj * setOneBuffer.view * constants.model * vec4(inPosition, 1.0); - fragPos = vec3(setZeroBuffer.view * constants.model * vec4(inPosition, 1.0)); - fragNorm = mat3(transpose(inverse(setZeroBuffer.view * constants.model))) * inNorm; + fragPos = vec3(setOneBuffer.view * constants.model * vec4(inPosition, 1.0)); + fragNorm = mat3(transpose(inverse(setOneBuffer.view * constants.model))) * inNorm; fragUV = inUV; vec3 lightPos = vec3(2000.0, 2000.0, -2000.0); - fragLightPos = vec3(setZeroBuffer.view * vec4(lightPos, 1.0)); + fragLightPos = vec3(setOneBuffer.view * vec4(lightPos, 1.0)); } diff --git a/src/application.cpp b/src/application.cpp index 8f5d41b..d7195ca 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -75,15 +75,23 @@ namespace engine { // initialise the render data renderData.gfxdev = std::make_unique(appName, appVersion, m_window->getHandle(), graphicsSettings); + renderData.setZeroLayout = gfx()->createDescriptorSetLayout(); renderData.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout); - RenderData::SetZeroBuffer initialData{ - .view = glm::mat4{1.0f}, + RenderData::SetZeroBuffer initialSetZeroData{ .proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f), }; - renderData.setZeroBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetZeroBuffer), &initialData); + renderData.setZeroBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData); gfx()->updateDescriptor(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer)); + renderData.setOneLayout = gfx()->createDescriptorSetLayout(); + renderData.setOne = gfx()->allocateDescriptorSet(renderData.setOneLayout); + RenderData::SetOneBuffer initialSetOneData{ + .view = glm::mat4{ 1.0f }, + }; + renderData.setOneBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData); + gfx()->updateDescriptor(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer)); + // default resources { resources::Shader::VertexParams vertParams{}; @@ -99,7 +107,7 @@ namespace engine { ); getResourceManager()->addPersistent("builtin.standard", std::move(texturedShader)); } - { + if (0) { resources::Shader::VertexParams vertParams{}; vertParams.hasNormal = true; vertParams.hasUV0 = true; @@ -127,6 +135,8 @@ namespace engine { Application::~Application() { + gfx()->destroyDescriptorBuffer(renderData.setOneBuffer); + gfx()->destroyDescriptorSetLayout(renderData.setOneLayout); gfx()->destroyDescriptorBuffer(renderData.setZeroBuffer); gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout); } diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 18d2b8f..e8e49c2 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -1,5 +1,14 @@ // The implementation of the graphics layer using Vulkan 1.3. +/* IMPORTANT INFORMATION + * + * When allocating memory with VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, always set a memory priority. + * This feature uses the device extension VK_EXT_memory_priority. Depth buffers have a priority of 0.9f. + * Other, non-essential allocations will have a priority of 0.5f. + * + * + */ + #include #include #include @@ -84,6 +93,7 @@ namespace engine { FrameData frameData{}; uint32_t currentFrameIndex = 0; // corresponds to the frameData uint32_t imageIndex = 0; // for swapchain present + std::vector copySemaphores{}; }; struct gfx::DescriptorSetLayout { @@ -97,6 +107,7 @@ namespace engine { struct gfx::DescriptorBuffer { gfx::Buffer stagingBuffer{}; std::array gpuBuffers; + std::array copySemaphores; }; // enum converters @@ -268,58 +279,6 @@ namespace engine { vmaDestroyImage(allocator, target.colorImage, target.colorImageAllocation); } - static DepthBuffer createDepthBuffer(VkDevice device, VmaAllocator allocator, VkExtent2D extent, VkSampleCountFlagBits msaaSamples) - { - DepthBuffer db{}; - - [[maybe_unused]] VkResult res; - - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = extent.width; - imageInfo.extent.height = extent.height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = VK_FORMAT_D32_SFLOAT; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = msaaSamples; - imageInfo.flags = 0; - - VmaAllocationCreateInfo allocInfo{}; - allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; - allocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - allocInfo.priority = 1.0f; - - res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &db.image, &db.allocation, nullptr); - assert(res == VK_SUCCESS); - - VkImageViewCreateInfo imageViewInfo{}; - imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewInfo.image = db.image; - imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewInfo.format = VK_FORMAT_D32_SFLOAT; - imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - imageViewInfo.subresourceRange.baseMipLevel = 0; - imageViewInfo.subresourceRange.levelCount = 1; - imageViewInfo.subresourceRange.baseArrayLayer = 0; - imageViewInfo.subresourceRange.layerCount = 1; - res = vkCreateImageView(device, &imageViewInfo, nullptr, &db.view); - assert(res == VK_SUCCESS); - - return db; - } - - static void destroyDepthBuffer(DepthBuffer db, VkDevice device, VmaAllocator allocator) - { - vkDestroyImageView(device, db.view, nullptr); - vmaDestroyImage(allocator, db.image, db.allocation); - } - static VkSampleCountFlagBits getMaxSampleCount(VkPhysicalDevice physicalDevice, gfx::MSAALevel maxLevel) { VkSampleCountFlags max = vkinternal::getSampleCountFlags(maxLevel); @@ -601,9 +560,10 @@ namespace engine { }; DeviceRequirements deviceRequirements{}; - deviceRequirements.requiredExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + deviceRequirements.requiredExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME }; deviceRequirements.requiredFeatures.samplerAnisotropy = VK_TRUE; deviceRequirements.requiredFeatures.fillModeNonSolid = VK_TRUE; + deviceRequirements.memoryPriorityFeature = VK_TRUE; deviceRequirements.formats.push_back( FormatRequirements{ .format = VK_FORMAT_R8G8B8A8_SRGB, @@ -770,6 +730,8 @@ namespace engine { { VkResult res; + gfx::DrawBuffer* drawBuffer = new gfx::DrawBuffer; + const uint32_t currentFrameIndex = pimpl->FRAMECOUNT % FRAMES_IN_FLIGHT; const FrameData frameData = pimpl->frameData[currentFrameIndex]; @@ -779,13 +741,80 @@ namespace engine { res = vkResetFences(pimpl->device.device, 1, &frameData.renderFence); VKCHECK(res); + if (pimpl->device.queues.transferQueues.size() < 2) throw std::runtime_error("Need at least 2 transfer queues!"); + /* first empty the descriptor buffer write queue */ auto& writeQueue = pimpl->descriptorBufferWriteQueues[currentFrameIndex]; //if (writeQueue.empty() == false) vkQueueWaitIdle(pimpl->device.queues.drawQueues[0]); for (gfx::DescriptorBuffer* buffer : writeQueue) { - copyBuffer(pimpl->device.device, pimpl->transferCommandPool, pimpl->device.queues.transferQueues[0], buffer->stagingBuffer.buffer, buffer->gpuBuffers[currentFrameIndex].buffer, buffer->stagingBuffer.size); + + // record the command buffer + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = pimpl->transferCommandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + res = vkAllocateCommandBuffers(pimpl->device.device, &allocInfo, &commandBuffer); + assert(res == VK_SUCCESS); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + res = vkBeginCommandBuffer(commandBuffer, &beginInfo); + assert(res == VK_SUCCESS); + + VkBufferCopy copyRegion{}; + copyRegion.srcOffset = 0; + copyRegion.dstOffset = 0; + copyRegion.size = buffer->stagingBuffer.size; + vkCmdCopyBuffer(commandBuffer, buffer->stagingBuffer.buffer, buffer->gpuBuffers[currentFrameIndex].buffer, 1, ©Region); + + /* barrier to perform ownership transfer from transferQueue to drawQueue */ + VkBufferMemoryBarrier bufferMemoryBarrier{}; + bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + bufferMemoryBarrier.pNext = nullptr; + bufferMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + bufferMemoryBarrier.dstAccessMask = 0; + bufferMemoryBarrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; + bufferMemoryBarrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; + bufferMemoryBarrier.buffer = buffer->gpuBuffers[currentFrameIndex].buffer; + bufferMemoryBarrier.offset = 0; + bufferMemoryBarrier.size = buffer->stagingBuffer.size; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask + 0, + 0, + nullptr, + 1, + &bufferMemoryBarrier, + 0, + nullptr + ); + + res = vkEndCommandBuffer(commandBuffer); + assert(res == VK_SUCCESS); + + // submit + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &buffer->copySemaphores[currentFrameIndex]; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &frameData.renderSemaphore; + + res = vkQueueSubmit(pimpl->device.queues.transferQueues[1], 1, &submitInfo, VK_NULL_HANDLE); + assert(res == VK_SUCCESS); + + drawBuffer->copySemaphores.push_back(buffer->copySemaphores[currentFrameIndex]); + } - writeQueue.clear(); uint32_t swapchainImageIndex; @@ -819,6 +848,34 @@ namespace engine { { // RECORDING + for (gfx::DescriptorBuffer* buffer : writeQueue) { + /* barrier to perform ownership transfer from transferQueue to drawQueue (ACQUIRE) */ + VkBufferMemoryBarrier bufferMemoryBarrier{}; + bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + bufferMemoryBarrier.pNext = nullptr; + bufferMemoryBarrier.srcAccessMask = 0; + bufferMemoryBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; + bufferMemoryBarrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; + bufferMemoryBarrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; + bufferMemoryBarrier.buffer = buffer->gpuBuffers[currentFrameIndex].buffer; + bufferMemoryBarrier.offset = 0; + bufferMemoryBarrier.size = buffer->stagingBuffer.size; + + vkCmdPipelineBarrier( + frameData.drawBuf, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // dstStageMask + 0, + 0, + nullptr, + 1, + &bufferMemoryBarrier, + 0, + nullptr + ); + } + writeQueue.clear(); + std::array clearValues{}; // Using same value for all components enables compression according to NVIDIA Best Practices clearValues[0].color.float32[0] = 1.0f; clearValues[0].color.float32[1] = 1.0f; @@ -854,7 +911,6 @@ namespace engine { } // hand command buffer over to caller - gfx::DrawBuffer* drawBuffer = new gfx::DrawBuffer; drawBuffer->frameData = frameData; drawBuffer->currentFrameIndex = currentFrameIndex; drawBuffer->imageIndex = swapchainImageIndex; @@ -877,14 +933,20 @@ namespace engine { // SUBMIT - VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + std::vector waitDstStageMasks{}; + for (size_t i = 0; i < drawBuffer->copySemaphores.size(); i++) { + waitDstStageMasks.push_back(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); + } + + drawBuffer->copySemaphores.push_back(drawBuffer->frameData.presentSemaphore); + waitDstStageMasks.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); VkSubmitInfo submitInfo{ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = nullptr, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &drawBuffer->frameData.presentSemaphore, - .pWaitDstStageMask = &waitStage, + .waitSemaphoreCount = (uint32_t)drawBuffer->copySemaphores.size(), + .pWaitSemaphores = drawBuffer->copySemaphores.data(), + .pWaitDstStageMask = waitDstStageMasks.data(), .commandBufferCount = 1, .pCommandBuffers = &drawBuffer->frameData.drawBuf, .signalSemaphoreCount = 1, @@ -1280,6 +1342,12 @@ namespace engine { /* create the device-local set of buffers */ for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { + VkSemaphoreCreateInfo semInfo{}; + semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semInfo.pNext = nullptr; + semInfo.flags = 0; + VKCHECK(vkCreateSemaphore(pimpl->device.device, &semInfo, nullptr, &out->copySemaphores[i])); + out->gpuBuffers[i].size = out->stagingBuffer.size; out->gpuBuffers[i].type = gfx::BufferType::UNIFORM; out->gpuBuffers[i].hostVisible = false; @@ -1309,6 +1377,7 @@ namespace engine { { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { vmaDestroyBuffer(pimpl->allocator, descriptorBuffer->gpuBuffers[i].buffer, descriptorBuffer->gpuBuffers[i].allocation); + vkDestroySemaphore(pimpl->device.device, descriptorBuffer->copySemaphores[i], nullptr); } vmaDestroyBuffer(pimpl->allocator, descriptorBuffer->stagingBuffer.buffer, descriptorBuffer->stagingBuffer.allocation); diff --git a/src/resources/shader.cpp b/src/resources/shader.cpp index b488a24..6bcccc5 100644 --- a/src/resources/shader.cpp +++ b/src/resources/shader.cpp @@ -45,6 +45,7 @@ namespace engine::resources { info.alphaBlending = alphaBlending; info.backfaceCulling = cullBackFace; info.descriptorSetLayouts.push_back(renderData->setZeroLayout); + info.descriptorSetLayouts.push_back(renderData->setOneLayout); m_pipeline = m_gfx->createPipeline(info); diff --git a/src/systems/render.cpp b/src/systems/render.cpp index 33d0ca3..d29bfca 100644 --- a/src/systems/render.cpp +++ b/src/systems/render.cpp @@ -42,43 +42,69 @@ namespace engine { uint32_t w, h; m_gfx->getViewportSize(&w, &h); m_viewportAspectRatio = (float)w / (float)h; + const float verticalFovRadians = glm::radians(m_camera.verticalFovDegrees); + const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar); + /* update SET 0 */ + RenderData::SetZeroBuffer setZeroBuffer{ + .proj = projMatrix + }; + m_gfx->writeDescriptorBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &setZeroBuffer); } - const float verticalFovRadians = glm::radians(m_camera.verticalFovDegrees); - const glm::mat4 projMatrix = glm::perspectiveZO(verticalFovRadians, m_viewportAspectRatio, m_camera.clipNear, m_camera.clipFar); - /* update SET 0 */ - RenderData::SetZeroBuffer uniform{ - .view = viewMatrix, - .proj = projMatrix + RenderData::SetOneBuffer setOneBuffer{ + .view = viewMatrix }; - m_gfx->writeDescriptorBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &uniform); + //m_gfx->writeDescriptorBuffer(renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer), &setOneBuffer); /* render all renderable entities */ + struct PushConstants { + glm::mat4 model; + }; + + struct DrawCallData { + const gfx::Buffer* vb; + const gfx::Buffer* ib; + uint32_t indexCount; + PushConstants pushConsts; + }; + std::unordered_map > pipelineDrawCalls{}; + for (uint32_t entity : m_entities) { auto r = m_scene->getComponent(entity); + assert(r != nullptr); + assert(r->material != nullptr); + assert(r->mesh != nullptr); if (r->shown == false) continue; auto t = m_scene->getComponent(entity); + assert(t != nullptr); - assert(r->material != nullptr); - assert(r->mesh != nullptr); - //assert(r->material->m_texture != nullptr); + const gfx::Pipeline* pipeline = r->material->getShader()->getPipeline(); + DrawCallData data{}; + data.vb = r->mesh->getVB(); + data.ib = r->mesh->getIB(); + data.indexCount = r->mesh->getCount(); + data.pushConsts.model = t->worldMatrix; - struct { - glm::mat4 model; - } pushConsts{}; + pipelineDrawCalls[pipeline].push_back(data); - pushConsts.model = t->worldMatrix; + } - m_gfx->cmdBindPipeline(renderData.drawBuffer, r->material->getShader()->getPipeline()); - m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, r->material->getShader()->getPipeline(), renderData.setZero, 0); - m_gfx->cmdPushConstants(renderData.drawBuffer, r->material->getShader()->getPipeline(), 0, sizeof(pushConsts), &pushConsts); - m_gfx->cmdBindVertexBuffer(renderData.drawBuffer, 0, r->mesh->getVB()); - m_gfx->cmdBindIndexBuffer(renderData.drawBuffer, r->mesh->getIB()); - m_gfx->cmdDrawIndexed(renderData.drawBuffer, r->mesh->getCount(), 1, 0, 0, 0); + /* these descriptor set bindings should persist across pipeline changes */ + const gfx::Pipeline* firstPipeline = pipelineDrawCalls.begin()->first; + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setZero, 0); + m_gfx->cmdBindDescriptorSet(renderData.drawBuffer, firstPipeline, renderData.setOne, 1); + for (const auto& [pipeline, drawCalls] : pipelineDrawCalls) { + m_gfx->cmdBindPipeline(renderData.drawBuffer, pipeline); + for (const auto& drawCall : drawCalls) { + m_gfx->cmdPushConstants(renderData.drawBuffer, pipeline, 0, sizeof(PushConstants), &drawCall.pushConsts); + m_gfx->cmdBindVertexBuffer(renderData.drawBuffer, 0, drawCall.vb); + m_gfx->cmdBindIndexBuffer(renderData.drawBuffer, drawCall.ib); + m_gfx->cmdDrawIndexed(renderData.drawBuffer, drawCall.indexCount, 1, 0, 0, 0); + } } } diff --git a/src/vulkan/device.cpp b/src/vulkan/device.cpp index 8758943..0c2916c 100644 --- a/src/vulkan/device.cpp +++ b/src/vulkan/device.cpp @@ -72,119 +72,126 @@ namespace engine { } /* check features */ - VkPhysicalDeviceFeatures devFeatures; - vkGetPhysicalDeviceFeatures(physDev, &devFeatures); + VkPhysicalDeviceMemoryPriorityFeaturesEXT memoryPriorityFeatures{}; + memoryPriorityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; + VkPhysicalDeviceFeatures2 devFeatures{}; + devFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + devFeatures.pNext = &memoryPriorityFeatures; + vkGetPhysicalDeviceFeatures2(physDev, &devFeatures); { if (requirements.requiredFeatures.robustBufferAccess) - if (devFeatures.robustBufferAccess == VK_FALSE) continue; + if (devFeatures.features.robustBufferAccess == VK_FALSE) continue; if (requirements.requiredFeatures.fullDrawIndexUint32) - if (devFeatures.fullDrawIndexUint32 == VK_FALSE) continue; + if (devFeatures.features.fullDrawIndexUint32 == VK_FALSE) continue; if (requirements.requiredFeatures.imageCubeArray == VK_TRUE) - if (devFeatures.imageCubeArray == VK_FALSE) continue; + if (devFeatures.features.imageCubeArray == VK_FALSE) continue; if (requirements.requiredFeatures.independentBlend == VK_TRUE) - if (devFeatures.independentBlend == VK_FALSE) continue; + if (devFeatures.features.independentBlend == VK_FALSE) continue; if (requirements.requiredFeatures.geometryShader == VK_TRUE) - if (devFeatures.geometryShader == VK_FALSE) continue; + if (devFeatures.features.geometryShader == VK_FALSE) continue; if (requirements.requiredFeatures.tessellationShader == VK_TRUE) - if (devFeatures.tessellationShader == VK_FALSE) continue; + if (devFeatures.features.tessellationShader == VK_FALSE) continue; if (requirements.requiredFeatures.sampleRateShading == VK_TRUE) - if (devFeatures.sampleRateShading == VK_FALSE) continue; + if (devFeatures.features.sampleRateShading == VK_FALSE) continue; if (requirements.requiredFeatures.dualSrcBlend == VK_TRUE) - if (devFeatures.dualSrcBlend == VK_FALSE) continue; + if (devFeatures.features.dualSrcBlend == VK_FALSE) continue; if (requirements.requiredFeatures.logicOp == VK_TRUE) - if (devFeatures.logicOp == VK_FALSE) continue; + if (devFeatures.features.logicOp == VK_FALSE) continue; if (requirements.requiredFeatures.multiDrawIndirect == VK_TRUE) - if (devFeatures.multiDrawIndirect == VK_FALSE) continue; + if (devFeatures.features.multiDrawIndirect == VK_FALSE) continue; if (requirements.requiredFeatures.drawIndirectFirstInstance == VK_TRUE) - if (devFeatures.drawIndirectFirstInstance == VK_FALSE) continue; + if (devFeatures.features.drawIndirectFirstInstance == VK_FALSE) continue; if (requirements.requiredFeatures.depthClamp == VK_TRUE) - if (devFeatures.depthClamp == VK_FALSE) continue; + if (devFeatures.features.depthClamp == VK_FALSE) continue; if (requirements.requiredFeatures.depthBiasClamp == VK_TRUE) - if (devFeatures.depthBiasClamp == VK_FALSE) continue; + if (devFeatures.features.depthBiasClamp == VK_FALSE) continue; if (requirements.requiredFeatures.fillModeNonSolid == VK_TRUE) - if (devFeatures.fillModeNonSolid == VK_FALSE) continue; + if (devFeatures.features.fillModeNonSolid == VK_FALSE) continue; if (requirements.requiredFeatures.depthBounds == VK_TRUE) - if (devFeatures.depthBounds == VK_FALSE) continue; + if (devFeatures.features.depthBounds == VK_FALSE) continue; if (requirements.requiredFeatures.wideLines == VK_TRUE) - if (devFeatures.wideLines == VK_FALSE) continue; + if (devFeatures.features.wideLines == VK_FALSE) continue; if (requirements.requiredFeatures.largePoints == VK_TRUE) - if (devFeatures.largePoints == VK_FALSE) continue; + if (devFeatures.features.largePoints == VK_FALSE) continue; if (requirements.requiredFeatures.alphaToOne == VK_TRUE) - if (devFeatures.alphaToOne == VK_FALSE) continue; + if (devFeatures.features.alphaToOne == VK_FALSE) continue; if (requirements.requiredFeatures.multiViewport == VK_TRUE) - if (devFeatures.multiViewport == VK_FALSE) continue; + if (devFeatures.features.multiViewport == VK_FALSE) continue; if (requirements.requiredFeatures.samplerAnisotropy == VK_TRUE) - if (devFeatures.samplerAnisotropy == VK_FALSE) continue; + if (devFeatures.features.samplerAnisotropy == VK_FALSE) continue; if (requirements.requiredFeatures.textureCompressionETC2 == VK_TRUE) - if (devFeatures.textureCompressionETC2 == VK_FALSE) continue; + if (devFeatures.features.textureCompressionETC2 == VK_FALSE) continue; if (requirements.requiredFeatures.textureCompressionASTC_LDR == VK_TRUE) - if (devFeatures.textureCompressionASTC_LDR == VK_FALSE) continue; + if (devFeatures.features.textureCompressionASTC_LDR == VK_FALSE) continue; if (requirements.requiredFeatures.textureCompressionBC == VK_TRUE) - if (devFeatures.textureCompressionBC == VK_FALSE) continue; + if (devFeatures.features.textureCompressionBC == VK_FALSE) continue; if (requirements.requiredFeatures.occlusionQueryPrecise == VK_TRUE) - if (devFeatures.occlusionQueryPrecise == VK_FALSE) continue; + if (devFeatures.features.occlusionQueryPrecise == VK_FALSE) continue; if (requirements.requiredFeatures.pipelineStatisticsQuery == VK_TRUE) - if (devFeatures.pipelineStatisticsQuery == VK_FALSE) continue; + if (devFeatures.features.pipelineStatisticsQuery == VK_FALSE) continue; if (requirements.requiredFeatures.vertexPipelineStoresAndAtomics == VK_TRUE) - if (devFeatures.vertexPipelineStoresAndAtomics == VK_FALSE) continue; + if (devFeatures.features.vertexPipelineStoresAndAtomics == VK_FALSE) continue; if (requirements.requiredFeatures.fragmentStoresAndAtomics == VK_TRUE) - if (devFeatures.fragmentStoresAndAtomics == VK_FALSE) continue; + if (devFeatures.features.fragmentStoresAndAtomics == VK_FALSE) continue; if (requirements.requiredFeatures.shaderTessellationAndGeometryPointSize == VK_TRUE) - if (devFeatures.shaderTessellationAndGeometryPointSize == VK_FALSE) continue; + if (devFeatures.features.shaderTessellationAndGeometryPointSize == VK_FALSE) continue; if (requirements.requiredFeatures.shaderImageGatherExtended == VK_TRUE) - if (devFeatures.shaderImageGatherExtended == VK_FALSE) continue; + if (devFeatures.features.shaderImageGatherExtended == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageImageExtendedFormats == VK_TRUE) - if (devFeatures.shaderStorageImageExtendedFormats == VK_FALSE) continue; + if (devFeatures.features.shaderStorageImageExtendedFormats == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageImageMultisample == VK_TRUE) - if (devFeatures.shaderStorageImageMultisample == VK_FALSE) continue; + if (devFeatures.features.shaderStorageImageMultisample == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageImageReadWithoutFormat == VK_TRUE) - if (devFeatures.shaderStorageImageReadWithoutFormat == VK_FALSE) continue; + if (devFeatures.features.shaderStorageImageReadWithoutFormat == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageImageWriteWithoutFormat == VK_TRUE) - if (devFeatures.shaderStorageImageWriteWithoutFormat == VK_FALSE) continue; + if (devFeatures.features.shaderStorageImageWriteWithoutFormat == VK_FALSE) continue; if (requirements.requiredFeatures.shaderUniformBufferArrayDynamicIndexing == VK_TRUE) - if (devFeatures.shaderUniformBufferArrayDynamicIndexing == VK_FALSE) continue; + if (devFeatures.features.shaderUniformBufferArrayDynamicIndexing == VK_FALSE) continue; if (requirements.requiredFeatures.shaderSampledImageArrayDynamicIndexing == VK_TRUE) - if (devFeatures.shaderSampledImageArrayDynamicIndexing == VK_FALSE) continue; + if (devFeatures.features.shaderSampledImageArrayDynamicIndexing == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageBufferArrayDynamicIndexing == VK_TRUE) - if (devFeatures.shaderStorageBufferArrayDynamicIndexing == VK_FALSE) continue; + if (devFeatures.features.shaderStorageBufferArrayDynamicIndexing == VK_FALSE) continue; if (requirements.requiredFeatures.shaderStorageImageArrayDynamicIndexing == VK_TRUE) - if (devFeatures.shaderStorageImageArrayDynamicIndexing == VK_FALSE) continue; + if (devFeatures.features.shaderStorageImageArrayDynamicIndexing == VK_FALSE) continue; if (requirements.requiredFeatures.shaderClipDistance == VK_TRUE) - if (devFeatures.shaderClipDistance == VK_FALSE) continue; + if (devFeatures.features.shaderClipDistance == VK_FALSE) continue; if (requirements.requiredFeatures.shaderCullDistance == VK_TRUE) - if (devFeatures.shaderCullDistance == VK_FALSE) continue; + if (devFeatures.features.shaderCullDistance == VK_FALSE) continue; if (requirements.requiredFeatures.shaderFloat64 == VK_TRUE) - if (devFeatures.shaderFloat64 == VK_FALSE) continue; + if (devFeatures.features.shaderFloat64 == VK_FALSE) continue; if (requirements.requiredFeatures.shaderInt64 == VK_TRUE) - if (devFeatures.shaderInt64 == VK_FALSE) continue; + if (devFeatures.features.shaderInt64 == VK_FALSE) continue; if (requirements.requiredFeatures.shaderInt16 == VK_TRUE) - if (devFeatures.shaderInt16 == VK_FALSE) continue; + if (devFeatures.features.shaderInt16 == VK_FALSE) continue; if (requirements.requiredFeatures.shaderResourceResidency == VK_TRUE) - if (devFeatures.shaderResourceResidency == VK_FALSE) continue; + if (devFeatures.features.shaderResourceResidency == VK_FALSE) continue; if (requirements.requiredFeatures.shaderResourceMinLod == VK_TRUE) - if (devFeatures.shaderResourceMinLod == VK_FALSE) continue; + if (devFeatures.features.shaderResourceMinLod == VK_FALSE) continue; if (requirements.requiredFeatures.sparseBinding == VK_TRUE) - if (devFeatures.sparseBinding == VK_FALSE) continue; + if (devFeatures.features.sparseBinding == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidencyBuffer == VK_TRUE) - if (devFeatures.sparseResidencyBuffer == VK_FALSE) continue; + if (devFeatures.features.sparseResidencyBuffer == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidencyImage2D == VK_TRUE) - if (devFeatures.sparseResidencyImage2D == VK_FALSE) continue; + if (devFeatures.features.sparseResidencyImage2D == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidencyImage3D == VK_TRUE) - if (devFeatures.sparseResidencyImage3D == VK_FALSE) continue; + if (devFeatures.features.sparseResidencyImage3D == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidency2Samples == VK_TRUE) - if (devFeatures.sparseResidency2Samples == VK_FALSE) continue; + if (devFeatures.features.sparseResidency2Samples == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidency4Samples == VK_TRUE) - if (devFeatures.sparseResidency4Samples == VK_FALSE) continue; + if (devFeatures.features.sparseResidency4Samples == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidency8Samples == VK_TRUE) - if (devFeatures.sparseResidency8Samples == VK_FALSE) continue; + if (devFeatures.features.sparseResidency8Samples == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidency16Samples == VK_TRUE) - if (devFeatures.sparseResidency16Samples == VK_FALSE) continue; + if (devFeatures.features.sparseResidency16Samples == VK_FALSE) continue; if (requirements.requiredFeatures.sparseResidencyAliased == VK_TRUE) - if (devFeatures.sparseResidencyAliased == VK_FALSE) continue; + if (devFeatures.features.sparseResidencyAliased == VK_FALSE) continue; if (requirements.requiredFeatures.variableMultisampleRate == VK_TRUE) - if (devFeatures.variableMultisampleRate == VK_FALSE) continue; + if (devFeatures.features.variableMultisampleRate == VK_FALSE) continue; if (requirements.requiredFeatures.inheritedQueries == VK_TRUE) - if (devFeatures.inheritedQueries == VK_FALSE) continue; + if (devFeatures.features.inheritedQueries == VK_FALSE) continue; + + if (requirements.memoryPriorityFeature == VK_TRUE) + if (memoryPriorityFeatures.memoryPriority == VK_FALSE) continue; } bool formatsSupported = true; @@ -295,10 +302,19 @@ namespace engine { }); } + /* set enabled features */ + VkPhysicalDeviceMemoryPriorityFeaturesEXT memoryPriorityFeaturesToEnable{}; + memoryPriorityFeaturesToEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; + memoryPriorityFeaturesToEnable.memoryPriority = requirements.memoryPriorityFeature; + VkPhysicalDeviceFeatures2 featuresToEnable{}; + featuresToEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + featuresToEnable.pNext = &memoryPriorityFeaturesToEnable; + featuresToEnable.features = requirements.requiredFeatures; + /* create device now */ VkDeviceCreateInfo deviceCreateInfo{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, + .pNext = &featuresToEnable, .flags = 0, .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), @@ -306,7 +322,7 @@ namespace engine { .ppEnabledLayerNames = nullptr, // deprecated and ignored .enabledExtensionCount = static_cast(requirements.requiredExtensions.size()), .ppEnabledExtensionNames = requirements.requiredExtensions.data(), - .pEnabledFeatures = &requirements.requiredFeatures + .pEnabledFeatures = nullptr, }; res = vkCreateDevice(d.physicalDevice, &deviceCreateInfo, nullptr, &d.device); diff --git a/src/vulkan/device.h b/src/vulkan/device.h index 6686614..7e20b11 100644 --- a/src/vulkan/device.h +++ b/src/vulkan/device.h @@ -14,6 +14,7 @@ namespace engine { struct DeviceRequirements { std::vector requiredExtensions; VkPhysicalDeviceFeatures requiredFeatures; + VkBool32 memoryPriorityFeature; std::vector formats{}; }; diff --git a/src/vulkan/gpu_allocator.cpp b/src/vulkan/gpu_allocator.cpp index 8ace5de..2bf7fed 100644 --- a/src/vulkan/gpu_allocator.cpp +++ b/src/vulkan/gpu_allocator.cpp @@ -44,7 +44,7 @@ namespace engine { }; VmaAllocatorCreateInfo createInfo{ - .flags = 0, + .flags = VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT, .physicalDevice = physicalDevice, .device = device, .preferredLargeHeapBlockSize = 0, diff --git a/src/vulkan/instance.cpp b/src/vulkan/instance.cpp index 45346b5..8570fd6 100644 --- a/src/vulkan/instance.cpp +++ b/src/vulkan/instance.cpp @@ -47,7 +47,9 @@ namespace engine { } } - throw std::runtime_error("Unable to find validation layer!"); + LOG_WARN("Unable to find validation layer!"); + + return nullptr; } @@ -144,28 +146,27 @@ namespace engine { const std::vector windowExtensions = getWindowExtensions(window); std::vector instanceExtensionsToUse = windowExtensions; - if (useValidation) instanceExtensionsToUse.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); const char* validationLayer = nullptr; if (useValidation) { validationLayer = getValidationLayer(); } + if (validationLayer) instanceExtensionsToUse.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + VkDebugUtilsMessengerCreateInfoEXT debugMessengerInfo = getDebugMessengerCreateInfo(validationLevel); VkInstanceCreateInfo instanceInfo{}; instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instanceInfo.pNext = &debugMessengerInfo; + if (validationLayer) { + instanceInfo.pNext = &debugMessengerInfo; + } instanceInfo.flags = 0; instanceInfo.pApplicationInfo = &applicationInfo; if (validationLayer) { instanceInfo.enabledLayerCount = 1; instanceInfo.ppEnabledLayerNames = &validationLayer; } - else { - instanceInfo.enabledLayerCount = 0; - instanceInfo.ppEnabledLayerNames = nullptr; - } instanceInfo.enabledExtensionCount = (uint32_t)instanceExtensionsToUse.size(); instanceInfo.ppEnabledExtensionNames = instanceExtensionsToUse.data(); diff --git a/src/vulkan/swapchain.cpp b/src/vulkan/swapchain.cpp index b6ab455..1b8b7a5 100644 --- a/src/vulkan/swapchain.cpp +++ b/src/vulkan/swapchain.cpp @@ -286,7 +286,7 @@ namespace engine { VmaAllocationCreateInfo depthAllocInfo{}; depthAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; depthAllocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - depthAllocInfo.priority = 1.0f; + depthAllocInfo.priority = 0.9f; res = vmaCreateImage(sc->allocator, &depthImageInfo, &depthAllocInfo, &depthImage, &depthAllocation, nullptr); if (res != VK_SUCCESS) throw std::runtime_error("Failed to create depth buffer image! Code: " + std::to_string(res)); diff --git a/test/src/game.cpp b/test/src/game.cpp index cbae24b..43b311d 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -99,7 +99,7 @@ void playGame(GameSettings settings) ); /* skybox */ - { + if (0) { uint32_t skybox = myScene->createEntity("skybox"); auto skyboxRenderable = myScene->addComponent(skybox); skyboxRenderable->material = std::make_unique(app.getResource("builtin.skybox")); @@ -116,6 +116,9 @@ void playGame(GameSettings settings) auto cubeRenderable = myScene->addComponent(cube); cubeRenderable->material = std::make_shared(app.getResource("builtin.standard")); cubeRenderable->mesh = genCuboidMesh(app.gfx(), 1.0f, 1.0f, 1.0f, 1); + auto cubeCollider = myScene->addComponent(cube); + cubeCollider->isStatic = true; + cubeCollider->aabb = { { 0.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f } }; } /* floor */