Fix descriptor pool fragmentation (#2949)
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <mbgl/vulkan/uniform_buffer.hpp>
|
||||
#include <mbgl/vulkan/renderer_backend.hpp>
|
||||
#include <mbgl/vulkan/pipeline.hpp>
|
||||
#include <mbgl/vulkan/descriptor_set.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -135,21 +136,14 @@ public:
|
||||
const std::unique_ptr<BufferResource>& getDummyVertexBuffer();
|
||||
const std::unique_ptr<BufferResource>& getDummyUniformBuffer();
|
||||
const std::unique_ptr<Texture2D>& getDummyTexture();
|
||||
const vk::UniqueDescriptorSetLayout& getImageDescriptorSetLayout();
|
||||
const vk::UniqueDescriptorSetLayout& buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout,
|
||||
size_t uniformCount,
|
||||
const std::string& name);
|
||||
|
||||
const std::vector<vk::DescriptorSetLayout>& getDescriptorSetLayouts();
|
||||
const vk::DescriptorSetLayout& getDescriptorSetLayout(DescriptorSetType type);
|
||||
DescriptorPoolGrowable& getDescriptorPool(DescriptorSetType type);
|
||||
const vk::UniquePipelineLayout& getGeneralPipelineLayout();
|
||||
const vk::UniquePipelineLayout& getPushConstantPipelineLayout();
|
||||
|
||||
void bindDescriptorSet(DescriptorSetType type, const vk::DescriptorSet& descriptorSet);
|
||||
|
||||
uint8_t getCurrentFrameResourceIndex() const { return frameResourceIndex; }
|
||||
const vk::UniqueDescriptorPool& getGlobalDescriptorPool() const;
|
||||
void enqueueDeletion(std::function<void(const Context&)>&& function);
|
||||
void enqueueDeletion(std::function<void(Context&)>&& function);
|
||||
void submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function) const;
|
||||
|
||||
void requestSurfaceUpdate() { surfaceUpdateRequested = true; }
|
||||
@@ -162,7 +156,7 @@ private:
|
||||
vk::UniqueSemaphore frameSemaphore;
|
||||
vk::UniqueFence flightFrameFence;
|
||||
|
||||
std::vector<std::function<void(const Context&)>> deletionQueue;
|
||||
std::vector<std::function<void(Context&)>> deletionQueue;
|
||||
|
||||
FrameResources(vk::UniqueCommandBuffer& cb,
|
||||
vk::UniqueSemaphore&& surf,
|
||||
@@ -173,17 +167,22 @@ private:
|
||||
frameSemaphore(std::move(frame)),
|
||||
flightFrameFence(std::move(flight)) {}
|
||||
|
||||
void runDeletionQueue(const Context&);
|
||||
void runDeletionQueue(Context&);
|
||||
};
|
||||
|
||||
void initFrameResources();
|
||||
void destroyResources();
|
||||
|
||||
void buildImageDescriptorSetLayout();
|
||||
void buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout,
|
||||
size_t uniformCount,
|
||||
const std::string& name);
|
||||
|
||||
private:
|
||||
RendererBackend& backend;
|
||||
|
||||
vulkan::UniformBufferArray globalUniformBuffers;
|
||||
vk::UniqueDescriptorPool globalDescriptorPool;
|
||||
std::unordered_map<DescriptorSetType, DescriptorPoolGrowable> descriptorPoolMap;
|
||||
|
||||
std::unique_ptr<BufferResource> dummyVertexBuffer;
|
||||
std::unique_ptr<BufferResource> dummyUniformBuffer;
|
||||
@@ -191,8 +190,7 @@ private:
|
||||
vk::UniqueDescriptorSetLayout globalUniformDescriptorSetLayout;
|
||||
vk::UniqueDescriptorSetLayout layerUniformDescriptorSetLayout;
|
||||
vk::UniqueDescriptorSetLayout drawableUniformDescriptorSetLayout;
|
||||
vk::UniqueDescriptorSetLayout imageDescriptorSetLayout;
|
||||
std::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
|
||||
vk::UniqueDescriptorSetLayout drawableImageDescriptorSetLayout;
|
||||
vk::UniquePipelineLayout generalPipelineLayout;
|
||||
vk::UniquePipelineLayout pushConstantPipelineLayout;
|
||||
|
||||
|
||||
@@ -17,6 +17,32 @@ enum class DescriptorSetType : uint8_t {
|
||||
Count,
|
||||
};
|
||||
|
||||
struct DescriptorPoolGrowable {
|
||||
struct PoolInfo {
|
||||
vk::UniqueDescriptorPool pool;
|
||||
uint32_t remainingSets{0};
|
||||
|
||||
PoolInfo(vk::UniqueDescriptorPool&& pool_, uint32_t remainingSets_)
|
||||
: pool(std::move(pool_)),
|
||||
remainingSets(remainingSets_) {}
|
||||
};
|
||||
|
||||
const uint32_t maxSets{0};
|
||||
const uint32_t descriptorsPerSet{0};
|
||||
const float growFactor{1.5f};
|
||||
|
||||
std::vector<PoolInfo> pools;
|
||||
int32_t currentPoolIndex{-1};
|
||||
|
||||
PoolInfo& current() { return pools[currentPoolIndex]; }
|
||||
|
||||
DescriptorPoolGrowable() = default;
|
||||
DescriptorPoolGrowable(uint32_t maxSets_, uint32_t descriptorsPerSet_, float growFactor_ = 1.5f)
|
||||
: maxSets(maxSets_),
|
||||
descriptorsPerSet(descriptorsPerSet_),
|
||||
growFactor(growFactor_) {}
|
||||
};
|
||||
|
||||
class DescriptorSet {
|
||||
public:
|
||||
DescriptorSet(Context& context_, DescriptorSetType type_);
|
||||
@@ -27,12 +53,16 @@ public:
|
||||
void markDirty(bool value = true);
|
||||
void bind(CommandEncoder& encoder);
|
||||
|
||||
protected:
|
||||
void createDescriptorPool(DescriptorPoolGrowable& growablePool);
|
||||
|
||||
protected:
|
||||
Context& context;
|
||||
DescriptorSetType type;
|
||||
|
||||
std::vector<bool> dirty;
|
||||
std::vector<vk::DescriptorSet> descriptorSets;
|
||||
int32_t descriptorPoolIndex{-1};
|
||||
};
|
||||
|
||||
class UniformDescriptorSet : public DescriptorSet {
|
||||
|
||||
@@ -118,7 +118,7 @@ BufferResource::~BufferResource() noexcept {
|
||||
|
||||
if (!bufferAllocation) return;
|
||||
|
||||
context.enqueueDeletion([allocation = std::move(bufferAllocation)](const auto&) mutable { allocation.reset(); });
|
||||
context.enqueueDeletion([allocation = std::move(bufferAllocation)](auto&) mutable { allocation.reset(); });
|
||||
}
|
||||
|
||||
BufferResource BufferResource::clone() const {
|
||||
|
||||
@@ -27,10 +27,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef MLN_VULKAN_DESCRIPTOR_POOL_SIZE
|
||||
#define MLN_VULKAN_DESCRIPTOR_POOL_SIZE 30000
|
||||
#endif
|
||||
|
||||
namespace mbgl {
|
||||
namespace vulkan {
|
||||
|
||||
@@ -39,6 +35,12 @@ namespace vulkan {
|
||||
// per https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxVertexInputBindings
|
||||
// this can be queried at runtime (VkPhysicalDeviceLimits.maxVertexInputBindings)
|
||||
constexpr uint32_t maximumVertexBindingCount = 16;
|
||||
|
||||
constexpr uint32_t globalDescriptorPoolSize = 3 * 4;
|
||||
constexpr uint32_t layerDescriptorPoolSize = 3 * 256;
|
||||
constexpr uint32_t drawableUniformDescriptorPoolSize = 3 * 1024;
|
||||
constexpr uint32_t drawableImageDescriptorPoolSize = drawableUniformDescriptorPoolSize / 2;
|
||||
|
||||
static uint32_t glslangRefCount = 0;
|
||||
|
||||
class RenderbufferResource : public gfx::RenderbufferResource {
|
||||
@@ -71,17 +73,19 @@ void Context::initFrameResources() {
|
||||
const auto& device = backend.getDevice();
|
||||
const auto frameCount = backend.getMaxFrames();
|
||||
|
||||
// descriptor pool info
|
||||
const std::vector<vk::DescriptorPoolSize> poolSizes = {
|
||||
{vk::DescriptorType::eUniformBuffer, MLN_VULKAN_DESCRIPTOR_POOL_SIZE},
|
||||
{vk::DescriptorType::eCombinedImageSampler, MLN_VULKAN_DESCRIPTOR_POOL_SIZE},
|
||||
};
|
||||
descriptorPoolMap.emplace(DescriptorSetType::Global,
|
||||
DescriptorPoolGrowable(globalDescriptorPoolSize, shaders::globalUBOCount));
|
||||
|
||||
const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet)
|
||||
.setPoolSizes(poolSizes)
|
||||
.setMaxSets(MLN_VULKAN_DESCRIPTOR_POOL_SIZE);
|
||||
descriptorPoolMap.emplace(DescriptorSetType::Layer,
|
||||
DescriptorPoolGrowable(layerDescriptorPoolSize, shaders::maxUBOCountPerLayer));
|
||||
|
||||
globalDescriptorPool = device->createDescriptorPoolUnique(descriptorPoolInfo);
|
||||
descriptorPoolMap.emplace(
|
||||
DescriptorSetType::DrawableUniform,
|
||||
DescriptorPoolGrowable(drawableUniformDescriptorPoolSize, shaders::maxUBOCountPerDrawable));
|
||||
|
||||
descriptorPoolMap.emplace(
|
||||
DescriptorSetType::DrawableImage,
|
||||
DescriptorPoolGrowable(drawableImageDescriptorPoolSize, shaders::maxTextureCountPerShader));
|
||||
|
||||
// command buffers
|
||||
const vk::CommandBufferAllocateInfo allocateInfo(
|
||||
@@ -107,6 +111,14 @@ void Context::initFrameResources() {
|
||||
|
||||
// force placeholder texture upload before any descriptor sets
|
||||
(void)getDummyTexture();
|
||||
|
||||
buildUniformDescriptorSetLayout(
|
||||
globalUniformDescriptorSetLayout, shaders::globalUBOCount, "GlobalUniformDescriptorSetLayout");
|
||||
buildUniformDescriptorSetLayout(
|
||||
layerUniformDescriptorSetLayout, shaders::maxUBOCountPerLayer, "LayerUniformDescriptorSetLayout");
|
||||
buildUniformDescriptorSetLayout(
|
||||
drawableUniformDescriptorSetLayout, shaders::maxUBOCountPerDrawable, "DrawableUniformDescriptorSetLayout");
|
||||
buildImageDescriptorSetLayout();
|
||||
}
|
||||
|
||||
void Context::destroyResources() {
|
||||
@@ -122,11 +134,7 @@ void Context::destroyResources() {
|
||||
frameResources.clear();
|
||||
}
|
||||
|
||||
const vk::UniqueDescriptorPool& Context::getGlobalDescriptorPool() const {
|
||||
return globalDescriptorPool;
|
||||
}
|
||||
|
||||
void Context::enqueueDeletion(std::function<void(const Context&)>&& function) {
|
||||
void Context::enqueueDeletion(std::function<void(Context&)>&& function) {
|
||||
if (frameResources.empty()) {
|
||||
function(*this);
|
||||
return;
|
||||
@@ -522,13 +530,9 @@ const std::unique_ptr<Texture2D>& Context::getDummyTexture() {
|
||||
return dummyTexture2D;
|
||||
}
|
||||
|
||||
const vk::UniqueDescriptorSetLayout& Context::buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout,
|
||||
size_t uniformCount,
|
||||
const std::string& name) {
|
||||
if (layout) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
void Context::buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout,
|
||||
size_t uniformCount,
|
||||
const std::string& name) {
|
||||
std::vector<vk::DescriptorSetLayoutBinding> bindings;
|
||||
const auto stageFlags = vk::ShaderStageFlags() | vk::ShaderStageFlagBits::eVertex |
|
||||
vk::ShaderStageFlagBits::eFragment;
|
||||
@@ -544,62 +548,63 @@ const vk::UniqueDescriptorSetLayout& Context::buildUniformDescriptorSetLayout(vk
|
||||
const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings);
|
||||
layout = backend.getDevice()->createDescriptorSetLayoutUnique(descriptorSetLayoutCreateInfo);
|
||||
backend.setDebugName(layout.get(), name);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
const vk::UniqueDescriptorSetLayout& Context::getImageDescriptorSetLayout() {
|
||||
if (!imageDescriptorSetLayout) {
|
||||
std::vector<vk::DescriptorSetLayoutBinding> bindings;
|
||||
void Context::buildImageDescriptorSetLayout() {
|
||||
std::vector<vk::DescriptorSetLayoutBinding> bindings;
|
||||
|
||||
for (size_t i = 0; i < shaders::maxTextureCountPerShader; ++i) {
|
||||
bindings.push_back(vk::DescriptorSetLayoutBinding()
|
||||
.setBinding(static_cast<uint32_t>(i))
|
||||
.setStageFlags(vk::ShaderStageFlagBits::eFragment)
|
||||
.setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
|
||||
.setDescriptorCount(1));
|
||||
}
|
||||
|
||||
const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings);
|
||||
imageDescriptorSetLayout = backend.getDevice()->createDescriptorSetLayoutUnique(descriptorSetLayoutCreateInfo);
|
||||
backend.setDebugName(imageDescriptorSetLayout.get(), "ImageDescriptorSetLayout");
|
||||
for (size_t i = 0; i < shaders::maxTextureCountPerShader; ++i) {
|
||||
bindings.push_back(vk::DescriptorSetLayoutBinding()
|
||||
.setBinding(static_cast<uint32_t>(i))
|
||||
.setStageFlags(vk::ShaderStageFlagBits::eFragment)
|
||||
.setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
|
||||
.setDescriptorCount(1));
|
||||
}
|
||||
|
||||
return imageDescriptorSetLayout;
|
||||
}
|
||||
|
||||
const std::vector<vk::DescriptorSetLayout>& Context::getDescriptorSetLayouts() {
|
||||
if (descriptorSetLayouts.empty()) {
|
||||
descriptorSetLayouts = {
|
||||
buildUniformDescriptorSetLayout(
|
||||
globalUniformDescriptorSetLayout, shaders::globalUBOCount, "GlobalUniformDescriptorSetLayout")
|
||||
.get(),
|
||||
buildUniformDescriptorSetLayout(
|
||||
layerUniformDescriptorSetLayout, shaders::maxUBOCountPerLayer, "LayerUniformDescriptorSetLayout")
|
||||
.get(),
|
||||
buildUniformDescriptorSetLayout(drawableUniformDescriptorSetLayout,
|
||||
shaders::maxUBOCountPerDrawable,
|
||||
"DrawableUniformDescriptorSetLayout")
|
||||
.get(),
|
||||
getImageDescriptorSetLayout().get()};
|
||||
}
|
||||
|
||||
return descriptorSetLayouts;
|
||||
const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings);
|
||||
drawableImageDescriptorSetLayout = backend.getDevice()->createDescriptorSetLayoutUnique(
|
||||
descriptorSetLayoutCreateInfo);
|
||||
backend.setDebugName(drawableImageDescriptorSetLayout.get(), "ImageDescriptorSetLayout");
|
||||
}
|
||||
|
||||
const vk::DescriptorSetLayout& Context::getDescriptorSetLayout(DescriptorSetType type) {
|
||||
uint32_t index = static_cast<uint32_t>(type);
|
||||
assert(index < static_cast<uint32_t>(DescriptorSetType::Count));
|
||||
return getDescriptorSetLayouts()[index];
|
||||
switch (type) {
|
||||
case DescriptorSetType::Global:
|
||||
return globalUniformDescriptorSetLayout.get();
|
||||
|
||||
case DescriptorSetType::Layer:
|
||||
return layerUniformDescriptorSetLayout.get();
|
||||
|
||||
case DescriptorSetType::DrawableUniform:
|
||||
return drawableUniformDescriptorSetLayout.get();
|
||||
|
||||
case DescriptorSetType::DrawableImage:
|
||||
return drawableImageDescriptorSetLayout.get();
|
||||
|
||||
default:
|
||||
assert(static_cast<uint32_t>(type) < static_cast<uint32_t>(DescriptorSetType::Count));
|
||||
return globalUniformDescriptorSetLayout.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DescriptorPoolGrowable& Context::getDescriptorPool(DescriptorSetType type) {
|
||||
assert(static_cast<uint32_t>(type) < static_cast<uint32_t>(DescriptorSetType::Count));
|
||||
return descriptorPoolMap[type];
|
||||
}
|
||||
|
||||
const vk::UniquePipelineLayout& Context::getGeneralPipelineLayout() {
|
||||
if (generalPipelineLayout) return generalPipelineLayout;
|
||||
|
||||
const auto& descriptorLayouts = getDescriptorSetLayouts();
|
||||
const std::vector<vk::DescriptorSetLayout> layouts = {
|
||||
globalUniformDescriptorSetLayout.get(),
|
||||
layerUniformDescriptorSetLayout.get(),
|
||||
drawableUniformDescriptorSetLayout.get(),
|
||||
drawableImageDescriptorSetLayout.get(),
|
||||
};
|
||||
|
||||
generalPipelineLayout = backend.getDevice()->createPipelineLayoutUnique(
|
||||
vk::PipelineLayoutCreateInfo().setSetLayouts(descriptorLayouts));
|
||||
vk::PipelineLayoutCreateInfo().setSetLayouts(layouts));
|
||||
|
||||
backend.setDebugName(generalPipelineLayout.get(), "PipelineLayout_general");
|
||||
|
||||
@@ -620,7 +625,7 @@ const vk::UniquePipelineLayout& Context::getPushConstantPipelineLayout() {
|
||||
return pushConstantPipelineLayout;
|
||||
}
|
||||
|
||||
void Context::FrameResources::runDeletionQueue(const Context& context) {
|
||||
void Context::FrameResources::runDeletionQueue(Context& context) {
|
||||
for (const auto& function : deletionQueue) function(context);
|
||||
|
||||
deletionQueue.clear();
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
#include <mbgl/vulkan/context.hpp>
|
||||
#include <mbgl/vulkan/command_encoder.hpp>
|
||||
#include <mbgl/vulkan/texture2d.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <math.h>
|
||||
|
||||
namespace mbgl {
|
||||
namespace vulkan {
|
||||
@@ -14,25 +16,58 @@ DescriptorSet::DescriptorSet(Context& context_, DescriptorSetType type_)
|
||||
type(type_) {}
|
||||
|
||||
DescriptorSet::~DescriptorSet() {
|
||||
context.enqueueDeletion([sets = std::move(descriptorSets)](const auto& context_) mutable {
|
||||
context_.getBackend().getDevice()->freeDescriptorSets(context_.getGlobalDescriptorPool().get(), sets);
|
||||
});
|
||||
context.enqueueDeletion(
|
||||
[type_ = type, poolIndex = descriptorPoolIndex, sets = std::move(descriptorSets)](auto& context_) mutable {
|
||||
auto& poolInfo = context_.getDescriptorPool(type_).pools[poolIndex];
|
||||
context_.getBackend().getDevice()->freeDescriptorSets(poolInfo.pool.get(), sets);
|
||||
poolInfo.remainingSets += sets.size();
|
||||
});
|
||||
}
|
||||
|
||||
void DescriptorSet::createDescriptorPool(DescriptorPoolGrowable& growablePool) {
|
||||
const auto& device = context.getBackend().getDevice();
|
||||
|
||||
const uint32_t maxSets = static_cast<uint32_t>(growablePool.maxSets *
|
||||
std::pow(growablePool.growFactor, growablePool.pools.size()));
|
||||
const vk::DescriptorPoolSize size = {type != DescriptorSetType::DrawableImage
|
||||
? vk::DescriptorType::eUniformBuffer
|
||||
: vk::DescriptorType::eCombinedImageSampler,
|
||||
maxSets * growablePool.descriptorsPerSet};
|
||||
|
||||
const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet)
|
||||
.setPoolSizes(size)
|
||||
.setMaxSets(maxSets);
|
||||
|
||||
growablePool.pools.emplace_back(device->createDescriptorPoolUnique(descriptorPoolInfo), maxSets);
|
||||
growablePool.currentPoolIndex = growablePool.pools.size() - 1;
|
||||
};
|
||||
|
||||
void DescriptorSet::allocate() {
|
||||
if (!descriptorSets.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& device = context.getBackend().getDevice();
|
||||
const auto& descriptorPool = context.getGlobalDescriptorPool();
|
||||
const auto& descriptorSetLayout = context.getDescriptorSetLayout(type);
|
||||
auto& growablePool = context.getDescriptorPool(type);
|
||||
const std::vector<vk::DescriptorSetLayout> layouts(context.getBackend().getMaxFrames(), descriptorSetLayout);
|
||||
|
||||
const auto descriptorAllocInfo =
|
||||
vk::DescriptorSetAllocateInfo().setDescriptorPool(*descriptorPool).setSetLayouts(layouts);
|
||||
if (growablePool.currentPoolIndex == -1 || growablePool.current().remainingSets < layouts.size()) {
|
||||
const auto& poolIt = std::find_if(growablePool.pools.begin(), growablePool.pools.end(), [&](const auto& p) {
|
||||
return p.remainingSets >= layouts.size();
|
||||
});
|
||||
|
||||
descriptorSets = device->allocateDescriptorSets(descriptorAllocInfo);
|
||||
if (poolIt != growablePool.pools.end()) {
|
||||
growablePool.currentPoolIndex = std::distance(growablePool.pools.begin(), poolIt);
|
||||
} else {
|
||||
createDescriptorPool(growablePool);
|
||||
}
|
||||
}
|
||||
|
||||
descriptorPoolIndex = growablePool.currentPoolIndex;
|
||||
descriptorSets = device->allocateDescriptorSets(
|
||||
vk::DescriptorSetAllocateInfo().setDescriptorPool(growablePool.current().pool.get()).setSetLayouts(layouts));
|
||||
growablePool.current().remainingSets -= descriptorSets.size();
|
||||
|
||||
markDirty(true);
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ void Texture2D::uploadSubRegion(const void* pixelData,
|
||||
|
||||
enqueueCommands(commandBuffer);
|
||||
|
||||
context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](const auto&) mutable { buffAlloc.reset(); });
|
||||
context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](auto&) mutable { buffAlloc.reset(); });
|
||||
|
||||
context.renderingStats().numTextureUpdates++;
|
||||
}
|
||||
@@ -391,7 +391,7 @@ void Texture2D::createSampler() {
|
||||
|
||||
void Texture2D::destroyTexture() {
|
||||
if (imageAllocation) {
|
||||
context.enqueueDeletion([allocation = std::move(imageAllocation)](const auto&) mutable { allocation.reset(); });
|
||||
context.enqueueDeletion([allocation = std::move(imageAllocation)](auto&) mutable { allocation.reset(); });
|
||||
|
||||
imageLayout = vk::ImageLayout::eUndefined;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ void Texture2D::destroyTexture() {
|
||||
|
||||
void Texture2D::destroySampler() {
|
||||
if (sampler) {
|
||||
context.enqueueDeletion([sampler_ = std::move(sampler)](const auto& context_) mutable {
|
||||
context.enqueueDeletion([sampler_ = std::move(sampler)](auto& context_) mutable {
|
||||
context_.getBackend().getDevice()->destroySampler(sampler_);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user