void op3d::Engine::initVulkan() { instance.create(); callback.setup(instance); surface.create(instance, window); physicalDevice.create(instance, surface); device.create(physicalDevice, surface, graphicsQueue, presentQueue); swapChain.create(device, surface, physicalDevice, window); swapChain.createImageViews(device, swapChainImageViews); createRenderPass(); createDescriptorSetLayout(); createGraphicsPipeline(); commandBufferManager.createCommandPool(physicalDevice, surface); createDepthResources(); createFramebuffers(); createTextureImage(); createTextureImageView(); createTextureSampler(); createVertexBuffer(); createIndexBuffer(); createUniformBuffer(); descriptorPool.createPool(); descriptorSet.createSet(uniformBuffer, textureImageView, textureSampler, descriptorSetLayout, descriptorPool, device); createCommandBuffers(); createSemaphores(); }
void initVulkan() { createInstance(); setupDebugCallback(); createSurface(); pickPhysicalDevice(); createLogicalDevice(); createSwapChain(); createImageViews(); createRenderPass(); createGraphicsPipeline(); }
void op3d::Engine::recreateSwapChain() { vkDeviceWaitIdle(device); swapChain.create(device, surface, physicalDevice, window); swapChain.createImageViews(device, swapChainImageViews); createRenderPass(); createGraphicsPipeline(); createDepthResources(); createFramebuffers(); createCommandBuffers(); }
void SparseShaderIntrinsicsInstanceSampledBase::recordCommands (const VkCommandBuffer commandBuffer, const VkImageCreateInfo& imageSparseInfo, const VkImage imageSparse, const VkImage imageTexels, const VkImage imageResidency) { const InstanceInterface& instance = m_context.getInstanceInterface(); const DeviceInterface& deviceInterface = getDeviceInterface(); const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice); if (imageSparseInfo.extent.width > deviceProperties.limits.maxFramebufferWidth || imageSparseInfo.extent.height > deviceProperties.limits.maxFramebufferHeight || imageSparseInfo.arrayLayers > deviceProperties.limits.maxFramebufferLayers) { TCU_THROW(NotSupportedError, "Image size exceeds allowed framebuffer dimensions"); } // Check if device supports image format for sampled images if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) TCU_THROW(NotSupportedError, "Device does not support image format for sampled images"); // Check if device supports image format for color attachment if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) TCU_THROW(NotSupportedError, "Device does not support image format for color attachment"); // Make sure device supports VK_FORMAT_R32_UINT format for color attachment if (!checkImageFormatFeatureSupport(instance, physicalDevice, mapTextureFormat(m_residencyFormat), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) TCU_THROW(TestError, "Device does not support VK_FORMAT_R32_UINT format for color attachment"); // Create buffer storing vertex data std::vector<tcu::Vec2> vertexData; vertexData.push_back(tcu::Vec2(-1.0f,-1.0f)); vertexData.push_back(tcu::Vec2( 0.0f, 0.0f)); vertexData.push_back(tcu::Vec2(-1.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 0.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 1.0f,-1.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 0.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 1.0f)); vertexData.push_back(tcu::Vec2( 1.0f, 1.0f)); const VkDeviceSize vertexDataSizeInBytes = sizeInBytes(vertexData); const VkBufferCreateInfo vertexBufferCreateInfo = makeBufferCreateInfo(vertexDataSizeInBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); m_vertexBuffer = createBuffer(deviceInterface, getDevice(), &vertexBufferCreateInfo); m_vertexBufferAlloc = bindBuffer(deviceInterface, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible); deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeInBytes)); flushMappedMemoryRange(deviceInterface, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexDataSizeInBytes); // Create render pass const VkAttachmentDescription texelsAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; imageSparseInfo.format, // VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; }; const VkAttachmentDescription residencyAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; mapTextureFormat(m_residencyFormat), // VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; }; const VkAttachmentDescription colorAttachmentsDescription[] = { texelsAttachmentDescription, residencyAttachmentDescription }; const VkAttachmentReference texelsAttachmentReference = { 0u, // deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; }; const VkAttachmentReference residencyAttachmentReference = { 1u, // deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; }; const VkAttachmentReference colorAttachmentsReference[] = { texelsAttachmentReference, residencyAttachmentReference }; const VkAttachmentReference depthAttachmentReference = { VK_ATTACHMENT_UNUSED, // deUint32 attachment; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout; }; const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 0u, // deUint32 inputAttachmentCount; DE_NULL, // const VkAttachmentReference* pInputAttachments; 2u, // deUint32 colorAttachmentCount; colorAttachmentsReference, // const VkAttachmentReference* pColorAttachments; DE_NULL, // const VkAttachmentReference* pResolveAttachments; &depthAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment; 0u, // deUint32 preserveAttachmentCount; DE_NULL // const deUint32* pPreserveAttachments; }; const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; 2u, // deUint32 attachmentCount; colorAttachmentsDescription, // const VkAttachmentDescription* pAttachments; 1u, // deUint32 subpassCount; &subpassDescription, // const VkSubpassDescription* pSubpasses; 0u, // deUint32 dependencyCount; DE_NULL // const VkSubpassDependency* pDependencies; }; m_renderPass = createRenderPass(deviceInterface, getDevice(), &renderPassInfo); // Create descriptor set layout DescriptorSetLayoutBuilder descriptorLayerBuilder; descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); const Unique<VkDescriptorSetLayout> descriptorSetLayout(descriptorLayerBuilder.build(deviceInterface, getDevice())); // Create descriptor pool DescriptorPoolBuilder descriptorPoolBuilder; descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSparseInfo.mipLevels); descriptorPool = descriptorPoolBuilder.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, imageSparseInfo.mipLevels); // Create sampler object const tcu::Sampler samplerObject(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST); const VkSamplerCreateInfo samplerCreateInfo = mapSampler(samplerObject, m_format); m_sampler = createSampler(deviceInterface, getDevice(), &samplerCreateInfo); struct PushConstants { deUint32 lod; deUint32 padding; // padding needed to satisfy std430 rules float lodWidth; float lodHeight; }; // Create pipeline layout const VkPushConstantRange lodConstantRange = { VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags; 0u, // deUint32 offset; sizeof(PushConstants), // deUint32 size; }; const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts; 1u, // deUint32 pushConstantRangeCount; &lodConstantRange, // const VkPushConstantRange* pPushConstantRanges; }; const Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(deviceInterface, getDevice(), &pipelineLayoutParams)); // Create graphics pipeline { Move<VkShaderModule> vertexModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0); Move<VkShaderModule> fragmentModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("fragment_shader"), (VkShaderModuleCreateFlags)0); Move<VkShaderModule> geometryModule; if (imageSparseInfo.arrayLayers > 1u) { requireFeatures(instance, physicalDevice, FEATURE_GEOMETRY_SHADER); geometryModule = createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("geometry_shader"), (VkShaderModuleCreateFlags)0); } pipelines.push_back(makeVkSharedPtr(makeGraphicsPipeline( deviceInterface, getDevice(), *pipelineLayout, *m_renderPass, *vertexModule, *fragmentModule, *geometryModule))); } const VkPipeline graphicsPipeline = **pipelines[0]; { const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); VkImageMemoryBarrier imageShaderAccessBarriers[3]; imageShaderAccessBarriers[0] = makeImageMemoryBarrier ( VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, imageSparse, fullImageSubresourceRange ); imageShaderAccessBarriers[1] = makeImageMemoryBarrier ( 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, imageTexels, fullImageSubresourceRange ); imageShaderAccessBarriers[2] = makeImageMemoryBarrier ( 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, imageResidency, fullImageSubresourceRange ); deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 3u, imageShaderAccessBarriers); } imageSparseViews.resize(imageSparseInfo.mipLevels); imageTexelsViews.resize(imageSparseInfo.mipLevels); imageResidencyViews.resize(imageSparseInfo.mipLevels); m_framebuffers.resize(imageSparseInfo.mipLevels); descriptorSets.resize(imageSparseInfo.mipLevels); std::vector<VkClearValue> clearValues; clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))); clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f))); for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx) { const vk::VkExtent3D mipLevelSize = mipLevelExtents(imageSparseInfo.extent, mipLevelNdx); const vk::VkRect2D renderArea = makeRect2D(mipLevelSize); const VkViewport viewport = makeViewport(mipLevelSize); const VkImageSubresourceRange mipLevelRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevelNdx, 1u, 0u, imageSparseInfo.arrayLayers); // Create color attachments image views imageTexelsViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageTexels, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange)); imageResidencyViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageResidency, mapImageViewType(m_imageType), mapTextureFormat(m_residencyFormat), mipLevelRange)); const VkImageView attachmentsViews[] = { **imageTexelsViews[mipLevelNdx], **imageResidencyViews[mipLevelNdx] }; // Create framebuffer const VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkFramebufferCreateFlags)0, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 2u, // uint32_t attachmentCount; attachmentsViews, // const VkImageView* pAttachments; mipLevelSize.width, // uint32_t width; mipLevelSize.height, // uint32_t height; imageSparseInfo.arrayLayers, // uint32_t layers; }; m_framebuffers[mipLevelNdx] = makeVkSharedPtr(createFramebuffer(deviceInterface, getDevice(), &framebufferInfo)); // Create descriptor set descriptorSets[mipLevelNdx] = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout)); const VkDescriptorSet descriptorSet = **descriptorSets[mipLevelNdx]; // Update descriptor set const VkImageSubresourceRange sparseImageSubresourceRange = sampledImageRangeToBind(imageSparseInfo, mipLevelNdx); imageSparseViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageSparse, mapImageViewType(m_imageType), imageSparseInfo.format, sparseImageSubresourceRange)); const VkDescriptorImageInfo imageSparseDescInfo = makeDescriptorImageInfo(*m_sampler, **imageSparseViews[mipLevelNdx], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); DescriptorSetUpdateBuilder descriptorUpdateBuilder; descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_SPARSE), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSparseDescInfo); descriptorUpdateBuilder.update(deviceInterface, getDevice()); // Begin render pass beginRenderPass(deviceInterface, commandBuffer, *m_renderPass, **m_framebuffers[mipLevelNdx], renderArea, (deUint32)clearValues.size(), &clearValues[0]); // Bind graphics pipeline deviceInterface.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); // Bind descriptor set deviceInterface.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); // Bind vertex buffer { const VkDeviceSize offset = 0ull; deviceInterface.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &m_vertexBuffer.get(), &offset); } // Bind Viewport deviceInterface.cmdSetViewport(commandBuffer, 0u, 1u, &viewport); // Bind Scissor Rectangle deviceInterface.cmdSetScissor(commandBuffer, 0u, 1u, &renderArea); const PushConstants pushConstants = { mipLevelNdx, 0u, // padding static_cast<float>(mipLevelSize.width), static_cast<float>(mipLevelSize.height) }; // Update push constants deviceInterface.cmdPushConstants(commandBuffer, *pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(PushConstants), &pushConstants); // Draw full screen quad deviceInterface.cmdDraw(commandBuffer, 4u, 1u, 0u, 0u); // End render pass endRenderPass(deviceInterface, commandBuffer); } { const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers); VkImageMemoryBarrier imageOutputTransferSrcBarriers[2]; imageOutputTransferSrcBarriers[0] = makeImageMemoryBarrier ( VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageTexels, fullImageSubresourceRange ); imageOutputTransferSrcBarriers[1] = makeImageMemoryBarrier ( VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageResidency, fullImageSubresourceRange ); deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 2u, imageOutputTransferSrcBarriers); } }
int main() { // first, create a vulkan instance // the needed/used instance extensions constexpr const char* iniExtensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME }; // enables all default layers constexpr auto layer = "VK_LAYER_LUNARG_standard_validation"; // basic application info // we use vulkan api version 1.0 vk::ApplicationInfo appInfo ("vpp-intro", 1, "vpp", 1, VK_API_VERSION_1_0); vk::InstanceCreateInfo instanceInfo; instanceInfo.pApplicationInfo = &appInfo; instanceInfo.enabledExtensionCount = sizeof(iniExtensions) / sizeof(iniExtensions[0]); instanceInfo.ppEnabledExtensionNames = iniExtensions; instanceInfo.enabledLayerCount = 1; instanceInfo.ppEnabledLayerNames = &layer; vpp::Instance instance(instanceInfo); // create a debug callback for our instance and the default layers // the default implementation will just output to std::cerr when a debug callback // is received vpp::DebugCallback debugCallback(instance); // this function will create a winapi window wrapper and also create a surface for it // this should usually be done by a cross platform window abstraction Window window(instance); // now create a device for the instance and surface // note how vpp will automatically select a suited physical device and query // queue families to create basic-needs queues with this constructor. // We also retrieve the present queue to present on our surface from this // constructor const vpp::Queue* presentQueue; vpp::Device device(instance, window.surface, presentQueue); // now we can create a vulkan swapchain // again, we just use the fast way that choses quite sane defaults for us but note // that the class offers many convininient configuration possibilities vpp::Swapchain swapchain(device, window.surface); // to render the triangle we also need to create a render pass vpp::RenderPass renderPass = createRenderPass(swapchain); // we also create the graphics pipeline that will render our triangle as well // as the buffer to hold our vertices vpp::PipelineLayout pipelineLayout(device, {}); auto pipeline = createGraphicsPipeline(device, renderPass, pipelineLayout); // note how vpp takes care of buffer allocation (in an efficient way, even when used // for multiple resources) constexpr auto size = 3u * (2u + 4u) * 4u; // 3 vertices, vec2, vec4 with 4 bytes components constexpr auto usage = vk::BufferUsageBits::vertexBuffer | vk::BufferUsageBits::transferDst; vpp::Buffer vertexBuffer(device, {{}, size, usage}); // vertex data (only positions and color) constexpr std::array<float, 6 * 3> vertexData = {{ 0.f, -0.75f, 1.f, 0.f, 0.f, 1.f, // top -0.75f, 0.75f, 0.f, 1.f, 0.f, 1.f, // left 0.75f, 0.75f, 0.f, 0.f, 1.f, 1.f // right }}; // vpp can now be used to fill the vertex buffer with data in the most efficient way // in this case the buffer layout does not matter since its a vertex buffer // note how vpp automatically unpacks the std::array vpp::fill140(vertexBuffer, vpp::raw(vertexData)); // to render onto the created swapchain we can use vpp::SwapchainRenderer // the class implements the default framebuffer and commandbuffer handling // we simply implement the vpp::RendererBuilder interface that will be used // to build the render command buffers vpp::SwapchainRenderer::CreateInfo rendererInfo; rendererInfo.queueFamily = device.queue(vk::QueueBits::graphics)->family(); rendererInfo.renderPass = renderPass; auto impl = std::make_unique<IntroRendererImpl>(); impl->pipeline = pipeline; impl->vertexBuffer = vertexBuffer; vpp::SwapchainRenderer renderer(swapchain, rendererInfo, std::move(impl)); renderer.record(); // run the main loop // we just recevie windows events and render after all are processed // sry for windows again... using Clock = std::chrono::high_resolution_clock; auto frames = 0u; auto point = Clock::now(); auto run = true; while(run) { MSG msg; while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != 0) { if(msg.message == WM_QUIT) { run = false; break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } if(!run) break; renderer.renderBlock(*presentQueue); ++frames; // output the average fps count ever second auto duration = Clock::now() - point; if(duration >= std::chrono::seconds(1)) { auto count = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); std::cout << static_cast<int>(frames * (1000.0 / count)) << " fps\n"; point = Clock::now(); frames = 0u; } } return EXIT_SUCCESS; }