Added ImageManager and ported Box.
- BufferManager can construct UniformBuffers - Box uses Managers for all the tasks.
This commit is contained in:
parent
9ca5751a78
commit
88d8a2acc2
|
|
@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.13)
|
|||
target_sources(aster_core
|
||||
INTERFACE
|
||||
"manager.h"
|
||||
"buffer_manager.h")
|
||||
"buffer_manager.h"
|
||||
"image_manager.h")
|
||||
|
|
|
|||
|
|
@ -20,5 +20,6 @@ class BufferManager final : public Manager<Buffer>
|
|||
BufferManager(const Device *device, const u32 maxCount);
|
||||
|
||||
Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||
Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// =============================================
|
||||
// Aster: image_manager.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/image.h"
|
||||
#include "manager.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
|
||||
struct Texture2DCreateInfo
|
||||
{
|
||||
vk::Format m_Format = vk::Format::eUndefined;
|
||||
vk::Extent2D m_Extent = {};
|
||||
cstr m_Name = nullptr;
|
||||
bool m_IsSampled = true;
|
||||
bool m_IsMipMapped = false;
|
||||
bool m_IsStorage = false;
|
||||
};
|
||||
|
||||
struct TextureCubeCreateInfo
|
||||
{
|
||||
vk::Format m_Format = vk::Format::eUndefined;
|
||||
u32 m_Side = 0;
|
||||
cstr m_Name = nullptr;
|
||||
bool m_IsSampled = true;
|
||||
bool m_IsMipMapped = false;
|
||||
bool m_IsStorage = false;
|
||||
};
|
||||
|
||||
struct AttachmentCreateInfo
|
||||
{
|
||||
vk::Format m_Format = vk::Format::eUndefined;
|
||||
vk::Extent2D m_Extent = {};
|
||||
cstr m_Name = nullptr;
|
||||
};
|
||||
|
||||
struct DepthStencilImageCreateInfo
|
||||
{
|
||||
vk::Extent2D m_Extent = {};
|
||||
cstr m_Name = nullptr;
|
||||
};
|
||||
|
||||
using ImageHandle = Handle<Image>;
|
||||
|
||||
class ImageManager final : public Manager<Image>
|
||||
{
|
||||
public:
|
||||
ImageManager(const Device *device, const u32 maxCount);
|
||||
|
||||
Handle CreateTexture2D(const Texture2DCreateInfo& createInfo);
|
||||
Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
||||
Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
||||
Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.13)
|
|||
target_sources(aster_core
|
||||
PRIVATE
|
||||
"manager.cpp"
|
||||
"buffer_manager.cpp")
|
||||
"buffer_manager.cpp"
|
||||
"image_manager.cpp")
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
Manager<Buffer> *Manager<Buffer>::m_Instance;
|
||||
|
||||
systems::BufferManager::Ref
|
||||
systems::BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||
using namespace systems;
|
||||
|
||||
BufferHandle
|
||||
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||
{
|
||||
Ref object = Alloc();
|
||||
auto [handle, object] = Alloc();
|
||||
|
||||
// TODO: Storage and Index buffer are set.
|
||||
// This is hacky and should be improved.
|
||||
|
|
@ -22,11 +24,25 @@ systems::BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
|||
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||
|
||||
return object;
|
||||
return std::move(handle);
|
||||
}
|
||||
|
||||
systems::BufferManager::BufferManager(const Device *device, const u32 maxCount)
|
||||
Manager<Buffer>::Handle
|
||||
BufferManager::CreateUniformBuffer(usize size, cstr name)
|
||||
{
|
||||
auto [handle, object] = Alloc();
|
||||
|
||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer;
|
||||
constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||
|
||||
return std::move(handle);
|
||||
}
|
||||
|
||||
BufferManager::BufferManager(const Device *device, const u32 maxCount)
|
||||
: Manager{device, maxCount}
|
||||
{
|
||||
SetInstance(this);
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
// =============================================
|
||||
// Aster: buffer_manager.cpp
|
||||
// Copyright (c) 2020-2025 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "systems/image_manager.h"
|
||||
|
||||
#include "core/device.h"
|
||||
|
||||
Manager<Image> *Manager<Image>::m_Instance;
|
||||
|
||||
using namespace systems;
|
||||
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo);
|
||||
|
||||
namespace usage_flags
|
||||
{
|
||||
constexpr vk::ImageUsageFlags MIPMAP = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
constexpr vk::ImageUsageFlags SAMPLE = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
constexpr vk::ImageUsageFlags STORAGE =
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc;
|
||||
constexpr vk::ImageUsageFlags COLOR_ATTACHMENT =
|
||||
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
|
||||
constexpr vk::ImageUsageFlags DEPTH_STENCIL_ATTACHMENT = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
} // namespace usage_flags
|
||||
|
||||
ImageHandle
|
||||
ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageCreateInfo.format,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = imageCreateInfo.mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = imageCreateInfo.arrayLayers,
|
||||
},
|
||||
};
|
||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
auto [handle, object] = Alloc();
|
||||
object->m_Image = image;
|
||||
object->m_View = view;
|
||||
object->m_Allocation = allocation;
|
||||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::eCube,
|
||||
.format = imageCreateInfo.format,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = imageCreateInfo.mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = imageCreateInfo.arrayLayers,
|
||||
},
|
||||
};
|
||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
auto [handle, object] = Alloc();
|
||||
object->m_Image = image;
|
||||
object->m_View = view;
|
||||
object->m_Allocation = allocation;
|
||||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageCreateInfo.format,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = imageCreateInfo.mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = imageCreateInfo.arrayLayers,
|
||||
},
|
||||
};
|
||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
auto [handle, object] = Alloc();
|
||||
object->m_Image = image;
|
||||
object->m_View = view;
|
||||
object->m_Allocation = allocation;
|
||||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageCreateInfo.format,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = imageCreateInfo.mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = imageCreateInfo.arrayLayers,
|
||||
},
|
||||
};
|
||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
auto [handle, object] = Alloc();
|
||||
object->m_Image = image;
|
||||
object->m_View = view;
|
||||
object->m_Allocation = allocation;
|
||||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo
|
||||
ToImageCreateInfo(const Texture2DCreateInfo &createInfo)
|
||||
{
|
||||
auto &[format, extent, name, isSampled, isMipMapped, isStorage] = createInfo;
|
||||
|
||||
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 u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
||||
|
||||
auto usage = vk::ImageUsageFlags{};
|
||||
if (isSampled)
|
||||
usage |= usage_flags::SAMPLE;
|
||||
if (isMipMapped)
|
||||
usage |= usage_flags::MIPMAP;
|
||||
if (isStorage)
|
||||
usage |= usage_flags::STORAGE;
|
||||
|
||||
return {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 1,
|
||||
.usage = usage,
|
||||
};
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo
|
||||
ToImageCreateInfo(const TextureCubeCreateInfo &createInfo)
|
||||
{
|
||||
auto &[format, side, name, isSampled, isMipMapped, isStorage] = createInfo;
|
||||
|
||||
WARN_IF(!IsPowerOfTwo(side), "ImageCube {1} is {0}x{0} (Non Power of Two)", side, name ? name : "<unnamed>");
|
||||
|
||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(side))) : 1;
|
||||
|
||||
auto usage = vk::ImageUsageFlags{};
|
||||
if (isSampled)
|
||||
usage |= usage_flags::SAMPLE;
|
||||
if (isMipMapped)
|
||||
usage |= usage_flags::MIPMAP;
|
||||
if (isStorage)
|
||||
usage |= usage_flags::STORAGE;
|
||||
|
||||
return {
|
||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = {side, side, 1},
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 6,
|
||||
.usage = usage,
|
||||
};
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo
|
||||
ToImageCreateInfo(const AttachmentCreateInfo &createInfo)
|
||||
{
|
||||
auto &[format, extent, name] = createInfo;
|
||||
|
||||
constexpr auto usage = usage_flags::COLOR_ATTACHMENT;
|
||||
|
||||
return {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.usage = usage,
|
||||
};
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo
|
||||
ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo)
|
||||
{
|
||||
auto &[extent, name] = createInfo;
|
||||
|
||||
constexpr vk::Format format = vk::Format::eD24UnormS8Uint;
|
||||
constexpr auto usage = usage_flags::DEPTH_STENCIL_ATTACHMENT;
|
||||
|
||||
return {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.usage = usage,
|
||||
};
|
||||
}
|
||||
|
||||
ImageManager::ImageManager(const Device *device, const u32 maxCount)
|
||||
: Manager{device, maxCount}
|
||||
{
|
||||
}
|
||||
|
|
@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.13)
|
|||
add_executable(box "box.cpp" "stb_image.h")
|
||||
add_shader(box "shader/box.vert.glsl")
|
||||
add_shader(box "shader/box.frag.glsl")
|
||||
add_shader(box "shader/box.vs.hlsl")
|
||||
add_shader(box "shader/box.ps.hlsl")
|
||||
|
||||
target_link_libraries(box PRIVATE aster_core)
|
||||
target_link_libraries(box PRIVATE util_helper)
|
||||
|
|
|
|||
|
|
@ -9,23 +9,25 @@
|
|||
#include "aster/core/constants.h"
|
||||
#include "aster/core/context.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
#include "aster/core/physical_device.h"
|
||||
#include "aster/core/pipeline.h"
|
||||
#include "aster/core/swapchain.h"
|
||||
#include "aster/core/window.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "aster/systems/buffer_manager.h"
|
||||
#include "aster/systems/image_manager.h"
|
||||
#include "frame.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vs.hlsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.ps.hlsl.spv";
|
||||
|
||||
struct ImageFile
|
||||
{
|
||||
|
|
@ -76,32 +78,9 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
|||
struct Vertex
|
||||
{
|
||||
vec3 m_Position;
|
||||
f32 m_PositionW = 1.0;
|
||||
vec2 m_TexCoord0;
|
||||
|
||||
constexpr static vk::VertexInputBindingDescription
|
||||
GetBinding(const u32 binding)
|
||||
{
|
||||
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
||||
}
|
||||
|
||||
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
||||
GetAttributes(const u32 binding)
|
||||
{
|
||||
return {
|
||||
vk::VertexInputAttributeDescription{
|
||||
.location = 0,
|
||||
.binding = binding,
|
||||
.format = vk::Format::eR32G32B32Sfloat,
|
||||
.offset = offsetof(Vertex, m_Position),
|
||||
},
|
||||
vk::VertexInputAttributeDescription{
|
||||
.location = 1,
|
||||
.binding = binding,
|
||||
.format = vk::Format::eR32G32Sfloat,
|
||||
.offset = offsetof(Vertex, m_TexCoord0),
|
||||
},
|
||||
};
|
||||
}
|
||||
vec2 m_Padding0_ = {0.0f, 0.0f};
|
||||
};
|
||||
|
||||
struct Camera
|
||||
|
|
@ -127,7 +106,8 @@ main(int, char **)
|
|||
|
||||
Features enabledDeviceFeatures = {
|
||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||
.m_Vulkan13Features = {.dynamicRendering = true},
|
||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||
};
|
||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||
|
|
@ -135,6 +115,9 @@ main(int, char **)
|
|||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||
|
||||
systems::BufferManager bufferManager{&device, 12};
|
||||
systems::ImageManager imageManager{&device, 12};
|
||||
|
||||
Camera camera = {
|
||||
.m_Model = {1.0f},
|
||||
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
||||
|
|
@ -155,6 +138,10 @@ main(int, char **)
|
|||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||
|
|
@ -235,24 +222,32 @@ main(int, char **)
|
|||
assert(loaded);
|
||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||
|
||||
VertexBuffer vbo;
|
||||
Texture crate;
|
||||
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
||||
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, "Crate Texture");
|
||||
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
||||
auto crate = imageManager
|
||||
.CreateTexture2D({
|
||||
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
||||
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
||||
.m_Name = "Crate Texture",
|
||||
})
|
||||
.ToPointer();
|
||||
vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||
|
||||
{
|
||||
StagingBuffer vertexStaging, imageStaging;
|
||||
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
||||
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||
StagingBuffer imageStaging;
|
||||
|
||||
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyToWrite = {
|
||||
vk::ImageMemoryBarrier2 imageReadyToWrite = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.image = crate.m_Image,
|
||||
.image = crate->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -262,13 +257,21 @@ main(int, char **)
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageReadyToWriteDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageReadyToWrite,
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyToRead = {
|
||||
vk::ImageMemoryBarrier2 imageReadyToRead = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.image = crate.m_Image,
|
||||
.image = crate->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -278,6 +281,10 @@ main(int, char **)
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageReadyToReadDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageReadyToRead,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||
|
|
@ -285,11 +292,8 @@ main(int, char **)
|
|||
|
||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageReadyToWrite);
|
||||
|
||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
||||
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||
copyBuffer.pipelineBarrier2(&imageReadyToWriteDependency);
|
||||
|
||||
vk::BufferImageCopy imageCopy = {
|
||||
.bufferOffset = 0,
|
||||
|
|
@ -305,11 +309,10 @@ main(int, char **)
|
|||
.imageOffset = {},
|
||||
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
||||
};
|
||||
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate->m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||
&imageCopy);
|
||||
|
||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
||||
0, nullptr, 0, nullptr, 1, &imageReadyToRead);
|
||||
copyBuffer.pipelineBarrier2(&imageReadyToReadDependency);
|
||||
|
||||
AbortIfFailed(copyBuffer.end());
|
||||
|
||||
|
|
@ -327,7 +330,6 @@ main(int, char **)
|
|||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||
|
||||
device.m_Device.destroy(fence, nullptr);
|
||||
vertexStaging.Destroy(&device);
|
||||
imageStaging.Destroy(&device);
|
||||
}
|
||||
|
||||
|
|
@ -351,19 +353,23 @@ main(int, char **)
|
|||
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||
}
|
||||
|
||||
UniformBuffer ubo;
|
||||
ubo.Init(&device, sizeof camera, "Camera UBO");
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
||||
.buffer = ubo.m_Buffer,
|
||||
.buffer = ubo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = ubo.GetSize(),
|
||||
.range = ubo->GetSize(),
|
||||
};
|
||||
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||
.sampler = sampler,
|
||||
.imageView = crate.m_View,
|
||||
.imageView = crate->m_View,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
};
|
||||
vk::DescriptorBufferInfo descriptorStorageBufferInfo = {
|
||||
.buffer = vbo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = vbo->GetSize(),
|
||||
};
|
||||
eastl::array writeDescriptors = {
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
|
|
@ -381,6 +387,14 @@ main(int, char **)
|
|||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &descriptorImageInfo,
|
||||
},
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 2,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.pBufferInfo = &descriptorStorageBufferInfo,
|
||||
},
|
||||
};
|
||||
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||
|
||||
|
|
@ -414,35 +428,56 @@ main(int, char **)
|
|||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
};
|
||||
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
||||
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
||||
// For Color Attachment output ref:
|
||||
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7193#issuecomment-1875960974
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
||||
vk::DependencyInfo topOfThePipeDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &topOfThePipeBarrier,
|
||||
};
|
||||
vk::ImageMemoryBarrier2 renderToPresentBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::DependencyInfo renderToPresentDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &renderToPresentBarrier,
|
||||
};
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
||||
for (auto &depthImage : depthImages)
|
||||
{
|
||||
depthImage.Init(&device, swapchain.m_Extent, "Depth");
|
||||
}
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
|
||||
auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
|
||||
for (auto &depthImage : depthImages)
|
||||
auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) {
|
||||
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||
{
|
||||
depthImage.Destroy(&device);
|
||||
depthImage.Init(&device, extent, "Depth");
|
||||
depthImages.push_back(
|
||||
imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
||||
}
|
||||
};
|
||||
|
||||
initDepthImages(swapchain.m_Extent);
|
||||
|
||||
auto recreateDepthBuffers = [&depthImages, &initDepthImages](const vk::Extent2D extent) {
|
||||
depthImages.clear();
|
||||
initDepthImages(extent);
|
||||
};
|
||||
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||
|
||||
Time::Init();
|
||||
|
|
@ -453,7 +488,7 @@ main(int, char **)
|
|||
Time::Update();
|
||||
|
||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
|
|
@ -461,7 +496,7 @@ main(int, char **)
|
|||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
|
||||
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx]->m_View;
|
||||
|
||||
topOfThePipeBarrier.image = currentImage;
|
||||
renderToPresentBarrier.image = currentImage;
|
||||
|
|
@ -469,8 +504,7 @@ main(int, char **)
|
|||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(cmd.begin(&beginInfo));
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
||||
|
||||
// Render
|
||||
eastl::array attachmentInfos = {
|
||||
|
|
@ -480,7 +514,7 @@ main(int, char **)
|
|||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -507,14 +541,11 @@ main(int, char **)
|
|||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
usize offsets = 0;
|
||||
cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets);
|
||||
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||
|
||||
cmd.endRendering();
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
||||
cmd.pipelineBarrier2(&renderToPresentDependency);
|
||||
|
||||
AbortIfFailed(cmd.end());
|
||||
|
||||
|
|
@ -534,17 +565,9 @@ main(int, char **)
|
|||
}
|
||||
|
||||
device.WaitIdle();
|
||||
|
||||
for (auto &depthImage : depthImages)
|
||||
{
|
||||
depthImage.Destroy(&device);
|
||||
}
|
||||
device.m_Device.destroy(sampler, nullptr);
|
||||
ubo.Destroy(&device);
|
||||
device.m_Device.destroy(descriptorPool, nullptr);
|
||||
device.m_Device.destroy(copyPool, nullptr);
|
||||
crate.Destroy(&device);
|
||||
vbo.Destroy(&device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -582,6 +605,12 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 2,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||
},
|
||||
};
|
||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||
|
|
@ -601,15 +630,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
device->SetName(pipelineLayout, "Box Layout");
|
||||
|
||||
vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0);
|
||||
auto inputAttributeDescription = Vertex::GetAttributes(0);
|
||||
|
||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &inputBindingDescription,
|
||||
.vertexAttributeDescriptionCount = Cast<u32>(inputAttributeDescription.size()),
|
||||
.pVertexAttributeDescriptions = inputAttributeDescription.data(),
|
||||
};
|
||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
|
||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||
.primitiveRestartEnable = false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
struct FS_Input {
|
||||
float2 UV0 : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct FS_Output
|
||||
{
|
||||
float4 ColorTarget : SV_Target0;
|
||||
};
|
||||
|
||||
[[vk::binding(1, 0)]] Texture2D<float4> Texture;
|
||||
[[vk::binding(1, 0)]] SamplerState Sampler;
|
||||
|
||||
FS_Output main(FS_Input StageInput) {
|
||||
FS_Output output;
|
||||
|
||||
output.ColorTarget = float4(Texture.Sample(Sampler, StageInput.UV0).rgb, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
struct VS_Input
|
||||
{
|
||||
uint VertexIndex : SV_VertexID;
|
||||
};
|
||||
|
||||
struct VS_Output
|
||||
{
|
||||
float2 UV0 : TEXCOORD0;
|
||||
float4 VertexPosition : SV_Position;
|
||||
};
|
||||
|
||||
struct CameraData {
|
||||
float4x4 Model;
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
};
|
||||
|
||||
struct VertexData {
|
||||
float4 Position;
|
||||
float2 UV0;
|
||||
};
|
||||
|
||||
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
||||
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
||||
|
||||
VS_Output main(VS_Input StageInput) {
|
||||
VS_Output output;
|
||||
|
||||
output.UV0 = Vertices[StageInput.VertexIndex].UV0;
|
||||
|
||||
float4 position = Vertices[StageInput.VertexIndex].Position;
|
||||
|
||||
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
||||
|
||||
return output;
|
||||
}
|
||||
Loading…
Reference in New Issue