Let VkTextureManager manage the VkHardwareTexture resources

Let VkDescriptorSetManager manage the VkMaterial resources
Add the resources to the delete list instead of freeing them immediately as the backend cannot rely on exactly when the hardware renderer decides to destroy them
This commit is contained in:
Magnus Norddahl 2022-06-10 02:17:44 +02:00 committed by Christoph Oelckers
parent 298c023b1d
commit b3316fbe21
11 changed files with 106 additions and 115 deletions

View file

@ -41,6 +41,8 @@ VkDescriptorSetManager::VkDescriptorSetManager(VulkanFrameBuffer* fb) : fb(fb)
VkDescriptorSetManager::~VkDescriptorSetManager() VkDescriptorSetManager::~VkDescriptorSetManager()
{ {
while (!Materials.empty())
RemoveMaterial(Materials.back());
} }
void VkDescriptorSetManager::Init() void VkDescriptorSetManager::Init()
@ -115,8 +117,11 @@ void VkDescriptorSetManager::UpdateFixedSet()
update.updateSets(fb->device); update.updateSets(fb->device);
} }
void VkDescriptorSetManager::TextureSetPoolReset() void VkDescriptorSetManager::ResetHWTextureSets()
{ {
for (auto mat : Materials)
mat->DeleteDescriptors();
auto& deleteList = fb->GetCommands()->FrameDeleteList; auto& deleteList = fb->GetCommands()->FrameDeleteList;
for (auto& desc : TextureDescriptorPools) for (auto& desc : TextureDescriptorPools)
@ -131,12 +136,6 @@ void VkDescriptorSetManager::TextureSetPoolReset()
TextureDescriptorsLeft = 0; TextureDescriptorsLeft = 0;
} }
void VkDescriptorSetManager::FilterModeChanged()
{
// Destroy the texture descriptors as they used the old samplers
VkMaterial::ResetAllDescriptors();
}
void VkDescriptorSetManager::CreateNullTexture() void VkDescriptorSetManager::CreateNullTexture()
{ {
ImageBuilder imgbuilder; ImageBuilder imgbuilder;
@ -210,3 +209,15 @@ VulkanDescriptorSetLayout* VkDescriptorSetManager::GetTextureSetLayout(int numLa
layout->SetDebugName("VkDescriptorSetManager.TextureSetLayout"); layout->SetDebugName("VkDescriptorSetManager.TextureSetLayout");
return layout.get(); return layout.get();
} }
void VkDescriptorSetManager::AddMaterial(VkMaterial* texture)
{
texture->it = Materials.insert(Materials.end(), texture);
}
void VkDescriptorSetManager::RemoveMaterial(VkMaterial* texture)
{
texture->DeleteDescriptors();
texture->fb = nullptr;
Materials.erase(texture->it);
}

View file

@ -2,8 +2,10 @@
#pragma once #pragma once
#include "vulkan/system/vk_objects.h" #include "vulkan/system/vk_objects.h"
#include <list>
class VulkanFrameBuffer; class VulkanFrameBuffer;
class VkMaterial;
class VkDescriptorSetManager class VkDescriptorSetManager
{ {
@ -14,8 +16,7 @@ public:
void Init(); void Init();
void UpdateFixedSet(); void UpdateFixedSet();
void UpdateDynamicSet(); void UpdateDynamicSet();
void TextureSetPoolReset(); void ResetHWTextureSets();
void FilterModeChanged();
VulkanDescriptorSetLayout* GetDynamicSetLayout() { return DynamicSetLayout.get(); } VulkanDescriptorSetLayout* GetDynamicSetLayout() { return DynamicSetLayout.get(); }
VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); } VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); }
@ -29,6 +30,9 @@ public:
VulkanImageView* GetNullTextureView() { return NullTextureView.get(); } VulkanImageView* GetNullTextureView() { return NullTextureView.get(); }
void AddMaterial(VkMaterial* texture);
void RemoveMaterial(VkMaterial* texture);
private: private:
void CreateDynamicSet(); void CreateDynamicSet();
void CreateFixedSet(); void CreateFixedSet();
@ -53,4 +57,6 @@ private:
std::unique_ptr<VulkanImage> NullTexture; std::unique_ptr<VulkanImage> NullTexture;
std::unique_ptr<VulkanImageView> NullTextureView; std::unique_ptr<VulkanImageView> NullTextureView;
std::list<VkMaterial*> Materials;
}; };

View file

@ -86,7 +86,6 @@ VulkanFrameBuffer::~VulkanFrameBuffer()
vkDeviceWaitIdle(device->device); // make sure the GPU is no longer using any objects before RAII tears them down vkDeviceWaitIdle(device->device); // make sure the GPU is no longer using any objects before RAII tears them down
// All descriptors must be destroyed before the descriptor pool in renderpass manager is destroyed // All descriptors must be destroyed before the descriptor pool in renderpass manager is destroyed
VkHardwareTexture::ResetAll();
VkHardwareBuffer::ResetAll(); VkHardwareBuffer::ResetAll();
PPResource::ResetAll(); PPResource::ResetAll();
@ -258,12 +257,12 @@ void VulkanFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture(int numchannels) IHardwareTexture *VulkanFrameBuffer::CreateHardwareTexture(int numchannels)
{ {
return new VkHardwareTexture(numchannels); return new VkHardwareTexture(this, numchannels);
} }
FMaterial* VulkanFrameBuffer::CreateMaterial(FGameTexture* tex, int scaleflags) FMaterial* VulkanFrameBuffer::CreateMaterial(FGameTexture* tex, int scaleflags)
{ {
return new VkMaterial(tex, scaleflags); return new VkMaterial(this, tex, scaleflags);
} }
IVertexBuffer *VulkanFrameBuffer::CreateVertexBuffer() IVertexBuffer *VulkanFrameBuffer::CreateVertexBuffer()
@ -298,15 +297,15 @@ void VulkanFrameBuffer::SetTextureFilterMode()
{ {
if (mSamplerManager) if (mSamplerManager)
{ {
mDescriptorSetManager->FilterModeChanged(); mDescriptorSetManager->ResetHWTextureSets();
mSamplerManager->FilterModeChanged(); mSamplerManager->ResetHWSamplers();
} }
} }
void VulkanFrameBuffer::StartPrecaching() void VulkanFrameBuffer::StartPrecaching()
{ {
// Destroy the texture descriptors to avoid problems with potentially stale textures. // Destroy the texture descriptors to avoid problems with potentially stale textures.
VkMaterial::ResetAllDescriptors(); mDescriptorSetManager->ResetHWTextureSets();
} }
void VulkanFrameBuffer::BlurScene(float amount) void VulkanFrameBuffer::BlurScene(float amount)
@ -446,12 +445,7 @@ void VulkanFrameBuffer::InitLightmap(int LMTextureSize, int LMTextureCount, TArr
int pixelsize = 8; int pixelsize = 8;
auto& lightmap = mActiveRenderBuffers->Lightmap; auto& lightmap = mActiveRenderBuffers->Lightmap;
if (lightmap.Image) lightmap.Reset(this);
{
GetCommands()->FrameDeleteList.Images.push_back(std::move(lightmap.Image));
GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(lightmap.View));
lightmap.reset();
}
ImageBuilder builder; ImageBuilder builder;
builder.setSize(w, h, 1, count); builder.setSize(w, h, 1, count);

View file

