// ============================================= // Aster: triangle.cpp // Copyright (c) 2020-2025 Anish Bhobe // ============================================= #include "aster/aster.h" #include "aster/core/buffer.h" #include "aster/core/constants.h" #include "aster/core/instance.h" #include "aster/core/physical_device.h" #include "aster/core/pipeline.h" #include "aster/core/swapchain.h" #include "aster/core/window.h" #include "aster/core/pipeline.h" #include "aster/systems/device.h" #include "aster/util/files.h" #include "helpers.h" #include constexpr auto SHADER_MODULE = "triangle.slang"; struct Vertex { vec3 m_Position; vec3 m_Color; static eastl::vector GetAttributes() { return { { .m_Location = 0, .m_Offset = offsetof(Vertex, m_Position), .m_Format = systems::AttributeInfo::Format::eFloat32X3, }, { .m_Location = 1, .m_Offset = offsetof(Vertex, m_Color), .m_Format = systems::AttributeInfo::Format::eFloat32X3, }, }; } }; int main(int, char **) { MIN_LOG_LEVEL(Logger::LogType::eInfo); Window window = {"Triangle (Aster)", {640, 480}}; systems::Device device{{ .m_Window = window, .m_Features = {.m_Vulkan12Features = {.bufferDeviceAddress = true}, .m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}}, .m_AppName = "Triangle", .m_ShaderSearchPaths = {"shader/"}, .m_Name = "Primary", }}; Pipeline pipeline; auto pipelineError = device.CreatePipeline( pipeline, { .m_VertexInputs = {{ .m_Attribute = Vertex::GetAttributes(), .m_Stride = sizeof(Vertex), }}, .m_Shaders = {{ .m_ShaderFile = SHADER_MODULE, .m_EntryPoints = {"vsmain", "fsmain"}, }}, }); ERROR_IF(pipelineError, "Error creating pipeline. Cause: {}", pipelineError.What()); // eastl::array vertices{}; eastl::array vertices = { Vertex{.m_Position = {-0.5f, -0.5f, 0.0f}, .m_Color = {1.0f, 0.0f, 0.0f}}, Vertex{.m_Position = {0.5f, -0.5f, 0.0f}, .m_Color = {0.0f, 1.0f, 0.0f}}, Vertex{.m_Position = {0.0f, 0.5f, 0.0f}, .m_Color = {0.0f, 0.0f, 1.0f}}, }; auto vbo = device.CreateVertexBuffer(vertices.size() * sizeof vertices[0], "VBO"); vbo->Write(0, vertices.size() * sizeof vertices[0], vertices.data()); // Persistent variables vk::ImageSubresourceRange subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1, }; vk::ImageMemoryBarrier2 topOfThePipeBarrier = { .srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, .srcAccessMask = vk::AccessFlagBits2::eNone, .dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, .dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eColorAttachmentOptimal, .srcQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored, .subresourceRange = subresourceRange, }; vk::DependencyInfo topOfThePipeDependency = { .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &topOfThePipeBarrier, }; vk::ImageMemoryBarrier2 renderToPresentBarrier = { .srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, .srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, .dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe, .dstAccessMask = vk::AccessFlagBits2::eNone, .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, .newLayout = vk::ImageLayout::ePresentSrcKHR, .srcQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored, .subresourceRange = subresourceRange, }; vk::DependencyInfo renderToPresentDependency = { .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &renderToPresentBarrier, }; INFO("Starting loop"); while (window.Poll()) { systems::Frame ¤tFrame = device.GetNextFrame(); Size2D swapchainSize = currentFrame.m_SwapchainSize; vk::Viewport viewport = { .x = 0, .y = Cast(swapchainSize.m_Height), .width = Cast(swapchainSize.m_Width), .height = -Cast(swapchainSize.m_Height), .minDepth = 0.0, .maxDepth = 1.0, }; vk::Rect2D scissor = { .offset = {0, 0}, .extent = Cast(swapchainSize), }; auto context = currentFrame.CreateGraphicsContext(); topOfThePipeBarrier.image = currentFrame.m_SwapchainImage; renderToPresentBarrier.image = currentFrame.m_SwapchainImage; context.Begin(); context.Dependency(topOfThePipeDependency); // Render vk::RenderingAttachmentInfo attachmentInfo = { .imageView = currentFrame.m_SwapchainImageView, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .resolveMode = vk::ResolveModeFlagBits::eNone, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f}, }; vk::RenderingInfo renderingInfo = { .renderArea = scissor, .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, }; context.BeginRendering(renderingInfo); context.SetViewport(viewport); context.BindPipeline(pipeline); context.BindVertexBuffer(vbo); context.Draw(3); context.EndRendering(); context.Dependency(renderToPresentDependency); context.End(); device.Submit(currentFrame, context); device.Present(currentFrame); } device.WaitIdle(); return 0; }