Compare commits
8 Commits
6b5442527f
...
e82b37b2d9
| Author | SHA1 | Date |
|---|---|---|
|
|
e82b37b2d9 | |
|
|
b9d5ba56d4 | |
|
|
23cd7eae8b | |
|
|
8a865e2e49 | |
|
|
7ba132ec0c | |
|
|
ba2e21f52e | |
|
|
f735b63d7e | |
|
|
6d39576b5c |
|
|
@ -9,9 +9,10 @@ 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- /Zi")
|
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
||||||
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)
|
||||||
|
add_compile_definitions(${MSVC_DEFINES})
|
||||||
else ()
|
else ()
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -g -fno-rtti -fno-exceptions")
|
set(CMAKE_CXX_FLAGS "-Wall -g -fno-rtti -fno-exceptions")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 2,
|
"version": 6,
|
||||||
"configurePresets": [
|
"configurePresets": [
|
||||||
{
|
{
|
||||||
"name": "linux",
|
"name": "linux",
|
||||||
|
|
@ -11,16 +11,83 @@
|
||||||
"CMAKE_C_COMPILER": "/usr/bin/clang",
|
"CMAKE_C_COMPILER": "/usr/bin/clang",
|
||||||
"CMAKE_CXX_COMPILER": "/usr/bin/clang++",
|
"CMAKE_CXX_COMPILER": "/usr/bin/clang++",
|
||||||
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Linux"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "windows",
|
"name": "windows-debug",
|
||||||
"generator": "Ninja",
|
"generator": "Ninja",
|
||||||
"binaryDir": "${sourceDir}/build",
|
"binaryDir": "${sourceDir}/build/debug/",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
"CMAKE_MAKE_PROGRAM": "ninja",
|
"CMAKE_MAKE_PROGRAM": "ninja",
|
||||||
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"DXC_SHADER_FLAGS": "-Zi",
|
||||||
|
"GLSLC_SHADER_FLAGS": "-g"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-reldebug",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build/reldebug/",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
|
"CMAKE_MAKE_PROGRAM": "ninja",
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"DXC_SHADER_FLAGS": "-Zi",
|
||||||
|
"GLSLC_SHADER_FLAGS": "-g"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-reldebug-nobreak",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build/reldebug/",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
|
"CMAKE_MAKE_PROGRAM": "ninja",
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"DXC_SHADER_FLAGS": "-Zi",
|
||||||
|
"GLSLC_SHADER_FLAGS": "-g",
|
||||||
|
"MSVC_DEFINES": "ASTER_NO_BREAK"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-release",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build/release/",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||||
|
"CMAKE_MAKE_PROGRAM": "ninja",
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"MSVC_DEFINES": "ASTER_NDEBUG"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ function(add_shader TARGET SHADER)
|
||||||
message("Marked as hlsl file. ${current-output-path}")
|
message("Marked as hlsl file. ${current-output-path}")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${current-output-path}
|
OUTPUT ${current-output-path}
|
||||||
COMMAND Vulkan::dxc_exe -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}
|
||||||
DEPENDS ${current-shader-path}
|
DEPENDS ${current-shader-path}
|
||||||
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
@ -24,7 +24,7 @@ function(add_shader TARGET SHADER)
|
||||||
message("Marked as glsl file. ${current-output-path}")
|
message("Marked as glsl file. ${current-output-path}")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${current-output-path}
|
OUTPUT ${current-output-path}
|
||||||
COMMAND Vulkan::glslc -o ${current-output-path} ${current-shader-path}
|
COMMAND Vulkan::glslc ${GLSLC_SHADER_FLAGS} -o ${current-output-path} ${current-shader-path}
|
||||||
DEPENDS ${current-shader-path}
|
DEPENDS ${current-shader-path}
|
||||||
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#define EASTL_NO_EXCEPTIONS 1
|
#define EASTL_NO_EXCEPTIONS 1
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(ASTER_NDEBUG)
|
||||||
#define USE_OPTICK (0)
|
#define USE_OPTICK (0)
|
||||||
#else
|
#else
|
||||||
#define USE_OPTICK (1)
|
#define USE_OPTICK (1)
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,18 @@ struct Context final
|
||||||
vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
|
vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Context(cstr appName, Version version, bool enableValidation = true);
|
Context(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE);
|
||||||
~Context();
|
~Context();
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
Context(Context &&other) noexcept;
|
Context(Context &&other) noexcept;
|
||||||
Context &operator=(Context &&other) noexcept;
|
Context &operator=(Context &&other) noexcept;
|
||||||
|
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = true;
|
||||||
|
#else
|
||||||
|
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Context);
|
DISALLOW_COPY_AND_ASSIGN(Context);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features
|
||||||
NameString &&name)
|
NameString &&name)
|
||||||
: m_Name(std::move(name))
|
: m_Name(std::move(name))
|
||||||
, m_PhysicalDevice(physicalDevice->m_PhysicalDevice)
|
, m_PhysicalDevice(physicalDevice->m_PhysicalDevice)
|
||||||
|
, m_ValidationEnabled(context->m_DebugMessenger != nullptr)
|
||||||
{
|
{
|
||||||
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
|
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
|
||||||
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
|
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ struct Device final
|
||||||
vk::Device m_Device = nullptr;
|
vk::Device m_Device = nullptr;
|
||||||
VmaAllocator m_Allocator = nullptr;
|
VmaAllocator m_Allocator = nullptr;
|
||||||
vk::PipelineCache m_PipelineCache = nullptr;
|
vk::PipelineCache m_PipelineCache = nullptr;
|
||||||
|
bool m_ValidationEnabled = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires vk::isVulkanHandleType<T>::value void SetName(const T &object, cstr name) const;
|
requires vk::isVulkanHandleType<T>::value void SetName(const T &object, cstr name) const;
|
||||||
|
|
@ -54,8 +55,9 @@ template <typename T>
|
||||||
requires vk::isVulkanHandleType<T>::value void
|
requires vk::isVulkanHandleType<T>::value void
|
||||||
Device::SetName(const T &object, cstr name) const
|
Device::SetName(const T &object, cstr name) const
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!m_ValidationEnabled || !name || !object)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto handle = Recast<u64>(Cast<typename T::NativeType>(object));
|
auto handle = Recast<u64>(Cast<typename T::NativeType>(object));
|
||||||
const vk::DebugUtilsObjectNameInfoEXT objectNameInfo = {
|
const vk::DebugUtilsObjectNameInfoEXT objectNameInfo = {
|
||||||
.objectType = object.objectType,
|
.objectType = object.objectType,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@
|
||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||||
|
#endif
|
||||||
#include <EASTL/fixed_string.h>
|
#include <EASTL/fixed_string.h>
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
@ -51,7 +53,7 @@ Failed(const vk::Result result)
|
||||||
using NameString = eastl::fixed_string<char, 32, false>;
|
using NameString = eastl::fixed_string<char, 32, false>;
|
||||||
|
|
||||||
template <typename TFlagBits>
|
template <typename TFlagBits>
|
||||||
struct std::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
|
struct eastl::hash<vk::Flags<TFlagBits>> // NOLINT(*-dcl58-cpp)
|
||||||
{
|
{
|
||||||
[[nodiscard]] usize
|
[[nodiscard]] usize
|
||||||
operator()(const vk::Flags<TFlagBits> &val)
|
operator()(const vk::Flags<TFlagBits> &val)
|
||||||
|
|
@ -64,7 +66,7 @@ template <typename T>
|
||||||
[[nodiscard]] usize
|
[[nodiscard]] usize
|
||||||
HashAny(const T &val)
|
HashAny(const T &val)
|
||||||
{
|
{
|
||||||
return std::hash<std::remove_cvref_t<T>>()(val);
|
return eastl::hash<std::remove_cvref_t<T>>()(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline usize
|
[[nodiscard]] inline usize
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ void
|
||||||
Image::Destroy(const Device *device)
|
Image::Destroy(const Device *device)
|
||||||
{
|
{
|
||||||
if (!IsValid() || !IsOwned())
|
if (!IsValid() || !IsOwned())
|
||||||
|
{
|
||||||
|
m_MipLevels_ = 0;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
device->m_Device.destroy(m_View, nullptr);
|
device->m_Device.destroy(m_View, nullptr);
|
||||||
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
|
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
|
||||||
|
|
@ -280,7 +283,6 @@ void
|
||||||
StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format imageFormat, const bool isSampled,
|
StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format imageFormat, const bool isSampled,
|
||||||
cstr name)
|
cstr name)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Reasoning:
|
// Reasoning:
|
||||||
// Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
// Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||||
// results.
|
// results.
|
||||||
|
|
@ -342,3 +344,72 @@ StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
device->SetName(m_Image, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StorageTextureCube::Init(const Device* device, u32 cubeSide, vk::Format imageFormat, bool isSampled, bool isMipMapped, cstr name)
|
||||||
|
{
|
||||||
|
// Reasoning:
|
||||||
|
// Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||||
|
// results.
|
||||||
|
auto usage =
|
||||||
|
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||||
|
if (isSampled)
|
||||||
|
{
|
||||||
|
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)",
|
||||||
|
cubeSide, name ? name : "<unnamed>");
|
||||||
|
usage |= vk::ImageUsageFlagBits::eSampled;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 mipLevels = isMipMapped ? 1 + Cast<u32>(floor(log2(cubeSide))) : 1;
|
||||||
|
assert(mipLevels <= MIP_MASK);
|
||||||
|
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = {
|
||||||
|
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = imageFormat,
|
||||||
|
.extent = {cubeSide, cubeSide, 1},
|
||||||
|
.mipLevels = mipLevels,
|
||||||
|
.arrayLayers = 6,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
|
.tiling = vk::ImageTiling::eOptimal,
|
||||||
|
.usage = usage,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive,
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
};
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = {},
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
vk::ImageView view;
|
||||||
|
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = image,
|
||||||
|
.viewType = vk::ImageViewType::eCube,
|
||||||
|
.format = imageFormat,
|
||||||
|
.components = {},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 6,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Image = image;
|
||||||
|
m_View = view;
|
||||||
|
m_Allocation = allocation;
|
||||||
|
m_Extent = imageCreateInfo.extent;
|
||||||
|
m_MipLevels_ = mipLevels | OWNED_BIT | VALID_BIT;
|
||||||
|
|
||||||
|
device->SetName(m_Image, name);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,27 +59,45 @@ struct Texture : Image
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(Texture) == sizeof(Image));
|
||||||
|
|
||||||
struct TextureCube : Texture
|
struct TextureCube : Texture
|
||||||
{
|
{
|
||||||
void
|
void
|
||||||
Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped = false, cstr name = nullptr);
|
Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped = false, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(TextureCube) == sizeof(Image));
|
||||||
|
|
||||||
struct AttachmentImage : Image
|
struct AttachmentImage : Image
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(AttachmentImage) == sizeof(Image));
|
||||||
|
|
||||||
struct DepthImage : Image
|
struct DepthImage : Image
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DepthImage) == sizeof(Image));
|
||||||
|
|
||||||
struct StorageTexture : Texture
|
struct StorageTexture : Texture
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isSampled, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isSampled, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(StorageTexture) == sizeof(Image));
|
||||||
|
|
||||||
|
struct StorageTextureCube : StorageTexture
|
||||||
|
{
|
||||||
|
void Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isSampled, bool isMipMapped = false,
|
||||||
|
cstr name = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(StorageTextureCube) == sizeof(Image));
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
Image::IsValid() const
|
Image::IsValid() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,5 @@ void
|
||||||
AssertionFailure(const char *af)
|
AssertionFailure(const char *af)
|
||||||
{
|
{
|
||||||
ERROR("{}", af);
|
ERROR("{}", af);
|
||||||
debug_break();
|
|
||||||
}
|
}
|
||||||
} // namespace eastl
|
} // namespace eastl
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,12 @@ struct Logger
|
||||||
fmt::println("{}{} {} {} at {}:{}{}", ToColorCstr<TLogLevel>(), ToCstr<TLogLevel>(), message.data(),
|
fmt::println("{}{} {} {} at {}:{}{}", ToColorCstr<TLogLevel>(), ToCstr<TLogLevel>(), message.data(),
|
||||||
ansi_color::Black, loc, line, ansi_color::Reset);
|
ansi_color::Black, loc, line, ansi_color::Reset);
|
||||||
}
|
}
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG) && !defined(ASTER_NO_BREAK)
|
||||||
if constexpr (TLogLevel == LogType::eError)
|
if constexpr (TLogLevel == LogType::eError)
|
||||||
{
|
{
|
||||||
debug_break();
|
debug_break();
|
||||||
}
|
}
|
||||||
#endif // !defined(NDEBUG)
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <LogType TLogLevel>
|
template <LogType TLogLevel>
|
||||||
|
|
@ -86,12 +86,12 @@ struct Logger
|
||||||
fmt::println("{}{} ({}) {} {} at {}:{}{}", ToColorCstr<TLogLevel>(), ToCstr<TLogLevel>(), exprStr,
|
fmt::println("{}{} ({}) {} {} at {}:{}{}", ToColorCstr<TLogLevel>(), ToCstr<TLogLevel>(), exprStr,
|
||||||
message.data(), ansi_color::Black, loc, line, ansi_color::Reset);
|
message.data(), ansi_color::Black, loc, line, ansi_color::Reset);
|
||||||
}
|
}
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG) && !defined(ASTER_NO_BREAK)
|
||||||
if constexpr (TLogLevel == LogType::eError)
|
if constexpr (TLogLevel == LogType::eError)
|
||||||
{
|
{
|
||||||
debug_break();
|
debug_break();
|
||||||
}
|
}
|
||||||
#endif // !defined(NDEBUG)
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ extern Logger g_Logger;
|
||||||
; \
|
; \
|
||||||
else g_Logger.Log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
else g_Logger.Log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||||
|
|
||||||
#if !defined(DEBUG_LOG_DISABLED) && !defined(NDEBUG)
|
#if !defined(DEBUG_LOG_DISABLED) && !defined(ASTER_NDEBUG)
|
||||||
|
|
||||||
#define DEBUG(...) g_Logger.Log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
#define DEBUG(...) g_Logger.Log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||||
#define DEBUG_IF(expr, ...) \
|
#define DEBUG_IF(expr, ...) \
|
||||||
|
|
@ -151,24 +151,26 @@ extern Logger g_Logger;
|
||||||
|
|
||||||
#else // !defined(DEBUG_LOG_DISABLED)
|
#else // !defined(DEBUG_LOG_DISABLED)
|
||||||
|
|
||||||
#define DEBUG(msg) \
|
#define DEBUG(...) \
|
||||||
{ \
|
{ \
|
||||||
}
|
}
|
||||||
#define DEBUG_IF(expr, msg) \
|
#define DEBUG_IF(expr, ...) \
|
||||||
if (expr) \
|
if (false) \
|
||||||
(void)msg
|
{ \
|
||||||
#define ELSE_IF_DEBUG(expr, msg) \
|
}
|
||||||
|
#define ELSE_IF_DEBUG(expr, ...) \
|
||||||
; \
|
; \
|
||||||
if (expr) \
|
if (false) \
|
||||||
(void)msg
|
{ \
|
||||||
#define ELSE_DEBUG(msg) \
|
}
|
||||||
|
#define ELSE_DEBUG(...) \
|
||||||
; \
|
; \
|
||||||
{ \
|
{ \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !defined(DEBUG_LOG_DISABLED)
|
#endif // !defined(DEBUG_LOG_DISABLED)
|
||||||
|
|
||||||
#if !defined(VERBOSE_LOG_DISABLED) && !defined(NDEBUG)
|
#if !defined(VERBOSE_LOG_DISABLED) && !defined(ASTER_NDEBUG)
|
||||||
|
|
||||||
#define VERBOSE(...) g_Logger.Log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
#define VERBOSE(...) g_Logger.Log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||||
#define VERBOSE_IF(expr, ...) \
|
#define VERBOSE_IF(expr, ...) \
|
||||||
|
|
@ -184,17 +186,20 @@ extern Logger g_Logger;
|
||||||
|
|
||||||
#else // !defined(DEBUG_LOG_DISABLED)
|
#else // !defined(DEBUG_LOG_DISABLED)
|
||||||
|
|
||||||
#define VERBOSE(msg) \
|
#define VERBOSE(...) \
|
||||||
{ \
|
{ \
|
||||||
}
|
}
|
||||||
#define VERBOSE_IF(expr, msg) \
|
#define VERBOSE_IF(expr, ...) \
|
||||||
if (expr) \
|
if (false) \
|
||||||
(void)msg
|
{ \
|
||||||
#define ELSE_IF_VERBOSE(expr, msg) \
|
} \
|
||||||
|
}
|
||||||
|
#define ELSE_IF_VERBOSE(expr, ...) \
|
||||||
; \
|
; \
|
||||||
if (expr) \
|
if (false) \
|
||||||
(void)msg
|
{ \
|
||||||
#define ELSE_VERBOSE(msg) \
|
}
|
||||||
|
#define ELSE_VERBOSE(...) \
|
||||||
; \
|
; \
|
||||||
{ \
|
{ \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ TextureManager::Init(const u32 maxCapacity)
|
||||||
TextureHandle
|
TextureHandle
|
||||||
TextureManager::Commit(Texture *texture)
|
TextureManager::Commit(Texture *texture)
|
||||||
{
|
{
|
||||||
ERROR_IF(!texture || !texture->IsValid() || !texture->IsOwned(), "Texture must be valid and owned for commital")
|
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for commital")
|
||||||
THEN_ABORT(-1);
|
THEN_ABORT(-1);
|
||||||
|
|
||||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||||
|
|
@ -193,6 +193,79 @@ StorageTextureManager::Release(const Device *device, const StorageTextureHandle
|
||||||
TextureManager::Release(device, {handle.m_Index});
|
TextureManager::Release(device, {handle.m_Index});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usize
|
||||||
|
HashSamplerCreateInfo(const vk::SamplerCreateInfo *createInfo)
|
||||||
|
{
|
||||||
|
usize hash = HashAny(createInfo->flags);
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->magFilter));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->minFilter));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->mipmapMode));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeU));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeV));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->addressModeW));
|
||||||
|
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo->mipLodBias * 1000))); // Resolution of 10^-3
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->anisotropyEnable));
|
||||||
|
hash = HashCombine(hash,
|
||||||
|
HashAny(Cast<usize>(createInfo->maxAnisotropy * 0x10))); // 16:1 Anisotropy is enough resolution
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->compareEnable));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->compareOp));
|
||||||
|
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo->minLod * 1000))); // 0.001 resolution is enough.
|
||||||
|
hash = HashCombine(hash,
|
||||||
|
HashAny(Cast<usize>(createInfo->maxLod * 1000))); // 0.001 resolution is enough. (1 == NO Clamp)
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->borderColor));
|
||||||
|
hash = HashCombine(hash, HashAny(createInfo->unnormalizedCoordinates));
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SamplerManager::Init(usize size)
|
||||||
|
{
|
||||||
|
m_Samplers.reserve(size);
|
||||||
|
m_SamplerHashes.reserve(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
SamplerHandle
|
||||||
|
SamplerManager::Create(const Device *device, const vk::SamplerCreateInfo *createInfo)
|
||||||
|
{
|
||||||
|
const usize hash = HashSamplerCreateInfo(createInfo);
|
||||||
|
|
||||||
|
for (u32 index = 0; usize samplerHash : m_SamplerHashes)
|
||||||
|
{
|
||||||
|
if (samplerHash == hash)
|
||||||
|
{
|
||||||
|
return {index};
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Sampler sampler;
|
||||||
|
AbortIfFailed(device->m_Device.createSampler(createInfo, nullptr, &sampler));
|
||||||
|
const u32 index = Cast<u32>(m_SamplerHashes.size());
|
||||||
|
m_SamplerHashes.push_back(hash);
|
||||||
|
m_Samplers.push_back(sampler);
|
||||||
|
return {index};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Sampler
|
||||||
|
SamplerManager::Fetch(const SamplerHandle handle)
|
||||||
|
{
|
||||||
|
assert(!handle.IsInvalid());
|
||||||
|
|
||||||
|
return m_Samplers[handle.m_Index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SamplerManager::Destroy(const Device *device)
|
||||||
|
{
|
||||||
|
for (const auto &sampler : m_Samplers)
|
||||||
|
{
|
||||||
|
device->m_Device.destroy(sampler, nullptr);
|
||||||
|
}
|
||||||
|
m_Samplers.clear();
|
||||||
|
m_SamplerHashes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
||||||
: uBufferInfo(info)
|
: uBufferInfo(info)
|
||||||
{
|
{
|
||||||
|
|
@ -230,7 +303,7 @@ GpuResourceManager::Commit(StorageBuffer *storageBuffer)
|
||||||
|
|
||||||
m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index);
|
m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
++m_CommitedBufferCount;
|
++m_CommitedBufferCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -276,7 +349,7 @@ GpuResourceManager::Release(BufferHandle handle)
|
||||||
|
|
||||||
m_BufferManager.Release(m_Device, handle);
|
m_BufferManager.Release(m_Device, handle);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
--m_CommitedBufferCount;
|
--m_CommitedBufferCount;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +377,7 @@ GpuResourceManager::Release(TextureHandle handle)
|
||||||
|
|
||||||
m_TextureManager.Release(m_Device, handle);
|
m_TextureManager.Release(m_Device, handle);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
--m_CommitedTextureCount;
|
--m_CommitedTextureCount;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -323,12 +396,14 @@ GpuResourceManager::Release(Texture *texture, TextureHandle handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureHandle
|
TextureHandle
|
||||||
GpuResourceManager::Commit(Texture *texture)
|
GpuResourceManager::CommitTexture(Texture *texture, const SamplerHandle sampler)
|
||||||
{
|
{
|
||||||
TextureHandle handle = m_TextureManager.Commit(texture);
|
TextureHandle handle = m_TextureManager.Commit(texture);
|
||||||
|
|
||||||
|
const vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
.sampler = nullptr,
|
.sampler = samplerImpl,
|
||||||
.imageView = texture->m_View,
|
.imageView = texture->m_View,
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
});
|
});
|
||||||
|
|
@ -344,7 +419,7 @@ GpuResourceManager::Commit(Texture *texture)
|
||||||
|
|
||||||
m_WriteOwner.emplace_back(HandleType::eTexture, handle.m_Index);
|
m_WriteOwner.emplace_back(HandleType::eTexture, handle.m_Index);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
++m_CommitedTextureCount;
|
++m_CommitedTextureCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -352,12 +427,14 @@ GpuResourceManager::Commit(Texture *texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageTextureHandle
|
StorageTextureHandle
|
||||||
GpuResourceManager::Commit(StorageTexture *storageTexture)
|
GpuResourceManager::CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler)
|
||||||
{
|
{
|
||||||
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
||||||
|
|
||||||
|
vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
.sampler = nullptr,
|
.sampler = samplerImpl,
|
||||||
.imageView = storageTexture->m_View,
|
.imageView = storageTexture->m_View,
|
||||||
.imageLayout = vk::ImageLayout::eGeneral,
|
.imageLayout = vk::ImageLayout::eGeneral,
|
||||||
});
|
});
|
||||||
|
|
@ -373,7 +450,7 @@ GpuResourceManager::Commit(StorageTexture *storageTexture)
|
||||||
|
|
||||||
m_WriteOwner.emplace_back(HandleType::eStorageTexture, handle.m_Index);
|
m_WriteOwner.emplace_back(HandleType::eStorageTexture, handle.m_Index);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
++m_CommitedStorageTextureCount;
|
++m_CommitedStorageTextureCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -390,7 +467,7 @@ GpuResourceManager::Release(StorageTextureHandle handle)
|
||||||
|
|
||||||
m_StorageTextureManager.Release(m_Device, handle);
|
m_StorageTextureManager.Release(m_Device, handle);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
--m_CommitedStorageTextureCount;
|
--m_CommitedStorageTextureCount;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -432,8 +509,16 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
u32 storageTexturesCount =
|
u32 storageTexturesCount =
|
||||||
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
||||||
|
|
||||||
// TODO: Switch to bindless samplers / multiple sampler configurations
|
INFO("Max Buffer Count: {}", buffersCount);
|
||||||
vk::SamplerCreateInfo samplerCreateInfo = {
|
INFO("Max Texture Count: {}", texturesCount);
|
||||||
|
INFO("Max Storage Texture Count: {}", storageTexturesCount);
|
||||||
|
|
||||||
|
m_BufferManager.Init(buffersCount);
|
||||||
|
m_TextureManager.Init(texturesCount);
|
||||||
|
m_StorageTextureManager.Init(storageTexturesCount);
|
||||||
|
m_SamplerManager.Init(storageTexturesCount);
|
||||||
|
|
||||||
|
m_DefaultSamplerCreateInfo = {
|
||||||
.magFilter = vk::Filter::eLinear,
|
.magFilter = vk::Filter::eLinear,
|
||||||
.minFilter = vk::Filter::eLinear,
|
.minFilter = vk::Filter::eLinear,
|
||||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||||
|
|
@ -449,15 +534,8 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
||||||
.unnormalizedCoordinates = false,
|
.unnormalizedCoordinates = false,
|
||||||
};
|
};
|
||||||
AbortIfFailed(device->m_Device.createSampler(&samplerCreateInfo, nullptr, &m_ImmutableSampler));
|
|
||||||
|
|
||||||
INFO("Max Buffer Count: {}", buffersCount);
|
m_DefaultSampler = m_SamplerManager.Fetch(m_SamplerManager.Create(device, &m_DefaultSamplerCreateInfo));
|
||||||
INFO("Max Texture Count: {}", texturesCount);
|
|
||||||
INFO("Max Storage Texture Count: {}", storageTexturesCount);
|
|
||||||
|
|
||||||
m_BufferManager.Init(buffersCount);
|
|
||||||
m_TextureManager.Init(texturesCount);
|
|
||||||
m_StorageTextureManager.Init(storageTexturesCount);
|
|
||||||
|
|
||||||
eastl::array poolSizes = {
|
eastl::array poolSizes = {
|
||||||
vk::DescriptorPoolSize{
|
vk::DescriptorPoolSize{
|
||||||
|
|
@ -495,7 +573,6 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.pBindingFlags = layoutBindingFlags.data(),
|
.pBindingFlags = layoutBindingFlags.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::vector immutableSamplers(texturesCount, m_ImmutableSampler);
|
|
||||||
eastl::array descriptorLayoutBindings = {
|
eastl::array descriptorLayoutBindings = {
|
||||||
vk::DescriptorSetLayoutBinding{
|
vk::DescriptorSetLayoutBinding{
|
||||||
.binding = BUFFER_BINDING_INDEX,
|
.binding = BUFFER_BINDING_INDEX,
|
||||||
|
|
@ -508,7 +585,6 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorCount = Cast<u32>(texturesCount),
|
.descriptorCount = Cast<u32>(texturesCount),
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.pImmutableSamplers = immutableSamplers.data(),
|
|
||||||
},
|
},
|
||||||
vk::DescriptorSetLayoutBinding{
|
vk::DescriptorSetLayoutBinding{
|
||||||
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||||
|
|
@ -543,7 +619,7 @@ GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||||
|
|
||||||
GpuResourceManager::~GpuResourceManager()
|
GpuResourceManager::~GpuResourceManager()
|
||||||
{
|
{
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0 || m_CommitedStorageTextureCount > 0,
|
WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0 || m_CommitedStorageTextureCount > 0,
|
||||||
"Resources alive: SSBO = {}, Textures = {}, RWTexture = {}", m_CommitedBufferCount, m_CommitedTextureCount,
|
"Resources alive: SSBO = {}, Textures = {}, RWTexture = {}", m_CommitedBufferCount, m_CommitedTextureCount,
|
||||||
m_CommitedStorageTextureCount);
|
m_CommitedStorageTextureCount);
|
||||||
|
|
@ -552,7 +628,7 @@ GpuResourceManager::~GpuResourceManager()
|
||||||
m_BufferManager.Destroy(m_Device);
|
m_BufferManager.Destroy(m_Device);
|
||||||
m_TextureManager.Destroy(m_Device);
|
m_TextureManager.Destroy(m_Device);
|
||||||
m_StorageTextureManager.Destroy(m_Device);
|
m_StorageTextureManager.Destroy(m_Device);
|
||||||
m_Device->m_Device.destroy(m_ImmutableSampler, nullptr);
|
m_SamplerManager.Destroy(m_Device);
|
||||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||||
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -561,16 +637,19 @@ GpuResourceManager::GpuResourceManager(GpuResourceManager &&other) noexcept
|
||||||
: m_WriteInfos(std::move(other.m_WriteInfos))
|
: m_WriteInfos(std::move(other.m_WriteInfos))
|
||||||
, m_Writes(std::move(other.m_Writes))
|
, m_Writes(std::move(other.m_Writes))
|
||||||
, m_WriteOwner(std::move(other.m_WriteOwner))
|
, m_WriteOwner(std::move(other.m_WriteOwner))
|
||||||
, m_ImmutableSampler(other.m_ImmutableSampler)
|
|
||||||
, m_BufferManager(std::move(other.m_BufferManager))
|
, m_BufferManager(std::move(other.m_BufferManager))
|
||||||
, m_TextureManager(std::move(other.m_TextureManager))
|
, m_TextureManager(std::move(other.m_TextureManager))
|
||||||
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
||||||
|
, m_SamplerManager(std::move(other.m_SamplerManager))
|
||||||
, m_Device(Take(other.m_Device))
|
, m_Device(Take(other.m_Device))
|
||||||
, m_DescriptorPool(other.m_DescriptorPool)
|
, m_DescriptorPool(other.m_DescriptorPool)
|
||||||
, m_SetLayout(other.m_SetLayout)
|
, m_SetLayout(other.m_SetLayout)
|
||||||
, m_DescriptorSet(other.m_DescriptorSet)
|
, m_DescriptorSet(other.m_DescriptorSet)
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
, m_CommitedBufferCount(other.m_CommitedBufferCount)
|
, m_CommitedBufferCount(other.m_CommitedBufferCount)
|
||||||
, m_CommitedTextureCount(other.m_CommitedTextureCount)
|
, m_CommitedTextureCount(other.m_CommitedTextureCount)
|
||||||
|
, m_CommitedStorageTextureCount(other.m_CommitedStorageTextureCount)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
assert(!other.m_Device);
|
assert(!other.m_Device);
|
||||||
}
|
}
|
||||||
|
|
@ -583,17 +662,26 @@ GpuResourceManager::operator=(GpuResourceManager &&other) noexcept
|
||||||
m_WriteInfos = std::move(other.m_WriteInfos);
|
m_WriteInfos = std::move(other.m_WriteInfos);
|
||||||
m_Writes = std::move(other.m_Writes);
|
m_Writes = std::move(other.m_Writes);
|
||||||
m_WriteOwner = std::move(other.m_WriteOwner);
|
m_WriteOwner = std::move(other.m_WriteOwner);
|
||||||
m_ImmutableSampler = other.m_ImmutableSampler;
|
|
||||||
m_BufferManager = std::move(other.m_BufferManager);
|
m_BufferManager = std::move(other.m_BufferManager);
|
||||||
m_TextureManager = std::move(other.m_TextureManager);
|
m_TextureManager = std::move(other.m_TextureManager);
|
||||||
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
||||||
|
m_SamplerManager = std::move(other.m_SamplerManager);
|
||||||
m_Device = Take(other.m_Device); // Ensure taken.
|
m_Device = Take(other.m_Device); // Ensure taken.
|
||||||
m_DescriptorPool = other.m_DescriptorPool;
|
m_DescriptorPool = other.m_DescriptorPool;
|
||||||
m_SetLayout = other.m_SetLayout;
|
m_SetLayout = other.m_SetLayout;
|
||||||
m_DescriptorSet = other.m_DescriptorSet;
|
m_DescriptorSet = other.m_DescriptorSet;
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
m_CommitedBufferCount = other.m_CommitedBufferCount;
|
m_CommitedBufferCount = other.m_CommitedBufferCount;
|
||||||
m_CommitedTextureCount = other.m_CommitedTextureCount;
|
m_CommitedTextureCount = other.m_CommitedTextureCount;
|
||||||
|
m_CommitedStorageTextureCount = other.m_CommitedStorageTextureCount;
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(!other.m_Device);
|
assert(!other.m_Device);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SamplerHandle
|
||||||
|
GpuResourceManager::CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo)
|
||||||
|
{
|
||||||
|
return m_SamplerManager.Create(m_Device, samplerCreateInfo);
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,10 @@ struct StorageTextureHandle : GpuResourceHandle
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SamplerHandle : GpuResourceHandle
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
struct TextureManager
|
struct TextureManager
|
||||||
{
|
{
|
||||||
eastl::vector<Texture> m_Textures;
|
eastl::vector<Texture> m_Textures;
|
||||||
|
|
@ -72,6 +76,18 @@ struct StorageTextureManager : TextureManager
|
||||||
void Release(const Device *device, StorageTextureHandle handle);
|
void Release(const Device *device, StorageTextureHandle handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SamplerManager
|
||||||
|
{
|
||||||
|
// There can only be so many samplers.
|
||||||
|
eastl::vector<vk::Sampler> m_Samplers;
|
||||||
|
eastl::vector<usize> m_SamplerHashes;
|
||||||
|
|
||||||
|
void Init(usize size);
|
||||||
|
SamplerHandle Create(const Device *device, const vk::SamplerCreateInfo *createInfo);
|
||||||
|
vk::Sampler Fetch(SamplerHandle handle);
|
||||||
|
void Destroy(const Device *device);
|
||||||
|
};
|
||||||
|
|
||||||
struct GpuResourceManager
|
struct GpuResourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -102,11 +118,12 @@ struct GpuResourceManager
|
||||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||||
eastl::vector<WriteOwner> m_WriteOwner;
|
eastl::vector<WriteOwner> m_WriteOwner;
|
||||||
|
|
||||||
vk::Sampler m_ImmutableSampler;
|
vk::Sampler m_DefaultSampler;
|
||||||
|
|
||||||
BufferManager m_BufferManager;
|
BufferManager m_BufferManager;
|
||||||
TextureManager m_TextureManager;
|
TextureManager m_TextureManager;
|
||||||
StorageTextureManager m_StorageTextureManager;
|
StorageTextureManager m_StorageTextureManager;
|
||||||
|
SamplerManager m_SamplerManager;
|
||||||
|
|
||||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||||
|
|
||||||
|
|
@ -117,6 +134,8 @@ struct GpuResourceManager
|
||||||
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
||||||
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
||||||
|
|
||||||
|
vk::SamplerCreateInfo m_DefaultSamplerCreateInfo;
|
||||||
|
|
||||||
vk::DescriptorPool m_DescriptorPool;
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
vk::DescriptorSetLayout m_SetLayout;
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
vk::DescriptorSet m_DescriptorSet;
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
@ -126,13 +145,16 @@ struct GpuResourceManager
|
||||||
void Release(BufferHandle handle); // Release and Destroy
|
void Release(BufferHandle handle); // Release and Destroy
|
||||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||||
|
|
||||||
TextureHandle Commit(Texture *texture); // Commit to GPU and take Ownership
|
TextureHandle CommitTexture(Texture *texture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||||
void Release(TextureHandle handle); // Release and Destroy
|
void Release(TextureHandle handle); // Release and Destroy
|
||||||
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
||||||
|
|
||||||
StorageTextureHandle Commit(StorageTexture *storageTexture);
|
StorageTextureHandle
|
||||||
void Release(StorageTextureHandle handle);
|
CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||||
void Release(StorageTexture *texture, StorageTextureHandle handle);
|
void Release(StorageTextureHandle handle); // Release and Destroy
|
||||||
|
void Release(StorageTexture *texture, StorageTextureHandle handle); // Release and Return
|
||||||
|
|
||||||
|
SamplerHandle CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo);
|
||||||
|
|
||||||
void Update(); // Update all the descriptors required.
|
void Update(); // Update all the descriptors required.
|
||||||
|
|
||||||
|
|
@ -143,7 +165,7 @@ struct GpuResourceManager
|
||||||
GpuResourceManager(GpuResourceManager &&other) noexcept;
|
GpuResourceManager(GpuResourceManager &&other) noexcept;
|
||||||
GpuResourceManager &operator=(GpuResourceManager &&other) noexcept;
|
GpuResourceManager &operator=(GpuResourceManager &&other) noexcept;
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
usize m_CommitedBufferCount = 0;
|
usize m_CommitedBufferCount = 0;
|
||||||
usize m_CommitedTextureCount = 0;
|
usize m_CommitedTextureCount = 0;
|
||||||
usize m_CommitedStorageTextureCount = 0;
|
usize m_CommitedStorageTextureCount = 0;
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk:
|
||||||
{
|
{
|
||||||
// OPTICK_EVENT();
|
// OPTICK_EVENT();
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
constexpr vk::DebugUtilsLabelEXT label = {
|
constexpr vk::DebugUtilsLabelEXT label = {
|
||||||
.pLabelName = "UI pass",
|
.pLabelName = "UI pass",
|
||||||
.color = std::array{0.9f, 0.9f, 1.0f, 1.0f},
|
.color = std::array{0.9f, 0.9f, 1.0f, 1.0f},
|
||||||
|
|
@ -195,7 +195,7 @@ Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk:
|
||||||
|
|
||||||
commandBuffer.endRendering();
|
commandBuffer.endRendering();
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
commandBuffer.endDebugUtilsLabelEXT();
|
commandBuffer.endDebugUtilsLabelEXT();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,12 @@ add_executable(model_render model_render.cpp
|
||||||
|
|
||||||
add_shader(model_render shader/model.vs.hlsl)
|
add_shader(model_render shader/model.vs.hlsl)
|
||||||
add_shader(model_render shader/model.ps.hlsl)
|
add_shader(model_render shader/model.ps.hlsl)
|
||||||
add_shader(model_render shader/eqrectToCube.cs.hlsl)
|
add_shader(model_render shader/eqrect_to_cube.cs.hlsl)
|
||||||
add_shader(model_render shader/background.vs.hlsl)
|
add_shader(model_render shader/background.vs.hlsl)
|
||||||
add_shader(model_render shader/background.ps.hlsl)
|
add_shader(model_render shader/background.ps.hlsl)
|
||||||
|
add_shader(model_render shader/diffuse_irradiance.cs.hlsl)
|
||||||
|
add_shader(model_render shader/prefilter.cs.hlsl)
|
||||||
|
add_shader(model_render shader/brdf_lut.cs.hlsl)
|
||||||
|
|
||||||
target_link_libraries(model_render PRIVATE aster_core)
|
target_link_libraries(model_render PRIVATE aster_core)
|
||||||
target_link_libraries(model_render PRIVATE util_helper)
|
target_link_libraries(model_render PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@
|
||||||
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
|
|
||||||
|
#include "EASTL/fixed_vector.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
|
||||||
#include <EASTL/hash_map.h>
|
#include <EASTL/hash_map.h>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
||||||
|
|
||||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += name ? name : path;
|
loadActionName += name ? name : path;
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
vk::DebugUtilsLabelEXT debugLabel = {
|
||||||
|
|
@ -165,7 +165,7 @@ AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
||||||
m_CommandBuffer.copyBufferToImage2(&stagingInfo);
|
m_CommandBuffer.copyBufferToImage2(&stagingInfo);
|
||||||
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -190,6 +190,176 @@ AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
||||||
stagingBuffer.Destroy(pDevice);
|
stagingBuffer.Destroy(pDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayout initialLayout,
|
||||||
|
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage)
|
||||||
|
{
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
vk::DebugUtilsLabelEXT label = {
|
||||||
|
.pLabelName = "Generate Mipmap",
|
||||||
|
.color = std::array{0.9f, 0.9f, 0.9f, 1.0f},
|
||||||
|
};
|
||||||
|
commandBuffer.beginDebugUtilsLabelEXT(&label);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier2 imageStartBarrier = {
|
||||||
|
.srcStageMask = prevStage,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||||
|
.oldLayout = initialLayout,
|
||||||
|
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = texture->m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vk::ImageMemoryBarrier2 mipsStartBarrier = imageStartBarrier;
|
||||||
|
mipsStartBarrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
|
||||||
|
mipsStartBarrier.oldLayout = vk::ImageLayout::eUndefined;
|
||||||
|
mipsStartBarrier.newLayout = vk::ImageLayout::eTransferDstOptimal;
|
||||||
|
mipsStartBarrier.subresourceRange = {
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 1,
|
||||||
|
.levelCount = texture->GetMipLevels() - 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
eastl::fixed_vector<vk::ImageMemoryBarrier2, 2> startBarriers = {
|
||||||
|
mipsStartBarrier,
|
||||||
|
};
|
||||||
|
if (initialLayout != imageStartBarrier.newLayout)
|
||||||
|
{
|
||||||
|
startBarriers.push_back(imageStartBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::DependencyInfo imageStartDependency = {
|
||||||
|
.imageMemoryBarrierCount = Cast<u32>(startBarriers.size()),
|
||||||
|
.pImageMemoryBarriers = startBarriers.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier2 nextMipBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||||
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = texture->m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vk::DependencyInfo interMipDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &nextMipBarrier,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier2 imageReadyBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
|
.dstStageMask = finalStage,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||||
|
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
.newLayout = finalLayout,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = texture->m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = texture->GetMipLevels(),
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vk::DependencyInfo imageReadyDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &imageReadyBarrier,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ImageBlit2 blitRegion = {
|
||||||
|
.srcSubresource =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
.dstSubresource =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::BlitImageInfo2 mipBlitInfo = {
|
||||||
|
.srcImage = texture->m_Image,
|
||||||
|
.srcImageLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
.dstImage = texture->m_Image,
|
||||||
|
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.regionCount = 1,
|
||||||
|
.pRegions = &blitRegion,
|
||||||
|
.filter = vk::Filter::eLinear,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); };
|
||||||
|
|
||||||
|
// Mip Mapping
|
||||||
|
|
||||||
|
commandBuffer.pipelineBarrier2(&imageStartDependency);
|
||||||
|
|
||||||
|
i32 prevMipWidth = Cast<i32>(texture->m_Extent.width);
|
||||||
|
i32 prevMipHeight = Cast<i32>(texture->m_Extent.height);
|
||||||
|
|
||||||
|
u32 maxPrevMip = texture->GetMipLevels() - 1;
|
||||||
|
for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel)
|
||||||
|
{
|
||||||
|
i32 currentMipWidth = calcNextMip(prevMipWidth);
|
||||||
|
i32 currentMipHeight = calcNextMip(prevMipHeight);
|
||||||
|
u32 currentMipLevel = prevMipLevel + 1;
|
||||||
|
|
||||||
|
blitRegion.srcSubresource.mipLevel = prevMipLevel;
|
||||||
|
blitRegion.srcOffsets = std::array{
|
||||||
|
vk::Offset3D{0, 0, 0},
|
||||||
|
vk::Offset3D{prevMipWidth, prevMipHeight, 1},
|
||||||
|
};
|
||||||
|
blitRegion.dstSubresource.mipLevel = currentMipLevel;
|
||||||
|
blitRegion.dstOffsets = std::array{
|
||||||
|
vk::Offset3D{0, 0, 0},
|
||||||
|
vk::Offset3D{currentMipWidth, currentMipHeight, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel;
|
||||||
|
|
||||||
|
commandBuffer.blitImage2(&mipBlitInfo);
|
||||||
|
commandBuffer.pipelineBarrier2(&interMipDependency);
|
||||||
|
|
||||||
|
prevMipHeight = currentMipHeight;
|
||||||
|
prevMipWidth = currentMipWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBuffer.pipelineBarrier2(&imageReadyDependency);
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
commandBuffer.endDebugUtilsLabelEXT();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
TextureHandle
|
TextureHandle
|
||||||
AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const
|
AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const
|
||||||
{
|
{
|
||||||
|
|
@ -209,7 +379,7 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
||||||
stagingBuffer->Init(m_ResourceManager->m_Device, byteSize);
|
stagingBuffer->Init(m_ResourceManager->m_Device, byteSize);
|
||||||
stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
|
stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += image->name.empty() ? "<texture>" : image->name.c_str();
|
loadActionName += image->name.empty() ? "<texture>" : image->name.c_str();
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
vk::DebugUtilsLabelEXT debugLabel = {
|
||||||
|
|
@ -235,7 +405,7 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = texture.GetMipLevels(),
|
.levelCount = 1,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
|
|
@ -247,15 +417,13 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
||||||
.pImageMemoryBarriers = &imageStartBarrier,
|
.pImageMemoryBarriers = &imageStartBarrier,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 nextMipBarrier = {
|
vk::ImageMemoryBarrier2 postStagingBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
.srcStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
.dstStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
||||||
.image = texture.m_Image,
|
.image = texture.m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
|
|
@ -266,33 +434,11 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
vk::DependencyInfo interMipDependency = {
|
;
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &nextMipBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 imageReadyBarrier = {
|
vk::DependencyInfo postStagingDependency = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
|
||||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
|
||||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
|
||||||
.image = texture.m_Image,
|
|
||||||
.subresourceRange =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = texture.GetMipLevels(),
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
vk::DependencyInfo imageReadyDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
.imageMemoryBarrierCount = 1,
|
||||||
.pImageMemoryBarriers = &imageReadyBarrier,
|
.pImageMemoryBarriers = &postStagingBarrier,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::BufferImageCopy2 imageCopy = {
|
vk::BufferImageCopy2 imageCopy = {
|
||||||
|
|
@ -317,78 +463,20 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
||||||
.pRegions = &imageCopy,
|
.pRegions = &imageCopy,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::ImageBlit2 blitRegion = {
|
|
||||||
.srcSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
.dstSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::BlitImageInfo2 mipBlitInfo = {
|
|
||||||
.srcImage = texture.m_Image,
|
|
||||||
.srcImageLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
||||||
.dstImage = texture.m_Image,
|
|
||||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.regionCount = 1,
|
|
||||||
.pRegions = &blitRegion,
|
|
||||||
.filter = vk::Filter::eLinear,
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
m_CommandBuffer.pipelineBarrier2(&imageStartDependency);
|
m_CommandBuffer.pipelineBarrier2(&imageStartDependency);
|
||||||
m_CommandBuffer.copyBufferToImage2(&stagingCopyInfo);
|
m_CommandBuffer.copyBufferToImage2(&stagingCopyInfo);
|
||||||
m_CommandBuffer.pipelineBarrier2(&interMipDependency);
|
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
||||||
|
|
||||||
auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); };
|
GenerateMipMaps(m_CommandBuffer, &texture, vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||||
|
|
||||||
// Mip Mapping
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
|
||||||
i32 prevMipWidth = Cast<i32>(texture.m_Extent.width);
|
|
||||||
i32 prevMipHeight = Cast<i32>(texture.m_Extent.height);
|
|
||||||
|
|
||||||
u32 maxPrevMip = texture.GetMipLevels() - 1;
|
|
||||||
for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel)
|
|
||||||
{
|
|
||||||
i32 currentMipWidth = calcNextMip(prevMipWidth);
|
|
||||||
i32 currentMipHeight = calcNextMip(prevMipHeight);
|
|
||||||
u32 currentMipLevel = prevMipLevel + 1;
|
|
||||||
|
|
||||||
blitRegion.srcSubresource.mipLevel = prevMipLevel;
|
|
||||||
blitRegion.srcOffsets = std::array{
|
|
||||||
vk::Offset3D{0, 0, 0},
|
|
||||||
vk::Offset3D{prevMipWidth, prevMipHeight, 1},
|
|
||||||
};
|
|
||||||
blitRegion.dstSubresource.mipLevel = currentMipLevel;
|
|
||||||
blitRegion.dstOffsets = std::array{
|
|
||||||
vk::Offset3D{0, 0, 0},
|
|
||||||
vk::Offset3D{currentMipWidth, currentMipHeight, 1},
|
|
||||||
};
|
|
||||||
|
|
||||||
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel;
|
|
||||||
|
|
||||||
m_CommandBuffer.blitImage2(&mipBlitInfo);
|
|
||||||
m_CommandBuffer.pipelineBarrier2(&interMipDependency);
|
|
||||||
|
|
||||||
prevMipHeight = currentMipHeight;
|
|
||||||
prevMipWidth = currentMipWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CommandBuffer.pipelineBarrier2(&imageReadyDependency);
|
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return m_ResourceManager->Commit(&texture);
|
return m_ResourceManager->CommitTexture(&texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model
|
Model
|
||||||
|
|
@ -425,7 +513,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
|
|
||||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += name ? name : path;
|
loadActionName += name ? name : path;
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
vk::DebugUtilsLabelEXT debugLabel = {
|
||||||
|
|
@ -808,7 +896,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||||
#endif
|
#endif
|
||||||
AbortIfFailed(m_CommandBuffer.end());
|
AbortIfFailed(m_CommandBuffer.end());
|
||||||
|
|
|
||||||
|
|
@ -118,3 +118,8 @@ struct AssetLoader
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AssetLoader);
|
DISALLOW_COPY_AND_ASSIGN(AssetLoader);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayout initialLayout,
|
||||||
|
vk::ImageLayout finalLayout,
|
||||||
|
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
||||||
|
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands);
|
||||||
|
|
@ -5,36 +5,86 @@
|
||||||
|
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
|
|
||||||
|
#include "EASTL/fixed_vector.h"
|
||||||
|
#include "EASTL/tuple.h"
|
||||||
|
#include "asset_loader.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "asset_loader.h"
|
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrectToCube.cs.hlsl.spv";
|
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
||||||
|
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||||
|
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||||
|
constexpr cstr BRDF_LUT_SHADER_FILE = "shader/brdf_lut.cs.hlsl.spv";
|
||||||
|
|
||||||
TextureHandle
|
void
|
||||||
|
Environment::Destroy(GpuResourceManager *resourceManager)
|
||||||
|
{
|
||||||
|
resourceManager->Release(Take(m_Skybox));
|
||||||
|
resourceManager->Release(Take(m_Diffuse));
|
||||||
|
resourceManager->Release(Take(m_Prefilter));
|
||||||
|
resourceManager->Release(Take(m_BrdfLut));
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment
|
||||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
||||||
const cstr name)
|
const cstr name)
|
||||||
{
|
{
|
||||||
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
||||||
const Device *pDevice = resMan->m_Device;
|
const Device *pDevice = resMan->m_Device;
|
||||||
|
|
||||||
TextureCube cubeMap;
|
vk::SamplerCreateInfo brdfLutSamplerCreateInfo = resMan->m_DefaultSamplerCreateInfo;
|
||||||
cubeMap.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, false, name ? name : "Env CubeMap");
|
brdfLutSamplerCreateInfo.addressModeU = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
brdfLutSamplerCreateInfo.addressModeV = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
brdfLutSamplerCreateInfo.addressModeW = vk::SamplerAddressMode::eClampToEdge;
|
||||||
|
|
||||||
StorageTexture stagingTexture;
|
StorageTextureCube skybox;
|
||||||
stagingTexture.Init(pDevice, {cubeSide * 3, cubeSide * 2}, vk::Format::eR16G16B16A16Sfloat, false, "EnvStaging");
|
StorageTextureCube diffuseIrradiance;
|
||||||
auto envStagingHandle = resMan->Commit(&stagingTexture);
|
StorageTextureCube prefilterCube;
|
||||||
|
StorageTexture brdfLut;
|
||||||
|
SamplerHandle brdfLutSampler;
|
||||||
|
|
||||||
vk::ImageSubresourceRange stagingSubresRange = {
|
skybox.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Skybox");
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
TextureHandle skyboxHandle = resMan->CommitTexture(&skybox);
|
||||||
.baseMipLevel = 0,
|
StorageTextureHandle skyboxStorageHandle = resMan->CommitStorageTexture(&skybox);
|
||||||
.levelCount = 1,
|
|
||||||
.baseArrayLayer = 0,
|
diffuseIrradiance.Init(pDevice, 64, vk::Format::eR16G16B16A16Sfloat, true, false, "Diffuse Irradiance");
|
||||||
.layerCount = 1,
|
TextureHandle diffuseIrradianceHandle = resMan->CommitTexture(&diffuseIrradiance);
|
||||||
};
|
StorageTextureHandle diffuseIrradianceStorageHandle = resMan->CommitStorageTexture(&diffuseIrradiance);
|
||||||
|
|
||||||
|
prefilterCube.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Prefilter");
|
||||||
|
TextureHandle prefilterHandle = resMan->CommitTexture(&prefilterCube); // This stores the original view for us.
|
||||||
|
constexpr u32 prefilterMipCountMax = 6;
|
||||||
|
eastl::array<StorageTextureHandle, prefilterMipCountMax> prefilterStorageHandles;
|
||||||
|
// All non-owning copies.
|
||||||
|
for (u32 mipLevel = 0; auto &tex : prefilterStorageHandles)
|
||||||
|
{
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = prefilterCube.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::eCube,
|
||||||
|
.format = vk::Format::eR16G16B16A16Sfloat,
|
||||||
|
.components = vk::ComponentMapping{},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = mipLevel++,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 6,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
AbortIfFailed(pDevice->m_Device.createImageView(&imageViewCreateInfo, nullptr, &prefilterCube.m_View));
|
||||||
|
tex = resMan->CommitStorageTexture(&prefilterCube);
|
||||||
|
}
|
||||||
|
|
||||||
|
brdfLut.Init(pDevice, {512, 512}, vk::Format::eR16G16Sfloat, true, "BRDF LUT");
|
||||||
|
brdfLutSampler = resMan->CreateSampler(&brdfLutSamplerCreateInfo);
|
||||||
|
TextureHandle brdfLutHandle = resMan->CommitTexture(&brdfLut, brdfLutSampler);
|
||||||
|
StorageTextureHandle brdfLutStorageHandle = resMan->CommitStorageTexture(&brdfLut);
|
||||||
|
|
||||||
|
#pragma region Dependencies and Copies
|
||||||
vk::ImageSubresourceRange cubeSubresRange = {
|
vk::ImageSubresourceRange cubeSubresRange = {
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
|
|
@ -42,8 +92,15 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 6,
|
.layerCount = 6,
|
||||||
};
|
};
|
||||||
|
vk::ImageSubresourceRange lutSubresRange = {
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 readyToWriteBarrier = {
|
vk::ImageMemoryBarrier2 readyToWriteBarrierTemplate = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
.dstStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
||||||
|
|
@ -52,117 +109,94 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.newLayout = vk::ImageLayout::eGeneral,
|
.newLayout = vk::ImageLayout::eGeneral,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = stagingTexture.m_Image,
|
|
||||||
.subresourceRange = stagingSubresRange,
|
|
||||||
};
|
|
||||||
vk::DependencyInfo readyToWriteDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &readyToWriteBarrier,
|
|
||||||
};
|
|
||||||
vk::ImageMemoryBarrier2 stagingReadyForTransfer = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eGeneral,
|
|
||||||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = stagingTexture.m_Image,
|
|
||||||
.subresourceRange = stagingSubresRange,
|
|
||||||
};
|
|
||||||
vk::ImageMemoryBarrier2 cubeReadyForTransfer = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
|
||||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = cubeMap.m_Image,
|
|
||||||
.subresourceRange = cubeSubresRange,
|
.subresourceRange = cubeSubresRange,
|
||||||
};
|
};
|
||||||
eastl::array transferBarriers = {stagingReadyForTransfer, cubeReadyForTransfer};
|
eastl::fixed_vector<vk::ImageMemoryBarrier2, 4> readyToWriteBarriers(4, readyToWriteBarrierTemplate);
|
||||||
vk::DependencyInfo preTransferDependency = {
|
readyToWriteBarriers[0].image = skybox.m_Image;
|
||||||
.imageMemoryBarrierCount = transferBarriers.size(),
|
readyToWriteBarriers[1].image = diffuseIrradiance.m_Image;
|
||||||
.pImageMemoryBarriers = transferBarriers.data(),
|
readyToWriteBarriers[2].image = prefilterCube.m_Image;
|
||||||
|
readyToWriteBarriers[3].image = brdfLut.m_Image;
|
||||||
|
readyToWriteBarriers[3].subresourceRange = lutSubresRange;
|
||||||
|
|
||||||
|
vk::DependencyInfo readyToWriteDependency = {
|
||||||
|
.imageMemoryBarrierCount = Cast<u32>(readyToWriteBarriers.size()),
|
||||||
|
.pImageMemoryBarriers = readyToWriteBarriers.data(),
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier2 cubemapToRead = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
vk::ImageMemoryBarrier2 readyToSampleBarrierTemplate = {
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
.srcStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite | vk::AccessFlagBits2::eShaderStorageRead,
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderSampledRead,
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eGeneral,
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = cubeMap.m_Image,
|
|
||||||
.subresourceRange = cubeSubresRange,
|
.subresourceRange = cubeSubresRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo cubemapToReadDependency = {
|
auto skyboxToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
skyboxToSampleBarrier.image = skybox.m_Image;
|
||||||
|
|
||||||
|
auto diffIrrToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
diffIrrToSampleBarrier.image = diffuseIrradiance.m_Image;
|
||||||
|
|
||||||
|
auto prefilterToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
prefilterToSampleBarrier.image = prefilterCube.m_Image;
|
||||||
|
|
||||||
|
auto brdfToSampleBarrier = readyToSampleBarrierTemplate;
|
||||||
|
prefilterToSampleBarrier.image = brdfLut.m_Image;
|
||||||
|
prefilterToSampleBarrier.subresourceRange = lutSubresRange;
|
||||||
|
|
||||||
|
vk::DependencyInfo skyboxToSampleDependency = {
|
||||||
.imageMemoryBarrierCount = 1,
|
.imageMemoryBarrierCount = 1,
|
||||||
.pImageMemoryBarriers = &cubemapToRead,
|
.pImageMemoryBarriers = &skyboxToSampleBarrier,
|
||||||
|
};
|
||||||
|
vk::DependencyInfo diffIrrToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &diffIrrToSampleBarrier,
|
||||||
|
};
|
||||||
|
vk::DependencyInfo prefilterToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &prefilterToSampleBarrier,
|
||||||
|
};
|
||||||
|
vk::DependencyInfo brdfToSampleDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &brdfToSampleBarrier,
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::ImageCopy2, 6> imageCopies;
|
#pragma endregion
|
||||||
for (i32 i = 0; i < 6; ++i)
|
|
||||||
{
|
|
||||||
imageCopies[i] = vk::ImageCopy2{
|
|
||||||
.srcSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.mipLevel = 0,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
.srcOffset =
|
|
||||||
{
|
|
||||||
(i % 3) * Cast<i32>(cubeSide),
|
|
||||||
(i / 3) * Cast<i32>(cubeSide),
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
.dstSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.mipLevel = 0,
|
|
||||||
.baseArrayLayer = Cast<u32>(i),
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
.dstOffset = {0, 0, 0},
|
|
||||||
.extent = {cubeSide, cubeSide, 1},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::CopyImageInfo2 copyFlatToCube = {
|
struct SkyboxPushConstants
|
||||||
.srcImage = stagingTexture.m_Image,
|
|
||||||
.srcImageLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
||||||
.dstImage = cubeMap.m_Image,
|
|
||||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.regionCount = imageCopies.size(),
|
|
||||||
.pRegions = imageCopies.data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WorkloadPushConstants
|
|
||||||
{
|
{
|
||||||
TextureHandle m_HdrEnvHandle;
|
TextureHandle m_HdrEnvHandle;
|
||||||
StorageTextureHandle m_OutputTexture;
|
StorageTextureHandle m_OutputTexture;
|
||||||
u32 m_CubeSide;
|
u32 m_CubeSide;
|
||||||
};
|
};
|
||||||
|
struct DiffuseIrradiancePushConstants
|
||||||
|
{
|
||||||
|
TextureHandle m_SkyboxHandle;
|
||||||
|
StorageTextureHandle m_OutputTexture;
|
||||||
|
u32 m_CubeSide;
|
||||||
|
};
|
||||||
|
struct PrefilterPushConstants
|
||||||
|
{
|
||||||
|
TextureHandle m_SkyboxHandle;
|
||||||
|
StorageTextureHandle m_OutputTexture;
|
||||||
|
u32 m_CubeSide;
|
||||||
|
f32 m_Roughness;
|
||||||
|
u32 m_EnvSide;
|
||||||
|
};
|
||||||
|
struct BrdfLutPushConstants
|
||||||
|
{
|
||||||
|
StorageTextureHandle m_OutputTexture;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma region Pipeline Creation etc
|
#pragma region Pipeline Creation etc
|
||||||
const auto shaderModule = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
|
||||||
|
|
||||||
const vk::PipelineShaderStageCreateInfo shaderStageCreateInfo = {
|
|
||||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
|
||||||
.module = shaderModule,
|
|
||||||
.pName = "main",
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = sizeof(WorkloadPushConstants),
|
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
|
@ -174,21 +208,83 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
};
|
};
|
||||||
AbortIfFailed(pDevice->m_Device.createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout));
|
AbortIfFailed(pDevice->m_Device.createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
|
|
||||||
const vk::ComputePipelineCreateInfo computePipelineCreateInfo = {
|
const auto eqRectToCubeShader = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
||||||
.stage = shaderStageCreateInfo,
|
const auto diffuseRadianceShader = CreateShader(pDevice, DIFFUSE_IRRADIANCE_SHADER_FILE);
|
||||||
.layout = pipelineLayout,
|
const auto prefilterShader = CreateShader(pDevice, PREFILTER_SHADER_FILE);
|
||||||
|
const auto brdfLutShader = CreateShader(pDevice, BRDF_LUT_SHADER_FILE);
|
||||||
|
eastl::array computePipelineCreateInfo = {
|
||||||
|
vk::ComputePipelineCreateInfo{
|
||||||
|
.stage =
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
.module = eqRectToCubeShader,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
},
|
||||||
|
vk::ComputePipelineCreateInfo{
|
||||||
|
.stage =
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
.module = diffuseRadianceShader,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
},
|
||||||
|
vk::ComputePipelineCreateInfo{
|
||||||
|
.stage =
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
.module = prefilterShader,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
},
|
||||||
|
vk::ComputePipelineCreateInfo{
|
||||||
|
.stage =
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
|
.module = brdfLutShader,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::Pipeline pipeline;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, 1, &computePipelineCreateInfo,
|
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
||||||
nullptr, &pipeline));
|
computePipelineCreateInfo.data(), nullptr,
|
||||||
|
pipelines.data()));
|
||||||
|
|
||||||
pDevice->m_Device.destroy(shaderModule, nullptr);
|
vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
||||||
|
vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
||||||
|
vk::Pipeline prefilterPipeline = pipelines[2];
|
||||||
|
vk::Pipeline brdfLutPipeline = pipelines[3];
|
||||||
|
|
||||||
|
for (auto &createInfos : computePipelineCreateInfo)
|
||||||
|
{
|
||||||
|
pDevice->m_Device.destroy(createInfos.stage.module, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
WorkloadPushConstants pushConstants = {
|
SkyboxPushConstants skyboxPushConstant = {
|
||||||
.m_HdrEnvHandle = hdrEnv, .m_OutputTexture = envStagingHandle, .m_CubeSide = cubeSide};
|
.m_HdrEnvHandle = hdrEnv,
|
||||||
|
.m_OutputTexture = skyboxStorageHandle,
|
||||||
|
.m_CubeSide = cubeSide,
|
||||||
|
};
|
||||||
|
DiffuseIrradiancePushConstants diffuseIrradiancePushConstants = {
|
||||||
|
.m_SkyboxHandle = skyboxHandle,
|
||||||
|
.m_OutputTexture = diffuseIrradianceStorageHandle,
|
||||||
|
.m_CubeSide = diffuseIrradiance.m_Extent.width,
|
||||||
|
};
|
||||||
|
PrefilterPushConstants prefilterPushConstants = {
|
||||||
|
.m_SkyboxHandle = skyboxHandle,
|
||||||
|
.m_EnvSide = cubeSide,
|
||||||
|
};
|
||||||
|
BrdfLutPushConstants brdfLutPushConstants = {
|
||||||
|
.m_OutputTexture = brdfLutStorageHandle,
|
||||||
|
};
|
||||||
|
|
||||||
resMan->Update();
|
resMan->Update();
|
||||||
|
|
||||||
|
|
@ -196,7 +292,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
constexpr vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
constexpr vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(cmd.begin(&beginInfo));
|
AbortIfFailed(cmd.begin(&beginInfo));
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
StackString<128> labelName = "Eqrect -> Cubemap: ";
|
StackString<128> labelName = "Eqrect -> Cubemap: ";
|
||||||
labelName += name ? name : "<unknown env>";
|
labelName += name ? name : "<unknown env>";
|
||||||
vk::DebugUtilsLabelEXT label = {
|
vk::DebugUtilsLabelEXT label = {
|
||||||
|
|
@ -209,17 +305,50 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
cmd.pipelineBarrier2(&readyToWriteDependency);
|
cmd.pipelineBarrier2(&readyToWriteDependency);
|
||||||
|
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &resMan->m_DescriptorSet, 0, nullptr);
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &resMan->m_DescriptorSet, 0, nullptr);
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, eqRectToCubePipeline);
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof pushConstants, &pushConstants);
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||||
cmd.dispatch(cubeSide / 16, cubeSide / 16, 6);
|
&skyboxPushConstant);
|
||||||
|
assert(skybox.m_Extent.width % 16 == 0 && skybox.m_Extent.height % 16 == 0);
|
||||||
|
cmd.dispatch(skybox.m_Extent.width / 16, skybox.m_Extent.height / 16, 6);
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&preTransferDependency);
|
GenerateMipMaps(cmd, &skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||||
|
vk::PipelineStageFlagBits2::eComputeShader, vk::PipelineStageFlagBits2::eComputeShader);
|
||||||
|
|
||||||
cmd.copyImage2(©FlatToCube);
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, diffuseIrradiancePipeline);
|
||||||
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||||
|
&diffuseIrradiancePushConstants);
|
||||||
|
assert(diffuseIrradiance.m_Extent.width % 16 == 0 && diffuseIrradiance.m_Extent.height % 16 == 0);
|
||||||
|
cmd.dispatch(diffuseIrradiance.m_Extent.width / 16, diffuseIrradiance.m_Extent.width / 16, 6);
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&cubemapToReadDependency);
|
cmd.pipelineBarrier2(&diffIrrToSampleDependency);
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, prefilterPipeline);
|
||||||
|
u32 mipSize = prefilterCube.m_Extent.width;
|
||||||
|
assert(mipSize % 16 == 0);
|
||||||
|
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
||||||
|
{
|
||||||
|
prefilterPushConstants.m_OutputTexture = tex;
|
||||||
|
prefilterPushConstants.m_CubeSide = mipSize;
|
||||||
|
prefilterPushConstants.m_Roughness = Cast<f32>(mipCount) / Cast<f32>(prefilterMipCountMax);
|
||||||
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof prefilterPushConstants,
|
||||||
|
&prefilterPushConstants);
|
||||||
|
u32 groupCount = eastl::max(mipSize / 16u, 1u);
|
||||||
|
cmd.dispatch(groupCount, groupCount, 6);
|
||||||
|
|
||||||
|
++mipCount;
|
||||||
|
mipSize = mipSize >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.pipelineBarrier2(&skyboxToSampleDependency);
|
||||||
|
cmd.pipelineBarrier2(&prefilterToSampleDependency);
|
||||||
|
|
||||||
|
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, brdfLutPipeline);
|
||||||
|
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof brdfLutPushConstants,
|
||||||
|
&brdfLutPushConstants);
|
||||||
|
assert(brdfLut.m_Extent.width % 16 == 0 && brdfLut.m_Extent.height % 16 == 0);
|
||||||
|
cmd.dispatch(brdfLut.m_Extent.width / 16, brdfLut.m_Extent.height / 16, 1);
|
||||||
|
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
cmd.endDebugUtilsLabelEXT();
|
cmd.endDebugUtilsLabelEXT();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -241,9 +370,26 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
|
|
||||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(assetLoader->m_CommandPool, {}));
|
AbortIfFailed(pDevice->m_Device.resetCommandPool(assetLoader->m_CommandPool, {}));
|
||||||
|
|
||||||
resMan->Release(envStagingHandle);
|
skybox = {};
|
||||||
pDevice->m_Device.destroy(pipeline, nullptr);
|
resMan->Release(skyboxStorageHandle);
|
||||||
|
resMan->Release(diffuseIrradianceStorageHandle);
|
||||||
|
resMan->Release(brdfLutStorageHandle);
|
||||||
|
for (auto &texHandles : prefilterStorageHandles)
|
||||||
|
{
|
||||||
|
StorageTextureCube st;
|
||||||
|
resMan->Release(&st, texHandles);
|
||||||
|
pDevice->m_Device.destroy(st.m_View, nullptr);
|
||||||
|
}
|
||||||
|
for (auto &pipeline : pipelines)
|
||||||
|
{
|
||||||
|
pDevice->m_Device.destroy(pipeline, nullptr);
|
||||||
|
}
|
||||||
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
||||||
|
|
||||||
return resMan->Commit(&cubeMap);
|
return {
|
||||||
|
.m_Skybox = skyboxHandle,
|
||||||
|
.m_Diffuse = diffuseIrradianceHandle,
|
||||||
|
.m_Prefilter = prefilterHandle,
|
||||||
|
.m_BrdfLut = brdfLutHandle,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -8,8 +8,23 @@
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
|
|
||||||
|
#include <EASTL/tuple.h>
|
||||||
|
|
||||||
|
struct Pipeline;
|
||||||
struct Texture;
|
struct Texture;
|
||||||
struct TextureCube;
|
struct TextureCube;
|
||||||
struct AssetLoader;
|
struct AssetLoader;
|
||||||
|
|
||||||
TextureHandle CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv, cstr name = nullptr);
|
struct Environment
|
||||||
|
{
|
||||||
|
TextureHandle m_Skybox;
|
||||||
|
TextureHandle m_Diffuse;
|
||||||
|
TextureHandle m_Prefilter;
|
||||||
|
TextureHandle m_BrdfLut;
|
||||||
|
|
||||||
|
void Destroy(GpuResourceManager *resourceManager);
|
||||||
|
};
|
||||||
|
|
||||||
|
Environment
|
||||||
|
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv,
|
||||||
|
cstr name = nullptr);
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -18,10 +18,10 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "light_manager.h"
|
#include "light_manager.h"
|
||||||
|
|
||||||
|
#include "asset_loader.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
#include "asset_loader.h"
|
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
@ -176,13 +176,13 @@ main(int, char **)
|
||||||
LightManager lightManager = LightManager{&resourceManager};
|
LightManager lightManager = LightManager{&resourceManager};
|
||||||
|
|
||||||
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
||||||
Texture environment;
|
Texture environmentHdri;
|
||||||
assetLoader.LoadHdrImage(&environment, BACKDROP_FILE);
|
assetLoader.LoadHdrImage(&environmentHdri, BACKDROP_FILE);
|
||||||
auto envHandle = resourceManager.Commit(&environment);
|
auto envHdriHandle = resourceManager.CommitTexture(&environmentHdri);
|
||||||
|
|
||||||
TextureHandle texCube = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 1024, envHandle, "Cube Env");
|
auto environment = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 512, envHdriHandle, "Cube Env");
|
||||||
|
|
||||||
resourceManager.Release(envHandle);
|
resourceManager.Release(envHdriHandle);
|
||||||
|
|
||||||
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
||||||
|
|
||||||
|
|
@ -371,6 +371,11 @@ main(int, char **)
|
||||||
queueAllocation.m_Family, graphicsQueue);
|
queueAllocation.m_Family, graphicsQueue);
|
||||||
bool rotating = false;
|
bool rotating = false;
|
||||||
bool lockToScreen = true;
|
bool lockToScreen = true;
|
||||||
|
bool showDiffuse = false;
|
||||||
|
bool useDiffuse = true;
|
||||||
|
bool showPrefilter = false;
|
||||||
|
bool useSpecular = true;
|
||||||
|
|
||||||
i32 height = Cast<i32>(internalResolution.height);
|
i32 height = Cast<i32>(internalResolution.height);
|
||||||
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
||||||
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
||||||
|
|
@ -445,6 +450,13 @@ main(int, char **)
|
||||||
{
|
{
|
||||||
cameraController.SetPosition(camPosition);
|
cameraController.SetPosition(camPosition);
|
||||||
}
|
}
|
||||||
|
gui::Separator();
|
||||||
|
gui::Text("IBL");
|
||||||
|
gui::Checkbox("Show DiffIrr", &showDiffuse);
|
||||||
|
gui::Checkbox("Use DiffIrr", &useDiffuse);
|
||||||
|
gui::Checkbox("Show Prefilter", &showPrefilter);
|
||||||
|
gui::Checkbox("Use Specular", &useSpecular);
|
||||||
|
gui::Separator();
|
||||||
gui::Checkbox("Rotate", &rotating);
|
gui::Checkbox("Rotate", &rotating);
|
||||||
gui::PopItemWidth();
|
gui::PopItemWidth();
|
||||||
if (gui::Button("Exit"))
|
if (gui::Button("Exit"))
|
||||||
|
|
@ -546,8 +558,32 @@ main(int, char **)
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof model.m_Handles,
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof model.m_Handles,
|
||||||
&model.m_Handles);
|
&model.m_Handles);
|
||||||
pcbOffset += sizeof model.m_Handles;
|
pcbOffset += sizeof model.m_Handles;
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof texCube, &texCube);
|
|
||||||
pcbOffset += sizeof texCube;
|
Environment thisFrameEnvBuffers = environment;
|
||||||
|
if (showDiffuse)
|
||||||
|
{
|
||||||
|
thisFrameEnvBuffers.m_Skybox = environment.m_Diffuse;
|
||||||
|
}
|
||||||
|
else if (showPrefilter)
|
||||||
|
{
|
||||||
|
thisFrameEnvBuffers.m_Skybox = environment.m_Prefilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!useDiffuse)
|
||||||
|
{
|
||||||
|
thisFrameEnvBuffers.m_Diffuse = {};
|
||||||
|
}
|
||||||
|
if (!useSpecular)
|
||||||
|
{
|
||||||
|
thisFrameEnvBuffers.m_BrdfLut = {};
|
||||||
|
thisFrameEnvBuffers.m_Prefilter = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pcbOffset == 16);
|
||||||
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof thisFrameEnvBuffers,
|
||||||
|
&thisFrameEnvBuffers);
|
||||||
|
pcbOffset += sizeof thisFrameEnvBuffers;
|
||||||
|
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo,
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo,
|
||||||
&lightManager.m_MetaInfo);
|
&lightManager.m_MetaInfo);
|
||||||
pcbOffset += sizeof lightManager.m_MetaInfo;
|
pcbOffset += sizeof lightManager.m_MetaInfo;
|
||||||
|
|
@ -625,7 +661,7 @@ main(int, char **)
|
||||||
|
|
||||||
AbortIfFailed(device.m_Device.waitIdle());
|
AbortIfFailed(device.m_Device.waitIdle());
|
||||||
|
|
||||||
resourceManager.Release(texCube);
|
environment.Destroy(&resourceManager);
|
||||||
|
|
||||||
pipelineCacheData = device.DumpPipelineCache();
|
pipelineCacheData = device.DumpPipelineCache();
|
||||||
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
||||||
vk::PushConstantRange pushConstantRange = {
|
vk::PushConstantRange pushConstantRange = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = 40,
|
.size = 52,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
|
@ -206,7 +206,7 @@ CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, cons
|
||||||
vk::PushConstantRange pushConstantRange = {
|
vk::PushConstantRange pushConstantRange = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = 40,
|
.size = 52,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,9 @@ struct DirectionalLight
|
||||||
|
|
||||||
#define INVALID_HANDLE 0xFFFFFFFF
|
#define INVALID_HANDLE 0xFFFFFFFF
|
||||||
|
|
||||||
|
static const float HALF_PI = 1.57079633f;
|
||||||
static const float PI = 3.14159265f;
|
static const float PI = 3.14159265f;
|
||||||
|
static const float TAU = 6.28318530f;
|
||||||
|
|
||||||
[[vk::binding(0, 0)]] StructuredBuffer<float4> VertexBuffer[];
|
[[vk::binding(0, 0)]] StructuredBuffer<float4> VertexBuffer[];
|
||||||
[[vk::binding(0, 0)]] StructuredBuffer<VertexData> VertexDataBuffer[];
|
[[vk::binding(0, 0)]] StructuredBuffer<VertexData> VertexDataBuffer[];
|
||||||
|
|
@ -58,7 +60,10 @@ static const float PI = 3.14159265f;
|
||||||
[[vk::binding(0, 0)]] StructuredBuffer<DirectionalLight> DirectionalLightBuffer[];
|
[[vk::binding(0, 0)]] StructuredBuffer<DirectionalLight> DirectionalLightBuffer[];
|
||||||
|
|
||||||
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
||||||
|
[[vk::binding(1, 0)]] Texture2D<float2> TexturesRG[];
|
||||||
[[vk::binding(1, 0)]] TextureCube<float4> TextureCubes[];
|
[[vk::binding(1, 0)]] TextureCube<float4> TextureCubes[];
|
||||||
[[vk::binding(1, 0)]] SamplerState ImmutableSamplers[];
|
[[vk::binding(1, 0)]] SamplerState ImmutableSamplers[];
|
||||||
|
|
||||||
[[vk::binding(2, 0)]] RWTexture2D<float4> StorageTextures[];
|
[[vk::binding(2, 0)]] RWTexture2D<float4> StorageTextures[];
|
||||||
|
[[vk::binding(2, 0)]] RWTexture2D<float2> StorageTexturesRG[];
|
||||||
|
[[vk::binding(2, 0)]] RWTexture2DArray<float4> StorageTextureArrays[];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "ibl_common.hlsli"
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
uint OutputTextureHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]]
|
||||||
|
Block Pcb;
|
||||||
|
|
||||||
|
float GeometrySchlickGGX(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float R = Roughness;
|
||||||
|
// (Rough + 1)^2 / 8 for Punctual Lights
|
||||||
|
// Rough^2 / 2 for IBL
|
||||||
|
float K = (R * R) / 2.0;
|
||||||
|
|
||||||
|
float Numerator = NdotV;
|
||||||
|
float Denominator = NdotV * (1.0f - K) + K;
|
||||||
|
|
||||||
|
return Numerator / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySmith(float NdotV, float NdotL, float Roughness)
|
||||||
|
{
|
||||||
|
float GGX1 = GeometrySchlickGGX(NdotV, Roughness);
|
||||||
|
float GGX2 = GeometrySchlickGGX(NdotL, Roughness);
|
||||||
|
|
||||||
|
return GGX1 * GGX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 IntegrateBRDF(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float3 ViewDir;
|
||||||
|
ViewDir.x = sqrt(1.0f - NdotV * NdotV);
|
||||||
|
ViewDir.y = 0.0f;
|
||||||
|
ViewDir.z = NdotV;
|
||||||
|
|
||||||
|
float A = 0.0f;
|
||||||
|
float B = 0.0f;
|
||||||
|
|
||||||
|
float3 Normal = float3(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
const uint SAMPLE_COUNT = 1024u;
|
||||||
|
|
||||||
|
for (uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
float2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
float3 Halfway = ImportanceSampleGGX(Xi, Normal, Roughness);
|
||||||
|
float3 LightDir = normalize(2.0f * dot(ViewDir, Halfway) * Halfway - ViewDir);
|
||||||
|
|
||||||
|
float NdotL = max(LightDir.z, 0.0f);
|
||||||
|
float NdotH = max(Halfway.z, 0.0f);
|
||||||
|
float VdotH = max(dot(ViewDir, Halfway), 0.0f);
|
||||||
|
|
||||||
|
if (NdotL > 0.0f)
|
||||||
|
{
|
||||||
|
float G = GeometrySmith(NdotV, NdotL, Roughness);
|
||||||
|
float G_Vis = (G * VdotH) / max((NdotH * NdotV), 0.0001f);
|
||||||
|
float Fc = pow(1.0f - VdotH, 5.0f);
|
||||||
|
|
||||||
|
A += (1.0f - Fc) * G_Vis;
|
||||||
|
B += Fc * G_Vis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
A /= float(SAMPLE_COUNT);
|
||||||
|
B /= float(SAMPLE_COUNT);
|
||||||
|
|
||||||
|
return float2(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
|
{
|
||||||
|
float Width, Height;
|
||||||
|
StorageTexturesRG[Pcb.OutputTextureHandle].GetDimensions(Width, Height);
|
||||||
|
|
||||||
|
float2 UV = GlobalInvocationID.xy / float2(Width, Height);
|
||||||
|
|
||||||
|
float2 IntegratedBRDF = IntegrateBRDF(UV.x, UV.y);
|
||||||
|
StorageTexturesRG[Pcb.OutputTextureHandle][GlobalInvocationID.xy] = IntegratedBRDF;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "ibl_common.hlsli"
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
uint SkyboxHandle;
|
||||||
|
uint OutputTextureHandle;
|
||||||
|
int CubeSide;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]]
|
||||||
|
Block pcb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
| Axis | Layer | Up |
|
||||||
|
|:----:|:-----:|:--:|
|
||||||
|
| +x | 0 | -y |
|
||||||
|
| -x | 1 | -y |
|
||||||
|
| +y | 2 | +z |
|
||||||
|
| -y | 3 | -z |
|
||||||
|
| -z | 4 | -y |
|
||||||
|
| +z | 5 | -y |
|
||||||
|
*/
|
||||||
|
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
|
{
|
||||||
|
float3 Forward, Up, Right;
|
||||||
|
|
||||||
|
Forward = GetCubeDir(GlobalInvocationID, pcb.CubeSide);
|
||||||
|
Up = abs(Forward.y) < 1.0f ? float3(0.0f, 1.0f, 0.0f) : float3(1.0f, 0.0f, 0.0f); // 0.01f offset to
|
||||||
|
Right = normalize(cross(Up, Forward));
|
||||||
|
Up = normalize(cross(Forward, Right));
|
||||||
|
|
||||||
|
float3 Irradiance = 0.0f.xxx;
|
||||||
|
float3 IrrDirr = 0.0f.xxx;
|
||||||
|
float SampleStep = 0.005f;
|
||||||
|
float SampleCount = 0.0f;
|
||||||
|
|
||||||
|
for (float Azimuth = 0.0f; Azimuth < TAU; Azimuth += SampleStep)
|
||||||
|
{
|
||||||
|
for (float Zenith = 0.0f; Zenith < HALF_PI; Zenith += SampleStep)
|
||||||
|
{
|
||||||
|
float3 DirectionTanSpace = float3(sin(Zenith) * cos(Azimuth), sin(Zenith) * sin(Azimuth), cos(Zenith));
|
||||||
|
float3 DirectionWorld = DirectionTanSpace.x * Right + DirectionTanSpace.y * Up + DirectionTanSpace.z * Forward;
|
||||||
|
|
||||||
|
Irradiance += TextureCubes[pcb.SkyboxHandle].SampleLevel(ImmutableSamplers[pcb.SkyboxHandle], DirectionWorld, 0).xyz * (cos(Zenith) * sin(Zenith));
|
||||||
|
SampleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageTextureArrays[pcb.OutputTextureHandle][GlobalInvocationID.xyz] = PI * float4(Irradiance * (1.0f / SampleCount), 1.0f);
|
||||||
|
}
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
#include "bindless_structs.hlsli"
|
|
||||||
|
|
||||||
struct Block
|
|
||||||
{
|
|
||||||
uint HdrEnvHandle;
|
|
||||||
uint OutputTextureHandle;
|
|
||||||
int CubeSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[vk::push_constant]]
|
|
||||||
Block pcb;
|
|
||||||
|
|
||||||
float2 SampleSphericalMap(float3 v)
|
|
||||||
{
|
|
||||||
const float2 invAtan = float2(0.1591f, 0.3183f);
|
|
||||||
float2 uv = float2(atan2(v.x, v.z), asin(v.y));
|
|
||||||
uv *= invAtan;
|
|
||||||
uv += 0.5;
|
|
||||||
return uv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
| Axis | Layer | Up |
|
|
||||||
|:----:|:-----:|:--:|
|
|
||||||
| +x | 0 | -y |
|
|
||||||
| -x | 1 | -y |
|
|
||||||
| +y | 2 | +z |
|
|
||||||
| -y | 3 | -z |
|
|
||||||
| -z | 4 | -y |
|
|
||||||
| +z | 5 | -y |
|
|
||||||
*/
|
|
||||||
|
|
||||||
[numthreads(16, 16, 1)]
|
|
||||||
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
|
||||||
{
|
|
||||||
float3 LocalDir;
|
|
||||||
float HalfSide = pcb.CubeSize / 2;
|
|
||||||
float AxisSign = 2.0f * (0.5f - (GlobalInvocationID.z % 2));
|
|
||||||
|
|
||||||
if (GlobalInvocationID.z < 2)
|
|
||||||
{
|
|
||||||
LocalDir = float3(AxisSign * HalfSide, GlobalInvocationID.y - HalfSide, (GlobalInvocationID.x - HalfSide) * AxisSign);
|
|
||||||
}
|
|
||||||
else if (GlobalInvocationID.z < 4)
|
|
||||||
{
|
|
||||||
LocalDir = float3(GlobalInvocationID.x - HalfSide, -AxisSign * HalfSide, -AxisSign * (GlobalInvocationID.y - HalfSide));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LocalDir = float3((GlobalInvocationID.x - HalfSide) * AxisSign, GlobalInvocationID.y - HalfSide, -AxisSign * HalfSide);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint TileX = GlobalInvocationID.z % 3;
|
|
||||||
uint TileY = GlobalInvocationID.z / 3;
|
|
||||||
|
|
||||||
float2 UV = SampleSphericalMap(normalize(LocalDir));
|
|
||||||
StorageTextures[pcb.OutputTextureHandle][GlobalInvocationID.xy + uint2(TileX, TileY) * pcb.CubeSize] = Textures[pcb.HdrEnvHandle].SampleLevel(ImmutableSamplers[pcb.HdrEnvHandle], UV, 0);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include "ibl_common.hlsli"
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
uint HdrEnvHandle;
|
||||||
|
uint OutputTextureHandle;
|
||||||
|
int CubeSide;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]]
|
||||||
|
Block pcb;
|
||||||
|
|
||||||
|
float2 SampleSphericalMap(float3 v)
|
||||||
|
{
|
||||||
|
const float2 InvTan = float2(0.1591f, 0.3183f); // (1/2PI, 1/PI)
|
||||||
|
float2 UV = float2(atan2(-v.x, v.z), asin(-v.y)); // (-PI, -PI/2) to (PI, PI/2)
|
||||||
|
UV *= InvTan; // (-1/2, -1/2) to (1/2, 1/2)
|
||||||
|
UV += 0.5f.xx; // (0, 0) to (1, 1)
|
||||||
|
return UV;
|
||||||
|
}
|
||||||
|
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
|
{
|
||||||
|
float3 LocalDir = GetCubeDir(GlobalInvocationID, pcb.CubeSide);
|
||||||
|
|
||||||
|
float2 UV = SampleSphericalMap(LocalDir);
|
||||||
|
StorageTextureArrays[pcb.OutputTextureHandle][GlobalInvocationID.xyz] = Textures[pcb.HdrEnvHandle].SampleLevel(ImmutableSamplers[pcb.HdrEnvHandle], UV, 0);
|
||||||
|
}
|
||||||
|
|
@ -15,10 +15,16 @@ struct Block
|
||||||
uint VertexDataHandle;
|
uint VertexDataHandle;
|
||||||
uint MaterialBufferHandle;
|
uint MaterialBufferHandle;
|
||||||
uint NodeBufferHandle;
|
uint NodeBufferHandle;
|
||||||
|
|
||||||
uint EnvCubeHandle;
|
uint EnvCubeHandle;
|
||||||
|
uint DiffuseIrradianceHandle;
|
||||||
|
uint PrefilterHandle;
|
||||||
|
uint BrdfLutHandle;
|
||||||
|
|
||||||
uint LightHandle;
|
uint LightHandle;
|
||||||
uint PointLightIndexer;
|
uint PointLightIndexer;
|
||||||
uint DirectionalLightIndexer;
|
uint DirectionalLightIndexer;
|
||||||
|
|
||||||
int MaterialIdx;
|
int MaterialIdx;
|
||||||
uint NodeIdx;
|
uint NodeIdx;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "bindless_structs.hlsli"
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Goal is simply to convert from a (0,0,0) to (CubeSide, CubeSide, FaceCount) Invocation ID space to a
|
||||||
|
(-1,-1,-1) to (1, 1, 1) space.
|
||||||
|
|
||||||
|
| Axis | Layer | Up |
|
||||||
|
|:----:|:-----:|:--:|
|
||||||
|
| +x | 0 | -y |
|
||||||
|
| -x | 1 | -y |
|
||||||
|
| +y | 2 | +z |
|
||||||
|
| -y | 3 | -z |
|
||||||
|
| -z | 4 | -y |
|
||||||
|
| +z | 5 | -y |
|
||||||
|
*/
|
||||||
|
float3 GetCubeDir(uint3 GlobalInvocationID, float SideLength)
|
||||||
|
{
|
||||||
|
float2 FaceUV = float2(GlobalInvocationID.xy) / SideLength; // (0, SideLength) -> (0, 1)
|
||||||
|
FaceUV = 2.0f * FaceUV - 1.0f; // (0, 1) -> (-1, 1)
|
||||||
|
|
||||||
|
switch (GlobalInvocationID.z)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return normalize(float3(1.0f, -FaceUV.y, -FaceUV.x)); // Face +X; x = 1, y = -v, z = -u
|
||||||
|
case 1:
|
||||||
|
return normalize(float3(-1.0f, -FaceUV.y, FaceUV.x)); // Face -X; x = -1, y = -v, z = u
|
||||||
|
case 2:
|
||||||
|
return normalize(float3(FaceUV.x, 1.0f, FaceUV.y)); // Face +Y; x = u, y = 1, z = v
|
||||||
|
case 3:
|
||||||
|
return normalize(float3(FaceUV.x, -1.0f, -FaceUV.y)); // Face -Y; x=u, y=-1, z=-v
|
||||||
|
case 4:
|
||||||
|
return normalize(float3(FaceUV.x, -FaceUV.y, 1.0f)); // Face +Z; x=u,y=-v, z=1
|
||||||
|
case 5:
|
||||||
|
return normalize(float3(-FaceUV.x, -FaceUV.y, -1.0f)); // Face -Z; x=u,y=-v, z=-1
|
||||||
|
default:
|
||||||
|
// Never reach here.
|
||||||
|
return 0.0f.xxx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float RadicalInverse_VdC(uint Bits)
|
||||||
|
{
|
||||||
|
Bits = (Bits << 16u) | (Bits >> 16u);
|
||||||
|
Bits = ((Bits & 0x55555555u) << 1u) | ((Bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
Bits = ((Bits & 0x33333333u) << 2u) | ((Bits & 0xCCCCCCCCu) >> 2u);
|
||||||
|
Bits = ((Bits & 0x0F0F0F0Fu) << 4u) | ((Bits & 0xF0F0F0F0u) >> 4u);
|
||||||
|
Bits = ((Bits & 0x00FF00FFu) << 8u) | ((Bits & 0xFF00FF00u) >> 8u);
|
||||||
|
return float(Bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 Hammersley(uint SampleIndex, uint SampleCount)
|
||||||
|
{
|
||||||
|
return float2(float(SampleIndex) / float(SampleCount), RadicalInverse_VdC(SampleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 ImportanceSampleGGX(float2 Xi, float3 Normal, float Roughness)
|
||||||
|
{
|
||||||
|
float A = Roughness * Roughness;
|
||||||
|
|
||||||
|
float Phi = 2.0f * PI * Xi.x;
|
||||||
|
float CosTheta = sqrt((1.0f - Xi.y) / (1.0f + (A * A - 1.0f) * Xi.y));
|
||||||
|
float SinTheta = sqrt(1.0f - CosTheta * CosTheta);
|
||||||
|
|
||||||
|
// from spherical coordinates to cartesian coordinates
|
||||||
|
float3 H;
|
||||||
|
H.x = cos(Phi) * SinTheta;
|
||||||
|
H.y = sin(Phi) * SinTheta;
|
||||||
|
H.z = CosTheta;
|
||||||
|
|
||||||
|
// from tangent-space vector to world-space sample vector
|
||||||
|
float3 Up = abs(Normal.z) < 0.999f ? float3(0.0f, 0.0f, 1.0f) : float3(1.0f, 0.0f, 0.0f);
|
||||||
|
float3 Tangent = normalize(cross(Up, Normal));
|
||||||
|
float3 Bitangent = cross(Normal, Tangent);
|
||||||
|
|
||||||
|
float3 SampleVec = Tangent * H.x + Bitangent * H.y + Normal * H.z;
|
||||||
|
return normalize(SampleVec);
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ struct FS_Input
|
||||||
|
|
||||||
struct FS_Output
|
struct FS_Output
|
||||||
{
|
{
|
||||||
float4 ColorTarget : SV_Target0;
|
float4 ColorTarget : SV_Target0;
|
||||||
};
|
};
|
||||||
|
|
||||||
float4 GetAlbedo(float2 UV, float4 InColor)
|
float4 GetAlbedo(float2 UV, float4 InColor)
|
||||||
|
|
@ -21,6 +21,13 @@ float4 GetAlbedo(float2 UV, float4 InColor)
|
||||||
return AlbedoFactor * InColor * (AlbedoTexId != INVALID_HANDLE ? Textures[AlbedoTexId].Sample(ImmutableSamplers[AlbedoTexId], UV) : 1.0f.xxxx);
|
return AlbedoFactor * InColor * (AlbedoTexId != INVALID_HANDLE ? Textures[AlbedoTexId].Sample(ImmutableSamplers[AlbedoTexId], UV) : 1.0f.xxxx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GetOcclusion(float2 UV)
|
||||||
|
{
|
||||||
|
uint OcclusionTexId = MaterialsBuffer[PushConstant.MaterialBufferHandle][PushConstant.MaterialIdx].OcclusionTex;
|
||||||
|
|
||||||
|
return OcclusionTexId != INVALID_HANDLE ? Textures[OcclusionTexId].Sample(ImmutableSamplers[OcclusionTexId], UV).r : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
float3 GetEmissive(float2 UV)
|
float3 GetEmissive(float2 UV)
|
||||||
{
|
{
|
||||||
float3 EmissionFactor = (float3) MaterialsBuffer[PushConstant.MaterialBufferHandle][PushConstant.MaterialIdx].EmissionFactor;
|
float3 EmissionFactor = (float3) MaterialsBuffer[PushConstant.MaterialBufferHandle][PushConstant.MaterialIdx].EmissionFactor;
|
||||||
|
|
@ -61,6 +68,35 @@ float2 GetMetalRough(float2 UV)
|
||||||
return MetalRoughFactors * (MetalRoughTexId != INVALID_HANDLE ? Textures[MetalRoughTexId].Sample(ImmutableSamplers[MetalRoughTexId], UV).bg : 1.0f.xx); // Metal is B, Rough is G.
|
return MetalRoughFactors * (MetalRoughTexId != INVALID_HANDLE ? Textures[MetalRoughTexId].Sample(ImmutableSamplers[MetalRoughTexId], UV).bg : 1.0f.xx); // Metal is B, Rough is G.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float3 SampleIrradiance(float3 Direction)
|
||||||
|
{
|
||||||
|
if (PushConstant.DiffuseIrradianceHandle != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return TextureCubes[PushConstant.DiffuseIrradianceHandle].Sample(ImmutableSamplers[PushConstant.DiffuseIrradianceHandle], Direction).rgb;
|
||||||
|
}
|
||||||
|
return 0.04f.xxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 SamplePrefiltered(float3 Direction, float Roughness)
|
||||||
|
{
|
||||||
|
const float MAX_MIP_LEVEL = 5.0f;
|
||||||
|
float Mip = MAX_MIP_LEVEL * Roughness;
|
||||||
|
if (PushConstant.PrefilterHandle != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return TextureCubes[PushConstant.PrefilterHandle].SampleLevel(ImmutableSamplers[PushConstant.PrefilterHandle], Direction, Mip).rgb;
|
||||||
|
}
|
||||||
|
return 0.0f.xxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 SampleBrdfLut(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
if (PushConstant.BrdfLutHandle != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return TexturesRG[PushConstant.BrdfLutHandle].Sample(ImmutableSamplers[PushConstant.BrdfLutHandle], float2(NdotV, Roughness));
|
||||||
|
}
|
||||||
|
return 0.0f.xx;
|
||||||
|
}
|
||||||
|
|
||||||
float TrowbridgeReitzGGX(float3 Normal, float3 Halfway, float Roughness)
|
float TrowbridgeReitzGGX(float3 Normal, float3 Halfway, float Roughness)
|
||||||
{
|
{
|
||||||
float Coeff = Roughness * Roughness;
|
float Coeff = Roughness * Roughness;
|
||||||
|
|
@ -100,6 +136,12 @@ float3 FresnelSchlick(float cosine, float3 F_0)
|
||||||
return F_0 + (1.0f - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
|
return F_0 + (1.0f - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sebastian Lagarde
|
||||||
|
float3 FresnelSchlickRoughness(float cosine, float3 F_0, float Roughness)
|
||||||
|
{
|
||||||
|
return F_0 + (max((1.0f - Roughness).xxx, F_0) - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
|
||||||
|
}
|
||||||
|
|
||||||
float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 Normal, float Metallic, float Roughness, float3 F_0, float3 LightDir, float LightDistance)
|
float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 Normal, float Metallic, float Roughness, float3 F_0, float3 LightDir, float LightDistance)
|
||||||
{
|
{
|
||||||
float Attenuation = 1.0f / (LightDistance * LightDistance); // TODO: Controlled Attenuation
|
float Attenuation = 1.0f / (LightDistance * LightDistance); // TODO: Controlled Attenuation
|
||||||
|
|
@ -113,18 +155,18 @@ float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 No
|
||||||
|
|
||||||
float NormalDistribution = TrowbridgeReitzGGX(Normal, Halfway, Roughness);
|
float NormalDistribution = TrowbridgeReitzGGX(Normal, Halfway, Roughness);
|
||||||
float Geometry = GeometrySmith(NdotV, NdotL, Roughness);
|
float Geometry = GeometrySmith(NdotV, NdotL, Roughness);
|
||||||
float3 Fresnel = FresnelSchlick(CosineFactor, F_0);
|
float3 Fresnel = FresnelSchlickRoughness(CosineFactor, F_0, Roughness);
|
||||||
|
|
||||||
float3 Numerator = (NormalDistribution * Geometry) * Fresnel;
|
float3 Numerator = (NormalDistribution * Geometry) * Fresnel;
|
||||||
float Denominator = 4.0f * NdotV * NdotL;
|
float Denominator = 4.0f * NdotV * NdotL;
|
||||||
float3 Specular = Numerator / max(Denominator, 0.00001);
|
float3 Specular = Numerator / (Denominator + 0.00001f);
|
||||||
|
|
||||||
float3 K_Specular = Fresnel;
|
float3 K_Specular = Fresnel;
|
||||||
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
||||||
|
|
||||||
K_Diffuse *= 1.0f - Metallic;
|
K_Diffuse *= 1.0f - Metallic;
|
||||||
|
|
||||||
return NdotL * Radiance * ((K_Diffuse * Albedo / PI) + Specular);
|
return NdotL * Radiance * (K_Diffuse * Albedo / PI + Specular);
|
||||||
}
|
}
|
||||||
|
|
||||||
float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
||||||
|
|
@ -144,7 +186,6 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position,
|
||||||
// TODO: Cite
|
// TODO: Cite
|
||||||
float3 F_0 = 0.04f.xxx;
|
float3 F_0 = 0.04f.xxx;
|
||||||
F_0 = lerp(F_0, Albedo, Metallic);
|
F_0 = lerp(F_0, Albedo, Metallic);
|
||||||
float3 LightAmp = float3(23.47f, 21.31f, 20.79f); // TODO: Get rid
|
|
||||||
|
|
||||||
float3 Contrib = 0.0f;
|
float3 Contrib = 0.0f;
|
||||||
for (uint i = 0; i < Count; ++i)
|
for (uint i = 0; i < Count; ++i)
|
||||||
|
|
@ -167,7 +208,7 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position,
|
||||||
float G = (Light.Color & 0x00FF0000) >> 16;
|
float G = (Light.Color & 0x00FF0000) >> 16;
|
||||||
float B = (Light.Color & 0x0000FF00) >> 8;
|
float B = (Light.Color & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
float3 LightColor = LightAmp * Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
||||||
|
|
||||||
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, LightDistance);
|
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, LightDistance);
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +216,6 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position,
|
||||||
return Contrib;
|
return Contrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
||||||
{
|
{
|
||||||
if (PushConstant.LightHandle == INVALID_HANDLE)
|
if (PushConstant.LightHandle == INVALID_HANDLE)
|
||||||
|
|
@ -192,7 +232,6 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos
|
||||||
// TODO: Cite
|
// TODO: Cite
|
||||||
float3 F_0 = 0.04f.xxx;
|
float3 F_0 = 0.04f.xxx;
|
||||||
F_0 = lerp(F_0, Albedo, Metallic);
|
F_0 = lerp(F_0, Albedo, Metallic);
|
||||||
float3 LightAmp = float3(23.47f, 21.31f, 20.79f); // TODO: Get rid
|
|
||||||
|
|
||||||
float3 Contrib = 0.0f;
|
float3 Contrib = 0.0f;
|
||||||
for (uint i = 0; i < Count; ++i)
|
for (uint i = 0; i < Count; ++i)
|
||||||
|
|
@ -209,7 +248,7 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos
|
||||||
float G = (Light.Color & 0x00FF0000) >> 16;
|
float G = (Light.Color & 0x00FF0000) >> 16;
|
||||||
float B = (Light.Color & 0x0000FF00) >> 8;
|
float B = (Light.Color & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
float3 LightColor = LightAmp * Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
||||||
|
|
||||||
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, 1.0f);
|
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
@ -217,12 +256,37 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos
|
||||||
return Contrib;
|
return Contrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float3 GetAmbientInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal, float Occlusion)
|
||||||
|
{
|
||||||
|
float3 ViewDir = normalize(Camera.Position.xyz - Position);
|
||||||
|
float CosineFactor = max(dot(Normal, ViewDir), 0.0f); // Normal instead of Halfway since there's no halfway in ambient.
|
||||||
|
|
||||||
|
float Metal = MetalRough.r;
|
||||||
|
float Roughness = MetalRough.g;
|
||||||
|
|
||||||
|
float3 F_0 = 0.04f.xxx;
|
||||||
|
F_0 = lerp(F_0, Albedo, MetalRough.r);
|
||||||
|
float3 K_Specular = FresnelSchlickRoughness(CosineFactor, F_0, Roughness);
|
||||||
|
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
||||||
|
|
||||||
|
K_Diffuse *= 1.0f - Metal; // Metals don't have diffuse/refractions.
|
||||||
|
|
||||||
|
float3 ReflectionDir = reflect(-ViewDir, Normal);
|
||||||
|
|
||||||
|
float NdotV = max(dot(Normal, ViewDir), 0.0f);
|
||||||
|
float3 PrefilteredColor = SamplePrefiltered(ReflectionDir, Roughness).rgb;
|
||||||
|
float2 EnvBRDF = SampleBrdfLut(NdotV, Roughness);
|
||||||
|
float3 Specular = PrefilteredColor * (K_Specular * EnvBRDF.x + EnvBRDF.y);
|
||||||
|
|
||||||
|
float3 DiffuseIrradiance = Albedo * SampleIrradiance(Normal);
|
||||||
|
|
||||||
|
return (K_Diffuse * DiffuseIrradiance + Specular) * Occlusion;
|
||||||
|
}
|
||||||
|
|
||||||
FS_Output main(FS_Input StageInput)
|
FS_Output main(FS_Input StageInput)
|
||||||
{
|
{
|
||||||
FS_Output Output;
|
FS_Output Output;
|
||||||
|
|
||||||
float3 Ambient = float3(0.02f, 0.02f, 0.02f);
|
|
||||||
|
|
||||||
// TODO: This should be invalid on the CPU side.
|
// TODO: This should be invalid on the CPU side.
|
||||||
if (PushConstant.MaterialIdx < 0)
|
if (PushConstant.MaterialIdx < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -238,7 +302,12 @@ FS_Output main(FS_Input StageInput)
|
||||||
float Alpha = AlbedoAlpha.a;
|
float Alpha = AlbedoAlpha.a;
|
||||||
float2 MetalRough = GetMetalRough(StageInput.InUV0);
|
float2 MetalRough = GetMetalRough(StageInput.InUV0);
|
||||||
float3 Emission = GetEmissive(StageInput.InUV0);
|
float3 Emission = GetEmissive(StageInput.InUV0);
|
||||||
float3 Color = GetDirectionalLightInfluence(Albedo, MetalRough, Position, Normal) + GetPointLightInfluence(Albedo, MetalRough, Position, Normal);
|
float Occlusion = GetOcclusion(StageInput.InUV0);
|
||||||
|
|
||||||
|
float3 DirectionalLightLum = GetDirectionalLightInfluence(Albedo, MetalRough, Position, Normal);
|
||||||
|
float3 PointLighLum = GetPointLightInfluence(Albedo, MetalRough, Position, Normal);
|
||||||
|
float3 AmbientLum = GetAmbientInfluence(Albedo, MetalRough, Position, Normal, Occlusion);
|
||||||
|
float3 Color = DirectionalLightLum + PointLighLum + AmbientLum;
|
||||||
|
|
||||||
Output.ColorTarget = float4(Uncharted2Tonemap(Color + Emission), Alpha);
|
Output.ColorTarget = float4(Uncharted2Tonemap(Color + Emission), Alpha);
|
||||||
return Output;
|
return Output;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include "ibl_common.hlsli"
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
uint SkyboxHandle;
|
||||||
|
uint OutputTextureHandle;
|
||||||
|
int CubeSide;
|
||||||
|
float Roughness;
|
||||||
|
uint EnvRes;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]]
|
||||||
|
Block Pcb;
|
||||||
|
|
||||||
|
float TrowbridgeReitzGGX(float NdotH, float Roughness)
|
||||||
|
{
|
||||||
|
float Coeff = Roughness * Roughness;
|
||||||
|
float Alpha2 = Coeff * Coeff;
|
||||||
|
float NdotH2 = NdotH * NdotH;
|
||||||
|
|
||||||
|
float Numerator = Alpha2;
|
||||||
|
float Denominator = NdotH2 * (Alpha2 - 1.0f) + 1.0f;
|
||||||
|
Denominator = PI * Denominator * Denominator;
|
||||||
|
|
||||||
|
return Numerator / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetSampleMipLevel(float NdotH, float HdotV, float SampleCount)
|
||||||
|
{
|
||||||
|
float D = TrowbridgeReitzGGX(NdotH, Pcb.Roughness);
|
||||||
|
float Pdf = (D * NdotH / (4.0f * HdotV)) + 0.0001f;
|
||||||
|
|
||||||
|
float SurfAreaTexel = 4.0f * PI / (6.0f * Pcb.EnvRes * Pcb.EnvRes);
|
||||||
|
float SurfAreaSample = 1.0f / (SampleCount * Pdf + 0.0001f);
|
||||||
|
|
||||||
|
return Pcb.Roughness == 0.0f ? 0.0f : 0.5f * log2(SurfAreaSample / SurfAreaTexel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(uint3 GlobalInvocationID : SV_DispatchThreadID)
|
||||||
|
{
|
||||||
|
float3 Normal = GetCubeDir(GlobalInvocationID, Pcb.CubeSide);
|
||||||
|
float3 ViewDir = Normal;
|
||||||
|
|
||||||
|
const uint SAMPLE_COUNT = 2048u;
|
||||||
|
float TotalWeight = 0.0f;
|
||||||
|
float3 PrefilterColor = 0.0f.xxx;
|
||||||
|
for (uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
float2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
float3 Halfway = ImportanceSampleGGX(Xi, Normal, Pcb.Roughness);
|
||||||
|
float3 LightDir = normalize(2.0 * dot(ViewDir, Halfway) * Halfway - ViewDir);
|
||||||
|
|
||||||
|
float NdotH = max(dot(Normal, Halfway), 0.0f);
|
||||||
|
|
||||||
|
float MipLevel = GetSampleMipLevel(NdotH, NdotH /* N = V :: NdotH = HdotV */, SAMPLE_COUNT);
|
||||||
|
|
||||||
|
float NdotL = max(dot(Normal, LightDir), 0.0);
|
||||||
|
if (NdotL > 0.0)
|
||||||
|
{
|
||||||
|
PrefilterColor += TextureCubes[Pcb.SkyboxHandle].SampleLevel(ImmutableSamplers[Pcb.SkyboxHandle], LightDir, MipLevel).rgb * NdotL;
|
||||||
|
TotalWeight += NdotL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrefilterColor = PrefilterColor / TotalWeight;
|
||||||
|
|
||||||
|
StorageTextureArrays[Pcb.OutputTextureHandle][GlobalInvocationID] = float4(PrefilterColor, 1.0f);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue