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(); }
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; }
int main(int argc, char *args[]) { // Initialize function pointers, much like GLEW in OpenGL mantleLoadFunctions(); // Set debug callback grDbgRegisterMsgCallback(debugCallback, nullptr); // Create device and presentable image GR_DEVICE device; GR_QUEUE universalQueue; createDeviceAndQueue(device, universalQueue); GR_IMAGE presentableImage; GR_MEMORY_REF presentableImageMemRef; GR_IMAGE_SUBRESOURCE_RANGE imageColorRange; initPresentableImage(device, universalQueue, presentableImage, presentableImageMemRef, imageColorRange); // Create window to present to SDL_Init(SDL_INIT_VIDEO); SDL_Window* window = SDL_CreateWindow("Mantle Hello Triangle", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, 0); GR_WSI_WIN_PRESENT_INFO presentInfo = {}; presentInfo.hWndDest = GetActiveWindow(); presentInfo.srcImage = presentableImage; presentInfo.presentMode = GR_WSI_WIN_PRESENT_MODE_WINDOWED; // Create color target view GR_COLOR_TARGET_VIEW colorTargetView; GR_COLOR_TARGET_VIEW_CREATE_INFO colorTargetViewCreateInfo = {}; colorTargetViewCreateInfo.image = presentableImage; colorTargetViewCreateInfo.arraySize = 1; colorTargetViewCreateInfo.baseArraySlice = 0; colorTargetViewCreateInfo.mipLevel = 0; colorTargetViewCreateInfo.format.channelFormat = GR_CH_FMT_R8G8B8A8; colorTargetViewCreateInfo.format.numericFormat = GR_NUM_FMT_UNORM; grCreateColorTargetView(device, &colorTargetViewCreateInfo, &colorTargetView); // Create dynamic states (viewport, depth/stencil operations, etc.) createTargetStates(device, msaaState, viewportState, colorBlendState, depthStencilState, rasterState); // Create graphics pipeline with shaders and descriptor bindings GR_PIPELINE pipeline; GR_MEMORY_REF pipelineMemRef; createGraphicsPipeline(device, pipeline, pipelineMemRef); // Set up descriptor set with vertex data memory views GR_DESCRIPTOR_SET descriptorSet; GR_MEMORY_REF descriptorMemRef, vertexDataMemRef; initDescriptorSet(device, universalQueue, descriptorSet, descriptorMemRef, vertexDataMemRef); // Create command buffers for rendering steps GR_CMD_BUFFER bufferPrepareRender = createPrepareBuffer(device, presentableImage, imageColorRange); GR_CMD_BUFFER bufferClear = createClearBuffer(device, presentableImage, imageColorRange); GR_CMD_BUFFER bufferDrawTriangle = createDrawTriangleBuffer(device, colorTargetView, descriptorSet, pipeline); GR_CMD_BUFFER bufferFinish = createFinishBuffer(device, presentableImage, imageColorRange); // Create fence for CPU synchronization with rendering GR_FENCE fence; GR_FENCE_CREATE_INFO fenceCreateInfo = {}; grCreateFence(device, &fenceCreateInfo, &fence); // Main loop while (true) { SDL_Event windowEvent; if (SDL_PollEvent(&windowEvent)) { if (windowEvent.type == SDL_QUIT) break; } // Wait for previous frame to end grWaitForFences(device, 1, &fence, true, 1); // Submit command buffers along with memory references GR_MEMORY_REF memoryRefs[] = {presentableImageMemRef, pipelineMemRef, descriptorMemRef, vertexDataMemRef}; GR_CMD_BUFFER commandBuffers[] = {bufferPrepareRender, bufferClear, bufferDrawTriangle, bufferFinish}; grQueueSubmit(universalQueue, 4, commandBuffers, 4, memoryRefs, fence); // Present image to the window grWsiWinQueuePresent(universalQueue, &presentInfo); } return 0; }