@ -31,39 +31,27 @@
#include "vulkan/system/vk_commandbuffer.h" #include "vulkan/system/vk_commandbuffer.h"
#include "vulkan/textures/vk_samplers.h" #include "vulkan/textures/vk_samplers.h"
#include "vulkan/textures/vk_renderbuffers.h" #include "vulkan/textures/vk_renderbuffers.h"
#include "vulkan/textures/vk_texture.h"
#include "vulkan/renderer/vk_descriptorset.h" #include "vulkan/renderer/vk_descriptorset.h"
#include "vulkan/renderer/vk_postprocess.h" #include "vulkan/renderer/vk_postprocess.h"
#include "vulkan/shaders/vk_shader.h" #include "vulkan/shaders/vk_shader.h"
#include "vk_hwtexture.h" #include "vk_hwtexture.h"
VkHardwareTexture *VkHardwareTexture::First = nullptr; VkHardwareTexture::VkHardwareTexture(VulkanFrameBuffer* fb, int numchannels) : fb(fb)
VkHardwareTexture::VkHardwareTexture(int numchannels)
{ {
mTexelsize = numchannels; mTexelsize = numchannels;
Next = First; fb->GetTextureManager()->AddTexture(this);
First = this;
if (Next) Next->Prev = this;
} }
VkHardwareTexture::~VkHardwareTexture() VkHardwareTexture::~VkHardwareTexture()
{ {
if (Next) Next->Prev = Prev; if (fb)
if (Prev) Prev->Next = Next; fb->GetTextureManager()->RemoveTexture(this);
else First = Next;
Reset();
}
void VkHardwareTexture::ResetAll()
{
for (VkHardwareTexture *cur = VkHardwareTexture::First; cur; cur = cur->Next)
cur->Reset();
} }
void VkHardwareTexture::Reset() void VkHardwareTexture::Reset()
{ {
if (auto fb = GetVulkanFrameBuffer()) if (fb)
{ {
if (mappedSWFB) if (mappedSWFB)
{ {
@ -71,15 +59,8 @@ void VkHardwareTexture::Reset()
mappedSWFB = nullptr; mappedSWFB = nullptr;
} }
auto &deleteList = fb->GetCommands()->FrameDeleteList; mImage.Reset(fb);
if (mImage.Image) deleteList.Images.push_back(std::move(mImage.Image)); mDepthStencil.Reset(fb);
if (mImage.View) deleteList.ImageViews.push_back(std::move(mImage.View));
for (auto &it : mImage.RSFramebuffers) deleteList.Framebuffers.push_back(std::move(it.second));
if (mDepthStencil.Image) deleteList.Images.push_back(std::move(mDepthStencil.Image));
if (mDepthStencil.View) deleteList.ImageViews.push_back(std::move(mDepthStencil.View));
for (auto &it : mDepthStencil.RSFramebuffers) deleteList.Framebuffers.push_back(std::move(it.second));
mImage.reset();
mDepthStencil.reset();
} }
} }
@ -96,8 +77,6 @@ VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex)
{ {
if (!mDepthStencil.View) if (!mDepthStencil.View)
{ {
auto fb = GetVulkanFrameBuffer();
VkFormat format = fb->GetBuffers()->SceneDepthStencilFormat; VkFormat format = fb->GetBuffers()->SceneDepthStencilFormat;
int w = tex->GetWidth(); int w = tex->GetWidth();
int h = tex->GetHeight(); int h = tex->GetHeight();
@ -133,8 +112,6 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
} }
else else
{ {
auto fb = GetVulkanFrameBuffer();
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
int w = tex->GetWidth(); int w = tex->GetWidth();
int h = tex->GetHeight(); int h = tex->GetHeight();
@ -164,8 +141,6 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
if (w <= 0 || h <= 0) if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture"); throw CVulkanError("Trying to create zero size texture");
auto fb = GetVulkanFrameBuffer();
int totalSize = w * h * pixelsize; int totalSize = w * h * pixelsize;
BufferBuilder bufbuilder; BufferBuilder bufbuilder;
@ -234,8 +209,6 @@ void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize)
if (!mImage.Image) if (!mImage.Image)
{ {
auto fb = GetVulkanFrameBuffer();
VkFormat format = texelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM; VkFormat format = texelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM;
ImageBuilder imgbuilder; ImageBuilder imgbuilder;
@ -283,8 +256,6 @@ unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int
void VkHardwareTexture::CreateWipeTexture(int w, int h, const char *name) void VkHardwareTexture::CreateWipeTexture(int w, int h, const char *name)
{ {
auto fb = GetVulkanFrameBuffer();
VkFormat format = VK_FORMAT_B8G8R8A8_UNORM; VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
ImageBuilder imgbuilder; ImageBuilder imgbuilder;
@ -331,28 +302,22 @@ void VkHardwareTexture::CreateWipeTexture(int w, int h, const char *name)
} }
} }
/////////////////////////////////////////////////////////////////////////////
VkMaterial* VkMaterial::First = nullptr; VkMaterial::VkMaterial(VulkanFrameBuffer* fb, FGameTexture* tex, int scaleflags) : FMaterial(tex, scaleflags), fb(fb)
VkMaterial::VkMaterial(FGameTexture* tex, int scaleflags) : FMaterial(tex, scaleflags)
{ {
Next = First; fb->GetDescriptorSetManager()->AddMaterial(this);
First = this;
if (Next) Next->Prev = this;
} }
VkMaterial::~VkMaterial() VkMaterial::~VkMaterial()
{ {
if (Next) Next->Prev = Prev; if (fb)
if (Prev) Prev->Next = Next; fb->GetDescriptorSetManager()->RemoveMaterial(this);
else First = Next;
DeleteDescriptors();
} }
void VkMaterial::DeleteDescriptors() void VkMaterial::DeleteDescriptors()
{ {
if (auto fb = GetVulkanFrameBuffer()) if (fb)
{ {
auto& deleteList = fb->GetCommands()->FrameDeleteList; auto& deleteList = fb->GetCommands()->FrameDeleteList;
@ -360,19 +325,9 @@ void VkMaterial::DeleteDescriptors()
{ {
deleteList.Descriptors.push_back(std::move(it.descriptor)); deleteList.Descriptors.push_back(std::move(it.descriptor));
} }
mDescriptorSets.clear();
} }
mDescriptorSets.clear();
}
void VkMaterial::ResetAllDescriptors()
{
for (VkMaterial* cur = First; cur; cur = cur->Next)
cur->DeleteDescriptors();
auto fb = GetVulkanFrameBuffer();
if (fb)
fb->GetDescriptorSetManager()->TextureSetPoolReset();
} }
VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
@ -391,7 +346,6 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state)
int numLayers = NumLayers(); int numLayers = NumLayers();
auto fb = GetVulkanFrameBuffer();
auto descriptor = fb->GetDescriptorSetManager()->AllocateTextureDescriptorSet(max(numLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS)); auto descriptor = fb->GetDescriptorSetManager()->AllocateTextureDescriptorSet(max(numLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS));
descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets");

View file

@ -12,22 +12,23 @@
#include "volk/volk.h" #include "volk/volk.h"
#include "vk_imagetransition.h" #include "vk_imagetransition.h"
#include "hw_material.h" #include "hw_material.h"
#include <list>
struct FMaterialState; struct FMaterialState;
class VulkanDescriptorSet; class VulkanDescriptorSet;
class VulkanImage; class VulkanImage;
class VulkanImageView; class VulkanImageView;
class VulkanBuffer; class VulkanBuffer;
class VulkanFrameBuffer;
class FGameTexture; class FGameTexture;
class VkHardwareTexture : public IHardwareTexture class VkHardwareTexture : public IHardwareTexture
{ {
friend class VkMaterial; friend class VkMaterial;
public: public:
VkHardwareTexture(int numchannels); VkHardwareTexture(VulkanFrameBuffer* fb, int numchannels);
~VkHardwareTexture(); ~VkHardwareTexture();
static void ResetAll();
void Reset(); void Reset();
// Software renderer stuff // Software renderer stuff
@ -41,6 +42,8 @@ public:
VkTextureImage *GetImage(FTexture *tex, int translation, int flags); VkTextureImage *GetImage(FTexture *tex, int translation, int flags);
VkTextureImage *GetDepthStencil(FTexture *tex); VkTextureImage *GetDepthStencil(FTexture *tex);
VulkanFrameBuffer* fb = nullptr;
std::list<VkHardwareTexture*>::iterator it;
private: private:
void CreateImage(FTexture *tex, int translation, int flags); void CreateImage(FTexture *tex, int translation, int flags);
@ -48,10 +51,6 @@ private:
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap); void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap);
static int GetMipLevels(int w, int h); static int GetMipLevels(int w, int h);
static VkHardwareTexture *First;
VkHardwareTexture *Prev = nullptr;
VkHardwareTexture *Next = nullptr;
VkTextureImage mImage; VkTextureImage mImage;
int mTexelsize = 4; int mTexelsize = 4;
@ -60,13 +59,20 @@ private:
uint8_t* mappedSWFB = nullptr; uint8_t* mappedSWFB = nullptr;
}; };
class VkMaterial : public FMaterial class VkMaterial : public FMaterial
{ {
static VkMaterial* First; public:
VkMaterial* Prev = nullptr; VkMaterial(VulkanFrameBuffer* fb, FGameTexture* tex, int scaleflags);
VkMaterial* Next = nullptr; ~VkMaterial();
VulkanDescriptorSet* GetDescriptorSet(const FMaterialState& state);
void DeleteDescriptors() override;
VulkanFrameBuffer* fb = nullptr;
std::list<VkMaterial*>::iterator it;
private:
struct DescriptorEntry struct DescriptorEntry
{ {
int clampmode; int clampmode;
@ -82,12 +88,4 @@ class VkMaterial : public FMaterial
}; };
std::vector<DescriptorEntry> mDescriptorSets; std::vector<DescriptorEntry> mDescriptorSets;
};
public:
VkMaterial(FGameTexture *tex, int scaleflags);
~VkMaterial();
VulkanDescriptorSet* GetDescriptorSet(const FMaterialState& state);
void DeleteDescriptors() override;
static void ResetAllDescriptors();
};

View file

@ -3,20 +3,25 @@
#include "vulkan/system/vk_objects.h" #include "vulkan/system/vk_objects.h"
#include "vulkan/system/vk_builders.h" #include "vulkan/system/vk_builders.h"
#include "vulkan/system/vk_framebuffer.h"
#include "vulkan/system/vk_commandbuffer.h"
#include "vulkan/renderer/vk_renderpass.h" #include "vulkan/renderer/vk_renderpass.h"
class VkTextureImage class VkTextureImage
{ {
public: public:
void reset() void Reset(VulkanFrameBuffer* fb)
{ {
AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; AspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
Layout = VK_IMAGE_LAYOUT_UNDEFINED; Layout = VK_IMAGE_LAYOUT_UNDEFINED;
PPFramebuffer.reset(); auto& deletelist = fb->GetCommands()->FrameDeleteList;
deletelist.Framebuffers.push_back(std::move(PPFramebuffer));
for (auto &it : RSFramebuffers)
deletelist.Framebuffers.push_back(std::move(it.second));
RSFramebuffers.clear(); RSFramebuffers.clear();
DepthOnlyView.reset(); deletelist.ImageViews.push_back(std::move(DepthOnlyView));
View.reset(); deletelist.ImageViews.push_back(std::move(View));
Image.reset(); deletelist.Images.push_back(std::move(Image));
} }
void GenerateMipmaps(VulkanCommandBuffer *cmdbuffer); void GenerateMipmaps(VulkanCommandBuffer *cmdbuffer);

View file

@ -88,7 +88,7 @@ void VkRenderBuffers::CreatePipeline(int width, int height)
{ {
for (int i = 0; i < NumPipelineImages; i++) for (int i = 0; i < NumPipelineImages; i++)
{ {
PipelineImage[i].reset(); PipelineImage[i].Reset(fb);
} }
VkImageTransition barrier; VkImageTransition barrier;
@ -113,10 +113,10 @@ void VkRenderBuffers::CreatePipeline(int width, int height)
void VkRenderBuffers::CreateScene(int width, int height, VkSampleCountFlagBits samples) void VkRenderBuffers::CreateScene(int width, int height, VkSampleCountFlagBits samples)
{ {
SceneColor.reset(); SceneColor.Reset(fb);
SceneDepthStencil.reset(); SceneDepthStencil.Reset(fb);
SceneNormal.reset(); SceneNormal.Reset(fb);
SceneFog.reset(); SceneFog.Reset(fb);
CreateSceneColor(width, height, samples); CreateSceneColor(width, height, samples);
CreateSceneDepthStencil(width, height, samples); CreateSceneDepthStencil(width, height, samples);
@ -219,7 +219,7 @@ void VkRenderBuffers::CreateShadowmap()
if (Shadowmap.Image && Shadowmap.Image->width == gl_shadowmap_quality) if (Shadowmap.Image && Shadowmap.Image->width == gl_shadowmap_quality)
return; return;
Shadowmap.reset(); Shadowmap.Reset(fb);
ImageBuilder builder; ImageBuilder builder;
builder.setSize(gl_shadowmap_quality, 1024); builder.setSize(gl_shadowmap_quality, 1024);

View file

@ -75,7 +75,7 @@ VkSamplerManager::~VkSamplerManager()
{ {
} }
void VkSamplerManager::FilterModeChanged() void VkSamplerManager::ResetHWSamplers()
{ {
DeleteHWSamplers(); DeleteHWSamplers();
CreateHWSamplers(); CreateHWSamplers();

View file

@ -14,7 +14,7 @@ public:
VkSamplerManager(VulkanFrameBuffer* fb); VkSamplerManager(VulkanFrameBuffer* fb);
~VkSamplerManager(); ~VkSamplerManager();
void FilterModeChanged(); void ResetHWSamplers();
VulkanSampler *Get(int no) const { return mSamplers[no].get(); } VulkanSampler *Get(int no) const { return mSamplers[no].get(); }
VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap); VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap);

View file

@ -21,6 +21,7 @@
*/ */
#include "vk_texture.h" #include "vk_texture.h"
#include "vk_hwtexture.h"
VkTextureManager::VkTextureManager(VulkanFrameBuffer* fb) : fb(fb) VkTextureManager::VkTextureManager(VulkanFrameBuffer* fb) : fb(fb)
{ {
@ -28,4 +29,18 @@ VkTextureManager::VkTextureManager(VulkanFrameBuffer* fb) : fb(fb)
VkTextureManager::~VkTextureManager() VkTextureManager::~VkTextureManager()
{ {
while (!Textures.empty())
RemoveTexture(Textures.back());
}
void VkTextureManager::AddTexture(VkHardwareTexture* texture)
{
texture->it = Textures.insert(Textures.end(), texture);
}
void VkTextureManager::RemoveTexture(VkHardwareTexture* texture)
{
texture->Reset();
texture->fb = nullptr;
Textures.erase(texture->it);
} }

View file

@ -2,8 +2,11 @@
#pragma once #pragma once
#include "vulkan/system/vk_objects.h" #include "vulkan/system/vk_objects.h"
#include <list>
class VulkanFrameBuffer; class VulkanFrameBuffer;
class VkHardwareTexture;
class VkMaterial;
class VkTextureManager class VkTextureManager
{ {
@ -11,6 +14,11 @@ public:
VkTextureManager(VulkanFrameBuffer* fb); VkTextureManager(VulkanFrameBuffer* fb);
~VkTextureManager(); ~VkTextureManager();
void AddTexture(VkHardwareTexture* texture);
void RemoveTexture(VkHardwareTexture* texture);
private: private:
VulkanFrameBuffer* fb = nullptr; VulkanFrameBuffer* fb = nullptr;
std::list<VkHardwareTexture*> Textures;
}; };