diff --git a/config/Sources.cmake b/config/Sources.cmake index 3254368f17d92549800af7ecb614b179df1ba16f..ac49dac1a030be3b3dff1c4f6dc3339b1baca422 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -53,7 +53,7 @@ set(vkcv_sources ${vkcv_source}/vkcv/Framebuffer.hpp ${vkcv_source}/vkcv/Framebuffer.cpp - + ${vkcv_include}/vkcv/VertexLayout.hpp ${vkcv_source}/vkcv/VertexLayout.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 66db4776d053352d8ccb2eea5e09c3fb77b68561..ab0d2aca0eccbd3c6adfea191cefa2c63623b0b9 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -186,8 +186,9 @@ namespace vkcv /** * @brief render a beautiful triangle */ - void renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, - const int width, const int height, const size_t pushConstantSize, const void* pushConstantData); + void renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, + const int width, const int height, const size_t pushConstantSize, const void* pushConstantData, + const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount); /** * @brief end recording and present image diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp index 1ad6be8d1979c8a89f7de9dbe24ff13b5f5bb3fa..26ad7053d5a732968093b0f8ffb2c23a0d70255d 100644 --- a/include/vkcv/PipelineConfig.hpp +++ b/include/vkcv/PipelineConfig.hpp @@ -1,12 +1,10 @@ +#pragma once /** * @authors Mara Vogt, Mark Mints * @file src/vkcv/Pipeline.hpp * @brief Pipeline class to handle shader stages */ -#ifndef VKCV_PIPELINECONFIG_HPP -#define VKCV_PIPELINECONFIG_HPP - #include <vector> #include <cstdint> #include "vkcv/Handles.hpp" @@ -39,5 +37,4 @@ namespace vkcv { PassHandle m_PassHandle; }; -} -#endif //VKCV_PIPELINECONFIG_HPP +} \ No newline at end of file diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp index f9579b5d7dfa8127d592532f55fd569cacb505c9..fceaa9cf5498f068b5c767534be0957fed96a033 100644 --- a/include/vkcv/VertexLayout.hpp +++ b/include/vkcv/VertexLayout.hpp @@ -3,6 +3,7 @@ #include <unordered_map> #include <vector> #include <iostream> +#include <vulkan/vulkan.hpp> namespace vkcv{ enum class VertexFormat{ @@ -33,5 +34,6 @@ namespace vkcv{ uint32_t stride; }; - + // currently assuming default 32 bit formats, no lower precision or normalized variants supported + vk::Format vertexFormatToVulkanFormat(const VertexFormat format); } \ No newline at end of file diff --git a/projects/first_mesh/CMakeLists.txt b/projects/first_mesh/CMakeLists.txt index ae9c5604cb83c6f3a16773e896521117460839f7..eb0f028db38707272f9fbcf61662633f2868eedc 100644 --- a/projects/first_mesh/CMakeLists.txt +++ b/projects/first_mesh/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include}) +target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries}) +target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/first_mesh/resources/shaders/compile.bat b/projects/first_mesh/resources/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..b4521235c40fe5fb163bab874560c2f219b7517f --- /dev/null +++ b/projects/first_mesh/resources/shaders/compile.bat @@ -0,0 +1,3 @@ +%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv +%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +pause \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/frag.spv b/projects/first_mesh/resources/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..cb13e606fc0041e24ff6a63c0ec7dcca466732aa Binary files /dev/null and b/projects/first_mesh/resources/shaders/frag.spv differ diff --git a/projects/first_mesh/resources/shaders/shader.frag b/projects/first_mesh/resources/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..d26446a73020111695aa2c86166205796dfa5e44 --- /dev/null +++ b/projects/first_mesh/resources/shaders/shader.frag @@ -0,0 +1,9 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/shader.vert b/projects/first_mesh/resources/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..e6c0e3d6bafda35e90a6bfd849a211e2b6de0f9c --- /dev/null +++ b/projects/first_mesh/resources/shaders/shader.vert @@ -0,0 +1,27 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 position; + +layout(location = 0) out vec3 fragColor; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + vec3 positions[3] = { + vec3(-0.5, 0.5, -1), + vec3( 0.5, 0.5, -1), + vec3(0, -0.5, -1) + }; + + vec3 colors[3] = { + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1) + }; + + gl_Position = mvp * vec4(position, 1.0); + fragColor = colors[gl_VertexIndex % 3]; +} \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/vert.spv b/projects/first_mesh/resources/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..74722f38ff0584d51d4a966c748b69a4d3f1d3cb Binary files /dev/null and b/projects/first_mesh/resources/shaders/vert.spv differ diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index b37429e1f7080b70aaab514125f86fbe03f329b5..e1cbc40e747f9f68e44db6ea9ca3dcd556148a4b 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -1,76 +1,101 @@ #include <iostream> -#include <stdio.h> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> #include <vkcv/asset/asset_loader.hpp> int main(int argc, const char** argv) { + const char* applicationName = "First Mesh"; + + const int windowWidth = 800; + const int windowHeight = 600; + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + false + ); + + vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); + + window.initEvents(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + {}, + { "VK_KHR_swapchain" } + ); + vkcv::asset::Mesh mesh; - - const char *path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; + + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; int result = vkcv::asset::loadMesh(path, mesh); - + if (result == 1) { std::cout << "Mesh loading successful!" << std::endl; - } else { + } + else { std::cout << "Mesh loading failed: " << result << std::endl; return 1; } - /* Demonstration of how to use the vkcv::asset::Mesh struct. */ - const char *primitive_modes[] = { - "points", "lines", "line loop", "line strip", "triangles", - "triangle strip", "triangle fan" - }; - const char *primitive_types[] = { - "unknown", "position", "normal", "texcoord0" - }; - printf("Mesh %s (%s) has %lu vertex group(s) and %lu material(s):\n", - mesh.name.c_str(), path, mesh.vertexGroups.size(), - mesh.materials.size()); - for (size_t i = 0; i < mesh.vertexGroups.size(); i++) { - printf("--- vertex group %lu ---\n", i); - const auto &vg = mesh.vertexGroups[i]; - printf("primitive mode: %d (%s)\n", vg.mode, - primitive_modes[vg.mode]); - printf("index buffer: %lu bytes for %lu indices ", - vg.indexBuffer.data.size(), vg.numIndices); - const auto itype = vg.indexBuffer.type; - printf("(%s @ %p)\n", - itype == vkcv::asset::UINT32 ? "UINT32" : - itype == vkcv::asset::UINT16 ? "UINT16" : - "UINT8", vg.indexBuffer.data.data()); - printf("\tindices: "); - const size_t n = vg.numIndices; - if (vg.indexBuffer.type == vkcv::asset::UINT32) { - uint32_t *idx = (uint32_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else - if (vg.indexBuffer.type == vkcv::asset::UINT16) { - uint16_t *idx = (uint16_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else - if (vg.indexBuffer.type == vkcv::asset::UINT8) { - uint8_t *idx = (uint8_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else { - fprintf(stderr, "ERROR Invalid IndexType: %d\n", - vg.indexBuffer.type); - return 0; - } - printf("\n"); - printf("vertex buffer: %lu bytes for %lu vertices with %lu " - "attributes (starting at %p)\n", - vg.vertexBuffer.data.size(), vg.numVertices, - vg.vertexBuffer.attributes.size(), - vg.vertexBuffer.data.data()); - printf("attributes:\toffset\tlength\tstride\tcomponents\n"); - for (const auto att : vg.vertexBuffer.attributes) { - printf("%11s\t%u\t%u\t%u\t%hhux%hu\n", - primitive_types[att.type], - att.offset, att.length, att.stride, - att.componentCount, att.componentType); - } + assert(mesh.vertexGroups.size() > 0); + const size_t vertexBufferSize = mesh.vertexGroups[0].vertexBuffer.data.size(); + auto vertexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::VERTEX, vertexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL); + vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data.data(), vertexBufferSize); + + const size_t indexBufferSize = mesh.vertexGroups[0].indexBuffer.data.size(); + auto indexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::INDEX, indexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL); + indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data.data(), indexBufferSize); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::COLOR_ATTACHMENT, + vkcv::AttachmentLayout::PRESENTATION, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchainImageFormat()); + + vkcv::PassConfig trianglePassDefinition({ present_color_attachment }); + vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); + + if (!trianglePass) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; } + + vkcv::ShaderProgram triangleShaderProgram{}; + triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT); + + const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass); + vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition); + if (!trianglePipeline) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto start = std::chrono::system_clock::now(); + while (window.isWindowOpen()) { + core.beginFrame(); + window.pollEvents(); + auto end = std::chrono::system_clock::now(); + auto deltatime = end - start; + start = end; + cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); + const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + + core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices); + core.endFrame(); + } return 0; } diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 78502661a5932804d622ffb25edc7cbd6828bfa4..8fcbf76f10e5749435c0fb4c8f3b5d04418bd471 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -40,15 +40,19 @@ int main(int argc, const char** argv) { const size_t n = 5027; - auto buffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); - vec3 vec_data [n]; - + auto testBuffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); + vec3 vec_data[n]; + for (size_t i = 0; i < n; i++) { vec_data[i] = { 42, static_cast<float>(i), 7 }; } - - buffer.fill(vec_data); - + + testBuffer.fill(vec_data); + + auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = { 0, 1, 2 }; + triangleIndexBuffer.fill(&indices[0], sizeof(indices)); + /*vec3* m = buffer.map(); m[0] = { 0, 0, 0 }; m[1] = { 0, 0, 0 }; @@ -143,7 +147,7 @@ int main(int argc, const char** argv) { cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); - core.renderTriangle(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp); + core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, testBuffer.getHandle(), triangleIndexBuffer.getHandle(), 3); core.endFrame(); } return 0; diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index afff7d4b3e3fc78a6dbb7535162857f21812721c..e27338d837e89b5a9442c4ba2dff2061bf0e0f53 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -69,6 +69,9 @@ namespace vkcv { case BufferType::STAGING: usageFlags = vk::BufferUsageFlagBits::eTransferSrc; break; + case BufferType::INDEX: + usageFlags = vk::BufferUsageFlagBits::eIndexBuffer; + break; default: // TODO: maybe an issue break; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 0ee414fb974676b1d2df820e69218f5bb247341b..13800254d78cb679c81d58a003089aa961986937 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -162,8 +162,9 @@ namespace vkcv destroyTemporaryFramebuffers(); } - void Core::renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, - const int width, const int height, const size_t pushConstantSize, const void *pushConstantData) { + void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, + const int width, const int height, const size_t pushConstantSize, const void *pushConstantData, + const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount) { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; @@ -174,6 +175,8 @@ namespace vkcv const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); + const vk::Buffer vulkanVertexBuffer = m_BufferManager->getBuffer(vertexBuffer); + const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer); const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView); m_TemporaryFramebuffers.push_back(framebuffer); @@ -181,7 +184,8 @@ namespace vkcv SubmitInfo submitInfo; submitInfo.queueType = QueueType::Graphics; submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, pushConstantSize, pushConstantData](const vk::CommandBuffer& cmdBuffer) { + submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, + pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) { const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f }; const vk::ClearValue clearValues(clearColor); @@ -191,8 +195,11 @@ namespace vkcv cmdBuffer.beginRenderPass(beginInfo, subpassContents, {}); cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); + + cmdBuffer.bindVertexBuffers(0, (vulkanVertexBuffer), { 0 }); + cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData); - cmdBuffer.draw(3, 1, 0, 0, {}); + cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {}); cmdBuffer.endRenderPass(); }, nullptr); } diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index c253aafd0438a64b2312fc4737d9b52d2b37f2e8..8b6202eb901f26c84585597e327c297902e54b03 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -67,15 +67,30 @@ namespace vkcv ); // vertex input state - vk::VertexInputBindingDescription vertexInputBindingDescription(0, 12, vk::VertexInputRate::eVertex); - vk::VertexInputAttributeDescription vertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, 0); + // Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers + std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions; + std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions; + + VertexLayout layout = config.m_ShaderProgram.getVertexLayout(); + std::unordered_map<uint32_t, VertexInputAttachment> attachments = layout.attachmentMap; + + for (auto& attachment: attachments) { + uint32_t location = attachment.second.location; + uint32_t binding = attachment.second.binding; + uint32_t offset = attachment.second.offset; + vk::Format vertexFormat = vertexFormatToVulkanFormat(attachment.second.format); + vertexBindingDescriptions.push_back({binding, layout.stride, vk::VertexInputRate::eVertex}); // TODO: What's about the input rate? + vertexAttributeDescriptions.push_back({location, binding, vk::Format::eR32G32B32Sfloat, offset}); + } + + // Handover Containers to PipelineVertexInputStateCreateIngo Struct vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo( - {}, // no vertex input until vertex buffer is implemented - 0, // 1, - nullptr, // &vertexInputBindingDescription, - 0, // 1, - nullptr // &vertexInputAttributeDescription + {}, + vertexBindingDescriptions.size(), + vertexBindingDescriptions.data(), + vertexAttributeDescriptions.size(), + vertexAttributeDescriptions.data() ); // input assembly state diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp index 88c9406bc321a76b48df60dae51486e39a4160de..ef2fedf6fe85a35df40a284554df40659b23470c 100644 --- a/src/vkcv/VertexLayout.cpp +++ b/src/vkcv/VertexLayout.cpp @@ -50,4 +50,18 @@ namespace vkcv { } } + vk::Format vertexFormatToVulkanFormat(const VertexFormat format) { + switch (format) { + case VertexFormat::FLOAT : return vk::Format::eR32Sfloat; + case VertexFormat::FLOAT2 : return vk::Format::eR32G32Sfloat; + case VertexFormat::FLOAT3 : return vk::Format::eR32G32B32Sfloat; + case VertexFormat::FLOAT4 : return vk::Format::eR32G32B32A32Sfloat; + case VertexFormat::INT : return vk::Format::eR32Sint; + case VertexFormat::INT2 : return vk::Format::eR32G32Sint; + case VertexFormat::INT3 : return vk::Format::eR32G32B32Sint; + case VertexFormat::INT4 : return vk::Format::eR32G32B32A32Sint; + default: std::cerr << "Warning: Unknown vertex format" << std::endl; return vk::Format::eUndefined; + } + } + } \ No newline at end of file