From cc0c661dd7f71f408d3afaf78241c9a2177b4895 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 6 Aug 2017 12:13:39 +0200 Subject: [PATCH] Add Vulkan demo --- examples/VulkanTest/build.lua | 19 + examples/VulkanTest/main.cpp | 784 ++++++++++++++++++++++++++++++++++ 2 files changed, 803 insertions(+) create mode 100644 examples/VulkanTest/build.lua create mode 100644 examples/VulkanTest/main.cpp diff --git a/examples/VulkanTest/build.lua b/examples/VulkanTest/build.lua new file mode 100644 index 000000000..eab5abd2c --- /dev/null +++ b/examples/VulkanTest/build.lua @@ -0,0 +1,19 @@ +EXAMPLE.Name = "VulkanTest" + +EXAMPLE.EnableConsole = true + +EXAMPLE.OsDefines.Windows = { + "VK_USE_PLATFORM_WIN32_KHR", + "WIN32_LEAN_AND_MEAN", + "NOMINMAX" +} + +EXAMPLE.Files = { + "main.cpp" +} + +EXAMPLE.Libraries = { + "NazaraCore", + "NazaraVulkanRenderer", + "NazaraUtility" +} diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp new file mode 100644 index 000000000..ab691d38b --- /dev/null +++ b/examples/VulkanTest/main.cpp @@ -0,0 +1,784 @@ +#include +#include +#include +#include +#include +#include + +VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData) +{ + std::cerr << pMessage << std::endl; + return VK_FALSE; +} + +int main() +{ + Nz::ParameterList params; + params.SetParameter("VkInstanceInfo_EnabledExtensionCount", 1LL); + params.SetParameter("VkInstanceInfo_EnabledExtension0", "VK_EXT_debug_report"); + + params.SetParameter("VkDeviceInfo_EnabledLayerCount", 1LL); + params.SetParameter("VkDeviceInfo_EnabledLayer0", "VK_LAYER_LUNARG_standard_validation"); + params.SetParameter("VkInstanceInfo_EnabledLayerCount", 1LL); + params.SetParameter("VkInstanceInfo_EnabledLayer0", "VK_LAYER_LUNARG_standard_validation"); + + Nz::Renderer::SetParameters(params); + + Nz::Initializer loader; + if (!loader) + { + std::cout << "Failed to initialize Vulkan" << std::endl;; + return __LINE__; + } + + Nz::VulkanRenderer* rendererImpl = static_cast(Nz::Renderer::GetRendererImpl()); + + Nz::Vk::Instance& instance = Nz::Vulkan::GetInstance(); + + VkDebugReportCallbackCreateInfoEXT callbackCreateInfo; + callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + callbackCreateInfo.pNext = nullptr; + callbackCreateInfo.flags = VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT & ~VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + callbackCreateInfo.pfnCallback = &MyDebugReportCallback; + callbackCreateInfo.pUserData = nullptr; + + /* Register the callback */ + VkDebugReportCallbackEXT callback; + + instance.vkCreateDebugReportCallbackEXT(instance, &callbackCreateInfo, nullptr, &callback); + + Nz::File shaderFile; + std::vector vertexShaderCode; + std::vector fragmentShaderCode; + + if (!shaderFile.Open("resources/shaders/triangle.vert.spv", Nz::OpenMode_ReadOnly)) + { + NazaraError("Failed to open vertex shader code"); + return __LINE__; + } + + vertexShaderCode.resize(shaderFile.GetSize()); + shaderFile.Read(vertexShaderCode.data(), vertexShaderCode.size()); + + if (!shaderFile.Open("resources/shaders/triangle.frag.spv", Nz::OpenMode_ReadOnly)) + { + NazaraError("Failed to open fragment shader code"); + return __LINE__; + } + + fragmentShaderCode.resize(shaderFile.GetSize()); + shaderFile.Read(fragmentShaderCode.data(), fragmentShaderCode.size()); + + shaderFile.Close(); + + std::vector layerProperties; + if (!Nz::Vk::Loader::EnumerateInstanceLayerProperties(&layerProperties)) + { + NazaraError("Failed to enumerate instance layer properties"); + return __LINE__; + } + + for (const VkLayerProperties& properties : layerProperties) + { + std::cout << properties.layerName << ": \t" << properties.description << std::endl; + } + /* + std::vector extensionProperties; + if (!Nz::Vk::Loader::EnumerateInstanceExtensionProperties(&extensionProperties)) + { + NazaraError("Failed to enumerate instance extension properties"); + return __LINE__; + } + + for (const VkExtensionProperties& properties : extensionProperties) + std::cout << properties.extensionName << ": \t" << properties.specVersion << std::endl; + + std::vector devices; + if (!instance.EnumeratePhysicalDevices(&devices)) + { + NazaraError("Failed to enumerate physical devices"); + return __LINE__; + } + */ + Nz::RenderWindow window; + + Nz::MeshParams meshParams; + meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 180.f)); + + Nz::Mesh drfreak; + if (!drfreak.LoadFromFile("resources/drfreak.md2", meshParams)) + { + NazaraError("Failed to load Dr. Freak"); + return __LINE__; + } + + Nz::String windowTitle = "Vulkan Test"; + if (!window.Create(Nz::VideoMode(800, 600, 32), windowTitle)) + { + std::cout << "Failed to create Window" << std::endl; + return __LINE__; + } + + Nz::VkRenderWindow& vulkanWindow = *static_cast(window.GetImpl()); + + /*VkPhysicalDeviceFeatures features; + instance.GetPhysicalDeviceFeatures(physDevice, &features); + + VkPhysicalDeviceMemoryProperties memoryProperties; + instance.GetPhysicalDeviceMemoryProperties(physDevice, &memoryProperties); + + VkPhysicalDeviceProperties properties; + instance.GetPhysicalDeviceProperties(physDevice, &properties); + + std::vector queues; + instance.GetPhysicalDeviceQueueFamilyProperties(physDevice, &queues);*/ + + Nz::Vk::DeviceHandle device = vulkanWindow.GetDevice(); + + Nz::Vk::ShaderModule vertexShader; + if (!vertexShader.Create(device, reinterpret_cast(vertexShaderCode.data()), vertexShaderCode.size())) + { + NazaraError("Failed to create vertex shader"); + return __LINE__; + } + + Nz::Vk::ShaderModule fragmentShader; + if (!fragmentShader.Create(device, reinterpret_cast(fragmentShaderCode.data()), fragmentShaderCode.size())) + { + NazaraError("Failed to create fragment shader"); + return __LINE__; + } + + VkMemoryRequirements memRequirement; + + Nz::StaticMesh* drfreakMesh = static_cast(drfreak.GetSubMesh(0)); + + const Nz::VertexBuffer* drfreakVB = drfreakMesh->GetVertexBuffer(); + const Nz::IndexBuffer* drfreakIB = drfreakMesh->GetIndexBuffer(); + + // Vertex buffer + struct Vertex { + Nz::Vector4f pos; + Nz::Vector3f col; + }; + + /*std::vector vertexBufferData = { + {{-1.f, 1.f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + {{1.f, 1.f, 0.0f}, {0.0f, 1.0f, 0.0f}}, + {{0.0f, -1.f, 0.0f}, {0.0f, 0.0f, 1.0f}} + }; + + Nz::Matrix4f projection = Nz::Matrix4f::Perspective(70.f, float(window.GetWidth()) / window.GetHeight(), 1.f, 1000.f); + Nz::Matrix4f world = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 5.f); + + for (unsigned int i = 0; i < 3; ++i) + { + Nz::Vector4f pos = vertexBufferData[i].pos; + vertexBufferData[i].pos = projection * (world * pos); + }*/ + + Nz::BufferMapper vertexMapper(drfreakVB, Nz::BufferAccess_ReadOnly); + Nz::MeshVertex* meshVertices = static_cast(vertexMapper.GetPointer()); + + std::size_t vertexCount = drfreakVB->GetVertexCount(); + + Nz::Image meshImage; + if (!meshImage.LoadFromFile("resources/drfreak.tga")) + { + NazaraError("Failed to load texture"); + return __LINE__; + } + + std::vector vertexBufferData; + vertexBufferData.reserve(vertexCount); + for (std::size_t i = 0; i < vertexCount; ++i) + { + std::size_t texX = meshVertices[i].uv.x * meshImage.GetWidth(); + std::size_t texY = meshVertices[i].uv.y * meshImage.GetHeight(); + + Nz::Color c = meshImage.GetPixelColor(texX, texY); + + Vertex vertex = { + meshVertices[i].position, + {c.r / 255.f, c.g / 255.f, c.b / 255.f} + }; + + vertexBufferData.push_back(vertex); + } + + Nz::UInt32 vertexBufferSize = static_cast(vertexBufferData.size() * sizeof(Vertex)); + + Nz::Vk::Buffer vertexBuffer; + if (!vertexBuffer.Create(device, 0, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)) + { + NazaraError("Failed to create vertex buffer"); + return __LINE__; + } + + memRequirement = vertexBuffer.GetMemoryRequirements(); + + Nz::Vk::DeviceMemory vertexBufferMemory; + if (!vertexBufferMemory.Create(device, memRequirement.size, memRequirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) + { + NazaraError("Failed to allocate vertex buffer memory"); + return __LINE__; + } + + if (!vertexBufferMemory.Map(0, vertexBufferSize)) + { + NazaraError("Failed to map vertex buffer"); + return __LINE__; + } + + std::memcpy(vertexBufferMemory.GetMappedPointer(), vertexBufferData.data(), vertexBufferSize); + + vertexBufferMemory.Unmap(); + + if (!vertexBuffer.BindBufferMemory(vertexBufferMemory)) + { + NazaraError("Failed to bind vertex buffer to its memory"); + return __LINE__; + } + + // Index buffer + Nz::IndexMapper indexMapper(drfreakIB); + + std::size_t indexCount = indexMapper.GetIndexCount(); + std::vector indexBufferData; + indexBufferData.reserve(indexCount); + + for (std::size_t i = 0; i < indexCount; ++i) + { + indexBufferData.push_back(indexMapper.Get(i)); + } + + Nz::UInt32 indexBufferSize = indexBufferData.size() * sizeof(Nz::UInt32); + + Nz::Vk::Buffer indexBuffer; + if (!indexBuffer.Create(device, 0, indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT)) + { + NazaraError("Failed to create vertex buffer"); + return __LINE__; + } + + memRequirement = indexBuffer.GetMemoryRequirements(); + + Nz::Vk::DeviceMemory indexBufferMemory; + if (!indexBufferMemory.Create(device, memRequirement.size, memRequirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) + { + NazaraError("Failed to allocate vertex buffer memory"); + return __LINE__; + } + + if (!indexBufferMemory.Map(0, indexBufferSize)) + { + NazaraError("Failed to map vertex buffer"); + return __LINE__; + } + + std::memcpy(indexBufferMemory.GetMappedPointer(), indexBufferData.data(), indexBufferSize); + + indexBufferMemory.Unmap(); + + if (!indexBuffer.BindBufferMemory(indexBufferMemory)) + { + NazaraError("Failed to bind vertex buffer to its memory"); + return __LINE__; + } + + struct + { + Nz::Matrix4f projectionMatrix; + Nz::Matrix4f modelMatrix; + Nz::Matrix4f viewMatrix; + } + ubo; + + ubo.projectionMatrix = Nz::Matrix4f::Perspective(70.f, float(window.GetWidth()) / window.GetHeight(), 0.1f, 1000.f); + ubo.viewMatrix = Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1); + ubo.modelMatrix = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); + + Nz::UInt32 uniformSize = sizeof(ubo); + + Nz::Vk::Buffer uniformBuffer; + if (!uniformBuffer.Create(device, 0, uniformSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) + { + NazaraError("Failed to create vertex buffer"); + return __LINE__; + } + + memRequirement = uniformBuffer.GetMemoryRequirements(); + + Nz::Vk::DeviceMemory uniformBufferMemory; + if (!uniformBufferMemory.Create(device, memRequirement.size, memRequirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) + { + NazaraError("Failed to allocate vertex buffer memory"); + return __LINE__; + } + + if (!uniformBufferMemory.Map(0, uniformSize)) + { + NazaraError("Failed to map vertex buffer"); + return __LINE__; + } + + std::memcpy(uniformBufferMemory.GetMappedPointer(), &ubo, uniformSize); + + uniformBufferMemory.Unmap(); + + if (!uniformBuffer.BindBufferMemory(uniformBufferMemory)) + { + NazaraError("Failed to bind uniform buffer to its memory"); + return __LINE__; + } + + + VkDescriptorSetLayoutBinding layoutBinding = {}; + layoutBinding.binding = 0; + layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layoutBinding.descriptorCount = 1; + layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layoutBinding.pImmutableSamplers = nullptr; + + Nz::Vk::DescriptorSetLayout descriptorLayout; + if (!descriptorLayout.Create(device, layoutBinding)) + { + NazaraError("Failed to create descriptor set layout"); + return __LINE__; + } + + VkDescriptorPoolSize poolSize; + poolSize.descriptorCount = 1; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + Nz::Vk::DescriptorPool descriptorPool; + if (!descriptorPool.Create(device, 1, poolSize, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)) + { + NazaraError("Failed to create descriptor pool"); + return __LINE__; + } + + Nz::Vk::DescriptorSet descriptorSet = descriptorPool.AllocateDescriptorSet(descriptorLayout); + + descriptorSet.WriteUniformDescriptor(0, uniformBuffer, 0, uniformSize); + + std::array shaderStageCreateInfo = { + { + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_VERTEX_BIT, + vertexShader, + "main", + nullptr + }, + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_FRAGMENT_BIT, + fragmentShader, + "main", + nullptr + } + } + }; + + VkVertexInputBindingDescription bindingDescription = { + 0, + sizeof(Vertex), + VK_VERTEX_INPUT_RATE_VERTEX + }; + + std::array attributeDescription = + { + { + { + 0, // uint32_t location + 0, // uint32_t binding; + VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; + 0 // uint32_t offset; + }, + { + 1, // uint32_t location + 0, // uint32_t binding; + VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format; + sizeof(float) * 4 // uint32_t offset; + } + } + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineVertexInputStateCreateFlags flags; + 1, // uint32_t vertexBindingDescriptionCount + &bindingDescription, // const VkVertexInputBindingDescription *pVertexBindingDescriptions + Nz::UInt32(attributeDescription.size()), // uint32_t vertexAttributeDescriptionCount + attributeDescription.data() // const VkVertexInputAttributeDescription *pVertexAttributeDescriptions + }; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineInputAssemblyStateCreateFlags flags + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology + VK_FALSE // VkBool32 primitiveRestartEnable + }; + + VkPipelineViewportStateCreateInfo viewport_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineViewportStateCreateFlags flags + 1, // uint32_t viewportCount + nullptr, // const VkViewport *pViewports + 1, // uint32_t scissorCount + nullptr // const VkRect2D *pScissors + }; + + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineRasterizationStateCreateFlags flags + VK_FALSE, // VkBool32 depthClampEnable + VK_FALSE, // VkBool32 rasterizerDiscardEnable + VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode + VK_CULL_MODE_NONE, // VkCullModeFlags cullMode + VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace + VK_FALSE, // VkBool32 depthBiasEnable + 0.0f, // float depthBiasConstantFactor + 0.0f, // float depthBiasClamp + 0.0f, // float depthBiasSlopeFactor + 1.0f // float lineWidth + }; + + VkPipelineMultisampleStateCreateInfo multisample_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineMultisampleStateCreateFlags flags + VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples + VK_FALSE, // VkBool32 sampleShadingEnable + 1.0f, // float minSampleShading + nullptr, // const VkSampleMask *pSampleMask + VK_FALSE, // VkBool32 alphaToCoverageEnable + VK_FALSE // VkBool32 alphaToOneEnable + }; + + VkPipelineColorBlendAttachmentState color_blend_attachment_state = { + VK_FALSE, // VkBool32 blendEnable + VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor + VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor + VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp + VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor + VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor + VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT + }; + + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineColorBlendStateCreateFlags flags + VK_FALSE, // VkBool32 logicOpEnable + VK_LOGIC_OP_COPY, // VkLogicOp logicOp + 1, // uint32_t attachmentCount + &color_blend_attachment_state, // const VkPipelineColorBlendAttachmentState *pAttachments + {0.0f, 0.0f, 0.0f, 0.0f} // float blendConstants[4] + }; + + VkDescriptorSetLayout descriptorSetLayout = descriptorLayout; + + VkPipelineLayoutCreateInfo layout_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineLayoutCreateFlags flags + 1U, // uint32_t setLayoutCount + &descriptorSetLayout, // const VkDescriptorSetLayout *pSetLayouts + 0, // uint32_t pushConstantRangeCount + nullptr // const VkPushConstantRange *pPushConstantRanges + }; + + Nz::Vk::PipelineLayout pipelineLayout; + pipelineLayout.Create(device, layout_create_info); + + std::array dynamicStates = { + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_VIEWPORT, + }; + + VkPipelineDynamicStateCreateInfo dynamicStateInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; + nullptr, // const void* pNext; + 0, // VkPipelineDynamicStateCreateFlags flags; + Nz::UInt32(dynamicStates.size()), // uint32_t dynamicStateCount; + dynamicStates.data() // const VkDynamicState* pDynamicStates; + }; + + VkPipelineDepthStencilStateCreateInfo depthStencilInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; + nullptr, // const void* pNext; + 0U, // VkPipelineDepthStencilStateCreateFlags flags; + VK_TRUE, // VkBool32 depthTestEnable; + VK_TRUE, // VkBool32 depthWriteEnable; + VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp; + VK_FALSE, // VkBool32 depthBoundsTestEnable; + VK_FALSE, // VkBool32 stencilTestEnable; + VkStencilOpState{},// VkStencilOpState front; + VkStencilOpState{},// VkStencilOpState back; + 0.f, // float minDepthBounds; + 0.f // float maxDepthBounds; + }; + + VkGraphicsPipelineCreateInfo pipeline_create_info = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType + nullptr, // const void *pNext + 0, // VkPipelineCreateFlags flags + static_cast(shaderStageCreateInfo.size()), // uint32_t stageCount + shaderStageCreateInfo.data(), // const VkPipelineShaderStageCreateInfo *pStages + &vertex_input_state_create_info, // const VkPipelineVertexInputStateCreateInfo *pVertexInputState; + &input_assembly_state_create_info, // const VkPipelineInputAssemblyStateCreateInfo *pInputAssemblyState + nullptr, // const VkPipelineTessellationStateCreateInfo *pTessellationState + &viewport_state_create_info, // const VkPipelineViewportStateCreateInfo *pViewportState + &rasterization_state_create_info, // const VkPipelineRasterizationStateCreateInfo *pRasterizationState + &multisample_state_create_info, // const VkPipelineMultisampleStateCreateInfo *pMultisampleState + &depthStencilInfo, // const VkPipelineDepthStencilStateCreateInfo *pDepthStencilState + &color_blend_state_create_info, // const VkPipelineColorBlendStateCreateInfo *pColorBlendState + &dynamicStateInfo, // const VkPipelineDynamicStateCreateInfo *pDynamicState + pipelineLayout, // VkPipelineLayout layout + vulkanWindow.GetRenderPass(), // VkRenderPass renderPass + 0, // uint32_t subpass + VK_NULL_HANDLE, // VkPipeline basePipelineHandle + -1 // int32_t basePipelineIndex + }; + + Nz::Vk::Pipeline pipeline; + if (!pipeline.CreateGraphics(device, pipeline_create_info)) + { + NazaraError("Failed to create pipeline"); + return __LINE__; + } + + Nz::Vk::CommandPool cmdPool; + if (!cmdPool.Create(device, 0, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)) + { + NazaraError("Failed to create rendering cmd pool"); + return __LINE__; + } + + std::array clearValues; + clearValues[0].color = {1.0f, 0.8f, 0.4f, 0.0f}; + clearValues[1].depthStencil = {1.f, 0}; + + Nz::Vk::Queue graphicsQueue(device, device->GetEnabledQueues()[0].queues[0].queue); + + Nz::UInt32 imageCount = vulkanWindow.GetFramebufferCount(); + std::vector renderCmds = cmdPool.AllocateCommandBuffers(imageCount, VK_COMMAND_BUFFER_LEVEL_PRIMARY); + for (Nz::UInt32 i = 0; i < imageCount; ++i) + { + Nz::Vk::CommandBuffer& renderCmd = renderCmds[i]; + + VkRect2D renderArea = { + { // VkOffset2D offset + 0, // int32_t x + 0 // int32_t y + }, + { // VkExtent2D extent + window.GetWidth(), // int32_t width + window.GetHeight(), // int32_t height + } + }; + + VkRenderPassBeginInfo render_pass_begin_info = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType + nullptr, // const void *pNext + vulkanWindow.GetRenderPass(), // VkRenderPass renderPass + vulkanWindow.GetFrameBuffer(i), // VkFramebuffer framebuffer + renderArea, + 2U, // uint32_t clearValueCount + clearValues.data() // const VkClearValue *pClearValues + }; + + VkClearAttachment clearAttachment = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0U, + clearValues[0] + }; + + VkClearAttachment clearAttachmentDepth = { + VK_IMAGE_ASPECT_DEPTH_BIT, + 0U, + clearValues[1] + }; + + VkClearRect clearRect = { + renderArea, + 0U, + 1U + }; + + renderCmd.Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); + + vulkanWindow.BuildPreRenderCommands(i, renderCmd); + + renderCmd.BeginRenderPass(render_pass_begin_info); + //renderCmd.ClearAttachment(clearAttachment, clearRect); + //renderCmd.ClearAttachment(clearAttachmentDepth, clearRect); + renderCmd.BindIndexBuffer(indexBuffer, 0, VK_INDEX_TYPE_UINT32); + renderCmd.BindVertexBuffer(0, vertexBuffer, 0); + renderCmd.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, descriptorSet); + renderCmd.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + renderCmd.SetScissor(Nz::Recti{0, 0, int(window.GetWidth()), int(window.GetHeight())}); + renderCmd.SetViewport({0.f, 0.f, float(window.GetWidth()), float(window.GetHeight())}, 0.f, 1.f); + renderCmd.DrawIndexed(indexCount); + renderCmd.EndRenderPass(); + + vulkanWindow.BuildPostRenderCommands(i, renderCmd); + + if (!renderCmd.End()) + { + NazaraError("Failed to specify render cmd"); + return __LINE__; + } + } + + Nz::Vector3f viewerPos = Nz::Vector3f::Zero(); + + Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f); + Nz::Quaternionf camQuat(camAngles); + + window.EnableEventPolling(true); + + Nz::Clock secondClock; + unsigned int fps = 0; + while (window.IsOpen()) + { + bool updateUniforms = false; + + Nz::WindowEvent event; + while (window.PollEvent(&event)) + { + switch (event.type) + { + case Nz::WindowEventType_Quit: + window.Close(); + break; + + case Nz::WindowEventType_MouseMoved: // La souris a bougé + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + camAngles.yaw = Nz::NormalizeAngle(camAngles.yaw - event.mouseMove.deltaX*sensitivity); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f); + + camQuat = camAngles; + + // Pour éviter que le curseur ne sorte de l'écran, nous le renvoyons au centre de la fenêtre + // Cette fonction est codée de sorte à ne pas provoquer d'évènement MouseMoved + Nz::Mouse::SetPosition(window.GetWidth() / 2, window.GetHeight() / 2, window); + updateUniforms = true; + break; + } + + case Nz::WindowEventType_KeyPressed: + { + switch (event.key.code) + { + case Nz::Keyboard::Up: + viewerPos += camQuat * Nz::Vector3f::Forward(); + updateUniforms = true; + break; + + case Nz::Keyboard::Down: + viewerPos += camQuat * Nz::Vector3f::Backward(); + updateUniforms = true; + break; + } + break; + } + } + } + + if (updateUniforms) + { + ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); + + if (!uniformBufferMemory.Map(0, uniformSize)) + { + NazaraError("Failed to map vertex buffer"); + return __LINE__; + } + + std::memcpy(uniformBufferMemory.GetMappedPointer(), &ubo, uniformSize); + + uniformBufferMemory.Unmap(); + } + + Nz::UInt32 imageIndex; + if (!vulkanWindow.Acquire(&imageIndex)) + { + std::cout << "Failed to acquire next image" << std::endl; + return EXIT_FAILURE; + } + + VkCommandBuffer renderCmdBuffer = renderCmds[imageIndex]; + VkSemaphore waitSemaphore = vulkanWindow.GetRenderSemaphore(); + + VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit_info = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType + nullptr, // const void *pNext + 1U, // uint32_t waitSemaphoreCount + &waitSemaphore, // const VkSemaphore *pWaitSemaphores + &wait_dst_stage_mask, // const VkPipelineStageFlags *pWaitDstStageMask; + 1, // uint32_t commandBufferCount + &renderCmdBuffer, // const VkCommandBuffer *pCommandBuffers + 0, // uint32_t signalSemaphoreCount + nullptr // const VkSemaphore *pSignalSemaphores + }; + + if (!graphicsQueue.Submit(submit_info)) + return false; + + vulkanWindow.Present(imageIndex); + + // On incrémente le compteur de FPS improvisé + fps++; + + if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes + { + // Et on insère ces données dans le titre de la fenêtre + window.SetTitle(windowTitle + " - " + Nz::String::Number(fps) + " FPS"); + + /* + Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier, + via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res". + Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier), + cela fonctionnera aussi comme ceci : "Chaîne de caractères". + */ + + // Et on réinitialise le compteur de FPS + fps = 0; + + // Et on relance l'horloge pour refaire ça dans une seconde + secondClock.Restart(); + } + } + +// instance.vkDestroyDebugReportCallbackEXT(instance, callback, nullptr); + + return EXIT_SUCCESS; +} \ No newline at end of file