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; }
void handleSpuSerial(char c, int isError) { //char strDebugMsg[1024]; //if it's an error flag and discard till the start of the next message if(isError){ s_isSpuRxError=isError; debugCallback(); return; } switch(s_nSpuRxState){ case eSpuStraightSerialRxInit: if('{'==c){ initSpuMsgStart(c); } break; case eSpuStraightSerialRxStartMsg: if('{' ==c){ //empty message initSpuMsgStart(c); } else if('}' ==c){ s_spuRxPacket.swarm_msg_payload[++s_nSpuRxStateByteNum]=c; if(!s_isSpuRxError){ s_spuRxPacket.swarm_msg_payload[s_nSpuRxStateByteNum+1]='\0'; (*s_pushSwarmMsgBus)(s_spuRxPacket, 1); } s_nSpuRxState=eSpuStraightSerialRxInit; } else{ s_nSpuRxState=eSpuStraightSerialRxPayload; s_nSpuRxStateByteNum++; s_spuRxPacket.swarm_msg_payload[s_nSpuRxStateByteNum]=c; } break; case eSpuStraightSerialRxPayload: if('{' ==c) initSpuMsgStart(c); else if('}'==c) { s_spuRxPacket.swarm_msg_payload[++s_nSpuRxStateByteNum]=c; //if not error first dispatch old message if(!s_isSpuRxError){ s_spuRxPacket.swarm_msg_payload[s_nSpuRxStateByteNum+1]='\0'; (*s_pushSwarmMsgBus)(s_spuRxPacket, 1); } s_nSpuRxState=eSpuStraightSerialRxInit; } else { //check for max size s_nSpuRxStateByteNum++; if(s_nSpuRxStateByteNum <= MAX_SWARM_MSG_LENGTH ) s_spuRxPacket.swarm_msg_payload[s_nSpuRxStateByteNum]=c; // else // debug("maximum size exceeded for message"); //else ignore till the end } break; default: break; } }
int main() { constexpr auto width = 1200u; constexpr auto height = 800u; // init ny app auto& backend = ny::Backend::choose(); if(!backend.vulkan()) { dlg_error("ny backend has no vulkan support!"); return 0; } auto ac = backend.createAppContext(); // basic vpp init auto iniExtensions = ac->vulkanExtensions(); iniExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); vk::ApplicationInfo appInfo ("vpp-intro", 1, "vpp", 1, VK_API_VERSION_1_0); vk::InstanceCreateInfo instanceInfo; instanceInfo.pApplicationInfo = &appInfo; instanceInfo.enabledExtensionCount = iniExtensions.size(); instanceInfo.ppEnabledExtensionNames = iniExtensions.data(); #ifdef WithLayers constexpr auto layer = "VK_LAYER_LUNARG_standard_validation"; instanceInfo.enabledLayerCount = 1; instanceInfo.ppEnabledLayerNames = &layer; #endif vpp::Instance instance(instanceInfo); #ifdef WithLayers vpp::DebugCallback debugCallback(instance); #endif // ny init auto run = true; auto listener = MyWindowListener {}; listener.run = &run; auto vkSurface = vk::SurfaceKHR {}; auto ws = ny::WindowSettings {}; ws.surface = ny::SurfaceType::vulkan; ws.listener = &listener; ws.size = {width, height}; ws.vulkan.instance = (VkInstance) instance.vkHandle(); ws.vulkan.storeSurface = &(std::uintptr_t&) (vkSurface); auto wc = ac->createWindowContext(ws); // further vpp init const vpp::Queue* presentQueue; vpp::Device device(instance, vkSurface, presentQueue); vpp::Swapchain swapchain(device, vkSurface, {width, height}, {}); // vvg setup auto nvgContext = vvg::createContext(swapchain); auto font = nvgCreateFont(nvgContext, "sans", "Roboto-Regular.ttf"); using Clock = std::chrono::high_resolution_clock; auto lastFrameTimer = Clock::now(); unsigned int framesCount = 0; std::string fpsString = "420 fps"; // main loop while(run) { if(!ac->dispatchEvents()) break; nvgBeginFrame(nvgContext, width, height, width / (float) height); nvgBeginPath(nvgContext); nvgMoveTo(nvgContext, 10, 10); nvgLineTo(nvgContext, 10, 400); nvgLineTo(nvgContext, 100, 400); nvgQuadTo(nvgContext, 100, 50, 400, 120); nvgLineTo(nvgContext, 450, 10); nvgClosePath(nvgContext); nvgFillColor(nvgContext, nvgRGBAf(0.5, 0.8, 0.7, 1.0)); nvgFill(nvgContext); nvgBeginPath(nvgContext); nvgFontFaceId(nvgContext, font); nvgFontSize(nvgContext, 100.f); nvgFontBlur(nvgContext, .8f); nvgFillColor(nvgContext, nvgRGBAf(1.0, 1.0, 1.0, 1.0)); nvgTextBox(nvgContext, 200, 200, width - 200, "Hello Vulkan Vector Graphics World", nullptr); nvgFontSize(nvgContext, 30.f); nvgFontBlur(nvgContext, .2f); nvgText(nvgContext, 10, height - 20, fpsString.c_str(), nullptr); nvgBeginPath(nvgContext); nvgRect(nvgContext, 700, 400, 300, 300); nvgPathWinding(nvgContext, NVG_HOLE); nvgRect(nvgContext, 750, 450, 50, 50); // auto paint = nvgRadialGradient(nvgContext, 750, 425,20, 50, nvgRGB(0, 0, 200), nvgRGB(200, 200, 0)); // auto paint = nvgRadialGradient(nvgContext, 0.0, 0.0, 0.2, 100.0, nvgRGB(0, 0, 200), nvgRGB(200, 200, 0)); auto paint = nvgLinearGradient(nvgContext, 700, 400, 800, 450, nvgRGB(0, 0, 200), nvgRGB(200, 200, 0)); nvgFillPaint(nvgContext, paint); // nvgFillColor(nvgContext, nvgRGBA(200, 200, 0, 200)); nvgClosePath(nvgContext); nvgFill(nvgContext); nvgEndFrame(nvgContext); // only refresh frame timer every second framesCount++; if(Clock::now() - lastFrameTimer >= std::chrono::seconds(1)) { fpsString = std::to_string(framesCount) + " fps"; lastFrameTimer = Clock::now(); framesCount = 0; } } vvg::destroyContext(*nvgContext); }