Added an HDR Skycube.
This commit is contained in:
parent
22cbc41af1
commit
6b5442527f
|
|
@ -100,12 +100,73 @@ struct Time
|
|||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] inline usize
|
||||
[[nodiscard]] constexpr usize
|
||||
ClosestMultiple(const usize val, const usize of)
|
||||
{
|
||||
return of * ((val + of - 1) / of);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32
|
||||
ClosestMultiple(const u32 val, const u32 of)
|
||||
{
|
||||
return of * ((val + of - 1) / of);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
IsPowerOfTwo(const usize val)
|
||||
{
|
||||
return val && !(val & (val - 1));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
IsPowerOfTwo(const u32 val)
|
||||
{
|
||||
return val && !(val & (val - 1));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr usize
|
||||
ClosestLargerPowerOfTwo(usize val)
|
||||
{
|
||||
val--;
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
val |= val >> 8;
|
||||
val |= val >> 16;
|
||||
val |= val >> 32;
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr usize
|
||||
ClosestPowerOfTwo(const usize val)
|
||||
{
|
||||
const usize largerPo2 = ClosestLargerPowerOfTwo(val);
|
||||
const usize smallerPo2 = largerPo2 >> 1;
|
||||
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32
|
||||
ClosestLargerPowerOfTwo(u32 val)
|
||||
{
|
||||
val--;
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
val |= val >> 8;
|
||||
val |= val >> 16;
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32
|
||||
ClosestPowerOfTwo(const u32 val)
|
||||
{
|
||||
const u32 largerPo2 = ClosestLargerPowerOfTwo(val);
|
||||
const u32 smallerPo2 = largerPo2 >> 1;
|
||||
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||
{
|
||||
|
|
|
|||
167
aster/image.cpp
167
aster/image.cpp
|
|
@ -22,6 +22,9 @@ void
|
|||
Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageFormat, const bool isMipMapped,
|
||||
const cstr name)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
extent.width, extent.height, name ? name : "<unnamed>");
|
||||
|
||||
const u32 mipLevels = isMipMapped ? 1 + Cast<u32>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
||||
assert(mipLevels <= MIP_MASK);
|
||||
|
||||
|
|
@ -34,7 +37,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
|
|||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
|
|
@ -75,7 +78,92 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
|
|||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = {extent.width, extent.height, 1};
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels_ = mipLevels | OWNED_BIT | VALID_BIT;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
/*
|
||||
Cube map Faces info.
|
||||
|
||||
TODO: Correct this based on the actual layout for upside down viewport.
|
||||
|
||||
| Axis | Layer | Up |
|
||||
|:----:|:-----:|:--:|
|
||||
| +x | 0 | -y |
|
||||
| -x | 1 | -y |
|
||||
| +y | 2 | +z |
|
||||
| -y | 3 | -z |
|
||||
| +z | 4 | -y |
|
||||
| -z | 5 | -y |
|
||||
|
||||
Remember, we use upside down viewport.
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
||||
|
||||
const u32 mipLevels = isMipMapped ? 1 + Cast<u32>(floor(log2(cubeSide))) : 1;
|
||||
assert(mipLevels <= MIP_MASK);
|
||||
|
||||
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (isMipMapped)
|
||||
{
|
||||
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||
}
|
||||
|
||||
vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = extent,
|
||||
.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;
|
||||
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 = extent;
|
||||
m_MipLevels_ = mipLevels | OWNED_BIT | VALID_BIT;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
|
|
@ -87,7 +175,7 @@ AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imag
|
|||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
|
|
@ -128,7 +216,7 @@ AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imag
|
|||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = {extent.width, extent.height, 1};
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels_ = 1 | OWNED_BIT | VALID_BIT;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
|
|
@ -141,7 +229,7 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
|
|||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
|
|
@ -182,7 +270,74 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
|
|||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = {extent.width, extent.height, 1};
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels_ = 1 | OWNED_BIT | VALID_BIT;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
void
|
||||
StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format imageFormat, const bool isSampled,
|
||||
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(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
extent.width, extent.height, name ? name : "<unnamed>");
|
||||
usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.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::e2D,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
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_ = 1 | OWNED_BIT | VALID_BIT;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ struct Texture : Image
|
|||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||
};
|
||||
|
||||
struct TextureCube : Texture
|
||||
{
|
||||
void
|
||||
Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped = false, cstr name = nullptr);
|
||||
};
|
||||
|
||||
struct AttachmentImage : Image
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name = nullptr);
|
||||
|
|
@ -69,6 +75,11 @@ struct DepthImage : Image
|
|||
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
|
||||
};
|
||||
|
||||
struct StorageTexture : Texture
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isSampled, cstr name = nullptr);
|
||||
};
|
||||
|
||||
inline bool
|
||||
Image::IsValid() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ TextureManager::Init(const u32 maxCapacity)
|
|||
TextureHandle
|
||||
TextureManager::Commit(Texture *texture)
|
||||
{
|
||||
ERROR_IF(!texture->IsValid() || !texture->IsOwned(), "Buffer must be valid and owned for commital")
|
||||
ERROR_IF(!texture || !texture->IsValid() || !texture->IsOwned(), "Texture must be valid and owned for commital")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
|
|
@ -38,7 +38,7 @@ TextureManager::Commit(Texture *texture)
|
|||
static_assert(std::is_trivially_copyable_v<Texture>);
|
||||
*allocatedTexture = *texture;
|
||||
|
||||
// Take ownership of the buffer.
|
||||
// Take ownership of the texture.
|
||||
texture->m_MipLevels_ &= ~Texture::OWNED_BIT;
|
||||
|
||||
return {index};
|
||||
|
|
@ -102,7 +102,8 @@ BufferManager::Init(const u32 maxCapacity)
|
|||
BufferHandle
|
||||
BufferManager::Commit(StorageBuffer *buffer)
|
||||
{
|
||||
ERROR_IF(!buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital") THEN_ABORT(-1);
|
||||
ERROR_IF(!buffer || !buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
{
|
||||
|
|
@ -171,6 +172,27 @@ BufferManager::Destroy(const Device *device)
|
|||
}
|
||||
}
|
||||
|
||||
StorageTextureHandle
|
||||
StorageTextureManager::Commit(StorageTexture *texture)
|
||||
{
|
||||
const TextureHandle tx = TextureManager::Commit(texture);
|
||||
return {tx.m_Index};
|
||||
}
|
||||
|
||||
StorageTexture *
|
||||
StorageTextureManager::Fetch(const StorageTextureHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return Recast<StorageTexture *>(&m_Textures[handle.m_Index]);
|
||||
}
|
||||
|
||||
void
|
||||
StorageTextureManager::Release(const Device *device, const StorageTextureHandle handle)
|
||||
{
|
||||
TextureManager::Release(device, {handle.m_Index});
|
||||
}
|
||||
|
||||
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
||||
: uBufferInfo(info)
|
||||
{
|
||||
|
|
@ -259,6 +281,19 @@ GpuResourceManager::Release(BufferHandle handle)
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageBuffer *storageBuffer, const BufferHandle handle)
|
||||
{
|
||||
assert(storageBuffer);
|
||||
assert(!storageBuffer->IsValid());
|
||||
|
||||
StorageBuffer *internal = m_BufferManager.Fetch(handle);
|
||||
*storageBuffer = *internal;
|
||||
internal->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(TextureHandle handle)
|
||||
{
|
||||
|
|
@ -274,6 +309,19 @@ GpuResourceManager::Release(TextureHandle handle)
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(Texture *texture, TextureHandle handle)
|
||||
{
|
||||
assert(texture);
|
||||
assert(!texture->IsValid());
|
||||
|
||||
Texture *internal = m_TextureManager.Fetch(handle);
|
||||
*texture = *internal;
|
||||
internal->m_MipLevels_ &= ~Texture::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
GpuResourceManager::Commit(Texture *texture)
|
||||
{
|
||||
|
|
@ -303,6 +351,63 @@ GpuResourceManager::Commit(Texture *texture)
|
|||
return {handle};
|
||||
}
|
||||
|
||||
StorageTextureHandle
|
||||
GpuResourceManager::Commit(StorageTexture *storageTexture)
|
||||
{
|
||||
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||
.sampler = nullptr,
|
||||
.imageView = storageTexture->m_View,
|
||||
.imageLayout = vk::ImageLayout::eGeneral,
|
||||
});
|
||||
|
||||
m_Writes.push_back({
|
||||
.dstSet = m_DescriptorSet,
|
||||
.dstBinding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
.dstArrayElement = handle.m_Index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eStorageTexture, handle.m_Index);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
++m_CommitedStorageTextureCount;
|
||||
#endif
|
||||
|
||||
return {handle};
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageTextureHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eTexture);
|
||||
|
||||
m_StorageTextureManager.Release(m_Device, handle);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
--m_CommitedStorageTextureCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageTexture *texture, const StorageTextureHandle handle)
|
||||
{
|
||||
assert(texture);
|
||||
assert(!texture->IsValid());
|
||||
|
||||
StorageTexture *internal = m_StorageTextureManager.Fetch(handle);
|
||||
*texture = *internal;
|
||||
internal->m_MipLevels_ &= ~StorageTexture::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Update()
|
||||
{
|
||||
|
|
@ -316,7 +421,7 @@ GpuResourceManager::Update()
|
|||
m_WriteOwner.clear();
|
||||
}
|
||||
|
||||
GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
||||
GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||
: m_Device(device)
|
||||
{
|
||||
vk::PhysicalDeviceProperties properties;
|
||||
|
|
@ -324,6 +429,8 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
|
||||
u32 buffersCount = eastl::min(properties.limits.maxPerStageDescriptorStorageBuffers - 1024, Cast<u32>(maxSize));
|
||||
u32 texturesCount = eastl::min(properties.limits.maxPerStageDescriptorSampledImages - 1024, Cast<u32>(maxSize));
|
||||
u32 storageTexturesCount =
|
||||
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
||||
|
||||
// TODO: Switch to bindless samplers / multiple sampler configurations
|
||||
vk::SamplerCreateInfo samplerCreateInfo = {
|
||||
|
|
@ -346,9 +453,11 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
|
||||
INFO("Max Buffer Count: {}", buffersCount);
|
||||
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 = {
|
||||
vk::DescriptorPoolSize{
|
||||
|
|
@ -359,7 +468,12 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = texturesCount,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageImage,
|
||||
.descriptorCount = storageTexturesCount,
|
||||
},
|
||||
};
|
||||
|
||||
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
|
||||
.maxSets = 1,
|
||||
|
|
@ -373,6 +487,7 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
eastl::array layoutBindingFlags = {
|
||||
bindingFlags,
|
||||
bindingFlags,
|
||||
bindingFlags,
|
||||
};
|
||||
|
||||
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
||||
|
|
@ -395,6 +510,12 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
.pImmutableSamplers = immutableSamplers.data(),
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.descriptorCount = Cast<u32>(storageTexturesCount),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
};
|
||||
static_assert(layoutBindingFlags.size() == descriptorLayoutBindings.size());
|
||||
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
|
|
@ -423,12 +544,14 @@ GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
|
|||
GpuResourceManager::~GpuResourceManager()
|
||||
{
|
||||
#if !defined(NDEBUG)
|
||||
WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0, "Resources alive: SSBO = {}, Textures = {}",
|
||||
m_CommitedBufferCount, m_CommitedTextureCount);
|
||||
WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0 || m_CommitedStorageTextureCount > 0,
|
||||
"Resources alive: SSBO = {}, Textures = {}, RWTexture = {}", m_CommitedBufferCount, m_CommitedTextureCount,
|
||||
m_CommitedStorageTextureCount);
|
||||
#endif
|
||||
|
||||
m_BufferManager.Destroy(m_Device);
|
||||
m_TextureManager.Destroy(m_Device);
|
||||
m_StorageTextureManager.Destroy(m_Device);
|
||||
m_Device->m_Device.destroy(m_ImmutableSampler, nullptr);
|
||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||
|
|
@ -441,6 +564,7 @@ GpuResourceManager::GpuResourceManager(GpuResourceManager &&other) noexcept
|
|||
, m_ImmutableSampler(other.m_ImmutableSampler)
|
||||
, m_BufferManager(std::move(other.m_BufferManager))
|
||||
, m_TextureManager(std::move(other.m_TextureManager))
|
||||
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
||||
, m_Device(Take(other.m_Device))
|
||||
, m_DescriptorPool(other.m_DescriptorPool)
|
||||
, m_SetLayout(other.m_SetLayout)
|
||||
|
|
@ -462,6 +586,7 @@ GpuResourceManager::operator=(GpuResourceManager &&other) noexcept
|
|||
m_ImmutableSampler = other.m_ImmutableSampler;
|
||||
m_BufferManager = std::move(other.m_BufferManager);
|
||||
m_TextureManager = std::move(other.m_TextureManager);
|
||||
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
||||
m_Device = Take(other.m_Device); // Ensure taken.
|
||||
m_DescriptorPool = other.m_DescriptorPool;
|
||||
m_SetLayout = other.m_SetLayout;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
struct Device;
|
||||
struct Texture;
|
||||
struct StorageTexture;
|
||||
struct StorageBuffer;
|
||||
|
||||
struct GpuResourceHandle
|
||||
|
|
@ -34,6 +35,10 @@ struct TextureHandle : GpuResourceHandle
|
|||
{
|
||||
};
|
||||
|
||||
struct StorageTextureHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct TextureManager
|
||||
{
|
||||
eastl::vector<Texture> m_Textures;
|
||||
|
|
@ -60,6 +65,13 @@ struct BufferManager
|
|||
void Destroy(const Device *device);
|
||||
};
|
||||
|
||||
struct StorageTextureManager : TextureManager
|
||||
{
|
||||
StorageTextureHandle Commit(StorageTexture *texture);
|
||||
StorageTexture *Fetch(StorageTextureHandle handle);
|
||||
void Release(const Device *device, StorageTextureHandle handle);
|
||||
};
|
||||
|
||||
struct GpuResourceManager
|
||||
{
|
||||
private:
|
||||
|
|
@ -81,6 +93,7 @@ struct GpuResourceManager
|
|||
{
|
||||
eBuffer,
|
||||
eTexture,
|
||||
eStorageTexture,
|
||||
};
|
||||
|
||||
using WriteOwner = eastl::pair<HandleType, u32>;
|
||||
|
|
@ -93,29 +106,38 @@ struct GpuResourceManager
|
|||
|
||||
BufferManager m_BufferManager;
|
||||
TextureManager m_TextureManager;
|
||||
StorageTextureManager m_StorageTextureManager;
|
||||
|
||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||
|
||||
public:
|
||||
const Device *m_Device;
|
||||
Device *m_Device;
|
||||
|
||||
constexpr static u32 BUFFER_BINDING_INDEX = 0;
|
||||
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
||||
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
||||
|
||||
vk::DescriptorPool m_DescriptorPool;
|
||||
vk::DescriptorSetLayout m_SetLayout;
|
||||
vk::DescriptorSet m_DescriptorSet;
|
||||
|
||||
BufferHandle Commit(StorageBuffer *storageBuffer);
|
||||
void Write(BufferHandle handle, usize offset, usize size, const void *data);
|
||||
void Release(BufferHandle handle);
|
||||
TextureHandle Commit(Texture *texture);
|
||||
void Release(TextureHandle handle);
|
||||
BufferHandle Commit(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
||||
void Write(BufferHandle handle, usize offset, usize size, const void *data); // Write to buffer
|
||||
void Release(BufferHandle handle); // Release and Destroy
|
||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||
|
||||
void Update();
|
||||
TextureHandle Commit(Texture *texture); // Commit to GPU and take Ownership
|
||||
void Release(TextureHandle handle); // Release and Destroy
|
||||
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
||||
|
||||
StorageTextureHandle Commit(StorageTexture *storageTexture);
|
||||
void Release(StorageTextureHandle handle);
|
||||
void Release(StorageTexture *texture, StorageTextureHandle handle);
|
||||
|
||||
void Update(); // Update all the descriptors required.
|
||||
|
||||
// Ctor/Dtor
|
||||
GpuResourceManager(const Device *device, u16 maxSize);
|
||||
GpuResourceManager(Device *device, u16 maxSize);
|
||||
~GpuResourceManager();
|
||||
|
||||
GpuResourceManager(GpuResourceManager &&other) noexcept;
|
||||
|
|
@ -124,6 +146,7 @@ struct GpuResourceManager
|
|||
#if !defined(NDEBUG)
|
||||
usize m_CommitedBufferCount = 0;
|
||||
usize m_CommitedTextureCount = 0;
|
||||
usize m_CommitedStorageTextureCount = 0;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GpuResourceManager);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "helpers.h"
|
||||
#include "image.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
|
@ -166,11 +165,13 @@ Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk:
|
|||
{
|
||||
// OPTICK_EVENT();
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
constexpr vk::DebugUtilsLabelEXT label = {
|
||||
.pLabelName = "UI pass",
|
||||
.color = std::array{0.0f, 0.0f, 1.0f, 1.0f},
|
||||
.color = std::array{0.9f, 0.9f, 1.0f, 1.0f},
|
||||
};
|
||||
commandBuffer.beginDebugUtilsLabelEXT(&label);
|
||||
#endif
|
||||
vk::RenderingAttachmentInfo attachmentInfo = {
|
||||
.imageView = view,
|
||||
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
|
|
@ -194,7 +195,9 @@ Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk:
|
|||
|
||||
commandBuffer.endRendering();
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
commandBuffer.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ eastl::vector<u32> ReadFile(cstr fileName);
|
|||
eastl::vector<u8> ReadFileBytes(cstr fileName, bool errorOnFail = true);
|
||||
bool WriteFileBytes(cstr fileName, eastl::span<u8> data);
|
||||
|
||||
template <usize TSize>
|
||||
using StackString = eastl::fixed_string<char, TSize, false>;
|
||||
|
||||
#define AbortIfFailed(RESULT) \
|
||||
do \
|
||||
{ \
|
||||
|
|
|
|||
|
|
@ -8,15 +8,20 @@ find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
|||
add_executable(model_render model_render.cpp
|
||||
pipeline_utils.cpp
|
||||
pipeline_utils.h
|
||||
model_loader.cpp
|
||||
model_loader.h
|
||||
asset_loader.cpp
|
||||
asset_loader.h
|
||||
light_manager.cpp
|
||||
light_manager.h
|
||||
nodes.cpp
|
||||
nodes.h)
|
||||
nodes.h
|
||||
ibl_helpers.cpp
|
||||
ibl_helpers.h)
|
||||
|
||||
add_shader(model_render shader/model.vs.hlsl)
|
||||
add_shader(model_render shader/model.ps.hlsl)
|
||||
add_shader(model_render shader/eqrectToCube.cs.hlsl)
|
||||
add_shader(model_render shader/background.vs.hlsl)
|
||||
add_shader(model_render shader/background.ps.hlsl)
|
||||
|
||||
target_link_libraries(model_render PRIVATE aster_core)
|
||||
target_link_libraries(model_render PRIVATE util_helper)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// =============================================
|
||||
// Aster: model_loader.cpp
|
||||
// Aster: asset_loader.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include "model_loader.h"
|
||||
#include "asset_loader.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "device.h"
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
constexpr vk::CommandBufferBeginInfo OneTimeCmdBeginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
|
||||
vec4
|
||||
VectorToVec4(const std::vector<double> &vec)
|
||||
{
|
||||
|
|
@ -52,24 +54,178 @@ VectorToVec3(const std::vector<double> &vec)
|
|||
return {vec[0], vec[1], vec[2]};
|
||||
}
|
||||
|
||||
void
|
||||
AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
||||
{
|
||||
const Device *pDevice = m_ResourceManager->m_Device;
|
||||
ERROR_IF(texture->IsValid(), "Expected invalid image.") THEN_ABORT(-1);
|
||||
|
||||
i32 x, y, nChannels;
|
||||
const f32 *data = stbi_loadf(path, &x, &y, &nChannels, 4);
|
||||
assert(nChannels == 3);
|
||||
|
||||
ERROR_IF(!data, "Could not load {}", path) THEN_ABORT(-1);
|
||||
|
||||
u32 width = Cast<u32>(x);
|
||||
u32 height = Cast<u32>(y);
|
||||
|
||||
StagingBuffer stagingBuffer;
|
||||
texture->Init(m_ResourceManager->m_Device, {width, height}, vk::Format::eR32G32B32A32Sfloat, false, path);
|
||||
assert(texture->IsValid());
|
||||
stagingBuffer.Init(m_ResourceManager->m_Device, (sizeof *data) * x * y * 4, "HDR Staging Buffer");
|
||||
stagingBuffer.Write(m_ResourceManager->m_Device, 0, stagingBuffer.GetSize(), data);
|
||||
|
||||
#pragma region Setup Copy/Sync primitives
|
||||
vk::BufferImageCopy2 copyRegion = {
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = width,
|
||||
.bufferImageHeight = height,
|
||||
.imageSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = texture->m_Extent,
|
||||
};
|
||||
vk::CopyBufferToImageInfo2 stagingInfo = {
|
||||
.srcBuffer = stagingBuffer.m_Buffer,
|
||||
.dstImage = texture->m_Image,
|
||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.regionCount = 1,
|
||||
.pRegions = ©Region,
|
||||
};
|
||||
vk::ImageMemoryBarrier2 readyToStageBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
.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 = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo readyToStageDependency = {
|
||||
.memoryBarrierCount = 0,
|
||||
.bufferMemoryBarrierCount = 0,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &readyToStageBarrier,
|
||||
};
|
||||
vk::ImageMemoryBarrier2 postStagingBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader | vk::PipelineStageFlagBits2::eComputeShader,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo postStagingDependency = {
|
||||
.memoryBarrierCount = 0,
|
||||
.bufferMemoryBarrierCount = 0,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &postStagingBarrier,
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
StackString<128> loadActionName = "Load: ";
|
||||
loadActionName += name ? name : path;
|
||||
vk::DebugUtilsLabelEXT debugLabel = {
|
||||
.pLabelName = loadActionName.c_str(),
|
||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
||||
#endif
|
||||
|
||||
m_CommandBuffer.pipelineBarrier2(&readyToStageDependency);
|
||||
m_CommandBuffer.copyBufferToImage2(&stagingInfo);
|
||||
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
|
||||
AbortIfFailed(m_CommandBuffer.end());
|
||||
|
||||
vk::SubmitInfo submitInfo = {
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitDstStageMask = nullptr,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &m_CommandBuffer,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
||||
AbortIfFailed(m_TransferQueue.submit(1, &submitInfo, fence));
|
||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
||||
pDevice->m_Device.destroy(fence, nullptr);
|
||||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
||||
|
||||
stagingBuffer.Destroy(pDevice);
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const
|
||||
AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const
|
||||
{
|
||||
assert(image->component == 4);
|
||||
assert(image->height > 0 && image->width > 0);
|
||||
|
||||
u32 height = Cast<u32>(image->height);
|
||||
u32 width = Cast<u32>(image->width);
|
||||
|
||||
vk::Format imageFormat = isSrgb ? vk::Format::eR8G8B8A8Srgb : vk::Format::eR8G8B8A8Unorm;
|
||||
|
||||
Texture texture;
|
||||
|
||||
usize byteSize = image->image.size();
|
||||
texture.Init(m_ResourceManager->m_Device, {.width = Cast<u32>(image->width), .height = Cast<u32>(image->height)},
|
||||
imageFormat, true, image->name.data());
|
||||
texture.Init(m_ResourceManager->m_Device, {.width = width, .height = height}, imageFormat, true,
|
||||
image->name.data());
|
||||
stagingBuffer->Init(m_ResourceManager->m_Device, byteSize);
|
||||
stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
|
||||
|
||||
vk::ImageMemoryBarrier imageStartBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eNone,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
#if !defined(NDEBUG)
|
||||
StackString<128> loadActionName = "Load: ";
|
||||
loadActionName += image->name.empty() ? "<texture>" : image->name.c_str();
|
||||
vk::DebugUtilsLabelEXT debugLabel = {
|
||||
.pLabelName = loadActionName.c_str(),
|
||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
||||
#endif
|
||||
|
||||
#pragma region Barriers and Blits
|
||||
|
||||
vk::ImageMemoryBarrier2 imageStartBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
|
|
@ -84,10 +240,18 @@ ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, boo
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageStartDependency = {
|
||||
.memoryBarrierCount = 0,
|
||||
.bufferMemoryBarrierCount = 0,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageStartBarrier,
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier nextMipBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
|
||||
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,
|
||||
|
|
@ -102,10 +266,16 @@ ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, boo
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo interMipDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &nextMipBarrier,
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferRead,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
vk::ImageMemoryBarrier2 imageReadyBarrier = {
|
||||
.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,
|
||||
|
|
@ -120,8 +290,12 @@ ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, boo
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageReadyDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageReadyBarrier,
|
||||
};
|
||||
|
||||
vk::BufferImageCopy imageCopy = {
|
||||
vk::BufferImageCopy2 imageCopy = {
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = Cast<u32>(image->width),
|
||||
.bufferImageHeight = Cast<u32>(image->height),
|
||||
|
|
@ -135,16 +309,49 @@ ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, boo
|
|||
.imageOffset = {},
|
||||
.imageExtent = texture.m_Extent,
|
||||
};
|
||||
vk::CopyBufferToImageInfo2 stagingCopyInfo = {
|
||||
.srcBuffer = stagingBuffer->m_Buffer,
|
||||
.dstImage = texture.m_Image,
|
||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.regionCount = 1,
|
||||
.pRegions = &imageCopy,
|
||||
};
|
||||
|
||||
m_CommandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageStartBarrier);
|
||||
m_CommandBuffer.copyBufferToImage(stagingBuffer->m_Buffer, texture.m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||
&imageCopy);
|
||||
m_CommandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &nextMipBarrier);
|
||||
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
|
||||
|
||||
m_CommandBuffer.pipelineBarrier2(&imageStartDependency);
|
||||
m_CommandBuffer.copyBufferToImage2(&stagingCopyInfo);
|
||||
m_CommandBuffer.pipelineBarrier2(&interMipDependency);
|
||||
|
||||
auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); };
|
||||
|
||||
// Mip Mapping
|
||||
|
||||
i32 prevMipWidth = Cast<i32>(texture.m_Extent.width);
|
||||
i32 prevMipHeight = Cast<i32>(texture.m_Extent.height);
|
||||
|
||||
|
|
@ -155,51 +362,37 @@ ModelLoader::LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, boo
|
|||
i32 currentMipHeight = calcNextMip(prevMipHeight);
|
||||
u32 currentMipLevel = prevMipLevel + 1;
|
||||
|
||||
vk::ImageBlit blitRegion = {
|
||||
.srcSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = prevMipLevel,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffsets =
|
||||
std::array{
|
||||
blitRegion.srcSubresource.mipLevel = prevMipLevel;
|
||||
blitRegion.srcOffsets = std::array{
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{prevMipWidth, prevMipHeight, 1},
|
||||
},
|
||||
.dstSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = currentMipLevel,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.dstOffsets =
|
||||
std::array{
|
||||
};
|
||||
blitRegion.dstSubresource.mipLevel = currentMipLevel;
|
||||
blitRegion.dstOffsets = std::array{
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{currentMipWidth, currentMipHeight, 1},
|
||||
},
|
||||
};
|
||||
|
||||
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel;
|
||||
m_CommandBuffer.blitImage(texture.m_Image, vk::ImageLayout::eTransferSrcOptimal, texture.m_Image,
|
||||
vk::ImageLayout::eTransferDstOptimal, 1, &blitRegion, vk::Filter::eLinear);
|
||||
m_CommandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {},
|
||||
0, nullptr, 0, nullptr, 1, &nextMipBarrier);
|
||||
|
||||
m_CommandBuffer.blitImage2(&mipBlitInfo);
|
||||
m_CommandBuffer.pipelineBarrier2(&interMipDependency);
|
||||
|
||||
prevMipHeight = currentMipHeight;
|
||||
prevMipWidth = currentMipWidth;
|
||||
}
|
||||
|
||||
m_CommandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &imageReadyBarrier);
|
||||
m_CommandBuffer.pipelineBarrier2(&imageReadyDependency);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
|
||||
return m_ResourceManager->Commit(&texture);
|
||||
}
|
||||
|
||||
Model
|
||||
ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
||||
AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
tinygltf::Model model;
|
||||
|
|
@ -230,10 +423,17 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(m_CommandBuffer.begin(&beginInfo));
|
||||
}
|
||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
StackString<128> loadActionName = "Load: ";
|
||||
loadActionName += name ? name : path;
|
||||
vk::DebugUtilsLabelEXT debugLabel = {
|
||||
.pLabelName = loadActionName.c_str(),
|
||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
||||
#endif
|
||||
|
||||
eastl::vector<StagingBuffer> stagingBuffers;
|
||||
|
||||
|
|
@ -258,7 +458,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
|||
}
|
||||
|
||||
auto *image = &model.images[index];
|
||||
TextureHandle handle = LoadImage(&stagingBuffers.push_back(), image, isSrgb);
|
||||
TextureHandle handle = LoadImageToGpu(&stagingBuffers.push_back(), image, isSrgb);
|
||||
textureHandleMap.emplace(index, handle);
|
||||
return handle;
|
||||
};
|
||||
|
|
@ -608,6 +808,9 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
|||
|
||||
#pragma endregion
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
AbortIfFailed(m_CommandBuffer.end());
|
||||
|
||||
vk::SubmitInfo submitInfo = {
|
||||
|
|
@ -624,8 +827,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
|||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
||||
pDevice->m_Device.destroy(fence, nullptr);
|
||||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(
|
||||
m_CommandPool, batched ? vk::CommandPoolResetFlags{} : vk::CommandPoolResetFlagBits::eReleaseResources));
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
||||
|
||||
for (auto &buffer : stagingBuffers)
|
||||
{
|
||||
|
|
@ -726,7 +928,7 @@ Model::Update()
|
|||
}
|
||||
}
|
||||
|
||||
ModelLoader::ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
AssetLoader::AssetLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_TransferQueue(transferQueue)
|
||||
|
|
@ -741,15 +943,19 @@ ModelLoader::ModelLoader(GpuResourceManager *resourceManager, vk::Queue transfer
|
|||
AbortIfFailedM(pDevice->m_Device.createCommandPool(&poolCreateInfo, nullptr, &m_CommandPool),
|
||||
"Transfer command pool creation failed.");
|
||||
|
||||
pDevice->SetName(m_CommandPool, "Asset Loader Command Pool");
|
||||
|
||||
const vk::CommandBufferAllocateInfo commandBufferAllocateInfo = {
|
||||
.commandPool = m_CommandPool,
|
||||
.level = vk::CommandBufferLevel::ePrimary,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
AbortIfFailed(pDevice->m_Device.allocateCommandBuffers(&commandBufferAllocateInfo, &m_CommandBuffer));
|
||||
|
||||
pDevice->SetName(m_CommandBuffer, "Asset Loader Command Buffer");
|
||||
}
|
||||
|
||||
ModelLoader::~ModelLoader()
|
||||
AssetLoader::~AssetLoader()
|
||||
{
|
||||
if (m_ResourceManager)
|
||||
{
|
||||
|
|
@ -757,7 +963,7 @@ ModelLoader::~ModelLoader()
|
|||
}
|
||||
}
|
||||
|
||||
ModelLoader::ModelLoader(ModelLoader &&other) noexcept
|
||||
AssetLoader::AssetLoader(AssetLoader &&other) noexcept
|
||||
: m_ResourceManager(Take(other.m_ResourceManager))
|
||||
, m_CommandPool(other.m_CommandPool)
|
||||
, m_CommandBuffer(other.m_CommandBuffer)
|
||||
|
|
@ -767,8 +973,8 @@ ModelLoader::ModelLoader(ModelLoader &&other) noexcept
|
|||
{
|
||||
}
|
||||
|
||||
ModelLoader &
|
||||
ModelLoader::operator=(ModelLoader &&other) noexcept
|
||||
AssetLoader &
|
||||
AssetLoader::operator=(AssetLoader &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// =============================================
|
||||
// Aster: model_loader.h
|
||||
// Aster: asset_loader.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ namespace tinygltf
|
|||
struct Image;
|
||||
}
|
||||
|
||||
struct Image;
|
||||
struct TextureHandle;
|
||||
struct Texture;
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ struct Model
|
|||
const Model &operator=(const Model &) = delete;
|
||||
};
|
||||
|
||||
struct ModelLoader
|
||||
struct AssetLoader
|
||||
{
|
||||
GpuResourceManager *m_ResourceManager;
|
||||
vk::CommandPool m_CommandPool;
|
||||
|
|
@ -95,8 +96,9 @@ struct ModelLoader
|
|||
u32 m_TransferQueueIndex;
|
||||
u32 m_GraphicsQueueIndex;
|
||||
|
||||
TextureHandle LoadImage(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const;
|
||||
Model LoadModel(cstr path, cstr name = nullptr, bool batched = false);
|
||||
void LoadHdrImage(Texture *texture, cstr path, cstr name = nullptr) const;
|
||||
TextureHandle LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const;
|
||||
Model LoadModelToGpu(cstr path, cstr name = nullptr);
|
||||
|
||||
constexpr static auto ANormal = "NORMAL";
|
||||
constexpr static auto APosition = "POSITION";
|
||||
|
|
@ -107,12 +109,12 @@ struct ModelLoader
|
|||
constexpr static auto AJoints0 = "JOINTS_0";
|
||||
constexpr static auto AWeights0 = "WEIGHTS_0";
|
||||
|
||||
ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
AssetLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex);
|
||||
~ModelLoader();
|
||||
~AssetLoader();
|
||||
|
||||
ModelLoader(ModelLoader &&other) noexcept;
|
||||
ModelLoader &operator=(ModelLoader &&other) noexcept;
|
||||
AssetLoader(AssetLoader &&other) noexcept;
|
||||
AssetLoader &operator=(AssetLoader &&other) noexcept;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ModelLoader);
|
||||
DISALLOW_COPY_AND_ASSIGN(AssetLoader);
|
||||
};
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
// =============================================
|
||||
// Aster: ibl_helpers.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "ibl_helpers.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "image.h"
|
||||
#include "asset_loader.h"
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrectToCube.cs.hlsl.spv";
|
||||
|
||||
TextureHandle
|
||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
||||
const cstr name)
|
||||
{
|
||||
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
||||
const Device *pDevice = resMan->m_Device;
|
||||
|
||||
TextureCube cubeMap;
|
||||
cubeMap.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, false, name ? name : "Env CubeMap");
|
||||
|
||||
StorageTexture stagingTexture;
|
||||
stagingTexture.Init(pDevice, {cubeSide * 3, cubeSide * 2}, vk::Format::eR16G16B16A16Sfloat, false, "EnvStaging");
|
||||
auto envStagingHandle = resMan->Commit(&stagingTexture);
|
||||
|
||||
vk::ImageSubresourceRange stagingSubresRange = {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
};
|
||||
vk::ImageSubresourceRange cubeSubresRange = {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 6,
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier2 readyToWriteBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eComputeShader,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eShaderStorageWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eGeneral,
|
||||
.srcQueueFamilyIndex = 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,
|
||||
};
|
||||
eastl::array transferBarriers = {stagingReadyForTransfer, cubeReadyForTransfer};
|
||||
vk::DependencyInfo preTransferDependency = {
|
||||
.imageMemoryBarrierCount = transferBarriers.size(),
|
||||
.pImageMemoryBarriers = transferBarriers.data(),
|
||||
};
|
||||
vk::ImageMemoryBarrier2 cubemapToRead = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eShaderSampledRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = cubeMap.m_Image,
|
||||
.subresourceRange = cubeSubresRange,
|
||||
};
|
||||
vk::DependencyInfo cubemapToReadDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &cubemapToRead,
|
||||
};
|
||||
|
||||
eastl::array<vk::ImageCopy2, 6> imageCopies;
|
||||
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 = {
|
||||
.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;
|
||||
StorageTextureHandle m_OutputTexture;
|
||||
u32 m_CubeSide;
|
||||
};
|
||||
|
||||
#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 = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||
.offset = 0,
|
||||
.size = sizeof(WorkloadPushConstants),
|
||||
};
|
||||
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
const vk::PipelineLayoutCreateInfo layoutCreateInfo = {
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &resMan->m_SetLayout,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pcr,
|
||||
};
|
||||
AbortIfFailed(pDevice->m_Device.createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout));
|
||||
|
||||
const vk::ComputePipelineCreateInfo computePipelineCreateInfo = {
|
||||
.stage = shaderStageCreateInfo,
|
||||
.layout = pipelineLayout,
|
||||
};
|
||||
|
||||
vk::Pipeline pipeline;
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, 1, &computePipelineCreateInfo,
|
||||
nullptr, &pipeline));
|
||||
|
||||
pDevice->m_Device.destroy(shaderModule, nullptr);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
WorkloadPushConstants pushConstants = {
|
||||
.m_HdrEnvHandle = hdrEnv, .m_OutputTexture = envStagingHandle, .m_CubeSide = cubeSide};
|
||||
|
||||
resMan->Update();
|
||||
|
||||
auto cmd = assetLoader->m_CommandBuffer;
|
||||
constexpr vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(cmd.begin(&beginInfo));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
StackString<128> labelName = "Eqrect -> Cubemap: ";
|
||||
labelName += name ? name : "<unknown env>";
|
||||
vk::DebugUtilsLabelEXT label = {
|
||||
.pLabelName = labelName.c_str(),
|
||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
cmd.beginDebugUtilsLabelEXT(&label);
|
||||
#endif
|
||||
|
||||
cmd.pipelineBarrier2(&readyToWriteDependency);
|
||||
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &resMan->m_DescriptorSet, 0, nullptr);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
|
||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof pushConstants, &pushConstants);
|
||||
cmd.dispatch(cubeSide / 16, cubeSide / 16, 6);
|
||||
|
||||
cmd.pipelineBarrier2(&preTransferDependency);
|
||||
|
||||
cmd.copyImage2(©FlatToCube);
|
||||
|
||||
cmd.pipelineBarrier2(&cubemapToReadDependency);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
cmd.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
|
||||
AbortIfFailed(cmd.end());
|
||||
|
||||
vk::SubmitInfo submitInfo = {
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitDstStageMask = nullptr,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmd,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
||||
AbortIfFailed(computeQueue.submit(1, &submitInfo, fence));
|
||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
||||
pDevice->m_Device.destroy(fence, nullptr);
|
||||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(assetLoader->m_CommandPool, {}));
|
||||
|
||||
resMan->Release(envStagingHandle);
|
||||
pDevice->m_Device.destroy(pipeline, nullptr);
|
||||
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
||||
|
||||
return resMan->Commit(&cubeMap);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// =============================================
|
||||
// Aster: ibl_helpers.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
|
||||
struct Texture;
|
||||
struct TextureCube;
|
||||
struct AssetLoader;
|
||||
|
||||
TextureHandle CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv, cstr name = nullptr);
|
||||
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "gui.h"
|
||||
#include "model_loader.h"
|
||||
#include "ibl_helpers.h"
|
||||
#include "asset_loader.h"
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
|
@ -30,12 +31,26 @@
|
|||
|
||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||
constexpr auto PIPELINE_CACHE_FILE = "PipelineCacheData.bin";
|
||||
constexpr auto MODEL_FILE = "model/DamagedHelmet.glb";
|
||||
constexpr auto BACKDROP_FILE = "image/photo_studio_loft_hall_4k.hdr";
|
||||
constexpr u32 INIT_WIDTH = 1280;
|
||||
constexpr u32 INIT_HEIGHT = 720;
|
||||
|
||||
struct Camera
|
||||
{
|
||||
mat4 m_View;
|
||||
mat4 m_Perspective;
|
||||
vec4 m_Position;
|
||||
mat4 m_InverseView;
|
||||
mat4 m_InversePerspective;
|
||||
vec3 m_Position;
|
||||
f32 m_PositionHomogenousPad_ = 1.0f;
|
||||
|
||||
void
|
||||
CalculateInverses()
|
||||
{
|
||||
m_InverseView = inverse(m_View);
|
||||
m_InversePerspective = inverse(m_Perspective);
|
||||
}
|
||||
};
|
||||
|
||||
struct CameraController
|
||||
|
|
@ -57,9 +72,13 @@ struct CameraController
|
|||
, m_Camera{
|
||||
.m_View = lookAt(position, target, UP),
|
||||
.m_Perspective = glm::perspective(vFov, aspectRatio, 0.1f, 100.0f),
|
||||
.m_Position = vec4{0.0f, 2.0f, 2.0f, 1.0f},
|
||||
.m_Position = position,
|
||||
}
|
||||
{
|
||||
const vec3 dir = normalize(target - vec3(position));
|
||||
m_Pitch = asin(dir.y);
|
||||
m_Yaw = acos(-dir.z / sqrt(1.0f - dir.y * dir.y));
|
||||
m_Camera.CalculateInverses();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -67,6 +86,8 @@ struct CameraController
|
|||
{
|
||||
m_AspectRatio = aspectRatio;
|
||||
m_Camera.m_Perspective = glm::perspective(m_Fov, aspectRatio, 0.1f, 100.0f);
|
||||
|
||||
m_Camera.CalculateInverses();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -77,6 +98,8 @@ struct CameraController
|
|||
f32 cosPitch = cos(m_Pitch);
|
||||
const vec3 target = vec3(sin(m_Yaw) * cosPitch, sin(m_Pitch), -cos(m_Yaw) * cosPitch);
|
||||
m_Camera.m_View = lookAt(position, position + target, UP);
|
||||
|
||||
m_Camera.CalculateInverses();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -87,8 +110,21 @@ struct CameraController
|
|||
|
||||
f32 cosPitch = cos(m_Pitch);
|
||||
const vec3 target = vec3(sin(m_Yaw) * cosPitch, sin(m_Pitch), -cos(m_Yaw) * cosPitch);
|
||||
const vec3 position = vec3{m_Camera.m_Position};
|
||||
const vec3 position = m_Camera.m_Position;
|
||||
m_Camera.m_View = lookAt(position, position + target, UP);
|
||||
|
||||
m_Camera.CalculateInverses();
|
||||
}
|
||||
|
||||
void
|
||||
SetLookAt(const vec3 &target)
|
||||
{
|
||||
const vec3 dir = normalize(target - m_Camera.m_Position);
|
||||
m_Pitch = acos(dir.y);
|
||||
m_Yaw = acos(dir.z / sqrt(1.0f - dir.y * dir.y));
|
||||
m_Camera.m_View = lookAt(m_Camera.m_Position, m_Camera.m_Position + target, UP);
|
||||
|
||||
m_Camera.CalculateInverses();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -98,7 +134,7 @@ main(int, char **)
|
|||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||
|
||||
Context context = {"ModelRender [WIP]", VERSION};
|
||||
Window window = {"ModelRender [WIP] (Aster)", &context, {640, 480}};
|
||||
Window window = {"ModelRender [WIP] (Aster)", &context, {INIT_WIDTH, INIT_HEIGHT}};
|
||||
|
||||
PhysicalDevices physicalDevices = {&window, &context};
|
||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||
|
|
@ -130,22 +166,28 @@ main(int, char **)
|
|||
auto pipelineCacheData = ReadFileBytes(PIPELINE_CACHE_FILE, false);
|
||||
|
||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
GpuResourceManager resourceManager = {&device, 1000};
|
||||
|
||||
ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||
AssetLoader assetLoader = {&resourceManager, graphicsQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||
LightManager lightManager = LightManager{&resourceManager};
|
||||
|
||||
Model model = modelLoader.LoadModel(MODEL_FILE);
|
||||
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
||||
Texture environment;
|
||||
assetLoader.LoadHdrImage(&environment, BACKDROP_FILE);
|
||||
auto envHandle = resourceManager.Commit(&environment);
|
||||
|
||||
TextureHandle texCube = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 1024, envHandle, "Cube Env");
|
||||
|
||||
resourceManager.Release(envHandle);
|
||||
|
||||
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
||||
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &resourceManager);
|
||||
|
||||
//lightManager.AddDirectional(vec3(0.0f, -1.0f, 0.0f), {0.0f, 0.7f, 0.0f});
|
||||
//lightManager.AddPoint(vec3{2.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 15.0f);
|
||||
//lightManager.AddPoint(vec3{-2.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, 15.0f);
|
||||
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &resourceManager);
|
||||
Pipeline backGroundPipeline = CreateBackgroundPipeline(&device, attachmentFormat, &resourceManager);
|
||||
|
||||
lightManager.AddPoint(vec3{-5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||
lightManager.AddPoint(vec3{5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||
|
|
@ -179,7 +221,7 @@ main(int, char **)
|
|||
|
||||
vk::Extent2D internalResolution = {1920, 1080};
|
||||
|
||||
CameraController cameraController = {vec3{0.0f, 2.0f, 2.0f}, vec3{0.0f}, 70_deg,
|
||||
CameraController cameraController = {vec3{0.0f, 0.0f, 2.0f}, vec3{0.0f}, 70_deg,
|
||||
Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height)};
|
||||
|
||||
UniformBuffer ubo;
|
||||
|
|
@ -326,11 +368,12 @@ main(int, char **)
|
|||
}
|
||||
|
||||
gui::Init(&context, &device, &window, swapchain.m_Format, Cast<u32>(swapchain.m_ImageViews.size()),
|
||||
queueAllocation.m_Family, commandQueue);
|
||||
queueAllocation.m_Family, graphicsQueue);
|
||||
bool rotating = false;
|
||||
bool lockToScreen = true;
|
||||
i32 height = Cast<i32>(internalResolution.height);
|
||||
vec2 camPitchYaw = vec2(0.0f);
|
||||
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
||||
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
||||
vec3 camPosition = cameraController.m_Camera.m_Position;
|
||||
vk::Extent2D inputResolution = internalResolution;
|
||||
|
||||
|
|
@ -349,7 +392,7 @@ main(int, char **)
|
|||
|
||||
gui::Begin("Settings");
|
||||
gui::Text("Window Resolution: %ux%u", swapchain.m_Extent.width, swapchain.m_Extent.height);
|
||||
gui::Text("FrameBuffer Resolution %ux%u", internalResolution.width, internalResolution.height);
|
||||
gui::Text("Render Resolution: %ux%u", internalResolution.width, internalResolution.height);
|
||||
gui::Checkbox("Lock Resolution to Window", &lockToScreen);
|
||||
if (!lockToScreen)
|
||||
{
|
||||
|
|
@ -390,15 +433,20 @@ main(int, char **)
|
|||
gui::Text("Delta: %0.6f ms", 1000.0f * Time::m_Delta);
|
||||
gui::Text("FPS: %0.6f", 1.0f / Time::m_Delta);
|
||||
gui::Separator();
|
||||
if (gui::DragFloat2("Camera Orientation", Recast<f32 *>(&camPitchYaw)))
|
||||
gui::PushItemWidth(100);
|
||||
bool yawChange = gui::DragFloat("Camera Yaw", &camYaw);
|
||||
bool pitchChange = gui::DragFloat("Camera Pitch", &camPitch, 1, -89.0f, 89.0f);
|
||||
if (yawChange || pitchChange)
|
||||
{
|
||||
cameraController.SetPitchYaw(glm::radians(camPitchYaw.x), glm::radians(camPitchYaw.y));
|
||||
camYaw = camYaw - floor((camYaw + 180.0f) / 360.0f) * 360.0f;
|
||||
cameraController.SetPitchYaw(glm::radians(camPitch), glm::radians(camYaw));
|
||||
}
|
||||
if (gui::InputFloat3("Camera Position", Recast<f32 *>(&camPosition)))
|
||||
{
|
||||
cameraController.SetPosition(camPosition);
|
||||
}
|
||||
gui::Checkbox("Rotate", &rotating);
|
||||
gui::PopItemWidth();
|
||||
if (gui::Button("Exit"))
|
||||
{
|
||||
window.RequestExit();
|
||||
|
|
@ -413,6 +461,7 @@ main(int, char **)
|
|||
rotate(model.GetModelTransform(), Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)));
|
||||
}
|
||||
model.Update();
|
||||
cameraController.m_Camera.CalculateInverses();
|
||||
ubo.Write(&device, 0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||
|
|
@ -485,17 +534,20 @@ main(int, char **)
|
|||
|
||||
cmd.setViewport(0, 1, &viewport);
|
||||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
||||
&resourceManager.m_DescriptorSet, 0, nullptr);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
|
||||
|
||||
cmd.bindIndexBuffer(model.m_IndexBuffer.m_Buffer, 0, vk::IndexType::eUint32);
|
||||
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
|
||||
u32 pcbOffset = 0;
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof model.m_Handles,
|
||||
&model.m_Handles);
|
||||
pcbOffset += sizeof model.m_Handles;
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof texCube, &texCube);
|
||||
pcbOffset += sizeof texCube;
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo,
|
||||
&lightManager.m_MetaInfo);
|
||||
pcbOffset += sizeof lightManager.m_MetaInfo;
|
||||
|
|
@ -512,6 +564,9 @@ main(int, char **)
|
|||
cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast<i32>(prim.m_VertexOffset), 0);
|
||||
}
|
||||
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, backGroundPipeline.m_Pipeline);
|
||||
cmd.draw(3, 1, 0, 0);
|
||||
|
||||
cmd.endRendering();
|
||||
|
||||
cmd.pipelineBarrier2(&postRenderDependencies);
|
||||
|
|
@ -563,13 +618,15 @@ main(int, char **)
|
|||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = ¤tFrame->m_RenderFinishSem,
|
||||
};
|
||||
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
|
||||
currentFrame->Present(commandQueue, &swapchain, &window);
|
||||
currentFrame->Present(graphicsQueue, &swapchain, &window);
|
||||
}
|
||||
|
||||
AbortIfFailed(device.m_Device.waitIdle());
|
||||
|
||||
resourceManager.Release(texCube);
|
||||
|
||||
pipelineCacheData = device.DumpPipelineCache();
|
||||
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "device.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "swapchain.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
|
|
@ -58,7 +57,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
vk::PushConstantRange pushConstantRange = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
.offset = 0,
|
||||
.size = 36,
|
||||
.size = 40,
|
||||
};
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||
|
|
@ -88,7 +87,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.polygonMode = vk::PolygonMode::eFill,
|
||||
.cullMode = vk::CullModeFlagBits::eNone,
|
||||
.cullMode = vk::CullModeFlagBits::eBack,
|
||||
.frontFace = vk::FrontFace::eCounterClockwise,
|
||||
.depthBiasEnable = false,
|
||||
.lineWidth = 1.0,
|
||||
|
|
@ -151,7 +150,8 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
.layout = pipelineLayout,
|
||||
};
|
||||
vk::Pipeline pipeline;
|
||||
AbortIfFailed(device->m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline));
|
||||
AbortIfFailed(
|
||||
device->m_Device.createGraphicsPipelines(device->m_PipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline));
|
||||
device->SetName(pipeline, "Box Pipeline");
|
||||
|
||||
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||
|
|
@ -160,6 +160,155 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts)};
|
||||
}
|
||||
|
||||
Pipeline
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager)
|
||||
{
|
||||
// Pipeline Setup
|
||||
auto vertexShaderModule = CreateShader(device, BACKGROUND_VERTEX_SHADER_FILE);
|
||||
auto fragmentShaderModule = CreateShader(device, BACKGROUND_FRAGMENT_SHADER_FILE);
|
||||
|
||||
eastl::array<vk::PipelineShaderStageCreateInfo, 2> shaderStages = {{
|
||||
{
|
||||
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||
.module = vertexShaderModule,
|
||||
.pName = "main",
|
||||
},
|
||||
{
|
||||
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||
.module = fragmentShaderModule,
|
||||
.pName = "main",
|
||||
},
|
||||
}};
|
||||
|
||||
eastl::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
|
||||
|
||||
descriptorSetLayouts.push_back(resourceManager->m_SetLayout);
|
||||
|
||||
{
|
||||
eastl::array descriptorSetLayoutBindings = {
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 0,
|
||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
};
|
||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.bindingCount = Cast<u32>(descriptorSetLayoutBindings.size()),
|
||||
.pBindings = descriptorSetLayoutBindings.data(),
|
||||
};
|
||||
vk::DescriptorSetLayout descriptorSetLayout;
|
||||
AbortIfFailed(
|
||||
device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout));
|
||||
descriptorSetLayouts.push_back(descriptorSetLayout);
|
||||
}
|
||||
|
||||
vk::PushConstantRange pushConstantRange = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
.offset = 0,
|
||||
.size = 40,
|
||||
};
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||
.setLayoutCount = Cast<u32>(descriptorSetLayouts.size()),
|
||||
.pSetLayouts = descriptorSetLayouts.data(),
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pushConstantRange,
|
||||
};
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
device->SetName(pipelineLayout, "Box Layout");
|
||||
|
||||
descriptorSetLayouts[0] = nullptr; // Not owned.
|
||||
|
||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
|
||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||
.primitiveRestartEnable = false,
|
||||
};
|
||||
|
||||
vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = {
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
|
||||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.polygonMode = vk::PolygonMode::eFill,
|
||||
.cullMode = vk::CullModeFlagBits::eBack,
|
||||
.frontFace = vk::FrontFace::eCounterClockwise,
|
||||
.depthBiasEnable = false,
|
||||
.lineWidth = 1.0,
|
||||
};
|
||||
vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
|
||||
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
||||
.sampleShadingEnable = false,
|
||||
};
|
||||
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
||||
.depthTestEnable = true,
|
||||
.depthWriteEnable = true,
|
||||
.depthCompareOp = vk::CompareOp::eLessOrEqual,
|
||||
};
|
||||
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
||||
.blendEnable = false,
|
||||
.srcColorBlendFactor = vk::BlendFactor::eSrcColor,
|
||||
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor,
|
||||
.colorBlendOp = vk::BlendOp::eAdd,
|
||||
.srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha,
|
||||
.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
|
||||
.alphaBlendOp = vk::BlendOp::eAdd,
|
||||
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||
};
|
||||
vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
|
||||
.logicOpEnable = false,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorBlendAttachmentState,
|
||||
};
|
||||
|
||||
eastl::array dynamicStates = {
|
||||
vk::DynamicState::eScissor,
|
||||
vk::DynamicState::eViewport,
|
||||
};
|
||||
|
||||
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
|
||||
.dynamicStateCount = Cast<u32>(dynamicStates.size()),
|
||||
.pDynamicStates = dynamicStates.data(),
|
||||
};
|
||||
|
||||
vk::PipelineRenderingCreateInfo renderingCreateInfo = {
|
||||
.viewMask = 0,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachmentFormats = &attachmentFormat,
|
||||
.depthAttachmentFormat = vk::Format::eD24UnormS8Uint,
|
||||
};
|
||||
|
||||
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||
.pNext = &renderingCreateInfo,
|
||||
.stageCount = Cast<u32>(shaderStages.size()),
|
||||
.pStages = shaderStages.data(),
|
||||
.pVertexInputState = &vertexInputStateCreateInfo,
|
||||
.pInputAssemblyState = &inputAssemblyStateCreateInfo,
|
||||
.pViewportState = &viewportStateCreateInfo,
|
||||
.pRasterizationState = &rasterizationStateCreateInfo,
|
||||
.pMultisampleState = &multisampleStateCreateInfo,
|
||||
.pDepthStencilState = &depthStencilStateCreateInfo,
|
||||
.pColorBlendState = &colorBlendStateCreateInfo,
|
||||
.pDynamicState = &dynamicStateCreateInfo,
|
||||
.layout = pipelineLayout,
|
||||
};
|
||||
vk::Pipeline pipeline;
|
||||
AbortIfFailed(
|
||||
device->m_Device.createGraphicsPipelines(device->m_PipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline));
|
||||
device->SetName(pipeline, "BG Pipeline");
|
||||
|
||||
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||
|
||||
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts)};
|
||||
}
|
||||
|
||||
vk::ShaderModule
|
||||
CreateShader(const Device *device, cstr shaderFile)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,5 +15,10 @@ struct Device;
|
|||
constexpr auto VERTEX_SHADER_FILE = "shader/model.vs.hlsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/model.ps.hlsl.spv";
|
||||
|
||||
constexpr auto BACKGROUND_VERTEX_SHADER_FILE = "shader/background.vs.hlsl.spv";
|
||||
constexpr auto BACKGROUND_FRAGMENT_SHADER_FILE = "shader/background.ps.hlsl.spv";
|
||||
|
||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||
Pipeline CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager);
|
||||
Pipeline
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#include "graphics_structs.hlsli"
|
||||
|
||||
struct PS_Input
|
||||
{
|
||||
float3 WorldPosition : POSITION;
|
||||
};
|
||||
|
||||
struct PS_Output
|
||||
{
|
||||
float4 Color : SV_Target0;
|
||||
};
|
||||
|
||||
PS_Output main(PS_Input StageInput)
|
||||
{
|
||||
PS_Output StageOutput;
|
||||
|
||||
float3 Direction = normalize(StageInput.WorldPosition - Camera.Position.xyz);
|
||||
float4 Color = TextureCubes[PushConstant.EnvCubeHandle].Sample(ImmutableSamplers[PushConstant.EnvCubeHandle], Direction);
|
||||
StageOutput.Color = float4(Uncharted2Tonemap(Color.rgb), Color.a);
|
||||
|
||||
return StageOutput;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include "graphics_structs.hlsli"
|
||||
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
uint VertexIndex : SV_VertexID;
|
||||
};
|
||||
|
||||
struct VS_Output
|
||||
{
|
||||
float4 VertexPosition : SV_Position;
|
||||
float3 WorldPosition : POSITION;
|
||||
};
|
||||
|
||||
VS_Output main(VS_Input StageInput)
|
||||
{
|
||||
float3 Points[] =
|
||||
{
|
||||
float3(-1.0f, -1.0f, 1.0f),
|
||||
float3(3.0f, -1.0f, 1.0f),
|
||||
float3(-1.0f, 3.0f, 1.0f),
|
||||
};
|
||||
|
||||
VS_Output StageOutput;
|
||||
StageOutput.VertexPosition = float4(Points[StageInput.VertexIndex], 1.0f);
|
||||
|
||||
float4 ClipSpace = mul(Camera.InvProjection, float4(Points[StageInput.VertexIndex], 1.0f));
|
||||
float4 WorldSpace = mul(Camera.InvView, ClipSpace / ClipSpace.wwww);
|
||||
StageOutput.WorldPosition = WorldSpace.xyz;
|
||||
|
||||
return StageOutput;
|
||||
}
|
||||
|
|
@ -26,19 +26,6 @@ struct MaterialData
|
|||
uint EmissionTex;
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
uint VertexBufferHandle;
|
||||
uint VertexDataHandle;
|
||||
uint MaterialBufferHandle;
|
||||
uint NodeBufferHandle;
|
||||
uint LightHandle;
|
||||
uint PointLightIndexer;
|
||||
uint DirectionalLightIndexer;
|
||||
int MaterialIdx;
|
||||
uint NodeIdx;
|
||||
};
|
||||
|
||||
struct PointLight
|
||||
{
|
||||
float Position[3];
|
||||
|
|
@ -55,13 +42,6 @@ struct DirectionalLight
|
|||
float Intensity;
|
||||
};
|
||||
|
||||
struct CameraData
|
||||
{
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
float4 Position;
|
||||
};
|
||||
|
||||
// Little Endian storage. First short is least significant.
|
||||
#define IndexerCount(Indexer) (Indexer & 0xFFFF)
|
||||
#define IndexerOffset(Indexer) ((Indexer & 0xFFFF0000) >> 16);
|
||||
|
|
@ -78,9 +58,7 @@ static const float PI = 3.14159265f;
|
|||
[[vk::binding(0, 0)]] StructuredBuffer<DirectionalLight> DirectionalLightBuffer[];
|
||||
|
||||
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
||||
[[vk::binding(1, 0)]] TextureCube<float4> TextureCubes[];
|
||||
[[vk::binding(1, 0)]] SamplerState ImmutableSamplers[];
|
||||
|
||||
[[vk::binding(0, 1)]] ConstantBuffer<CameraData> Camera;
|
||||
|
||||
[[vk::push_constant]]
|
||||
Block PushConstant;
|
||||
[[vk::binding(2, 0)]] RWTexture2D<float4> StorageTextures[];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
#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,41 @@
|
|||
#include "bindless_structs.hlsli"
|
||||
|
||||
struct CameraData
|
||||
{
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
float4x4 InvView;
|
||||
float4x4 InvProjection;
|
||||
float4 Position;
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
uint VertexBufferHandle;
|
||||
uint VertexDataHandle;
|
||||
uint MaterialBufferHandle;
|
||||
uint NodeBufferHandle;
|
||||
uint EnvCubeHandle;
|
||||
uint LightHandle;
|
||||
uint PointLightIndexer;
|
||||
uint DirectionalLightIndexer;
|
||||
int MaterialIdx;
|
||||
uint NodeIdx;
|
||||
};
|
||||
|
||||
[[vk::binding(0, 1)]] ConstantBuffer<CameraData> Camera;
|
||||
|
||||
[[vk::push_constant]]
|
||||
Block PushConstant;
|
||||
|
||||
float3 Uncharted2Tonemap(float3 color)
|
||||
{
|
||||
float A = 0.15f;
|
||||
float B = 0.50f;
|
||||
float C = 0.10f;
|
||||
float D = 0.20f;
|
||||
float E = 0.02f;
|
||||
float F = 0.30f;
|
||||
float W = 11.2f;
|
||||
return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "bindless_structs.hlsli"
|
||||
#include "graphics_structs.hlsli"
|
||||
|
||||
struct FS_Input
|
||||
{
|
||||
|
|
@ -217,18 +217,6 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos
|
|||
return Contrib;
|
||||
}
|
||||
|
||||
float3 Uncharted2Tonemap(float3 color)
|
||||
{
|
||||
float A = 0.15f;
|
||||
float B = 0.50f;
|
||||
float C = 0.10f;
|
||||
float D = 0.20f;
|
||||
float E = 0.02f;
|
||||
float F = 0.30f;
|
||||
float W = 11.2f;
|
||||
return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
|
||||
}
|
||||
|
||||
FS_Output main(FS_Input StageInput)
|
||||
{
|
||||
FS_Output Output;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "bindless_structs.hlsli"
|
||||
#include "graphics_structs.hlsli"
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue