Compare commits
3 Commits
cee0cad0bd
...
a87da63c98
| Author | SHA1 | Date |
|---|---|---|
|
|
a87da63c98 | |
|
|
41a1725c34 | |
|
|
ab947ad9f9 |
|
|
@ -9,10 +9,12 @@
|
||||||
#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))
|
||||||
, m_Format(vk::Format::eUndefined)
|
, m_Format(vk::Format::eUndefined)
|
||||||
{
|
{
|
||||||
this->Create(window);
|
this->Create(window);
|
||||||
}
|
}
|
||||||
|
|
@ -24,12 +26,12 @@ Swapchain::~Swapchain()
|
||||||
|
|
||||||
Swapchain::Swapchain(Swapchain &&other) noexcept
|
Swapchain::Swapchain(Swapchain &&other) noexcept
|
||||||
: m_Device(other.m_Device)
|
: m_Device(other.m_Device)
|
||||||
, m_Swapchain(Take(other.m_Swapchain))
|
, m_Swapchain(Take(other.m_Swapchain))
|
||||||
, m_Name(std::move(other.m_Name))
|
, m_Name(std::move(other.m_Name))
|
||||||
, m_Extent(other.m_Extent)
|
, m_Extent(other.m_Extent)
|
||||||
, m_Format(other.m_Format)
|
, m_Format(other.m_Format)
|
||||||
, m_Images(std::move(other.m_Images))
|
, m_Images(std::move(other.m_Images))
|
||||||
, m_ImageViews(std::move(other.m_ImageViews))
|
, m_ImageViews(std::move(other.m_ImageViews))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
@ -206,4 +203,22 @@ Swapchain::Cleanup()
|
||||||
m_Swapchain = nullptr;
|
m_Swapchain = nullptr;
|
||||||
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),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,12 +747,22 @@ 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)
|
||||||
, m_TransferQueue(transferQueue)
|
, m_TransferQueue(transferQueue)
|
||||||
, m_TransferQueueIndex(transferQueueIndex)
|
, m_TransferQueueIndex(transferQueueIndex)
|
||||||
, m_GraphicsQueueIndex(graphicsQueueIndex)
|
, m_GraphicsQueueIndex(graphicsQueueIndex)
|
||||||
{
|
{
|
||||||
const Device *pDevice = resourceManager->m_Device;
|
const Device *pDevice = resourceManager->m_Device;
|
||||||
const vk::CommandPoolCreateInfo poolCreateInfo = {
|
const vk::CommandPoolCreateInfo poolCreateInfo = {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue