// Blaze.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include #include #include #include #include #define SDL_MAIN_USE_CALLBACKS 1 #include #include #include #include #include "AppState.h" #include "Frame.h" #include "GlobalMemory.h" #include "MacroUtils.h" #include "MathUtil.h" #include "MiscData.h" #include "RenderDevice.h" constexpr uint32_t WIDTH = 1280; constexpr uint32_t HEIGHT = 720; constexpr uint32_t NUM_FRAMES = 3; namespace Blaze::Global { GlobalMemory g_Memory; } SDL_AppResult SDL_AppInit( void** appstate, int, char** ) { SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS ); Blaze::Global::g_Memory.init( 128_MiB ); *appstate = AppState_Create( &Blaze::Global::g_Memory, WIDTH, HEIGHT ); if ( !*appstate ) return SDL_APP_FAILURE; return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate( void* appstate ) { AppState& appState = *static_cast( appstate ); RenderDevice& renderDevice = *appState.renderDevice; MiscData& misc = *appState.miscData; Frame& currentFrame = renderDevice.frames[renderDevice.frameIndex]; VK_CHECK( vkWaitForFences( renderDevice.device, 1, ¤tFrame.frameReadyToReuse, VK_TRUE, std::numeric_limits::max() ) ); // All resources of frame 'frameIndex' are free. // time calc uint64_t const previousCounter = misc.previousCounter; uint64_t const currentCounter = SDL_GetPerformanceCounter(); uint64_t const deltaCount = currentCounter - previousCounter; uint64_t const perfFreq = SDL_GetPerformanceFrequency(); double const deltaTime = static_cast( deltaCount ) / static_cast( perfFreq ); misc.previousCounter = currentCounter; { double deltaTimeMs = deltaTime * 1000.0; double fps = 1.0 / deltaTime; ( void )sprintf_s<256>( appState.sprintfBuffer, "%.2f fps %.5fms %llu -> %llu", fps, deltaTimeMs, previousCounter, currentCounter ); SDL_SetWindowTitle( appState.window, appState.sprintfBuffer ); } for ( Transform& transform : misc.modelTransform ) { transform.rotation = DirectX::XMQuaternionMultiply( DirectX::XMQuaternionRotationAxis( DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ), DirectX::XMConvertToRadians( 60.0f ) * static_cast( deltaTime ) ), transform.rotation ); } uint32_t currentImageIndex; VK_CHECK( vkAcquireNextImageKHR( renderDevice.device, renderDevice.swapchain, std::numeric_limits::max(), currentFrame.imageAcquiredSemaphore, nullptr, ¤tImageIndex ) ); VK_CHECK( vkResetFences( renderDevice.device, 1, ¤tFrame.frameReadyToReuse ) ); VK_CHECK( vkResetCommandPool( renderDevice.device, currentFrame.commandPool, 0 ) ); misc.acquireToRenderBarrier.image = renderDevice.swapchainImages[currentImageIndex]; misc.renderToPresentBarrier.image = renderDevice.swapchainImages[currentImageIndex]; VkCommandBuffer cmd = currentFrame.commandBuffer; VkCommandBufferBeginInfo constexpr beginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = nullptr, .flags = 0, .pInheritanceInfo = nullptr, }; VkClearColorValue constexpr static BLACK_CLEAR = { .float32 = { 0.0f, 0.0f, 0.0f, 1.0f }, }; VK_CHECK( vkBeginCommandBuffer( cmd, &beginInfo ) ); { VkRenderingAttachmentInfo const attachmentInfo = { .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .pNext = nullptr, .imageView = renderDevice.swapchainViews[currentImageIndex], .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .resolveMode = VK_RESOLVE_MODE_NONE, .resolveImageView = nullptr, .resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .clearValue = { .color = BLACK_CLEAR }, }; VkRenderingInfo renderingInfo = { .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, .pNext = nullptr, .flags = 0, .renderArea = { .offset = { 0, 0 }, .extent = renderDevice.swapchainExtent }, .layerCount = 1, .viewMask = 0, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, .pDepthAttachment = nullptr, .pStencilAttachment = nullptr, }; vkCmdPipelineBarrier2( cmd, &misc.acquireToRenderDependency ); vkCmdBeginRendering( cmd, &renderingInfo ); { VkViewport viewport = { .x = 0, .y = static_cast( renderDevice.swapchainExtent.height ), .width = static_cast( renderDevice.swapchainExtent.width ), .height = -static_cast( renderDevice.swapchainExtent.height ), .minDepth = 0.0f, .maxDepth = 1.0f, }; vkCmdSetViewport( cmd, 0, 1, &viewport ); VkRect2D scissor = { .offset = { 0, 0 }, .extent = renderDevice.swapchainExtent, }; vkCmdSetScissor( cmd, 0, 1, &scissor ); // Render Something? vkCmdBindPipeline( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, misc.meshPipeline ); VkDeviceSize constexpr offset = 0; vkCmdBindVertexBuffers( cmd, 0, 1, &misc.vertexBuffer, &offset ); vkCmdBindDescriptorSets( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, misc.pipelineLayout, 0, 1, &misc.descriptorSet, 0, nullptr ); for ( Transform& localTransform : misc.modelTransform ) { DirectX::XMMATRIX worldTransform; { auto [x, y, z] = localTransform.position; auto scale = localTransform.scale; worldTransform = DirectX::XMMatrixScaling( scale, scale, scale ) * DirectX::XMMatrixRotationQuaternion( localTransform.rotation ) * DirectX::XMMatrixTranslation( x, y, z ); } vkCmdPushConstants( cmd, misc.pipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, sizeof worldTransform, &worldTransform ); vkCmdDraw( cmd, static_cast( misc.vertices.size() ), 1, 0, 0 ); } } vkCmdEndRendering( cmd ); vkCmdPipelineBarrier2( cmd, &misc.renderToPresentDependency ); } VK_CHECK( vkEndCommandBuffer( cmd ) ); VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo const submitInfo = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = nullptr, .waitSemaphoreCount = 1, .pWaitSemaphores = ¤tFrame.imageAcquiredSemaphore, .pWaitDstStageMask = &stageMask, .commandBufferCount = 1, .pCommandBuffers = &cmd, .signalSemaphoreCount = 1, .pSignalSemaphores = ¤tFrame.renderFinishedSemaphore, }; VK_CHECK( vkQueueSubmit( renderDevice.directQueue, 1, &submitInfo, currentFrame.frameReadyToReuse ) ); VkPresentInfoKHR const presentInfo = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = nullptr, .waitSemaphoreCount = 1, .pWaitSemaphores = ¤tFrame.renderFinishedSemaphore, .swapchainCount = 1, .pSwapchains = &renderDevice.swapchain, .pImageIndices = ¤tImageIndex, .pResults = nullptr, }; VK_CHECK( vkQueuePresentKHR( renderDevice.directQueue, &presentInfo ) ); renderDevice.frameIndex = ( renderDevice.frameIndex + 1 ) % NUM_FRAMES; return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent( void*, SDL_Event* event ) { if ( event->type == SDL_EVENT_QUIT ) { return SDL_APP_SUCCESS; } return SDL_APP_CONTINUE; } void SDL_AppQuit( void* appstate, SDL_AppResult ) { AppState* appState = static_cast( appstate ); if ( appState ) appState->destroy(); Blaze::Global::g_Memory.destroy(); }