Added slang for Shader code compilation.
TODO: Use slang to create descriptors.
This commit is contained in:
parent
7507394af9
commit
5d6ddbb158
|
|
@ -5,3 +5,4 @@ build/
|
||||||
.direnv/
|
.direnv/
|
||||||
.ccls-cache/
|
.ccls-cache/
|
||||||
*.user
|
*.user
|
||||||
|
/vcpkg_installed
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
project(Aster VERSION 0.1.0)
|
project(Aster VERSION 0.1.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS} /utf-8")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "/O3")
|
set(CMAKE_CXX_FLAGS_RELEASE "/O3")
|
||||||
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
function(add_shader TARGET SHADER)
|
function(add_shader TARGET SHADER)
|
||||||
find_package(Vulkan REQUIRED COMPONENTS dxc)
|
find_package(Vulkan REQUIRED COMPONENTS dxc)
|
||||||
|
|
||||||
|
get_filename_component(vulkan-bin-dir ${Vulkan_GLSLC_EXECUTABLE} DIRECTORY)
|
||||||
|
|
||||||
|
find_program(slangc_exe NAMES "slangc")
|
||||||
|
if (NOT slangc_exe STREQUAL "slangc_exe-NOTFOUND")
|
||||||
|
set(slangc_exe_FOUND true)
|
||||||
|
endif()
|
||||||
|
|
||||||
get_filename_component(shader-ext ${SHADER} LAST_EXT)
|
get_filename_component(shader-ext ${SHADER} LAST_EXT)
|
||||||
get_filename_component(shader-inner ${SHADER} NAME_WLE)
|
|
||||||
get_filename_component(shader-type ${shader-inner} LAST_EXT)
|
|
||||||
string(REPLACE "." "" shader-type ${shader-type})
|
|
||||||
|
|
||||||
set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
|
set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
|
||||||
set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv)
|
set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv)
|
||||||
|
|
@ -14,6 +18,11 @@ function(add_shader TARGET SHADER)
|
||||||
|
|
||||||
if (Vulkan_dxc_exe_FOUND AND ${shader-ext} STREQUAL ".hlsl")
|
if (Vulkan_dxc_exe_FOUND AND ${shader-ext} STREQUAL ".hlsl")
|
||||||
message("Marked as hlsl file. ${current-output-path}")
|
message("Marked as hlsl file. ${current-output-path}")
|
||||||
|
|
||||||
|
get_filename_component(shader-inner ${SHADER} NAME_WLE)
|
||||||
|
get_filename_component(shader-type ${shader-inner} LAST_EXT)
|
||||||
|
string(REPLACE "." "" shader-type ${shader-type})
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${current-output-path}
|
OUTPUT ${current-output-path}
|
||||||
COMMAND Vulkan::dxc_exe ${DXC_SHADER_FLAGS} -spirv -T "${shader-type}_6_0" -E main ${current-shader-path} -Fo ${current-output-path}
|
COMMAND Vulkan::dxc_exe ${DXC_SHADER_FLAGS} -spirv -T "${shader-type}_6_0" -E main ${current-shader-path} -Fo ${current-output-path}
|
||||||
|
|
@ -28,6 +37,14 @@ function(add_shader TARGET SHADER)
|
||||||
DEPENDS ${current-shader-path}
|
DEPENDS ${current-shader-path}
|
||||||
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
elseif (${shader-ext} STREQUAL ".slang")
|
||||||
|
message("Marked as slang file. ${current-output-path}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${current-output-path}
|
||||||
|
COMMAND ${slangc_exe} -target spirv -o ${current-output-path} ${current-shader-path}
|
||||||
|
DEPENDS ${current-shader-path}
|
||||||
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
|
VERBATIM)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Make sure our build depends on this output.
|
# Make sure our build depends on this output.
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,14 @@ find_package(Vulkan REQUIRED)
|
||||||
find_package(fmt CONFIG REQUIRED)
|
find_package(fmt CONFIG REQUIRED)
|
||||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
find_package(EASTL CONFIG REQUIRED)
|
find_package(EASTL CONFIG REQUIRED)
|
||||||
|
find_library(slang NAMES "slang" CONFIG REQUIRED)
|
||||||
|
|
||||||
add_library(aster_core STATIC)
|
add_library(aster_core STATIC)
|
||||||
|
|
||||||
add_subdirectory("include")
|
add_subdirectory("include")
|
||||||
add_subdirectory("src")
|
add_subdirectory("src")
|
||||||
|
|
||||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
target_compile_features(aster_core PUBLIC cxx_std_23)
|
||||||
|
|
||||||
target_include_directories(aster_core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/aster")
|
target_include_directories(aster_core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/aster")
|
||||||
target_include_directories(aster_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
target_include_directories(aster_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
|
@ -26,4 +27,5 @@ target_include_directories(aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS})
|
||||||
target_link_libraries(aster_core PRIVATE fmt::fmt)
|
target_link_libraries(aster_core PRIVATE fmt::fmt)
|
||||||
target_link_libraries(aster_core PRIVATE EASTL)
|
target_link_libraries(aster_core PRIVATE EASTL)
|
||||||
target_link_libraries(aster_core PUBLIC Vulkan::Headers GPUOpen::VulkanMemoryAllocator)
|
target_link_libraries(aster_core PUBLIC Vulkan::Headers GPUOpen::VulkanMemoryAllocator)
|
||||||
|
target_link_libraries(aster_core PUBLIC ${slang})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||||
format(vk::Result result, format_context &ctx) const
|
format(vk::Result result, format_context &ctx) const
|
||||||
{
|
{
|
||||||
return write_padded(ctx,
|
return write_padded(ctx,
|
||||||
[this, result](auto out) { return v10::format_to(out, "{}", nested(to_string(result))); });
|
[this, result](auto out) { return v11::format_to(out, "{}", nested(to_string(result))); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -240,7 +240,7 @@ struct fmt::formatter<eastl::fixed_string<TType, TCount, TOverflow>> : nested_fo
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable once CppInconsistentNaming
|
||||||
format(const eastl::fixed_string<TType, TCount, TOverflow> &str, format_context &ctx) const
|
format(const eastl::fixed_string<TType, TCount, TOverflow> &str, format_context &ctx) const
|
||||||
{
|
{
|
||||||
return write_padded(ctx, [this, str](auto out) { return v10::format_to(out, "{}", nested(str.c_str())); });
|
return write_padded(ctx, [this, str](auto out) { return v11::format_to(out, "{}", nested(str.c_str())); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,30 @@ struct Pipeline
|
||||||
vk::Pipeline m_Pipeline;
|
vk::Pipeline m_Pipeline;
|
||||||
eastl::vector<vk::DescriptorSetLayout> m_SetLayouts;
|
eastl::vector<vk::DescriptorSetLayout> m_SetLayouts;
|
||||||
|
|
||||||
|
Pipeline() = default;
|
||||||
Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
||||||
eastl::vector<vk::DescriptorSetLayout> &&setLayouts);
|
eastl::vector<vk::DescriptorSetLayout> &&setLayouts);
|
||||||
~Pipeline();
|
~Pipeline();
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Pipeline);
|
||||||
|
|
||||||
|
Pipeline(Pipeline &&other) noexcept
|
||||||
|
: m_Device{other.m_Device},
|
||||||
|
m_Layout{Take(other.m_Layout)},
|
||||||
|
m_Pipeline{Take(other.m_Pipeline)},
|
||||||
|
m_SetLayouts{std::move(other.m_SetLayouts)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline &
|
||||||
|
operator=(Pipeline &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
m_Device = other.m_Device;
|
||||||
|
m_Layout = Take(other.m_Layout);
|
||||||
|
m_Pipeline = Take(other.m_Pipeline);
|
||||||
|
m_SetLayouts = std::move(other.m_SetLayouts);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -20,7 +20,10 @@
|
||||||
#include <EASTL/optional.h>
|
#include <EASTL/optional.h>
|
||||||
#include <EASTL/vector_map.h>
|
#include <EASTL/vector_map.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <slang-com-ptr.h>
|
||||||
|
#include <slang.h>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
constexpr static u32 MAX_FRAMES_IN_FLIGHT = 3;
|
constexpr static u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
|
|
||||||
|
|
@ -225,6 +228,59 @@ struct SamplerCreateInfo
|
||||||
#pragma region Pipeline
|
#pragma region Pipeline
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct PipelineCreationError
|
||||||
|
{
|
||||||
|
enum class Kind
|
||||||
|
{
|
||||||
|
eNone,
|
||||||
|
eVulkan,
|
||||||
|
eSlang,
|
||||||
|
} m_Kind;
|
||||||
|
union {
|
||||||
|
u32 uNone;
|
||||||
|
vk::Result uVulkanResult;
|
||||||
|
SlangResult uSlangResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return m_Kind != Kind::eNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
What()
|
||||||
|
{
|
||||||
|
switch (m_Kind)
|
||||||
|
{
|
||||||
|
case Kind::eNone:
|
||||||
|
return "No Error";
|
||||||
|
case Kind::eVulkan:
|
||||||
|
return fmt::format("{}", uVulkanResult);
|
||||||
|
case Kind::eSlang:
|
||||||
|
return fmt::format("{}", uSlangResult);
|
||||||
|
}
|
||||||
|
return "No Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineCreationError()
|
||||||
|
: m_Kind{Kind::eNone}
|
||||||
|
, uNone{}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineCreationError(vk::Result result)
|
||||||
|
: m_Kind{Kind::eVulkan}
|
||||||
|
, uVulkanResult{result}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineCreationError(SlangResult result)
|
||||||
|
: m_Kind{Kind::eSlang}
|
||||||
|
, uSlangResult{result}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct AttributeInfo
|
struct AttributeInfo
|
||||||
{
|
{
|
||||||
u32 m_Location;
|
u32 m_Location;
|
||||||
|
|
@ -262,23 +318,34 @@ struct VertexInput
|
||||||
bool m_IsPerInstance;
|
bool m_IsPerInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsShaderModuleInfo
|
enum class ShaderType
|
||||||
|
{
|
||||||
|
eInvalid = 0,
|
||||||
|
eVertex = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
eTesselationControl = vk::ShaderStageFlagBits::eTessellationControl,
|
||||||
|
eTesselationEvaluation = vk::ShaderStageFlagBits::eTessellationEvaluation,
|
||||||
|
eGeometry = vk::ShaderStageFlagBits::eGeometry,
|
||||||
|
eFragment = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
eCompute = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
eTask = vk::ShaderStageFlagBits::eTaskEXT,
|
||||||
|
eMesh = vk::ShaderStageFlagBits::eMeshEXT,
|
||||||
|
eMax,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr static u32 ShaderTypeCount = 8;
|
||||||
|
|
||||||
|
static_assert(Cast<u32>(ShaderType::eMax) == 1 + (1 << (ShaderTypeCount - 1)));
|
||||||
|
|
||||||
|
struct ShaderInfo
|
||||||
{
|
{
|
||||||
std::string_view m_ShaderFile;
|
std::string_view m_ShaderFile;
|
||||||
std::string_view m_EntryPoint;
|
eastl::vector<std::string_view> m_EntryPoints;
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
eVertex = vk::ShaderStageFlagBits::eVertex,
|
|
||||||
eFragment = vk::ShaderStageFlagBits::eFragment,
|
|
||||||
eTesselationControl = vk::ShaderStageFlagBits::eTessellationControl,
|
|
||||||
eTesselationEvaluation = vk::ShaderStageFlagBits::eTessellationEvaluation,
|
|
||||||
} m_Type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsPipelineCreateInfo
|
struct GraphicsPipelineCreateInfo
|
||||||
{
|
{
|
||||||
eastl::fixed_vector<VertexInput, 4, false> m_VertexInputs;
|
eastl::fixed_vector<VertexInput, 4, false> m_VertexInputs;
|
||||||
eastl::fixed_vector<GraphicsShaderModuleInfo, 4, false> m_ShaderModules;
|
eastl::fixed_vector<ShaderInfo, 4, false> m_Shaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -294,13 +361,14 @@ static_assert(std::convertible_to<decltype(DefaultPhysicalDeviceSelector), Physi
|
||||||
|
|
||||||
struct DeviceCreateInfo
|
struct DeviceCreateInfo
|
||||||
{
|
{
|
||||||
|
std::reference_wrapper<Window> m_Window;
|
||||||
|
Features m_Features;
|
||||||
cstr m_AppName = "Aster App";
|
cstr m_AppName = "Aster App";
|
||||||
Version m_AppVersion = {0, 1, 0};
|
Version m_AppVersion = {0, 1, 0};
|
||||||
PhysicalDeviceSelectorFn m_PhysicalDeviceSelector = DefaultPhysicalDeviceSelector;
|
PhysicalDeviceSelectorFn m_PhysicalDeviceSelector = DefaultPhysicalDeviceSelector;
|
||||||
std::span<u8> m_PipelineCacheData = {};
|
std::span<u8> m_PipelineCacheData = {};
|
||||||
std::reference_wrapper<Window> m_Window;
|
eastl::vector<cstr> m_ShaderSearchPaths;
|
||||||
cstr m_Name = "Primary";
|
cstr m_Name = "Primary";
|
||||||
Features m_Features;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -472,10 +540,10 @@ class Device final
|
||||||
// Sampler Management
|
// Sampler Management
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
using Handle = Ref<Sampler>;
|
private:
|
||||||
using WeakHandle = WeakRef<Sampler>;
|
eastl::hash_map<vk::SamplerCreateInfo, WeakRef<Sampler>> m_HashToSamplerIdx;
|
||||||
eastl::hash_map<vk::SamplerCreateInfo, WeakHandle> m_HashToSamplerIdx;
|
|
||||||
|
|
||||||
|
public:
|
||||||
Ref<Sampler> CreateSampler(const SamplerCreateInfo &createInfo);
|
Ref<Sampler> CreateSampler(const SamplerCreateInfo &createInfo);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -484,11 +552,18 @@ class Device final
|
||||||
|
|
||||||
// TODO: Cache shader modules for reuse. Time to move to `slang`
|
// TODO: Cache shader modules for reuse. Time to move to `slang`
|
||||||
private:
|
private:
|
||||||
vk::ShaderModule CreateShader(std::string_view shaderFile);
|
Slang::ComPtr<slang::IGlobalSession> m_GlobalSlangSession;
|
||||||
|
Slang::ComPtr<slang::ISession> m_SlangSession;
|
||||||
|
|
||||||
|
PipelineCreationError
|
||||||
|
CreateShaders(eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> &shadersOut,
|
||||||
|
Slang::ComPtr<slang::IComponentType> &program, const std::span<const ShaderInfo> &shaders);
|
||||||
|
PipelineCreationError
|
||||||
|
CreatePipelineLayout(vk::PipelineLayout &pipelineLayout, const Slang::ComPtr<slang::IComponentType> &program);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Pipelines, unlike the other resources, are not ref-counted.
|
// Pipelines, unlike the other resources, are not ref-counted.
|
||||||
Pipeline CreatePipeline(const GraphicsPipelineCreateInfo &createInfo);
|
PipelineCreationError CreatePipeline(Pipeline &pipeline, const GraphicsPipelineCreateInfo &createInfo);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Frames
|
// Frames
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ Device::Device(const Instance &context, PhysicalDevice &physicalDevice, Features
|
||||||
SetName(m_Device, m_Name.data());
|
SetName(m_Device, m_Name.data());
|
||||||
|
|
||||||
VmaVulkanFunctions vmaVulkanFunctions = {
|
VmaVulkanFunctions vmaVulkanFunctions = {
|
||||||
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
.vkGetInstanceProcAddr = vk::detail::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
||||||
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
|
.vkGetDeviceProcAddr = vk::detail::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const VmaAllocatorCreateInfo allocatorCreateInfo = {
|
const VmaAllocatorCreateInfo allocatorCreateInfo = {
|
||||||
|
|
|
||||||
|
|
@ -56,18 +56,18 @@ struct fmt::formatter<MemorySize>
|
||||||
// return format_to(ctx.out(), "({}, {})", foo.a, foo.b); // --== KEY LINE ==--
|
// return format_to(ctx.out(), "({}, {})", foo.a, foo.b); // --== KEY LINE ==--
|
||||||
if (mem.m_Gigabytes > 0)
|
if (mem.m_Gigabytes > 0)
|
||||||
{
|
{
|
||||||
return v10::format_to(ctx.out(), "{}.{} GB", mem.m_Gigabytes, Cast<u16>(mem.m_Megabytes / 1024.0));
|
return v11::format_to(ctx.out(), "{}.{} GB", mem.m_Gigabytes, Cast<u16>(mem.m_Megabytes / 1024.0));
|
||||||
}
|
}
|
||||||
if (mem.m_Megabytes > 0)
|
if (mem.m_Megabytes > 0)
|
||||||
{
|
{
|
||||||
return v10::format_to(ctx.out(), "{}.{} MB", mem.m_Megabytes, Cast<u16>(mem.m_Kilobytes / 1024.0));
|
return v11::format_to(ctx.out(), "{}.{} MB", mem.m_Megabytes, Cast<u16>(mem.m_Kilobytes / 1024.0));
|
||||||
}
|
}
|
||||||
if (mem.m_Kilobytes > 0)
|
if (mem.m_Kilobytes > 0)
|
||||||
{
|
{
|
||||||
return v10::format_to(ctx.out(), "{}.{} KB", mem.m_Kilobytes, Cast<u16>(mem.m_Bytes / 1024.0));
|
return v11::format_to(ctx.out(), "{}.{} KB", mem.m_Kilobytes, Cast<u16>(mem.m_Bytes / 1024.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return v10::format_to(ctx.out(), "{} Bytes", mem.m_Bytes);
|
return v11::format_to(ctx.out(), "{} Bytes", mem.m_Bytes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,26 +11,22 @@
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
VKAPI_ATTR b32 VKAPI_CALL
|
VKAPI_ATTR b32 VKAPI_CALL
|
||||||
DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
DebugCallback(const vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
const VkDebugUtilsMessageTypeFlagsEXT messageType,
|
const vk::DebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT *callbackData, [[maybe_unused]] void *userData)
|
const vk::DebugUtilsMessengerCallbackDataEXT *callbackData, [[maybe_unused]] void *userData)
|
||||||
{
|
{
|
||||||
using Severity = vk::DebugUtilsMessageSeverityFlagsEXT;
|
|
||||||
using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
|
using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
|
||||||
using MessageType = vk::DebugUtilsMessageTypeFlagsEXT;
|
|
||||||
using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT;
|
using MessageTypeBits = vk::DebugUtilsMessageTypeFlagBitsEXT;
|
||||||
|
|
||||||
const auto severity = Severity(messageSeverity);
|
if (messageType & MessageTypeBits::eValidation)
|
||||||
|
|
||||||
if (MessageType(messageType) & MessageTypeBits::eValidation)
|
|
||||||
{
|
{
|
||||||
if (severity & SeverityBits::eError)
|
if (messageSeverity & SeverityBits::eError)
|
||||||
ERROR("{}", callbackData->pMessage);
|
ERROR("{}", callbackData->pMessage);
|
||||||
if (severity & SeverityBits::eWarning)
|
if (messageSeverity & SeverityBits::eWarning)
|
||||||
WARN("{}", callbackData->pMessage);
|
WARN("{}", callbackData->pMessage);
|
||||||
if (severity & SeverityBits::eInfo)
|
if (messageSeverity & SeverityBits::eInfo)
|
||||||
INFO("{}", callbackData->pMessage);
|
INFO("{}", callbackData->pMessage);
|
||||||
if (severity & SeverityBits::eVerbose)
|
if (messageSeverity & SeverityBits::eVerbose)
|
||||||
VERBOSE("{}", callbackData->pMessage);
|
VERBOSE("{}", callbackData->pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,7 +67,7 @@ Instance::Instance(const cstr appName, const Version version, bool enableValidat
|
||||||
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
const vk::DynamicLoader dl;
|
const vk::detail::DynamicLoader dl;
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable once CppInconsistentNaming
|
||||||
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ CommitManager::CommitManager(const Device *device, const u32 maxBuffers, const u
|
||||||
vk::DescriptorBindingFlags bindingFlags =
|
vk::DescriptorBindingFlags bindingFlags =
|
||||||
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
||||||
|
|
||||||
eastl::array<vk::DescriptorBindingFlags, decltype(descriptorLayoutBindings)::count> layoutBindingFlags;
|
eastl::array<vk::DescriptorBindingFlags, descriptorLayoutBindings.size()> layoutBindingFlags;
|
||||||
layoutBindingFlags.fill(bindingFlags);
|
layoutBindingFlags.fill(bindingFlags);
|
||||||
|
|
||||||
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "aster/util/files.h"
|
#include "aster/util/files.h"
|
||||||
|
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
static constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT =
|
static constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT =
|
||||||
QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute |
|
QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute |
|
||||||
QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
||||||
|
|
@ -421,55 +423,19 @@ systems::Device::CreateSampler(const SamplerCreateInfo &createInfo)
|
||||||
// Pipelines
|
// Pipelines
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
Pipeline
|
systems::PipelineCreationError
|
||||||
systems::Device::CreatePipeline(const GraphicsPipelineCreateInfo &createInfo)
|
systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCreateInfo &createInfo)
|
||||||
{
|
{
|
||||||
auto findShader = [&shaderModules = createInfo.m_ShaderModules](
|
eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> shaders;
|
||||||
GraphicsShaderModuleInfo::Type type) -> std::optional<GraphicsShaderModuleInfo> {
|
Slang::ComPtr<slang::IComponentType> program;
|
||||||
if (const auto res =
|
if (auto shaderResult = CreateShaders(shaders, program, {createInfo.m_Shaders.begin(), createInfo.m_Shaders.end()});
|
||||||
std::ranges::find_if(shaderModules, [type](const auto &v) { return v.m_Type == type; });
|
shaderResult)
|
||||||
res != std::ranges::end(shaderModules))
|
{
|
||||||
{
|
return shaderResult;
|
||||||
return *res;
|
}
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto vs = findShader(GraphicsShaderModuleInfo::Type::eVertex);
|
|
||||||
ERROR_IF(!vs, "Vertex Shader not found.");
|
|
||||||
GraphicsShaderModuleInfo vertexShader = *vs;
|
|
||||||
|
|
||||||
auto fs = findShader(GraphicsShaderModuleInfo::Type::eFragment);
|
|
||||||
ERROR_IF(!fs, "Fragment Shader not found.");
|
|
||||||
GraphicsShaderModuleInfo fragmentShader = *fs;
|
|
||||||
|
|
||||||
// Pipeline Setup
|
|
||||||
auto vertexShaderModule = CreateShader(vertexShader.m_ShaderFile);
|
|
||||||
auto fragmentShaderModule = CreateShader(fragmentShader.m_ShaderFile);
|
|
||||||
|
|
||||||
eastl::array<vk::PipelineShaderStageCreateInfo, 2> shaderStages = {{
|
|
||||||
{
|
|
||||||
.stage = vk::ShaderStageFlagBits::eVertex,
|
|
||||||
.module = vertexShaderModule,
|
|
||||||
.pName = vertexShader.m_EntryPoint.data(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.stage = vk::ShaderStageFlagBits::eFragment,
|
|
||||||
.module = fragmentShaderModule,
|
|
||||||
.pName = fragmentShader.m_EntryPoint.data(),
|
|
||||||
},
|
|
||||||
}};
|
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
|
||||||
.setLayoutCount = 0,
|
|
||||||
.pSetLayouts = nullptr,
|
|
||||||
.pushConstantRangeCount = 0,
|
|
||||||
.pPushConstantRanges = nullptr,
|
|
||||||
};
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
vk::Result result = m_Device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
auto result = CreatePipelineLayout(pipelineLayout, program);
|
||||||
ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result);
|
|
||||||
SetName(pipelineLayout, "Triangle Layout");
|
|
||||||
|
|
||||||
eastl::fixed_vector<vk::VertexInputBindingDescription, 4, false> inputBindingDescriptions;
|
eastl::fixed_vector<vk::VertexInputBindingDescription, 4, false> inputBindingDescriptions;
|
||||||
eastl::fixed_vector<vk::VertexInputAttributeDescription, 4, false> inputAttributeDescriptions;
|
eastl::fixed_vector<vk::VertexInputAttributeDescription, 4, false> inputAttributeDescriptions;
|
||||||
|
|
@ -479,8 +445,7 @@ systems::Device::CreatePipeline(const GraphicsPipelineCreateInfo &createInfo)
|
||||||
inputBindingDescriptions.push_back({
|
inputBindingDescriptions.push_back({
|
||||||
.binding = binding,
|
.binding = binding,
|
||||||
.stride = vertexInput.m_Stride,
|
.stride = vertexInput.m_Stride,
|
||||||
.inputRate =
|
.inputRate = vertexInput.m_IsPerInstance ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex,
|
||||||
vertexInput.m_IsPerInstance ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex,
|
|
||||||
});
|
});
|
||||||
for (auto attrInput : vertexInput.m_Attribute)
|
for (auto attrInput : vertexInput.m_Attribute)
|
||||||
{
|
{
|
||||||
|
|
@ -562,8 +527,8 @@ systems::Device::CreatePipeline(const GraphicsPipelineCreateInfo &createInfo)
|
||||||
|
|
||||||
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||||
.pNext = &renderingCreateInfo,
|
.pNext = &renderingCreateInfo,
|
||||||
.stageCount = Cast<u32>(shaderStages.size()),
|
.stageCount = Cast<u32>(shaders.size()),
|
||||||
.pStages = shaderStages.data(),
|
.pStages = shaders.data(),
|
||||||
.pVertexInputState = &vertexInputStateCreateInfo,
|
.pVertexInputState = &vertexInputStateCreateInfo,
|
||||||
.pInputAssemblyState = &inputAssemblyStateCreateInfo,
|
.pInputAssemblyState = &inputAssemblyStateCreateInfo,
|
||||||
.pViewportState = &viewportStateCreateInfo,
|
.pViewportState = &viewportStateCreateInfo,
|
||||||
|
|
@ -575,32 +540,271 @@ systems::Device::CreatePipeline(const GraphicsPipelineCreateInfo &createInfo)
|
||||||
.layout = pipelineLayout,
|
.layout = pipelineLayout,
|
||||||
};
|
};
|
||||||
vk::Pipeline pipeline;
|
vk::Pipeline pipeline;
|
||||||
result = m_Device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
auto vresult = m_Device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
||||||
ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result)
|
ERROR_IF(Failed(vresult), "Could not create a graphics pipeline. Cause: {}", vresult)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(vresult);
|
||||||
SetName(pipeline, "Triangle Pipeline");
|
SetName(pipeline, "Triangle Pipeline");
|
||||||
|
|
||||||
m_Device.m_Device.destroy(vertexShaderModule, nullptr);
|
for (auto &shader : shaders)
|
||||||
m_Device.m_Device.destroy(fragmentShaderModule, nullptr);
|
{
|
||||||
|
m_Device.m_Device.destroy(shader.module, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
return {&m_Device, pipelineLayout, pipeline, {}};
|
pipelineOut = {&m_Device, pipelineLayout, pipeline, {}};
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ShaderModule
|
#define MARK_FOUND_AND_VALIDATE_UNIQUE(VAR, STAGE) \
|
||||||
systems::Device::CreateShader(std::string_view shaderFile)
|
case SLANG_STAGE_##STAGE: \
|
||||||
|
if (VAR) \
|
||||||
|
{ \
|
||||||
|
ERROR("Multiple Entrypoints of Stage {}", #STAGE); \
|
||||||
|
return SLANG_FAIL; \
|
||||||
|
} \
|
||||||
|
VAR = true; \
|
||||||
|
break
|
||||||
|
|
||||||
|
#define UNIMPLEMENTED_STAGE(STAGE) \
|
||||||
|
case SLANG_STAGE_##STAGE: \
|
||||||
|
ERROR("Unimplemented Stage " #STAGE); \
|
||||||
|
return SLANG_FAIL
|
||||||
|
|
||||||
|
static vk::ShaderStageFlagBits
|
||||||
|
SlangToVulkanShaderStage(const SlangStage stage)
|
||||||
{
|
{
|
||||||
eastl::vector<u32> shaderCode = ReadFile(shaderFile);
|
switch (stage)
|
||||||
|
{
|
||||||
|
case SLANG_STAGE_VERTEX:
|
||||||
|
return vk::ShaderStageFlagBits::eVertex;
|
||||||
|
case SLANG_STAGE_HULL:
|
||||||
|
return vk::ShaderStageFlagBits::eTessellationControl;
|
||||||
|
case SLANG_STAGE_DOMAIN:
|
||||||
|
return vk::ShaderStageFlagBits::eTessellationEvaluation;
|
||||||
|
case SLANG_STAGE_GEOMETRY:
|
||||||
|
return vk::ShaderStageFlagBits::eGeometry;
|
||||||
|
case SLANG_STAGE_FRAGMENT:
|
||||||
|
return vk::ShaderStageFlagBits::eFragment;
|
||||||
|
case SLANG_STAGE_COMPUTE:
|
||||||
|
return vk::ShaderStageFlagBits::eCompute;
|
||||||
|
case SLANG_STAGE_RAY_GENERATION:
|
||||||
|
return vk::ShaderStageFlagBits::eRaygenKHR;
|
||||||
|
case SLANG_STAGE_INTERSECTION:
|
||||||
|
return vk::ShaderStageFlagBits::eIntersectionKHR;
|
||||||
|
case SLANG_STAGE_ANY_HIT:
|
||||||
|
return vk::ShaderStageFlagBits::eAnyHitKHR;
|
||||||
|
case SLANG_STAGE_CLOSEST_HIT:
|
||||||
|
return vk::ShaderStageFlagBits::eClosestHitKHR;
|
||||||
|
case SLANG_STAGE_MISS:
|
||||||
|
return vk::ShaderStageFlagBits::eMissKHR;
|
||||||
|
case SLANG_STAGE_CALLABLE:
|
||||||
|
return vk::ShaderStageFlagBits::eCallableKHR;
|
||||||
|
case SLANG_STAGE_MESH:
|
||||||
|
return vk::ShaderStageFlagBits::eMeshEXT;
|
||||||
|
case SLANG_STAGE_AMPLIFICATION:
|
||||||
|
return vk::ShaderStageFlagBits::eTaskEXT;
|
||||||
|
case SLANG_STAGE_NONE:
|
||||||
|
case SLANG_STAGE_COUNT:
|
||||||
|
ERROR("Invalid Shader Stage");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
ERROR("Unreachable") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
|
||||||
const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = {
|
systems::PipelineCreationError
|
||||||
.codeSize = shaderCode.size() * sizeof(u32),
|
systems::Device::CreateShaders(
|
||||||
.pCode = shaderCode.data(),
|
eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> &shadersOut,
|
||||||
|
Slang::ComPtr<slang::IComponentType> &program, const std::span<const ShaderInfo> &shaders)
|
||||||
|
{
|
||||||
|
using Slang::ComPtr;
|
||||||
|
|
||||||
|
ComPtr<slang::IBlob> shaderDiagnostics;
|
||||||
|
|
||||||
|
eastl::fixed_vector<slang::IComponentType *, ShaderTypeCount, false> components;
|
||||||
|
|
||||||
|
bool vertexFound = false;
|
||||||
|
bool fragmentFound = false;
|
||||||
|
bool tesselationControlFound = false;
|
||||||
|
bool tesselationEvalFound = false;
|
||||||
|
bool geometryFound = false;
|
||||||
|
bool computeFound = false;
|
||||||
|
|
||||||
|
u32 entryPointCount = 0;
|
||||||
|
|
||||||
|
for (const auto &shaderInfo : shaders)
|
||||||
|
{
|
||||||
|
ComPtr<slang::IModule> shaderModule;
|
||||||
|
shaderModule = m_SlangSession->loadModule(shaderInfo.m_ShaderFile.data(), shaderDiagnostics.writeRef());
|
||||||
|
if (shaderDiagnostics)
|
||||||
|
{
|
||||||
|
ERROR("{}", Cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
return SLANG_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
components.push_back(shaderModule);
|
||||||
|
|
||||||
|
for (auto entryPointName : shaderInfo.m_EntryPoints)
|
||||||
|
{
|
||||||
|
ComPtr<slang::IEntryPoint> actualEntryPoint;
|
||||||
|
auto slangResult = shaderModule->findEntryPointByName(entryPointName.data(), actualEntryPoint.writeRef());
|
||||||
|
|
||||||
|
slang::ProgramLayout *entryProgramLayout = actualEntryPoint->getLayout(0, shaderDiagnostics.writeRef());
|
||||||
|
if (shaderDiagnostics)
|
||||||
|
{
|
||||||
|
ERROR("{}", Cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
return SLANG_FAIL;
|
||||||
|
}
|
||||||
|
switch (entryProgramLayout->getEntryPointByIndex(0)->getStage())
|
||||||
|
{
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(vertexFound, VERTEX);
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(fragmentFound, FRAGMENT);
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(tesselationControlFound, HULL);
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(tesselationEvalFound, DOMAIN);
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(geometryFound, GEOMETRY);
|
||||||
|
MARK_FOUND_AND_VALIDATE_UNIQUE(computeFound, COMPUTE);
|
||||||
|
UNIMPLEMENTED_STAGE(RAY_GENERATION);
|
||||||
|
UNIMPLEMENTED_STAGE(INTERSECTION);
|
||||||
|
UNIMPLEMENTED_STAGE(ANY_HIT);
|
||||||
|
UNIMPLEMENTED_STAGE(CLOSEST_HIT);
|
||||||
|
UNIMPLEMENTED_STAGE(MISS);
|
||||||
|
UNIMPLEMENTED_STAGE(CALLABLE);
|
||||||
|
UNIMPLEMENTED_STAGE(MESH);
|
||||||
|
UNIMPLEMENTED_STAGE(AMPLIFICATION);
|
||||||
|
case SLANG_STAGE_COUNT:
|
||||||
|
case SLANG_STAGE_NONE:
|
||||||
|
ERROR("Invalid Stage.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slangResult < 0)
|
||||||
|
{
|
||||||
|
ERROR("Could not find entry point '{}' in '{}'. Cause: {}", entryPointName, shaderInfo.m_ShaderFile,
|
||||||
|
slangResult);
|
||||||
|
return slangResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
components.push_back(actualEntryPoint);
|
||||||
|
++entryPointCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validRasterShader = (vertexFound and fragmentFound) and not(tesselationControlFound xor tesselationEvalFound);
|
||||||
|
bool validComputeShader = computeFound;
|
||||||
|
bool validShaderSet = validRasterShader xor validComputeShader;
|
||||||
|
if (!validShaderSet)
|
||||||
|
{
|
||||||
|
eastl::fixed_vector<cstr, 6> shadersList;
|
||||||
|
if (vertexFound)
|
||||||
|
shadersList.push_back("vertex");
|
||||||
|
if (fragmentFound)
|
||||||
|
shadersList.push_back("fragment");
|
||||||
|
if (tesselationControlFound)
|
||||||
|
shadersList.push_back("tesselation control");
|
||||||
|
if (tesselationEvalFound)
|
||||||
|
shadersList.push_back("tesselation eval");
|
||||||
|
if (geometryFound)
|
||||||
|
shadersList.push_back("geometry");
|
||||||
|
if (computeFound)
|
||||||
|
shadersList.push_back("compute");
|
||||||
|
ERROR("Invalid combinations of shaders. [{}]", fmt::join(shadersList, " "));
|
||||||
|
return SLANG_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<slang::IComponentType> pipelineComposite;
|
||||||
|
auto slangResult = m_SlangSession->createCompositeComponentType(components.data(), Cast<u32>(components.size()),
|
||||||
|
pipelineComposite.writeRef());
|
||||||
|
|
||||||
|
if (slangResult < 0)
|
||||||
|
{
|
||||||
|
ERROR("Could not link program. Cause {}", slangResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
slangResult = pipelineComposite->link(program.writeRef(), shaderDiagnostics.writeRef());
|
||||||
|
|
||||||
|
if (slangResult < 0)
|
||||||
|
{
|
||||||
|
ERROR("{}", Cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
return slangResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Result result = vk::Result::eSuccess;
|
||||||
|
for (u32 entryPoint = 0; entryPoint < entryPointCount; ++entryPoint)
|
||||||
|
{
|
||||||
|
auto &outShader = shadersOut.push_back();
|
||||||
|
|
||||||
|
ComPtr<slang::IBlob> kernelCode;
|
||||||
|
slangResult = program->getEntryPointCode(entryPoint, 0, kernelCode.writeRef(), shaderDiagnostics.writeRef());
|
||||||
|
if (slangResult < 0)
|
||||||
|
{
|
||||||
|
ERROR("{}", Cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
return slangResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto progLayout = program->getLayout(0))
|
||||||
|
{
|
||||||
|
if (auto entryPointReflection = progLayout->getEntryPointByIndex(entryPoint))
|
||||||
|
{
|
||||||
|
outShader.pName = entryPointReflection->getName();
|
||||||
|
outShader.stage = SlangToVulkanShaderStage(entryPointReflection->getStage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = {
|
||||||
|
.codeSize = kernelCode->getBufferSize(),
|
||||||
|
.pCode = Cast<const u32 *>(kernelCode->getBufferPointer()),
|
||||||
|
};
|
||||||
|
|
||||||
|
result = m_Device.m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &outShader.module);
|
||||||
|
if (Failed(result))
|
||||||
|
{
|
||||||
|
ERROR("Shaders could not be created. Cause: {}", result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Failed(result))
|
||||||
|
{
|
||||||
|
for (auto &shader : shadersOut)
|
||||||
|
{
|
||||||
|
if (shader.module)
|
||||||
|
{
|
||||||
|
m_Device.m_Device.destroy(shader.module, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
systems::PipelineCreationError
|
||||||
|
systems::Device::CreatePipelineLayout(vk::PipelineLayout &pipelineLayout,
|
||||||
|
const Slang::ComPtr<slang::IComponentType> &program)
|
||||||
|
{
|
||||||
|
using Slang::ComPtr;
|
||||||
|
|
||||||
|
ComPtr<slang::IBlob> layoutDiagnostics;
|
||||||
|
slang::ProgramLayout *layout = program->getLayout(0, layoutDiagnostics.writeRef());
|
||||||
|
if (layoutDiagnostics)
|
||||||
|
{
|
||||||
|
ERROR_IF(!layout, "{}", Cast<cstr>(layoutDiagnostics->getBufferPointer()));
|
||||||
|
return SLANG_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Reflect to create the push constants and descriptor sets.
|
||||||
|
|
||||||
|
const vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
.setLayoutCount = 0,
|
||||||
|
.pSetLayouts = nullptr,
|
||||||
|
.pushConstantRangeCount = 0,
|
||||||
|
.pPushConstantRanges = nullptr,
|
||||||
};
|
};
|
||||||
vk::ShaderModule shaderModule;
|
vk::Result result = m_Device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
||||||
|
if (Failed(result))
|
||||||
|
{
|
||||||
|
ERROR("Could not create a pipeline layout. Cause: {}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
vk::Result result = m_Device.m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule);
|
return {};
|
||||||
ERROR_IF(Failed(result), "Shader {} could not be created. Cause: {}", shaderFile, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
return shaderModule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -647,6 +851,29 @@ systems::Device::Device(const DeviceCreateInfo &createInfo)
|
||||||
|
|
||||||
m_Swapchain = Swapchain{m_Surface, m_Device, m_Window.get().GetSize()};
|
m_Swapchain = Swapchain{m_Surface, m_Device, m_Window.get().GetSize()};
|
||||||
|
|
||||||
|
constexpr SlangGlobalSessionDesc globalSessionDesc = {};
|
||||||
|
auto result = slang::createGlobalSession(&globalSessionDesc, m_GlobalSlangSession.writeRef());
|
||||||
|
ERROR_IF(result < 0, "Could not create a slang global session.") THEN_ABORT(result);
|
||||||
|
|
||||||
|
slang::CompilerOptionEntry useOriginalEntrypointNames = {
|
||||||
|
.name = slang::CompilerOptionName::VulkanUseEntryPointName,
|
||||||
|
.value = slang::CompilerOptionValue{.kind = slang::CompilerOptionValueKind::Int, .intValue0 = 1},
|
||||||
|
};
|
||||||
|
const slang::TargetDesc spirvTargetDesc = {
|
||||||
|
.format = SLANG_SPIRV,
|
||||||
|
.profile = m_GlobalSlangSession->findProfile("glsl_450"),
|
||||||
|
.compilerOptionEntries = &useOriginalEntrypointNames,
|
||||||
|
.compilerOptionEntryCount = 1,
|
||||||
|
};
|
||||||
|
const slang::SessionDesc sessionDesc = {
|
||||||
|
.targets = &spirvTargetDesc,
|
||||||
|
.targetCount = 1,
|
||||||
|
.searchPaths = createInfo.m_ShaderSearchPaths.data(),
|
||||||
|
.searchPathCount = Cast<u32>(createInfo.m_ShaderSearchPaths.size()),
|
||||||
|
};
|
||||||
|
result = m_GlobalSlangSession->createSession(sessionDesc, m_SlangSession.writeRef());
|
||||||
|
ERROR_IF(result < 0, "Could not create a slang session.") THEN_ABORT(result);
|
||||||
|
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
for (auto &frame : m_Frames)
|
for (auto &frame : m_Frames)
|
||||||
{
|
{
|
||||||
|
|
@ -802,11 +1029,9 @@ systems::Device::Present(Frame &frame)
|
||||||
void
|
void
|
||||||
systems::Frame::Reset(u32 imageIdx, vk::Image swapchainImage, vk::ImageView swapchainImageView)
|
systems::Frame::Reset(u32 imageIdx, vk::Image swapchainImage, vk::ImageView swapchainImageView)
|
||||||
{
|
{
|
||||||
AbortIfFailedMV(m_Device->m_Device.resetFences(1, &m_FrameAvailableFence), "Fence {} reset failed.",
|
AbortIfFailedMV(m_Device->m_Device.resetFences(1, &m_FrameAvailableFence), "Fence {} reset failed.", m_FrameIdx);
|
||||||
m_FrameIdx);
|
|
||||||
|
|
||||||
AbortIfFailedMV(m_Device->m_Device.resetCommandPool(m_Pool, {}), "Command pool {} reset failed.",
|
AbortIfFailedMV(m_Device->m_Device.resetCommandPool(m_Pool, {}), "Command pool {} reset failed.", m_FrameIdx);
|
||||||
m_FrameIdx);
|
|
||||||
m_CommandBuffersAllocated = 0;
|
m_CommandBuffersAllocated = 0;
|
||||||
|
|
||||||
m_ImageIdx = imageIdx;
|
m_ImageIdx = imageIdx;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_executable(triangle "triangle.cpp")
|
add_executable(triangle "triangle.cpp")
|
||||||
add_shader(triangle "shader/triangle.vert.glsl")
|
add_shader(triangle "shader/triangle.slang")
|
||||||
add_shader(triangle "shader/triangle.frag.glsl")
|
add_resource_dir(triangle "shader")
|
||||||
|
|
||||||
target_link_libraries(triangle PRIVATE aster_core)
|
target_link_libraries(triangle PRIVATE aster_core)
|
||||||
target_link_libraries(triangle PRIVATE util_helper)
|
target_link_libraries(triangle PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
float3 point;
|
||||||
|
float3 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSIn {
|
||||||
|
Vertex vertex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSOut
|
||||||
|
{
|
||||||
|
float4 Pos : SV_POSITION;
|
||||||
|
float3 Color : COLOR0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("vertex")]
|
||||||
|
VSOut vsmain(VSIn input) {
|
||||||
|
VSOut output;
|
||||||
|
output.Pos = float4(input.vertex.point, 1.0f);
|
||||||
|
output.Color = input.vertex.color;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FSOut {
|
||||||
|
float4 Color;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("fragment")]
|
||||||
|
FSOut fsmain(VSOut input) {
|
||||||
|
FSOut outp;
|
||||||
|
outp.Color = float4(input.Color, 1.0);
|
||||||
|
return outp;
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#version 450
|
|
||||||
#pragma shader_stage(vertex)
|
|
||||||
|
|
||||||
layout(location=0) in vec4 position;
|
|
||||||
layout(location=1) in vec4 color;
|
|
||||||
|
|
||||||
layout(location=0) out vec3 outColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
/*
|
|
||||||
vec3 points[] = {
|
|
||||||
vec3(-0.5f, -0.5f, 0.0f),
|
|
||||||
vec3(0.5f, -0.5f, 0.0f),
|
|
||||||
vec3(0.0f, 0.5f, 0.0f)
|
|
||||||
};
|
|
||||||
vec3 colors[] = {
|
|
||||||
vec3( 1.0f, 0.0f, 0.0f ),
|
|
||||||
vec3( 0.0f, 1.0f, 0.0f ),
|
|
||||||
vec3( 0.0f, 0.0f, 1.0f ),
|
|
||||||
};
|
|
||||||
|
|
||||||
gl_Position = vec4(points[gl_VertexIndex], 1.0f);
|
|
||||||
outColor = vec3(colors[gl_VertexIndex]); //*/
|
|
||||||
//*
|
|
||||||
gl_Position = vec4(position.xyz, 1.0f);
|
|
||||||
outColor = vec3(color.rgb); //*/
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -20,35 +20,26 @@
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
constexpr auto VERTEX_SHADER_FILE = "shader/triangle.vert.glsl.spv";
|
constexpr auto SHADER_MODULE = "triangle.slang";
|
||||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/triangle.frag.glsl.spv";
|
|
||||||
|
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
vec3 m_Position;
|
vec3 m_Position;
|
||||||
vec3 m_Color;
|
vec3 m_Color;
|
||||||
|
|
||||||
constexpr static vk::VertexInputBindingDescription
|
static eastl::vector<systems::AttributeInfo>
|
||||||
GetBinding(const u32 binding)
|
GetAttributes()
|
||||||
{
|
|
||||||
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
|
||||||
GetAttributes(const u32 binding)
|
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
vk::VertexInputAttributeDescription{
|
{
|
||||||
.location = 0,
|
.m_Location = 0,
|
||||||
.binding = binding,
|
.m_Offset = offsetof(Vertex, m_Position),
|
||||||
.format = vk::Format::eR32G32B32Sfloat,
|
.m_Format = systems::AttributeInfo::Format::eFloat32X3,
|
||||||
.offset = offsetof(Vertex, m_Position),
|
|
||||||
},
|
},
|
||||||
vk::VertexInputAttributeDescription{
|
{
|
||||||
.location = 1,
|
.m_Location = 1,
|
||||||
.binding = binding,
|
.m_Offset = offsetof(Vertex, m_Color),
|
||||||
.format = vk::Format::eR32G32B32Sfloat,
|
.m_Format = systems::AttributeInfo::Format::eFloat32X3,
|
||||||
.offset = offsetof(Vertex, m_Color),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -61,44 +52,27 @@ main(int, char **)
|
||||||
|
|
||||||
Window window = {"Triangle (Aster)", {640, 480}};
|
Window window = {"Triangle (Aster)", {640, 480}};
|
||||||
systems::Device device{{
|
systems::Device device{{
|
||||||
.m_AppName = "Triangle",
|
|
||||||
.m_Window = window,
|
.m_Window = window,
|
||||||
.m_Name = "Primary",
|
|
||||||
.m_Features = {.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
.m_Features = {.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}},
|
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}},
|
||||||
|
.m_AppName = "Triangle",
|
||||||
|
.m_ShaderSearchPaths = {"shader/"},
|
||||||
|
.m_Name = "Primary",
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Pipeline pipeline = device.CreatePipeline({
|
Pipeline pipeline;
|
||||||
.m_VertexInputs = {{
|
auto pipelineError = device.CreatePipeline(
|
||||||
.m_Attribute =
|
pipeline, {
|
||||||
{
|
.m_VertexInputs = {{
|
||||||
{
|
.m_Attribute = Vertex::GetAttributes(),
|
||||||
.m_Location = 0,
|
.m_Stride = sizeof(Vertex),
|
||||||
.m_Offset = offsetof(Vertex, m_Position),
|
}},
|
||||||
.m_Format = systems::AttributeInfo::Format::eFloat32X3,
|
.m_Shaders = {{
|
||||||
},
|
.m_ShaderFile = SHADER_MODULE,
|
||||||
{
|
.m_EntryPoints = {"vsmain", "fsmain"},
|
||||||
.m_Location = 1,
|
}},
|
||||||
.m_Offset = offsetof(Vertex, m_Color),
|
});
|
||||||
.m_Format = systems::AttributeInfo::Format::eFloat32X3,
|
ERROR_IF(pipelineError, "Error creating pipeline. Cause: {}", pipelineError.What());
|
||||||
},
|
|
||||||
},
|
|
||||||
.m_Stride = sizeof(Vertex),
|
|
||||||
}},
|
|
||||||
.m_ShaderModules =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
.m_ShaderFile = VERTEX_SHADER_FILE,
|
|
||||||
.m_EntryPoint = "main",
|
|
||||||
.m_Type = systems::GraphicsShaderModuleInfo::Type::eVertex,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.m_ShaderFile = FRAGMENT_SHADER_FILE,
|
|
||||||
.m_EntryPoint = "main",
|
|
||||||
.m_Type = systems::GraphicsShaderModuleInfo::Type::eFragment,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// eastl::array<Vertex, 3> vertices{};
|
// eastl::array<Vertex, 3> vertices{};
|
||||||
eastl::array vertices = {
|
eastl::array vertices = {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_subdirectory("00_util")
|
add_subdirectory("00_util")
|
||||||
add_subdirectory("01_triangle")
|
add_subdirectory("01_triangle")
|
||||||
add_subdirectory("02_box")
|
# add_subdirectory("02_box")
|
||||||
add_subdirectory("03_model_render")
|
# add_subdirectory("03_model_render")
|
||||||
# add_subdirectory("04_scenes")
|
# add_subdirectory("04_scenes")
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"default-registry": {
|
"default-registry": {
|
||||||
"kind": "git",
|
"kind": "git",
|
||||||
"baseline": "b27651341123a59f7187b42ef2bc476284afb310",
|
"baseline": "41c447cc210dc39aa85d4a5f58b4a1b9e573b3dc",
|
||||||
"repository": "https://github.com/microsoft/vcpkg"
|
"repository": "https://github.com/microsoft/vcpkg"
|
||||||
},
|
},
|
||||||
"registries": [
|
"registries": [
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"scottt-debugbreak",
|
"scottt-debugbreak",
|
||||||
"tinygltf",
|
"tinygltf",
|
||||||
"vulkan-memory-allocator",
|
"vulkan-memory-allocator",
|
||||||
"entt"
|
"entt",
|
||||||
|
"shader-slang"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue