diff --git a/CMakeLists.txt b/CMakeLists.txt index b7485c64..acc8baaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ add_compile_definitions(USE_ETNA VK_GRAPHICS_BASIC_ROOT="${PROJECT_SOURCE_DIR}") add_subdirectory(external/etna) #add_subdirectory(external/volk) -#add_subdirectory(src/samples/quad2d) +add_subdirectory(src/samples/quad2d) add_subdirectory(src/samples/shadowmap) #add_subdirectory(src/samples/simpleforward) add_subdirectory(src/samples/simple_compute) diff --git a/src/samples/quad2d/CMakeLists.txt b/src/samples/quad2d/CMakeLists.txt index e4117888..6c13a123 100644 --- a/src/samples/quad2d/CMakeLists.txt +++ b/src/samples/quad2d/CMakeLists.txt @@ -6,19 +6,25 @@ else() include_directories(${GLFW_INCLUDE_DIRS}) endif() + set(RENDER_SOURCE - #../../render/scene_mgr.cpp + ../../render/scene_mgr.cpp ../../render/render_imgui.cpp - quad2d_render.cpp) + quad2d_render.cpp + render_init.cpp + update.cpp + draw.cpp + present.cpp +) -add_executable(quad_renderer main.cpp ../../utils/glfw_window.cpp ${VK_UTILS_SRC} ${SCENE_LOADER_SRC} ${RENDER_SOURCE} ${IMGUI_SRC}) +add_executable(quad2d_renderer main.cpp ../../utils/glfw_window.cpp ${VK_UTILS_SRC} ${SCENE_LOADER_SRC} ${RENDER_SOURCE} ${IMGUI_SRC}) if(CMAKE_SYSTEM_NAME STREQUAL Windows) - set_target_properties(quad_renderer PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + set_target_properties(quad2d_renderer PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") - target_link_libraries(quad_renderer PRIVATE project_options - volk glfw3 project_warnings) + target_link_libraries(quad2d_renderer PRIVATE project_options + glfw3 project_warnings etna ${CMAKE_DL_LIBS}) else() - target_link_libraries(quad_renderer PRIVATE project_options - volk glfw project_warnings) # + target_link_libraries(quad2d_renderer PRIVATE project_options + glfw project_warnings etna ${CMAKE_DL_LIBS}) # endif() \ No newline at end of file diff --git a/src/samples/quad2d/draw.cpp b/src/samples/quad2d/draw.cpp new file mode 100644 index 00000000..285a68e4 --- /dev/null +++ b/src/samples/quad2d/draw.cpp @@ -0,0 +1,62 @@ +#include "quad2d_render.h" +#include + +#include + +#include "../../render/render_gui.h" + +void SimpleQuad2dRender::DrawFrameSimple() +{ + vkWaitForFences(m_context->getDevice(), 1, &m_frameFences[m_presentationResources.currentFrame], VK_TRUE, UINT64_MAX); + vkResetFences(m_context->getDevice(), 1, &m_frameFences[m_presentationResources.currentFrame]); + + uint32_t imageIdx; + m_swapchain.AcquireNextImage(m_presentationResources.imageAvailable, &imageIdx); + + auto currentCmdBuf = m_cmdBuffersDrawMain[m_presentationResources.currentFrame]; + + VkSemaphore waitSemaphores[] = {m_presentationResources.imageAvailable}; + VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + + BuildCommandBufferSimple(currentCmdBuf, m_swapchain.GetAttachment(imageIdx).image, m_swapchain.GetAttachment(imageIdx).view); + + std::vector submitCmdBufs = { currentCmdBuf }; + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = submitCmdBufs.size(); + submitInfo.pCommandBuffers = submitCmdBufs.data(); + + VkSemaphore signalSemaphores[] = {m_presentationResources.renderingFinished}; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + + VK_CHECK_RESULT(vkQueueSubmit(m_context->getQueue(), + 1, &submitInfo, m_frameFences[m_presentationResources.currentFrame])); + + VkResult presentRes = m_swapchain.QueuePresent(m_presentationResources.queue, imageIdx, + m_presentationResources.renderingFinished); + + if (presentRes == VK_ERROR_OUT_OF_DATE_KHR || presentRes == VK_SUBOPTIMAL_KHR) + { + RecreateSwapChain(); + } + else if (presentRes != VK_SUCCESS) + { + RUN_TIME_ERROR("Failed to present swapchain image"); + } + + m_presentationResources.currentFrame = (m_presentationResources.currentFrame + 1) % m_framesInFlight; + + vkQueueWaitIdle(m_presentationResources.queue); + + etna::submit(); +} + +void SimpleQuad2dRender::DrawFrame(float a_time, DrawMode a_mode) +{ + DrawFrameSimple(); +} diff --git a/src/samples/quad2d/main.cpp b/src/samples/quad2d/main.cpp index 88b15ab1..281fba8e 100644 --- a/src/samples/quad2d/main.cpp +++ b/src/samples/quad2d/main.cpp @@ -1,7 +1,8 @@ #include "quad2d_render.h" #include "utils/glfw_window.h" +#include -void initVulkanGLFW(std::shared_ptr &app, GLFWwindow* window, int deviceID, bool initGUI) +void initVulkanGLFW(std::shared_ptr &app, GLFWwindow* window) { uint32_t glfwExtensionCount = 0; const char** glfwExtensions; @@ -12,14 +13,13 @@ void initVulkanGLFW(std::shared_ptr &app, GLFWwindow* window, int devic std::cout << "WARNING. Can't connect Vulkan to GLFW window (glfwGetRequiredInstanceExtensions returns NULL)" << std::endl; } - app->InitVulkan(glfwExtensions, glfwExtensionCount, deviceID); + app->InitVulkan(glfwExtensions, glfwExtensionCount, /* useless param */ 0); if(glfwExtensions != nullptr) { VkSurfaceKHR surface; VK_CHECK_RESULT(glfwCreateWindowSurface(app->GetVkInstance(), window, nullptr, &surface)); - setupImGuiContext(window); - app->InitPresentation(surface, initGUI); + app->InitPresentation(surface, false); } } @@ -27,10 +27,8 @@ int main() { constexpr int WIDTH = 1024; constexpr int HEIGHT = 1024; - constexpr int VULKAN_DEVICE_ID = 0; - constexpr bool showGUI = true; - std::shared_ptr app = std::make_unique(WIDTH, HEIGHT); + std::shared_ptr app = std::make_unique(WIDTH, HEIGHT); if(app == nullptr) { std::cout << "Can't create render of specified type" << std::endl; @@ -39,11 +37,15 @@ int main() auto* window = initWindow(WIDTH, HEIGHT); - initVulkanGLFW(app, window, VULKAN_DEVICE_ID, showGUI); + initVulkanGLFW(app, window); - app->LoadScene("../resources/scenes/043_cornell_normals/statex_00001.xml", false); + app->LoadScene(VK_GRAPHICS_BASIC_ROOT "", false); - mainLoop(app, window, showGUI); + mainLoop(app, window, true); + + app = {}; + if (etna::is_initilized()) + etna::shutdown(); return 0; } diff --git a/src/samples/quad2d/present.cpp b/src/samples/quad2d/present.cpp new file mode 100644 index 00000000..862af095 --- /dev/null +++ b/src/samples/quad2d/present.cpp @@ -0,0 +1,65 @@ +#include "quad2d_render.h" + +void SimpleQuad2dRender::InitPresentStuff() +{ + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VK_CHECK_RESULT(vkCreateSemaphore(m_context->getDevice(), &semaphoreInfo, nullptr, &m_presentationResources.imageAvailable)); + VK_CHECK_RESULT(vkCreateSemaphore(m_context->getDevice(), &semaphoreInfo, nullptr, &m_presentationResources.renderingFinished)); + + // TODO: Move to customizable initialization + m_commandPool = vk_utils::createCommandPool(m_context->getDevice(), m_context->getQueueFamilyIdx(), VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + + m_cmdBuffersDrawMain.reserve(m_framesInFlight); + m_cmdBuffersDrawMain = vk_utils::createCommandBuffers(m_context->getDevice(), m_commandPool, m_framesInFlight); + + m_frameFences.resize(m_framesInFlight); + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + for (size_t i = 0; i < m_framesInFlight; i++) + { + VK_CHECK_RESULT(vkCreateFence(m_context->getDevice(), &fenceInfo, nullptr, &m_frameFences[i])); + } +} + +void SimpleQuad2dRender::ResetPresentStuff() +{ + if (!m_cmdBuffersDrawMain.empty()) + { + vkFreeCommandBuffers(m_context->getDevice(), m_commandPool, static_cast(m_cmdBuffersDrawMain.size()), + m_cmdBuffersDrawMain.data()); + m_cmdBuffersDrawMain.clear(); + } + + for (size_t i = 0; i < m_frameFences.size(); i++) + { + vkDestroyFence(m_context->getDevice(), m_frameFences[i], nullptr); + } + + if (m_presentationResources.imageAvailable != VK_NULL_HANDLE) + { + vkDestroySemaphore(m_context->getDevice(), m_presentationResources.imageAvailable, nullptr); + } + if (m_presentationResources.renderingFinished != VK_NULL_HANDLE) + { + vkDestroySemaphore(m_context->getDevice(), m_presentationResources.renderingFinished, nullptr); + } + + if (m_commandPool != VK_NULL_HANDLE) + { + vkDestroyCommandPool(m_context->getDevice(), m_commandPool, nullptr); + } +} + +void SimpleQuad2dRender::InitPresentation(VkSurfaceKHR &a_surface, bool) +{ + m_surface = a_surface; + + m_presentationResources.queue = m_swapchain.CreateSwapChain( + m_context->getPhysicalDevice(), m_context->getDevice(), m_surface, + m_width, m_height, m_framesInFlight, m_vsync); + m_presentationResources.currentFrame = 0; + + InitPresentStuff(); +} diff --git a/src/samples/quad2d/quad2d_render.cpp b/src/samples/quad2d/quad2d_render.cpp index 0610c054..4ecdc379 100644 --- a/src/samples/quad2d/quad2d_render.cpp +++ b/src/samples/quad2d/quad2d_render.cpp @@ -1,298 +1,21 @@ #include "quad2d_render.h" -#include "utils/input_definitions.h" #include #include #include -#include +#include -Quad2D_Render::Quad2D_Render(uint32_t a_width, uint32_t a_height) : m_width(a_width), m_height(a_height) -{ -#ifdef NDEBUG - m_enableValidation = false; -#else - m_enableValidation = true; -#endif -} - -void Quad2D_Render::SetupDeviceFeatures() -{ - // m_enabledDeviceFeatures.fillModeNonSolid = VK_TRUE; -} - -void Quad2D_Render::SetupDeviceExtensions() -{ - m_deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); -} - -void Quad2D_Render::SetupValidationLayers() -{ - m_validationLayers.push_back("VK_LAYER_KHRONOS_validation"); - m_validationLayers.push_back("VK_LAYER_LUNARG_monitor"); -} - -void Quad2D_Render::InitVulkan(const char** a_instanceExtensions, uint32_t a_instanceExtensionsCount, uint32_t a_deviceId) -{ - m_instanceExtensions.clear(); - for (uint32_t i = 0; i < a_instanceExtensionsCount; ++i) { - m_instanceExtensions.push_back(a_instanceExtensions[i]); - } - SetupValidationLayers(); - VK_CHECK_RESULT(volkInitialize()); - CreateInstance(); - volkLoadInstance(m_instance); - - CreateDevice(a_deviceId); - volkLoadDevice(m_device); - - m_commandPool = vk_utils::createCommandPool(m_device, m_queueFamilyIDXs.graphics, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - - m_cmdBuffersDrawMain.reserve(m_framesInFlight); - m_cmdBuffersDrawMain = vk_utils::createCommandBuffers(m_device, m_commandPool, m_framesInFlight); - - m_frameFences.resize(m_framesInFlight); - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (size_t i = 0; i < m_framesInFlight; i++) - { - VK_CHECK_RESULT(vkCreateFence(m_device, &fenceInfo, nullptr, &m_frameFences[i])); - } - - m_pCopyHelper = std::make_shared(m_physicalDevice, m_device, m_transferQueue, m_queueFamilyIDXs.graphics, 8*1024*1024); -} - -void Quad2D_Render::InitPresentation(VkSurfaceKHR &a_surface, bool) -{ - m_surface = a_surface; - - m_presentationResources.queue = m_swapchain.CreateSwapChain(m_physicalDevice, m_device, m_surface, - m_width, m_height, m_framesInFlight, m_vsync); - m_presentationResources.currentFrame = 0; - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - VK_CHECK_RESULT(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_presentationResources.imageAvailable)); - VK_CHECK_RESULT(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_presentationResources.renderingFinished)); - - vk_utils::RenderTargetInfo2D rtargetInfo = {}; - rtargetInfo.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - rtargetInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rtargetInfo.format = m_swapchain.GetFormat(); - rtargetInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - m_screenRenderPass = vk_utils::createRenderPass(m_device, rtargetInfo); - - m_frameBuffers = vk_utils::createFrameBuffers(m_device, m_swapchain, m_screenRenderPass); - SetupQuadRenderer(); -} - -void Quad2D_Render::SetupQuadRenderer() -{ - m_pFSQuad.reset(); - m_pFSQuad = std::make_shared(0,0, 1024, 1024); - m_pFSQuad->Create(m_device, "../resources/shaders/quad3_vert.vert.spv", "../resources/shaders/my_quad.frag.spv", - vk_utils::RenderTargetInfo2D{ VkExtent2D{ m_width, m_height }, m_swapchain.GetFormat(), // this is debug full scree quad - VK_ATTACHMENT_LOAD_OP_LOAD, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR }); // seems we need LOAD_OP_LOAD if we want to draw quad to part of screen -} - -void Quad2D_Render::CreateInstance() -{ - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pNext = nullptr; - appInfo.pApplicationName = "VkRender"; - appInfo.applicationVersion = VK_MAKE_VERSION(0, 1, 0); - appInfo.pEngineName = "Quad2D"; - appInfo.engineVersion = VK_MAKE_VERSION(0, 1, 0); - appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0); - - m_instance = vk_utils::createInstance(m_enableValidation, m_validationLayers, m_instanceExtensions, &appInfo); - if (m_enableValidation) - vk_utils::initDebugReportCallback(m_instance, &debugReportCallbackFn, &m_debugReportCallback); -} - -void Quad2D_Render::CreateDevice(uint32_t a_deviceId) -{ - SetupDeviceExtensions(); - m_physicalDevice = vk_utils::findPhysicalDevice(m_instance, true, a_deviceId, m_deviceExtensions); - - SetupDeviceFeatures(); - m_device = vk_utils::createLogicalDevice(m_physicalDevice, m_validationLayers, m_deviceExtensions, - m_enabledDeviceFeatures, m_queueFamilyIDXs, - VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT); - - vkGetDeviceQueue(m_device, m_queueFamilyIDXs.graphics, 0, &m_graphicsQueue); - vkGetDeviceQueue(m_device, m_queueFamilyIDXs.transfer, 0, &m_transferQueue); -} +#include +#include +#include +#include -void Quad2D_Render::SetupSimplePipeline() +static std::vector LoadBMP(const char *filename, unsigned *pW, unsigned *pH) { - std::vector > dtypes = { - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1} - }; - - m_pBindings = std::make_shared(m_device, dtypes, 2); - - m_pBindings->BindBegin(VK_SHADER_STAGE_FRAGMENT_BIT); - m_pBindings->BindImage(0, m_imageData.view, m_imageSampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - m_pBindings->BindEnd(&m_quadDS, &m_quadDSLayout); -} + FILE *f = fopen(filename, "rb"); -void Quad2D_Render::BuildCommandBufferSimple(VkCommandBuffer a_cmdBuff, VkFramebuffer a_frameBuff, VkImageView a_targetImageView) -{ - vkResetCommandBuffer(a_cmdBuff, 0); - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - - VK_CHECK_RESULT(vkBeginCommandBuffer(a_cmdBuff, &beginInfo)); - - //// draw final scene to screen - // - { - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = m_screenRenderPass; - renderPassInfo.framebuffer = a_frameBuff; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = m_swapchain.GetExtent(); - - VkClearValue clearValues[2] = {}; - clearValues[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; - clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = 2; - renderPassInfo.pClearValues = &clearValues[0]; - - vkCmdBeginRenderPass(a_cmdBuff, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(a_cmdBuff); - } - - float scaleAndOffset[4] = {0.5f, 0.5f, -0.5f, +0.5f}; - m_pFSQuad->SetRenderTarget(a_targetImageView); - m_pFSQuad->DrawCmd(a_cmdBuff, m_quadDS, scaleAndOffset); - - VK_CHECK_RESULT(vkEndCommandBuffer(a_cmdBuff)); -} - - -void Quad2D_Render::CleanupPipelineAndSwapchain() -{ - if (!m_cmdBuffersDrawMain.empty()) - { - vkFreeCommandBuffers(m_device, m_commandPool, static_cast(m_cmdBuffersDrawMain.size()), - m_cmdBuffersDrawMain.data()); - m_cmdBuffersDrawMain.clear(); - } - - for (size_t i = 0; i < m_frameFences.size(); i++) - { - vkDestroyFence(m_device, m_frameFences[i], nullptr); - } - - vkDestroyImageView(m_device, m_imageData.view, nullptr); - vkDestroyImage(m_device, m_imageData.image, nullptr); - vkFreeMemory(m_device, m_imageData.mem, nullptr); - - for (size_t i = 0; i < m_frameBuffers.size(); i++) - { - vkDestroyFramebuffer(m_device, m_frameBuffers[i], nullptr); - } - - vkDestroyRenderPass(m_device, m_screenRenderPass, nullptr); - - //m_swapchain.Cleanup(); -} - -void Quad2D_Render::RecreateSwapChain() -{ - vkDeviceWaitIdle(m_device); - - CleanupPipelineAndSwapchain(); - auto oldImageNum = m_swapchain.GetImageCount(); - m_presentationResources.queue = m_swapchain.CreateSwapChain(m_physicalDevice, m_device, m_surface, m_width, m_height, - oldImageNum, m_vsync); - - vk_utils::RenderTargetInfo2D rtargetInfo = {}; - rtargetInfo.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - rtargetInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rtargetInfo.format = m_swapchain.GetFormat(); - rtargetInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - m_screenRenderPass = vk_utils::createRenderPass(m_device, rtargetInfo); - m_frameBuffers = vk_utils::createFrameBuffers(m_device, m_swapchain, m_screenRenderPass); - - m_frameFences.resize(m_framesInFlight); - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (size_t i = 0; i < m_framesInFlight; i++) - { - VK_CHECK_RESULT(vkCreateFence(m_device, &fenceInfo, nullptr, &m_frameFences[i])); - } - - m_cmdBuffersDrawMain = vk_utils::createCommandBuffers(m_device, m_commandPool, m_framesInFlight); - for (uint32_t i = 0; i < m_swapchain.GetImageCount(); ++i) - { - BuildCommandBufferSimple(m_cmdBuffersDrawMain[i], m_frameBuffers[i], m_swapchain.GetAttachment(i).view); - } -} - -void Quad2D_Render::Cleanup() -{ - m_pFSQuad = nullptr; // smartptr delete it's resources - CleanupPipelineAndSwapchain(); - - - if (m_presentationResources.imageAvailable != VK_NULL_HANDLE) - vkDestroySemaphore(m_device, m_presentationResources.imageAvailable, nullptr); - - if (m_presentationResources.renderingFinished != VK_NULL_HANDLE) - vkDestroySemaphore(m_device, m_presentationResources.renderingFinished, nullptr); - - if (m_commandPool != VK_NULL_HANDLE) - { - vkDestroyCommandPool(m_device, m_commandPool, nullptr); - } -} - -void Quad2D_Render::ProcessInput(const AppInput &input) -{ - // add keyboard controls here - // camera movement is processed separately - - // recreate pipeline to reload shaders - if(input.keyPressed[GLFW_KEY_B]) - { -#ifdef WIN32 - std::system("cd ../resources/shaders && python compile_quad_render_shaders.py"); -#else - std::system("cd ../resources/shaders && python3 compile_quad_render_shaders.py"); -#endif - - SetupQuadRenderer(); - SetupSimplePipeline(); - - for (uint32_t i = 0; i < m_framesInFlight; ++i) - { - BuildCommandBufferSimple(m_cmdBuffersDrawMain[i], m_frameBuffers[i], m_swapchain.GetAttachment(i).view); - } - } - -} - -void Quad2D_Render::UpdateCamera(const Camera*, uint32_t) -{ - -} - - -static std::vector LoadBMP(const char* filename, unsigned* pW, unsigned* pH) -{ - FILE* f = fopen(filename, "rb"); - - if(f == nullptr) + if (f == nullptr) { (*pW) = 0; (*pH) = 0; @@ -301,99 +24,122 @@ static std::vector LoadBMP(const char* filename, unsigned* pW, unsigne } unsigned char info[54]; - auto readRes = fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header - if(readRes != 54) + auto readRes = fread(info, sizeof(unsigned char), 54, f);// read the 54-byte header + if (readRes != 54) { std::cout << "can't read 54 byte BMP header" << std::endl; return {}; } - int width = *(int*)&info[18]; - int height = *(int*)&info[22]; + int width = *(int *)&info[18]; + int height = *(int *)&info[22]; - int row_padded = (width*3 + 3) & (~3); + int row_padded = (width * 3 + 3) & (~3); auto data = new unsigned char[row_padded]; - std::vector res(width*height); + std::vector res(width * height); - for(int i = 0; i < height; i++) + for (int i = 0; i < height; i++) { fread(data, sizeof(unsigned char), row_padded, f); - for(int j = 0; j < width; j++) - res[i*width+j] = (uint32_t(data[j*3+0]) << 16) | (uint32_t(data[j*3+1]) << 8) | (uint32_t(data[j*3+2]) << 0); + for (int j = 0; j < width; j++) + res[i * width + j] = (uint32_t(data[j * 3 + 0]) << 16) | (uint32_t(data[j * 3 + 1]) << 8) | (uint32_t(data[j * 3 + 2]) << 0); } fclose(f); - delete [] data; + delete[] data; (*pW) = unsigned(width); (*pH) = unsigned(height); return res; } -void Quad2D_Render::LoadScene(const char*, bool) +void SimpleQuad2dRender::LoadScene(const char* path, bool transpose_inst_matrices) { uint32_t texW, texH; auto texData = LoadBMP("../resources/textures/texture1.bmp", &texW, &texH); - - m_imageData = vk_utils::allocateColorTextureFromDataLDR(m_device, m_physicalDevice, (const unsigned char*)texData.data(), texW, texH, 1, VK_FORMAT_R8G8B8A8_UNORM, - m_pCopyHelper, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - m_imageSampler = vk_utils::createSampler(m_device, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); + m_imageData = vk_utils::allocateColorTextureFromDataLDR(m_context->getDevice(), m_context->getPhysicalDevice(), (const unsigned char *)texData.data(), + texW, texH, 1, VK_FORMAT_R8G8B8A8_UNORM, m_pCopyHelper, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - SetupSimplePipeline(); + m_imageSampler = vk_utils::createSampler(m_context->getDevice(), VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); - for (uint32_t i = 0; i < m_framesInFlight; ++i) - BuildCommandBufferSimple(m_cmdBuffersDrawMain[i], m_frameBuffers[i], m_swapchain.GetAttachment(i).view); + PreparePipelines(); } -void Quad2D_Render::DrawFrameSimple() +void SimpleQuad2dRender::DeallocateResources() { - vkWaitForFences(m_device, 1, &m_frameFences[m_presentationResources.currentFrame], VK_TRUE, UINT64_MAX); - vkResetFences(m_device, 1, &m_frameFences[m_presentationResources.currentFrame]); + vkDestroyImageView(m_context->getDevice(), m_imageData.view, nullptr); + vkDestroyImage(m_context->getDevice(), m_imageData.image, nullptr); + vkFreeMemory(m_context->getDevice(), m_imageData.mem, nullptr); + vkDestroySampler(m_context->getDevice(), m_imageSampler, nullptr); + + m_swapchain.Cleanup(); + vkDestroySurfaceKHR(GetVkInstance(), m_surface, nullptr); +} + +/// PIPELINES CREATION - uint32_t imageIdx; - m_swapchain.AcquireNextImage(m_presentationResources.imageAvailable, &imageIdx); +void SimpleQuad2dRender::PreparePipelines() +{ + // create full screen quad + // + m_pFSQuad.reset(); + m_pFSQuad = std::make_shared(0,0, 1024, 1024); + m_pFSQuad->Create(m_context->getDevice(), + VK_GRAPHICS_BASIC_ROOT "/resources/shaders/quad3_vert.vert.spv", + VK_GRAPHICS_BASIC_ROOT "/resources/shaders/my_quad.frag.spv", + vk_utils::RenderTargetInfo2D{ + .size = VkExtent2D{ m_width, m_height }, + .format = m_swapchain.GetFormat(), + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + } + ); + SetupSimplePipeline(); +} - auto currentCmdBuf = m_cmdBuffersDrawMain[m_presentationResources.currentFrame]; +void SimpleQuad2dRender::SetupSimplePipeline() +{ + std::vector > dtypes = { + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1} + }; - VkSemaphore waitSemaphores[] = {m_presentationResources.imageAvailable}; - VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + m_pBindings = std::make_shared(m_context->getDevice(), dtypes, 1); + + m_pBindings->BindBegin(VK_SHADER_STAGE_FRAGMENT_BIT); + m_pBindings->BindImage(0, m_imageData.view, m_imageSampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + m_pBindings->BindEnd(&m_quadDS, &m_quadDSLayout); +} - BuildCommandBufferSimple(currentCmdBuf, m_frameBuffers[imageIdx], m_swapchain.GetAttachment(imageIdx).view); +void SimpleQuad2dRender::DestroyPipelines() +{ + m_pFSQuad = nullptr; // smartptr delete it's resources +} - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = waitSemaphores; - submitInfo.pWaitDstStageMask = waitStages; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = ¤tCmdBuf; +/// COMMAND BUFFER FILLING - VkSemaphore signalSemaphores[] = {m_presentationResources.renderingFinished}; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphores; +void SimpleQuad2dRender::BuildCommandBufferSimple(VkCommandBuffer a_cmdBuff, VkImage a_targetImage, VkImageView a_targetImageView) +{ + vkResetCommandBuffer(a_cmdBuff, 0); - VK_CHECK_RESULT(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_frameFences[m_presentationResources.currentFrame])); + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - VkResult presentRes = m_swapchain.QueuePresent(m_presentationResources.queue, imageIdx, - m_presentationResources.renderingFinished); + VK_CHECK_RESULT(vkBeginCommandBuffer(a_cmdBuff, &beginInfo)); - if (presentRes == VK_ERROR_OUT_OF_DATE_KHR || presentRes == VK_SUBOPTIMAL_KHR) - { - RecreateSwapChain(); - } - else if (presentRes != VK_SUCCESS) - { - RUN_TIME_ERROR("Failed to present swapchain image"); - } + float scaleAndOffset[4] = { 0.5f, 0.5f, -0.5f, +0.5f }; + m_pFSQuad->SetRenderTarget(a_targetImageView); + m_pFSQuad->DrawCmd(a_cmdBuff, m_quadDS, scaleAndOffset); - m_presentationResources.currentFrame = (m_presentationResources.currentFrame + 1) % m_framesInFlight; + etna::set_state(a_cmdBuff, a_targetImage, vk::PipelineStageFlagBits2::eBottomOfPipe, + vk::AccessFlags2(), vk::ImageLayout::ePresentSrcKHR, + vk::ImageAspectFlagBits::eColor); - vkQueueWaitIdle(m_presentationResources.queue); -} + etna::finish_frame(a_cmdBuff); -void Quad2D_Render::DrawFrame(float, DrawMode) -{ - DrawFrameSimple(); + VK_CHECK_RESULT(vkEndCommandBuffer(a_cmdBuff)); } diff --git a/src/samples/quad2d/quad2d_render.h b/src/samples/quad2d/quad2d_render.h index c5bec3a6..e3fc549d 100644 --- a/src/samples/quad2d/quad2d_render.h +++ b/src/samples/quad2d/quad2d_render.h @@ -1,73 +1,51 @@ #ifndef SIMPLE_QUAD2D_RENDER_H #define SIMPLE_QUAD2D_RENDER_H -#define VK_NO_PROTOTYPES #include "../../render/render_common.h" -#include "../resources/shaders/common.h" +#include "../../../resources/shaders/common.h" +#include "etna/GraphicsPipeline.hpp" +#include #include #include #include #include -#include -#include +#include #include #include -class Quad2D_Render : public IRender +#include +#include + + +class IRenderGUI; + +class SimpleQuad2dRender : public IRender { public: - Quad2D_Render(uint32_t a_width, uint32_t a_height); - ~Quad2D_Render() { Cleanup(); }; + SimpleQuad2dRender(uint32_t a_width, uint32_t a_height); + ~SimpleQuad2dRender(); + + uint32_t GetWidth() const override { return m_width; } + uint32_t GetHeight() const override { return m_height; } + VkInstance GetVkInstance() const override { return m_context->getInstance(); } - inline uint32_t GetWidth() const override { return m_width; } - inline uint32_t GetHeight() const override { return m_height; } - inline VkInstance GetVkInstance() const override { return m_instance; } void InitVulkan(const char** a_instanceExtensions, uint32_t a_instanceExtensionsCount, uint32_t a_deviceId) override; void InitPresentation(VkSurfaceKHR &a_surface, bool initGUI) override; void ProcessInput(const AppInput& input) override; void UpdateCamera(const Camera* cams, uint32_t a_camsNumber) override; + Camera GetCurrentCamera() override {return m_cam;} - void LoadScene(const char* path, bool transpose_inst_matrices) override; + void LoadScene(const char *path, bool transpose_inst_matrices) override; void DrawFrame(float a_time, DrawMode a_mode) override; - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - // debugging utils - // - static VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallbackFn( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData) - { - (void)flags; - (void)objectType; - (void)object; - (void)location; - (void)messageCode; - (void)pUserData; - std::cout << pLayerPrefix << ": " << pMessage << std::endl; - return VK_FALSE; - } - - VkDebugReportCallbackEXT m_debugReportCallback = nullptr; private: + etna::GlobalContext* m_context; + etna::Sampler defaultSampler; - VkInstance m_instance = VK_NULL_HANDLE; VkCommandPool m_commandPool = VK_NULL_HANDLE; - VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; - VkDevice m_device = VK_NULL_HANDLE; - VkQueue m_graphicsQueue = VK_NULL_HANDLE; - VkQueue m_transferQueue = VK_NULL_HANDLE; - - vk_utils::QueueFID_T m_queueFamilyIDXs {UINT32_MAX, UINT32_MAX, UINT32_MAX}; struct { @@ -79,52 +57,54 @@ class Quad2D_Render : public IRender std::vector m_frameFences; std::vector m_cmdBuffersDrawMain; - VkRenderPass m_screenRenderPass = VK_NULL_HANDLE; // main renderpass - std::shared_ptr m_pBindings = nullptr; + etna::GraphicsPipeline m_basicForwardPipeline {}; + etna::GraphicsPipeline m_shadowPipeline {}; + std::shared_ptr m_pBindings = nullptr; + VkSurfaceKHR m_surface = VK_NULL_HANDLE; VulkanSwapChain m_swapchain; - std::vector m_frameBuffers; + Camera m_cam; uint32_t m_width = 1024u; uint32_t m_height = 1024u; uint32_t m_framesInFlight = 2u; bool m_vsync = false; - VkPhysicalDeviceFeatures m_enabledDeviceFeatures = {}; - std::vector m_deviceExtensions = {}; - std::vector m_instanceExtensions = {}; + vk::PhysicalDeviceFeatures m_enabledDeviceFeatures = {}; + std::vector m_deviceExtensions; + std::vector m_instanceExtensions; - bool m_enableValidation; - std::vector m_validationLayers; std::shared_ptr m_pCopyHelper; - - std::shared_ptr m_pFSQuad; + std::shared_ptr m_pFSQuad; VkDescriptorSet m_quadDS; VkDescriptorSetLayout m_quadDSLayout = nullptr; - - vk_utils::VulkanImageMem m_imageData; - VkSampler m_imageSampler; + vk_utils::VulkanImageMem m_imageData; + VkSampler m_imageSampler; + void DrawFrameSimple(); void CreateInstance(); void CreateDevice(uint32_t a_deviceId); - void BuildCommandBufferSimple(VkCommandBuffer a_cmdBuff, VkFramebuffer a_frameBuff, VkImageView a_targetImageView); + void BuildCommandBufferSimple(VkCommandBuffer a_cmdBuff, VkImage a_targetImage, VkImageView a_targetImageView); void SetupSimplePipeline(); - void SetupQuadRenderer(); - void CleanupPipelineAndSwapchain(); void RecreateSwapChain(); - void Cleanup(); - void SetupDeviceFeatures(); void SetupDeviceExtensions(); - void SetupValidationLayers(); + + void PreparePipelines(); + + void DestroyPipelines(); + void DeallocateResources(); + + void InitPresentStuff(); + void ResetPresentStuff(); }; -#endif //SIMPLE_QUAD2D_RENDER_H +#endif //CHIMERA_SIMPLE_RENDER_H diff --git a/src/samples/quad2d/render_init.cpp b/src/samples/quad2d/render_init.cpp new file mode 100644 index 00000000..50b097ec --- /dev/null +++ b/src/samples/quad2d/render_init.cpp @@ -0,0 +1,71 @@ +#include "quad2d_render.h" + +#include + + +SimpleQuad2dRender::SimpleQuad2dRender(uint32_t a_width, uint32_t a_height) : m_width(a_width), m_height(a_height) +{ +} + +void SimpleQuad2dRender::InitVulkan(const char** a_instanceExtensions, uint32_t a_instanceExtensionsCount, uint32_t) +{ + for(size_t i = 0; i < a_instanceExtensionsCount; ++i) + { + m_instanceExtensions.push_back(a_instanceExtensions[i]); + } + + #ifndef NDEBUG + m_instanceExtensions.push_back("VK_EXT_debug_report"); + #endif + + SetupDeviceExtensions(); + + etna::initialize(etna::InitParams + { + .applicationName = "Quad2dSample", + .applicationVersion = VK_MAKE_VERSION(0, 1, 0), + .instanceExtensions = m_instanceExtensions, + .deviceExtensions = m_deviceExtensions, + .features = vk::PhysicalDeviceFeatures2 + { + .features = m_enabledDeviceFeatures + }, + // Replace with an index if etna detects your preferred GPU incorrectly + .physicalDeviceIndexOverride = {} + }); + + m_context = &etna::get_context(); + + m_pCopyHelper = std::make_shared(m_context->getPhysicalDevice(), m_context->getDevice(), m_context->getQueue(), m_context->getQueueFamilyIdx(), 8 * 1024 * 1024); +} + +void SimpleQuad2dRender::SetupDeviceExtensions() +{ + m_deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); +} + +void SimpleQuad2dRender::RecreateSwapChain() +{ + ETNA_ASSERT(m_context->getDevice().waitIdle() == vk::Result::eSuccess); + + DeallocateResources(); + + DestroyPipelines(); + ResetPresentStuff(); + + auto oldImgNum = m_swapchain.GetImageCount(); + m_presentationResources.queue = m_swapchain.CreateSwapChain( + m_context->getPhysicalDevice(), m_context->getDevice(), m_surface, m_width, m_height, + oldImgNum, m_vsync); + + InitPresentStuff(); + + PreparePipelines(); +} + +SimpleQuad2dRender::~SimpleQuad2dRender() +{ + DeallocateResources(); + DestroyPipelines(); + ResetPresentStuff(); +} \ No newline at end of file diff --git a/src/samples/quad2d/update.cpp b/src/samples/quad2d/update.cpp new file mode 100644 index 00000000..0c0e6031 --- /dev/null +++ b/src/samples/quad2d/update.cpp @@ -0,0 +1,28 @@ +#include "../../utils/input_definitions.h" + +#include "etna/Etna.hpp" +#include "quad2d_render.h" + +void SimpleQuad2dRender::UpdateCamera(const Camera* cams, uint32_t a_camsNumber) +{ +} + +void SimpleQuad2dRender::ProcessInput(const AppInput &input) +{ + // recreate pipeline to reload shaders + if(input.keyPressed[GLFW_KEY_B]) + { +#ifdef WIN32 + std::system("cd ../resources/shaders && python compile_quad_render_shaders.py"); +#else + std::system("cd ../resources/shaders && python3 compile_quad_render_shaders.py"); +#endif + + PreparePipelines(); + + for (uint32_t i = 0; i < m_framesInFlight; ++i) + { + BuildCommandBufferSimple(m_cmdBuffersDrawMain[i], m_swapchain.GetAttachment(i).image, m_swapchain.GetAttachment(i).view); + } + } +}