Triangle rendered to screen.
This commit is contained in:
parent
c6ff2f4f76
commit
eaf4556bad
|
|
@ -10,10 +10,13 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "/W4 /GR- /Zi")
|
set(CMAKE_CXX_FLAGS "/W4 /GR- /Zi")
|
||||||
add_compile_definitions(_NO_EXCEPTIONS=1)
|
add_compile_definitions(_HAS_EXCEPTIONS=1)
|
||||||
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
else ()
|
else ()
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions")
|
set(CMAKE_CXX_FLAGS "-Wall -fno-rtti -fno-exceptions")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
include(add_shader.cmake)
|
||||||
|
|
||||||
add_subdirectory("aster")
|
add_subdirectory("aster")
|
||||||
add_subdirectory("triangle")
|
add_subdirectory("triangle")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
function(add_shader TARGET SHADER)
|
||||||
|
find_package(Vulkan REQUIRED COMPONENTS dxc)
|
||||||
|
|
||||||
|
get_filename_component(shader-ext ${SHADER} LAST_EXT)
|
||||||
|
|
||||||
|
set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
|
||||||
|
set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv)
|
||||||
|
|
||||||
|
get_filename_component(current-output-dir ${current-output-path} DIRECTORY)
|
||||||
|
file(MAKE_DIRECTORY ${current-output-dir})
|
||||||
|
|
||||||
|
if (Vulkan_dxc_exe_FOUND AND ${shader-ext} STREQUAL ".hlsl")
|
||||||
|
message("Marked as hlsl file. ${current-output-path}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${current-output-path}
|
||||||
|
COMMAND Vulkan::dxc_exe -spirv -T vs_6_0 -E main ${current-shader-path} -Fo ${current-output-path}
|
||||||
|
DEPENDS ${current-shader-path}
|
||||||
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
|
VERBATIM)
|
||||||
|
elseif (Vulkan_glslc_FOUND AND ${shader-ext} STREQUAL ".glsl")
|
||||||
|
message("Marked as glsl file. ${current-output-path}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${current-output-path}
|
||||||
|
COMMAND Vulkan::glslc -o ${current-output-path} ${current-shader-path}
|
||||||
|
DEPENDS ${current-shader-path}
|
||||||
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
|
VERBATIM)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Make sure our build depends on this output.
|
||||||
|
set_source_files_properties(${current-output-path} PROPERTIES GENERATED TRUE)
|
||||||
|
target_sources(${TARGET} PRIVATE ${current-output-path})
|
||||||
|
endfunction(add_shader)
|
||||||
|
|
@ -64,6 +64,8 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features
|
||||||
THEN_ABORT(result)
|
THEN_ABORT(result)
|
||||||
ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data());
|
ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data());
|
||||||
|
|
||||||
|
SetName(m_Device, m_Name.data());
|
||||||
|
|
||||||
VmaVulkanFunctions vmaVulkanFunctions = {
|
VmaVulkanFunctions vmaVulkanFunctions = {
|
||||||
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
||||||
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
|
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
|
||||||
|
|
|
||||||
|
|
@ -37,5 +37,24 @@ struct Device final
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
||||||
~Device();
|
~Device();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires vk::isVulkanHandleType<T>::value
|
||||||
|
void SetName(const T &object, cstr name) const;
|
||||||
[[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const;
|
[[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires vk::isVulkanHandleType<T>::value
|
||||||
|
void
|
||||||
|
Device::SetName(const T &object, cstr name) const
|
||||||
|
{
|
||||||
|
auto handle = Recast<u64>(Cast<typename T::NativeType>(object));
|
||||||
|
const vk::DebugUtilsObjectNameInfoEXT objectNameInfo = {
|
||||||
|
.objectType = object.objectType,
|
||||||
|
.objectHandle = handle,
|
||||||
|
.pObjectName = name,
|
||||||
|
};
|
||||||
|
vk::Result result = m_Device.setDebugUtilsObjectNameEXT(&objectNameInfo);
|
||||||
|
WARN_IF(Failed(result), "Could not name {:x}: {} as {}. Cause: {}", handle, to_string(object.objectType), name,
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ constexpr u32 ASTER_API_VERSION = vk::ApiVersion13;
|
||||||
|
|
||||||
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
||||||
|
|
||||||
|
#define FORCE_TODO static_assert(false)
|
||||||
|
|
||||||
[[nodiscard]] inline bool
|
[[nodiscard]] inline bool
|
||||||
Failed(const vk::Result result)
|
Failed(const vk::Result result)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Swapchain::Swapchain(const Window *window, const Device *device, NameString &&na
|
||||||
|
|
||||||
Swapchain::~Swapchain()
|
Swapchain::~Swapchain()
|
||||||
{
|
{
|
||||||
Cleanup();
|
this->Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -28,21 +28,21 @@ Swapchain::Create(const Window *window)
|
||||||
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
|
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
|
||||||
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
|
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
|
||||||
|
|
||||||
vk::Format swapchainFormat = vk::Format::eUndefined;
|
m_Format = vk::Format::eUndefined;
|
||||||
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
|
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
|
||||||
for (auto [format, colorSpace] : surfaceFormats)
|
for (auto [format, colorSpace] : surfaceFormats)
|
||||||
{
|
{
|
||||||
if (format == vk::Format::eB8G8R8A8Srgb && colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
|
if (format == vk::Format::eB8G8R8A8Srgb && colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
|
||||||
{
|
{
|
||||||
swapchainFormat = format;
|
m_Format = format;
|
||||||
swapchainColorSpace = colorSpace;
|
swapchainColorSpace = colorSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (swapchainFormat == vk::Format::eUndefined)
|
if (m_Format == vk::Format::eUndefined)
|
||||||
{
|
{
|
||||||
WARN("Preferred Swapchain format not found. Falling back.");
|
WARN("Preferred Swapchain format not found. Falling back.");
|
||||||
auto [format, colorSpace] = surfaceFormats.front();
|
auto [format, colorSpace] = surfaceFormats.front();
|
||||||
swapchainFormat = format;
|
m_Format = format;
|
||||||
swapchainColorSpace = colorSpace;
|
swapchainColorSpace = colorSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +82,7 @@ Swapchain::Create(const Window *window)
|
||||||
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
|
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
|
||||||
.surface = window->m_Surface,
|
.surface = window->m_Surface,
|
||||||
.minImageCount = swapchainImageCount,
|
.minImageCount = swapchainImageCount,
|
||||||
.imageFormat = swapchainFormat,
|
.imageFormat = m_Format,
|
||||||
.imageColorSpace = swapchainColorSpace,
|
.imageColorSpace = swapchainColorSpace,
|
||||||
.imageExtent = m_Extent,
|
.imageExtent = m_Extent,
|
||||||
.imageArrayLayers = 1,
|
.imageArrayLayers = 1,
|
||||||
|
|
@ -108,6 +108,8 @@ Swapchain::Create(const Window *window)
|
||||||
|
|
||||||
m_Swapchain = swapchain;
|
m_Swapchain = swapchain;
|
||||||
|
|
||||||
|
m_Device->SetName(m_Swapchain, m_Name.data());
|
||||||
|
|
||||||
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
||||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
@ -120,7 +122,7 @@ Swapchain::Create(const Window *window)
|
||||||
|
|
||||||
vk::ImageViewCreateInfo viewCreateInfo = {
|
vk::ImageViewCreateInfo viewCreateInfo = {
|
||||||
.viewType = vk::ImageViewType::e2D,
|
.viewType = vk::ImageViewType::e2D,
|
||||||
.format = swapchainFormat,
|
.format = m_Format,
|
||||||
.components = {.r = vk::ComponentSwizzle::eIdentity,
|
.components = {.r = vk::ComponentSwizzle::eIdentity,
|
||||||
.g = vk::ComponentSwizzle::eIdentity,
|
.g = vk::ComponentSwizzle::eIdentity,
|
||||||
.b = vk::ComponentSwizzle::eIdentity,
|
.b = vk::ComponentSwizzle::eIdentity,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ struct Swapchain final
|
||||||
vk::SwapchainKHR m_Swapchain;
|
vk::SwapchainKHR m_Swapchain;
|
||||||
NameString m_Name;
|
NameString m_Name;
|
||||||
vk::Extent2D m_Extent;
|
vk::Extent2D m_Extent;
|
||||||
|
vk::Format m_Format;
|
||||||
eastl::fixed_vector<vk::Image, 4> m_Images;
|
eastl::fixed_vector<vk::Image, 4> m_Images;
|
||||||
eastl::fixed_vector<vk::ImageView, 4> m_ImageViews;
|
eastl::fixed_vector<vk::ImageView, 4> m_ImageViews;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,7 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
add_executable(triangle "triangle.cpp")
|
add_executable(triangle "triangle.cpp")
|
||||||
add_dependencies(triangle aster_core)
|
add_dependencies(triangle aster_core)
|
||||||
|
|
||||||
|
add_shader(triangle shader/triangle.vs.hlsl)
|
||||||
|
add_shader(triangle shader/white.frag.glsl)
|
||||||
|
|
||||||
target_link_libraries(triangle PRIVATE aster_core)
|
target_link_libraries(triangle PRIVATE aster_core)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
struct VSIn {
|
||||||
|
int idx : SV_VERTEXID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSOut
|
||||||
|
{
|
||||||
|
float4 Pos : SV_POSITION;
|
||||||
|
[[vk::location(0)]] float3 Color : COLOR0;
|
||||||
|
};
|
||||||
|
|
||||||
|
VSOut main(VSIn input) {
|
||||||
|
float3 points[] = {
|
||||||
|
float3(-0.5f, -0.5f, 0.0f),
|
||||||
|
float3(0.5f, -0.5f, 0.0f),
|
||||||
|
float3(0.0f, 0.5f, 0.0f)
|
||||||
|
};
|
||||||
|
float3 colors[] = {
|
||||||
|
float3( 1.0f, 0.0f, 0.0f ),
|
||||||
|
float3( 0.0f, 1.0f, 0.0f ),
|
||||||
|
float3( 0.0f, 0.0f, 1.0f ),
|
||||||
|
};
|
||||||
|
|
||||||
|
VSOut output;
|
||||||
|
output.Pos = float4(points[input.idx], 1.0f);
|
||||||
|
output.Color = colors[input.idx];
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 450
|
||||||
|
#pragma shader_stage(fragment)
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 inColor;
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(inColor, 1.0);
|
||||||
|
}
|
||||||
|
|
@ -9,14 +9,15 @@
|
||||||
#include "aster/swapchain.h"
|
#include "aster/swapchain.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
|
||||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
|
|
||||||
bool IsSuitableDevice(const PhysicalDevice *physicalDevice);
|
bool IsSuitableDevice(const PhysicalDevice *physicalDevice);
|
||||||
|
|
||||||
PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices);
|
PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices);
|
||||||
|
|
||||||
QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice);
|
QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice);
|
||||||
|
eastl::optional<eastl::vector<u32>> ReadFile(cstr fileName);
|
||||||
|
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||||
|
|
||||||
struct Frame
|
struct Frame
|
||||||
{
|
{
|
||||||
|
|
@ -29,14 +30,19 @@ struct Frame
|
||||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||||
~Frame();
|
~Frame();
|
||||||
|
|
||||||
u32 BeginFrame(const Swapchain *swapchain, u32 frameIndex) const;
|
|
||||||
[[nodiscard]] vk::CommandBuffer AllocateCommandBuffer() const;
|
[[nodiscard]] vk::CommandBuffer AllocateCommandBuffer() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Shader
|
||||||
|
{
|
||||||
|
vk::ShaderModule m_ShaderModule;
|
||||||
|
vk::ShaderStageFlags m_Stage;
|
||||||
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int, char **)
|
main(int, char **)
|
||||||
{
|
{
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eVerbose);
|
||||||
|
|
||||||
GlfwContext glfwContext = {};
|
GlfwContext glfwContext = {};
|
||||||
Context context = {"Aster", VERSION};
|
Context context = {"Aster", VERSION};
|
||||||
|
|
@ -55,17 +61,177 @@ main(int, char **)
|
||||||
|
|
||||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||||
|
|
||||||
|
auto vertexShaderModule = CreateShader(&device, "shader/triangle.vs.hlsl.spv");
|
||||||
|
auto fragmentShaderModule = CreateShader(&device, "shader/white.frag.glsl.spv");
|
||||||
|
|
||||||
|
eastl::array<vk::PipelineShaderStageCreateInfo, 2> shaderStages = {{
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
.module = vertexShaderModule,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
.module = fragmentShaderModule,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
.setLayoutCount = 0,
|
||||||
|
.pSetLayouts = nullptr,
|
||||||
|
.pushConstantRangeCount = 0,
|
||||||
|
.pPushConstantRanges = nullptr,
|
||||||
|
};
|
||||||
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
vk::Result result = device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
||||||
|
ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result);
|
||||||
|
device.SetName(pipelineLayout, "Triangle Layout");
|
||||||
|
|
||||||
|
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
|
||||||
|
.vertexBindingDescriptionCount = 0,
|
||||||
|
.pVertexBindingDescriptions = nullptr,
|
||||||
|
.vertexAttributeDescriptionCount = 0,
|
||||||
|
.pVertexAttributeDescriptions = nullptr,
|
||||||
|
};
|
||||||
|
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||||
|
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||||
|
.primitiveRestartEnable = vk::False,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = {
|
||||||
|
.viewportCount = 1,
|
||||||
|
.scissorCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
|
||||||
|
.depthClampEnable = vk::False,
|
||||||
|
.rasterizerDiscardEnable = vk::False,
|
||||||
|
.polygonMode = vk::PolygonMode::eFill,
|
||||||
|
.cullMode = vk::CullModeFlagBits::eNone,
|
||||||
|
.frontFace = vk::FrontFace::eCounterClockwise,
|
||||||
|
.depthBiasEnable = vk::False,
|
||||||
|
.lineWidth = 1.0,
|
||||||
|
};
|
||||||
|
vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
|
||||||
|
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
||||||
|
.sampleShadingEnable = vk::False,
|
||||||
|
};
|
||||||
|
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
||||||
|
.depthTestEnable = vk::False,
|
||||||
|
.depthWriteEnable = vk::False,
|
||||||
|
};
|
||||||
|
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
||||||
|
.blendEnable = vk::False,
|
||||||
|
.srcColorBlendFactor = vk::BlendFactor::eSrcColor,
|
||||||
|
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor,
|
||||||
|
.colorBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha,
|
||||||
|
.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
|
||||||
|
.alphaBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||||
|
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||||
|
};
|
||||||
|
vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
|
||||||
|
.logicOpEnable = vk::False,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &colorBlendAttachmentState,
|
||||||
|
};
|
||||||
|
|
||||||
|
eastl::array dynamicStates = {
|
||||||
|
vk::DynamicState::eScissor,
|
||||||
|
vk::DynamicState::eViewport,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
|
||||||
|
.dynamicStateCount = Cast<u32>(dynamicStates.size()),
|
||||||
|
.pDynamicStates = dynamicStates.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineRenderingCreateInfo renderingCreateInfo = {
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachmentFormats = &swapchain.m_Format,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||||
|
.pNext = &renderingCreateInfo,
|
||||||
|
.stageCount = Cast<u32>(shaderStages.size()),
|
||||||
|
.pStages = shaderStages.data(),
|
||||||
|
.pVertexInputState = &vertexInputStateCreateInfo,
|
||||||
|
.pInputAssemblyState = &inputAssemblyStateCreateInfo,
|
||||||
|
.pViewportState = &viewportStateCreateInfo,
|
||||||
|
.pRasterizationState = &rasterizationStateCreateInfo,
|
||||||
|
.pMultisampleState = &multisampleStateCreateInfo,
|
||||||
|
.pDepthStencilState = &depthStencilStateCreateInfo,
|
||||||
|
.pColorBlendState = &colorBlendStateCreateInfo,
|
||||||
|
.pDynamicState = &dynamicStateCreateInfo,
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
};
|
||||||
|
vk::Pipeline pipeline;
|
||||||
|
result = device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
||||||
|
ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result) THEN_ABORT(result);
|
||||||
|
device.SetName(pipelineLayout, "Triangle Pipeline");
|
||||||
|
|
||||||
|
// Frames
|
||||||
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
||||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||||
{
|
{
|
||||||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vk::Viewport viewport = {
|
||||||
|
.x = 0,
|
||||||
|
.y = Cast<f32>(swapchain.m_Extent.height),
|
||||||
|
.width = Cast<f32>(swapchain.m_Extent.width),
|
||||||
|
.height = -Cast<f32>(swapchain.m_Extent.height),
|
||||||
|
.minDepth = 0.0,
|
||||||
|
.maxDepth = 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::Rect2D scissor = {
|
||||||
|
.offset = {0, 0},
|
||||||
|
.extent = swapchain.m_Extent,
|
||||||
|
};
|
||||||
|
|
||||||
u32 frameIndex = 0;
|
u32 frameIndex = 0;
|
||||||
while (window.Poll())
|
while (window.Poll())
|
||||||
{
|
{
|
||||||
Frame *currentFrame = &frames[frameIndex];
|
Frame *currentFrame = &frames[frameIndex];
|
||||||
u32 imageIndex = currentFrame->BeginFrame(&swapchain, frameIndex);
|
|
||||||
|
result = device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, vk::True, MaxValue<u64>);
|
||||||
|
ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
u32 imageIndex;
|
||||||
|
result = device.m_Device.acquireNextImageKHR(swapchain.m_Swapchain, MaxValue<u64>,
|
||||||
|
currentFrame->m_ImageAcquireSem, nullptr, &imageIndex);
|
||||||
|
if (Failed(result))
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
|
case vk::Result::eSuboptimalKHR:
|
||||||
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
|
swapchain.Create(&window);
|
||||||
|
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||||
|
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
scissor.extent = swapchain.m_Extent;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Waiting for swapchain image {} failed. Cause: {}", frameIndex, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence);
|
||||||
|
ERROR_IF(Failed(result), "Fence {} reset failed. Cause: {}", frameIndex, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
result = device.m_Device.resetCommandPool(currentFrame->m_Pool, {});
|
||||||
|
ERROR_IF(Failed(result), "Command pool {} reset failed. Cause: {}", frameIndex, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||||
|
|
@ -103,7 +269,7 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
vk::Result result = cmd.begin(&beginInfo);
|
result = cmd.begin(&beginInfo);
|
||||||
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
|
@ -115,13 +281,13 @@ main(int, char **)
|
||||||
.imageView = currentImageView,
|
.imageView = currentImageView,
|
||||||
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eLoad,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::RenderingInfo renderingInfo = {
|
vk::RenderingInfo renderingInfo = {
|
||||||
.renderArea = {.offset = {0, 0}, .extent = swapchain.m_Extent},
|
.renderArea = {.extent = swapchain.m_Extent},
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
.colorAttachmentCount = 1,
|
.colorAttachmentCount = 1,
|
||||||
.pColorAttachments = &attachmentInfo,
|
.pColorAttachments = &attachmentInfo,
|
||||||
|
|
@ -129,6 +295,11 @@ main(int, char **)
|
||||||
|
|
||||||
cmd.beginRendering(&renderingInfo);
|
cmd.beginRendering(&renderingInfo);
|
||||||
|
|
||||||
|
cmd.setViewport(0, 1, &viewport);
|
||||||
|
cmd.setScissor(0, 1, &scissor);
|
||||||
|
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
||||||
|
cmd.draw(3, 1, 0, 0);
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||||
|
|
@ -169,6 +340,10 @@ main(int, char **)
|
||||||
case vk::Result::eSuboptimalKHR:
|
case vk::Result::eSuboptimalKHR:
|
||||||
INFO("Recreating Swapchain. Cause: {}", result);
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
swapchain.Create(&window);
|
swapchain.Create(&window);
|
||||||
|
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||||
|
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
scissor.extent = swapchain.m_Extent;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("Command queue present failed. Cause: {}", result)
|
ERROR("Command queue present failed. Cause: {}", result)
|
||||||
|
|
@ -178,6 +353,14 @@ main(int, char **)
|
||||||
frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = device.m_Device.waitIdle();
|
||||||
|
ERROR_IF(Failed(result), "Wait idle failed. Cause: {}", result);
|
||||||
|
|
||||||
|
device.m_Device.destroy(pipeline, nullptr);
|
||||||
|
device.m_Device.destroy(pipelineLayout, nullptr);
|
||||||
|
device.m_Device.destroy(vertexShaderModule, nullptr);
|
||||||
|
device.m_Device.destroy(fragmentShaderModule, nullptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,6 +399,32 @@ FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice)
|
||||||
ERROR("No suitable queue family on the GPU.")
|
ERROR("No suitable queue family on the GPU.")
|
||||||
THEN_ABORT(vk::Result::eErrorUnknown);
|
THEN_ABORT(vk::Result::eErrorUnknown);
|
||||||
}
|
}
|
||||||
|
eastl::optional<eastl::vector<u32>>
|
||||||
|
ReadFile(cstr fileName)
|
||||||
|
{
|
||||||
|
FILE *filePtr = fopen(fileName, "rb");
|
||||||
|
|
||||||
|
if (!filePtr)
|
||||||
|
{
|
||||||
|
ERROR("Invalid read of {}", fileName);
|
||||||
|
return eastl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<u32> outputVec;
|
||||||
|
eastl::array<u32, 1024> buffer{};
|
||||||
|
usize totalRead = 0;
|
||||||
|
usize readCount;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
readCount = fread(buffer.data(), sizeof(u32), buffer.size(), filePtr);
|
||||||
|
const auto nextSize = totalRead + readCount;
|
||||||
|
outputVec.resize(nextSize);
|
||||||
|
memcpy(outputVec.data() + totalRead, buffer.data(), readCount * sizeof *buffer.data());
|
||||||
|
totalRead = nextSize;
|
||||||
|
} while (readCount == 1024);
|
||||||
|
|
||||||
|
return outputVec;
|
||||||
|
}
|
||||||
|
|
||||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||||
{
|
{
|
||||||
|
|
@ -245,31 +454,6 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo
|
||||||
DEBUG("Frame {} created successfully.", frameCount);
|
DEBUG("Frame {} created successfully.", frameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
|
||||||
Frame::BeginFrame(const Swapchain *swapchain, u32 frameIndex) const
|
|
||||||
{
|
|
||||||
const auto device = m_Device->m_Device;
|
|
||||||
|
|
||||||
vk::Result result = device.waitForFences(1, &m_FrameAvailableFence, VK_TRUE, MaxValue<u64>);
|
|
||||||
ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
u32 imageIndex;
|
|
||||||
result = device.acquireNextImageKHR(swapchain->m_Swapchain, MaxValue<u64>, m_ImageAcquireSem, nullptr, &imageIndex);
|
|
||||||
ERROR_IF(Failed(result), "Waiting for swapchain image {} failed. Cause: {}", frameIndex, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
// TODO: Deliberate failure on recreation. Will recreate later.
|
|
||||||
|
|
||||||
result = device.resetFences(1, &m_FrameAvailableFence);
|
|
||||||
ERROR_IF(Failed(result), "Fence {} reset failed. Cause: {}", frameIndex, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
result = device.resetCommandPool(m_Pool, {});
|
|
||||||
ERROR_IF(Failed(result), "Command pool {} reset failed. Cause: {}", frameIndex, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
return imageIndex;
|
|
||||||
}
|
|
||||||
vk::CommandBuffer
|
vk::CommandBuffer
|
||||||
Frame::AllocateCommandBuffer() const
|
Frame::AllocateCommandBuffer() const
|
||||||
{
|
{
|
||||||
|
|
@ -284,10 +468,33 @@ Frame::AllocateCommandBuffer() const
|
||||||
return commandBuffer;
|
return commandBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vk::ShaderModule
|
||||||
|
CreateShader(const Device *device, cstr shaderFile)
|
||||||
|
{
|
||||||
|
eastl::vector<u32> shaderCode;
|
||||||
|
if (auto res = ReadFile(shaderFile))
|
||||||
|
{
|
||||||
|
shaderCode = res.value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("Could not open {}.", shaderFile) THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = {
|
||||||
|
.codeSize = shaderCode.size() * sizeof(u32),
|
||||||
|
.pCode = shaderCode.data(),
|
||||||
|
};
|
||||||
|
vk::ShaderModule shaderModule;
|
||||||
|
|
||||||
|
vk::Result result = device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule);
|
||||||
|
ERROR_IF(Failed(result), "Shader {} could not be created. Cause: {}", shaderFile, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
Frame::~Frame()
|
Frame::~Frame()
|
||||||
{
|
{
|
||||||
auto result = m_Device->m_Device.waitIdle();
|
|
||||||
ERROR_IF(Failed(result), "Wait idle failed. Cause: {}", result);
|
|
||||||
m_Device->m_Device.destroy(m_RenderFinishSem, nullptr);
|
m_Device->m_Device.destroy(m_RenderFinishSem, nullptr);
|
||||||
m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr);
|
m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr);
|
||||||
m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);
|
m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue