Compare commits

...

3 Commits

Author SHA1 Message Date
Anish Bhobe a87da63c98 Added Model Root node for global transforms. 2024-07-20 10:25:16 +02:00
Anish Bhobe 41a1725c34 Fix a transform update issue. 2024-07-20 09:37:25 +02:00
Anish Bhobe ab947ad9f9 Fixed issue at window minimization. 2024-07-20 02:06:10 +02:00
8 changed files with 114 additions and 46 deletions

View File

@ -9,6 +9,8 @@
#include "physical_device.h" #include "physical_device.h"
#include "window.h" #include "window.h"
[[nodiscard]] vk::Extent2D GetExtent(const Window *window, vk::SurfaceCapabilitiesKHR *surfaceCapabilities);
Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name) Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name)
: m_Device(device) : m_Device(device)
, m_Name(std::move(name)) , m_Name(std::move(name))
@ -52,6 +54,15 @@ void
Swapchain::Create(const Window *window) Swapchain::Create(const Window *window)
{ {
auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface); auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface);
m_Extent = GetExtent(window, &surfaceCapabilities);
while (m_Extent.width == 0 || m_Extent.height == 0)
{
glfwWaitEvents();
surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface);
m_Extent = GetExtent(window, &surfaceCapabilities);
}
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface); auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface); auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
@ -83,20 +94,6 @@ Swapchain::Create(const Window *window)
} }
} }
if (surfaceCapabilities.currentExtent.width != MaxValue<u32>)
{
m_Extent = surfaceCapabilities.currentExtent;
}
else
{
auto [width, height] = window->GetSize();
auto [minWidth, minHeight] = surfaceCapabilities.minImageExtent;
auto [maxWidth, maxHeight] = surfaceCapabilities.maxImageExtent;
m_Extent.width = glm::clamp(width, minWidth, maxWidth);
m_Extent.height = glm::clamp(height, minHeight, maxHeight);
}
u32 swapchainImageCount = 3; u32 swapchainImageCount = 3;
if (surfaceCapabilities.maxImageCount > 0) if (surfaceCapabilities.maxImageCount > 0)
{ {
@ -207,3 +204,21 @@ Swapchain::Cleanup()
DEBUG("Swapchain '{}' destroyed.", m_Name); DEBUG("Swapchain '{}' destroyed.", m_Name);
} }
} }
vk::Extent2D
GetExtent(const Window *window, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
{
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
{
return surfaceCapabilities->currentExtent;
}
auto [width, height] = window->GetSize();
auto [minWidth, minHeight] = surfaceCapabilities->minImageExtent;
auto [maxWidth, maxHeight] = surfaceCapabilities->maxImageExtent;
return {
.width = glm::clamp(width, minWidth, maxWidth),
.height = glm::clamp(height, minHeight, maxHeight),
};
}

View File

@ -25,7 +25,7 @@ Window::GetSize() const
{ {
int width; int width;
int height; int height;
glfwGetWindowSize(m_Window, &width, &height); glfwGetFramebufferSize(m_Window, &width, &height);
return {Cast<u32>(width), Cast<u32>(height)}; return {Cast<u32>(width), Cast<u32>(height)};
} }

View File

@ -29,6 +29,7 @@ struct Window final
void SetWindowSize(const vk::Extent2D &extent) const noexcept; void SetWindowSize(const vk::Extent2D &extent) const noexcept;
void SetWindowSize(u32 width, u32 height) const noexcept; void SetWindowSize(u32 width, u32 height) const noexcept;
/// Actual size of the framebuffer being used for the window render.
[[nodiscard]] vk::Extent2D GetSize() const; [[nodiscard]] vk::Extent2D GetSize() const;
// Ctor/Dtor // Ctor/Dtor

View File

@ -513,6 +513,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
} }
Nodes nodes; Nodes nodes;
nodes.Add(mat4{1.0f}, -1);
{ {
if (model.defaultScene >= 0) if (model.defaultScene >= 0)
{ {
@ -533,6 +534,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
} }
if (node->scale.size() == 3) if (node->scale.size() == 3)
{ {
// We don't handle the scale 0 special case yet.
nodeScale = glm::make_vec3(node->scale.data()); nodeScale = glm::make_vec3(node->scale.data());
} }
if (node->matrix.size() == 16) if (node->matrix.size() == 16)
@ -542,14 +544,14 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
const mat4 transform = const mat4 transform =
translate(mat4(1.0f), nodeTranslation) * mat4_cast(nodeRotation) * scale(mat4(1.0f), nodeScale) * nodeMatrix; translate(mat4(1.0f), nodeTranslation) * mat4_cast(nodeRotation) * scale(mat4(1.0f), nodeScale) * nodeMatrix;
const u32 nodeArrayIndex = nodes.Add(transform, parent); const i32 nodeArrayIndex = Cast<i32>(nodes.Add(transform, parent));
if (node->mesh >= 0) if (node->mesh >= 0)
{ {
auto [start, count] = meshPrimRanges[node->mesh]; auto [start, count] = meshPrimRanges[node->mesh];
const auto end = start + count; const auto end = start + count;
for (usize i = start; i != end; ++i) for (usize i = start; i != end; ++i)
{ {
meshPrimitives[i].m_TransformIdx = Cast<i32>(nodeArrayIndex); meshPrimitives[i].m_TransformIdx = nodeArrayIndex;
} }
} }
@ -561,7 +563,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
auto *scene = &model.scenes[model.defaultScene]; auto *scene = &model.scenes[model.defaultScene];
for (i32 rootNodeIdx : scene->nodes) for (i32 rootNodeIdx : scene->nodes)
{ {
processNode(rootNodeIdx, -1); processNode(rootNodeIdx, 0);
} }
} }
} }
@ -660,8 +662,6 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
buffer.Destroy(pDevice); buffer.Destroy(pDevice);
} }
nodes.Update();
return Model{m_ResourceManager, std::move(textureHandles), std::move(nodes), return Model{m_ResourceManager, std::move(textureHandles), std::move(nodes),
materialsHandle, positionBufferHandle, normalBufferHandle, materialsHandle, positionBufferHandle, normalBufferHandle,
texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives, nodeHandle}; texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives, nodeHandle};
@ -711,12 +711,24 @@ Model::operator=(Model &&other) noexcept
m_NormalHandle = other.m_NormalHandle; m_NormalHandle = other.m_NormalHandle;
m_TexCoord0Handle = other.m_TexCoord0Handle; m_TexCoord0Handle = other.m_TexCoord0Handle;
m_VertexColorHandle = other.m_VertexColorHandle; m_VertexColorHandle = other.m_VertexColorHandle;
m_NodeHandle = std::move(other.m_NodeHandle); m_NodeHandle = other.m_NodeHandle;
m_IndexBuffer = other.m_IndexBuffer; m_IndexBuffer = other.m_IndexBuffer;
m_MeshPrimitives = std::move(other.m_MeshPrimitives); m_MeshPrimitives = std::move(other.m_MeshPrimitives);
return *this; return *this;
} }
const mat4 &
Model::GetModelTransform() const
{
return m_Nodes[0];
}
void
Model::SetModelTransform(const mat4 &transform)
{
m_Nodes.Set(0, transform);
}
Model::~Model() Model::~Model()
{ {
if (!m_ResourceManager) if (!m_ResourceManager)
@ -735,6 +747,16 @@ Model::~Model()
m_ResourceManager->Release(m_MaterialsHandle); m_ResourceManager->Release(m_MaterialsHandle);
} }
void
Model::Update()
{
if (m_Nodes.Update())
{
m_ResourceManager->Write(m_NodeHandle, 0, m_Nodes.GetGlobalTransformByteSize(),
m_Nodes.GetGlobalTransformPtr());
}
}
ModelLoader::ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, ModelLoader::ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
u32 graphicsQueueIndex) u32 graphicsQueueIndex)
: m_ResourceManager(resourceManager) : m_ResourceManager(resourceManager)

View File

@ -7,7 +7,6 @@
#include "buffer.h" #include "buffer.h"
#include "global.h" #include "global.h"
#include "image.h"
#include "render_resource_manager.h" #include "render_resource_manager.h"
@ -34,6 +33,7 @@ struct Nodes
{ {
eastl::vector<mat4> m_Transforms; eastl::vector<mat4> m_Transforms;
eastl::vector<mat4> m_GlobalTransforms; eastl::vector<mat4> m_GlobalTransforms;
/// Parents are also used for bookkeeping
eastl::vector<u32> m_Parents_; eastl::vector<u32> m_Parents_;
bool m_Dirty = true; bool m_Dirty = true;
@ -42,10 +42,10 @@ struct Nodes
constexpr static u32 PARENT_MASK = ~(ROOT_BIT | DIRTY_BIT); constexpr static u32 PARENT_MASK = ~(ROOT_BIT | DIRTY_BIT);
u32 u32
Add(const mat4& transform, i32 parent = -1) Add(const mat4& transform, const i32 parent = -1)
{ {
m_Dirty = true; m_Dirty = true;
u32 index = Count(); const u32 index = Count();
m_Transforms.push_back(transform); m_Transforms.push_back(transform);
m_GlobalTransforms.push_back(transform); m_GlobalTransforms.push_back(transform);
const u32 parentVal = (parent < 0 ? ROOT_BIT : parent & PARENT_MASK) | DIRTY_BIT; const u32 parentVal = (parent < 0 ? ROOT_BIT : parent & PARENT_MASK) | DIRTY_BIT;
@ -91,20 +91,20 @@ struct Nodes
[[nodiscard]] usize [[nodiscard]] usize
GetGlobalTransformByteSize() const GetGlobalTransformByteSize() const
{ {
return m_Transforms.size() * sizeof m_Transforms[0]; return m_GlobalTransforms.size() * sizeof m_GlobalTransforms[0];
} }
[[nodiscard]] const mat4 * [[nodiscard]] const mat4 *
GetGlobalTransformPtr() const GetGlobalTransformPtr() const
{ {
return m_Transforms.data(); return m_GlobalTransforms.data();
} }
void bool
Update() Update()
{ {
if (!m_Dirty) if (!m_Dirty)
return; return false;
auto transformIter = m_Transforms.begin(); auto transformIter = m_Transforms.begin();
auto globalTransformIter = m_GlobalTransforms.begin(); auto globalTransformIter = m_GlobalTransforms.begin();
@ -113,23 +113,41 @@ struct Nodes
while (parentIter != parentEnd) while (parentIter != parentEnd)
{ {
if (!(*parentIter & ROOT_BIT) && *parentIter & DIRTY_BIT) const bool isRoot = *parentIter & ROOT_BIT;
const bool isDirty = *parentIter & DIRTY_BIT;
if (isRoot)
{ {
u32 parent = *parentIter & PARENT_MASK; if (isDirty)
*globalTransformIter = m_GlobalTransforms[parent] * *transformIter; {
// Copy-update if the root is dirty.
*globalTransformIter = *transformIter;
}
} }
else else
{ {
*globalTransformIter = *transformIter; const u32 parentIdx = *parentIter & PARENT_MASK;
const bool isParentDirty = m_Parents_[parentIdx] & DIRTY_BIT;
if (isDirty || isParentDirty)
{
// Update w.r.t parent if either local or parent transforms updated.
*globalTransformIter = m_GlobalTransforms[parentIdx] * *transformIter;
m_Parents_[parentIdx] |= DIRTY_BIT; // Set dirty to propagate the update.
}
} }
*parentIter &= ~DIRTY_BIT;
++parentIter; ++parentIter;
++globalTransformIter; ++globalTransformIter;
++transformIter; ++transformIter;
} }
for (u32 &parentValue : m_Parents_)
{
parentValue &= ~DIRTY_BIT; // Unset dirty.
}
m_Dirty = false; m_Dirty = false;
return true;
} }
}; };
@ -163,13 +181,16 @@ struct Model
IndexBuffer m_IndexBuffer; IndexBuffer m_IndexBuffer;
eastl::vector<MeshPrimitive> m_MeshPrimitives; eastl::vector<MeshPrimitive> m_MeshPrimitives;
[[nodiscard]] const mat4 &GetModelTransform() const;
void SetModelTransform(const mat4 &transform);
void Update();
Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes&& nodes, Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes&& nodes,
BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, BufferHandle vertexColor, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, BufferHandle vertexColor,
const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives, BufferHandle nodeHandle); const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives, BufferHandle nodeHandle);
Model(Model &&other) noexcept; Model(Model &&other) noexcept;
Model &operator=(Model &&other) noexcept; Model &operator=(Model &&other) noexcept;
~Model(); ~Model();
DISALLOW_COPY_AND_ASSIGN(Model); DISALLOW_COPY_AND_ASSIGN(Model);

View File

@ -236,7 +236,9 @@ main(int, char **)
{ {
Time::Update(); Time::Update();
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)); model.SetModelTransform(
rotate(model.GetModelTransform(), Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)));
model.Update();
ubo.Write(&device, 0, sizeof camera, &camera); ubo.Write(&device, 0, sizeof camera, &camera);
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window); Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);

View File

@ -215,6 +215,12 @@ GpuResourceManager::Commit(StorageBuffer *storageBuffer)
return handle; return handle;
} }
void
GpuResourceManager::Write(const BufferHandle handle, const usize offset, const usize size, const void *data)
{
m_BufferManager.Fetch(handle)->Write(m_Device, offset, size, data);
}
void void
GpuResourceManager::EraseWrites(u32 handleIndex, HandleType handleType) GpuResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
{ {

View File

@ -115,6 +115,7 @@ public:
vk::DescriptorSet m_DescriptorSet; vk::DescriptorSet m_DescriptorSet;
BufferHandle Commit(StorageBuffer *storageBuffer); BufferHandle Commit(StorageBuffer *storageBuffer);
void Write(BufferHandle handle, usize offset, usize size, const void *data);
void Release(BufferHandle handle); void Release(BufferHandle handle);
TextureHandle Commit(Texture *texture); TextureHandle Commit(Texture *texture);
void Release(TextureHandle handle); void Release(TextureHandle handle);