Add DescriptorPool and set manager to GrVkProgram

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1765923002

Review URL: https://codereview.chromium.org/1765923002
This commit is contained in:
egdaniel 2016-03-18 13:18:23 -07:00 committed by Commit bot
parent 56cb377c75
commit c2dc1b29ba
7 changed files with 175 additions and 136 deletions

View File

@ -11,29 +11,24 @@
#include "SkTemplates.h"
GrVkDescriptorPool::GrVkDescriptorPool(const GrVkGpu* gpu, const DescriptorTypeCounts& typeCounts)
GrVkDescriptorPool::GrVkDescriptorPool(const GrVkGpu* gpu, VkDescriptorType type, uint32_t count)
: INHERITED()
, fTypeCounts(typeCounts) {
int numPools = fTypeCounts.numPoolSizes();
SkAutoTDeleteArray<VkDescriptorPoolSize> poolSizes(new VkDescriptorPoolSize[numPools]);
int currentPool = 0;
for (int i = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; i < VK_DESCRIPTOR_TYPE_END_RANGE; ++i) {
if (fTypeCounts.fDescriptorTypeCount[i]) {
VkDescriptorPoolSize& poolSize = poolSizes.get()[currentPool++];
poolSize.type = (VkDescriptorType)i;
poolSize.descriptorCount = fTypeCounts.fDescriptorTypeCount[i];
}
}
SkASSERT(currentPool == numPools);
, fType (type)
, fCount(count) {
VkDescriptorPoolSize poolSize;
memset(&poolSize, 0, sizeof(VkDescriptorPoolSize));
poolSize.descriptorCount = count;
poolSize.type = type;
VkDescriptorPoolCreateInfo createInfo;
memset(&createInfo, 0, sizeof(VkDescriptorPoolCreateInfo));
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.maxSets = 2; // Currently we allow one set for samplers and one set for uniforms
createInfo.poolSizeCount = numPools;
createInfo.pPoolSizes = poolSizes.get();
// This is an over/conservative estimate since each set may contain more than count descriptors.
createInfo.maxSets = count;
createInfo.poolSizeCount = 1;
createInfo.pPoolSizes = &poolSize;
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateDescriptorPool(gpu->device(),
&createInfo,
@ -41,8 +36,8 @@ GrVkDescriptorPool::GrVkDescriptorPool(const GrVkGpu* gpu, const DescriptorTypeC
&fDescPool));
}
bool GrVkDescriptorPool::isCompatible(const DescriptorTypeCounts& typeCounts) const {
return fTypeCounts.isSuperSet(typeCounts);
bool GrVkDescriptorPool::isCompatible(VkDescriptorType type, uint32_t count) const {
return fType == type && count <= fCount;
}
void GrVkDescriptorPool::reset(const GrVkGpu* gpu) {
@ -54,26 +49,3 @@ void GrVkDescriptorPool::freeGPUData(const GrVkGpu* gpu) const {
// allocated from the pool.
GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorPool(gpu->device(), fDescPool, nullptr));
}
///////////////////////////////////////////////////////////////////////////////
int GrVkDescriptorPool::DescriptorTypeCounts::numPoolSizes() const {
int count = 0;
for (int i = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; i < VK_DESCRIPTOR_TYPE_END_RANGE; ++i) {
count += fDescriptorTypeCount[i] ? 1 : 0;
}
return count;
}
bool GrVkDescriptorPool::DescriptorTypeCounts::isSuperSet(const DescriptorTypeCounts& that) const {
for (int i = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; i < VK_DESCRIPTOR_TYPE_END_RANGE; ++i) {
if (that.fDescriptorTypeCount[i] > fDescriptorTypeCount[i]) {
return false;
}
}
return true;
}
void GrVkDescriptorPool::DescriptorTypeCounts::setTypeCount(VkDescriptorType type, uint8_t count) {
fDescriptorTypeCount[type] = count;
}

View File

@ -14,39 +14,28 @@
class GrVkGpu;
/**
* We require that all descriptor sets are of a single descriptor type. We also use a pool to only
* make one type of descriptor set. Thus a single VkDescriptorPool will only allocated space for
* for one type of descriptor.
*/
class GrVkDescriptorPool : public GrVkResource {
public:
class DescriptorTypeCounts {
public:
DescriptorTypeCounts() {
memset(fDescriptorTypeCount, 0, sizeof(fDescriptorTypeCount));
}
void setTypeCount(VkDescriptorType type, uint8_t count);
int numPoolSizes() const;
// Determines if for each i, that.fDescriptorTypeCount[i] <= fDescriptorTypeCount[i];
bool isSuperSet(const DescriptorTypeCounts& that) const;
private:
uint8_t fDescriptorTypeCount[VK_DESCRIPTOR_TYPE_RANGE_SIZE];
friend class GrVkDescriptorPool;
};
explicit GrVkDescriptorPool(const GrVkGpu* gpu, const DescriptorTypeCounts& typeCounts);
explicit GrVkDescriptorPool(const GrVkGpu* gpu, VkDescriptorType type, uint32_t count);
VkDescriptorPool descPool() const { return fDescPool; }
void reset(const GrVkGpu* gpu);
// Returns whether or not this descriptor pool could be used, assuming it gets fully reset and
// not in use by another draw, to support the requested typeCounts.
bool isCompatible(const DescriptorTypeCounts& typeCounts) const;
// not in use by another draw, to support the requested type and count.
bool isCompatible(VkDescriptorType type, uint32_t count) const;
private:
void freeGPUData(const GrVkGpu* gpu) const override;
DescriptorTypeCounts fTypeCounts;
VkDescriptorType fType;
uint32_t fCount;
VkDescriptorPool fDescPool;
typedef GrVkResource INHERITED;

View File

@ -25,8 +25,6 @@ GrVkProgram::GrVkProgram(GrVkGpu* gpu,
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
GrVkDescriptorPool* descriptorPool,
VkDescriptorSet descriptorSets[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
@ -35,20 +33,31 @@ GrVkProgram::GrVkProgram(GrVkGpu* gpu,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors)
: fDescriptorPool(descriptorPool)
, fPipeline(pipeline)
: fPipeline(pipeline)
, fPipelineLayout(layout)
, fBuiltinUniformHandles(builtinUniformHandles)
, fGeometryProcessor(geometryProcessor)
, fXferProcessor(xferProcessor)
, fFragmentProcessors(fragmentProcessors)
, fProgramDataManager(uniforms, vertexUniformSize, fragmentUniformSize) {
, fProgramDataManager(uniforms, vertexUniformSize, fragmentUniformSize)
, fSamplerPoolManager(dsLayout[GrVkUniformHandler::kSamplerDescSet],
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numSamplers, gpu)
, fUniformPoolManager(dsLayout[GrVkUniformHandler::kUniformBufferDescSet],
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, gpu) {
fSamplers.setReserve(numSamplers);
fTextureViews.setReserve(numSamplers);
fTextures.setReserve(numSamplers);
memcpy(fDSLayout, dsLayout, 2 * sizeof(VkDescriptorSetLayout));
memcpy(fDescriptorSets, descriptorSets, 2 * sizeof(VkDescriptorSetLayout));
fDescriptorSets[0] = VK_NULL_HANDLE;
fDescriptorSets[1] = VK_NULL_HANDLE;
// Currently we are always binding a descriptor set for uniform buffers.
fStartDS = GrVkUniformHandler::kUniformBufferDescSet;
fDSCount = 1;
if (numSamplers) {
fDSCount++;
fStartDS = SkTMin(fStartDS, (int)GrVkUniformHandler::kSamplerDescSet);
}
fVertexUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, vertexUniformSize, true));
fFragmentUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, fragmentUniformSize, true));
@ -61,10 +70,7 @@ GrVkProgram::GrVkProgram(GrVkGpu* gpu,
GrVkProgram::~GrVkProgram() {
// Must of freed all GPU resources before this is destroyed
SkASSERT(!fPipeline);
SkASSERT(!fDescriptorPool);
SkASSERT(!fPipelineLayout);
SkASSERT(!fDSLayout[0]);
SkASSERT(!fDSLayout[1]);
SkASSERT(!fSamplers.count());
SkASSERT(!fTextureViews.count());
SkASSERT(!fTextures.count());
@ -92,10 +98,7 @@ void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
fPipeline->unref(gpu);
fPipeline = nullptr;
}
if (fDescriptorPool) {
fDescriptorPool->unref(gpu);
fDescriptorPool = nullptr;
}
if (fPipelineLayout) {
GR_VK_CALL(gpu->vkInterface(), DestroyPipelineLayout(gpu->device(),
fPipelineLayout,
@ -103,17 +106,6 @@ void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
fPipelineLayout = VK_NULL_HANDLE;
}
if (fDSLayout[0]) {
GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDSLayout[0],
nullptr));
fDSLayout[0] = VK_NULL_HANDLE;
}
if (fDSLayout[1]) {
GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDSLayout[1],
nullptr));
fDSLayout[1] = VK_NULL_HANDLE;
}
if (fVertexUniformBuffer) {
fVertexUniformBuffer->release(gpu);
}
@ -121,17 +113,18 @@ void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
if (fFragmentUniformBuffer) {
fFragmentUniformBuffer->release(gpu);
}
fSamplerPoolManager.freeGPUResources(gpu);
fUniformPoolManager.freeGPUResources(gpu);
this->freeTempResources(gpu);
}
void GrVkProgram::abandonGPUResources() {
fPipeline->unrefAndAbandon();
fPipeline = nullptr;
fDescriptorPool->unrefAndAbandon();
fDescriptorPool = nullptr;
fPipelineLayout = VK_NULL_HANDLE;
fDSLayout[0] = VK_NULL_HANDLE;
fDSLayout[1] = VK_NULL_HANDLE;
fVertexUniformBuffer->abandon();
fFragmentUniformBuffer->abandon();
@ -150,6 +143,9 @@ void GrVkProgram::abandonGPUResources() {
fTextures[i]->unrefAndAbandon();
}
fTextures.rewind();
fSamplerPoolManager.abandonGPUResources();
fUniformPoolManager.abandonGPUResources();
}
static void append_texture_bindings(const GrProcessor& processor,
@ -188,6 +184,14 @@ void GrVkProgram::setData(GrVkGpu* gpu,
fXferProcessor->setData(fProgramDataManager, pipeline.getXferProcessor());
append_texture_bindings(pipeline.getXferProcessor(), &textureBindings);
// Get new descriptor sets
if (fNumSamplers) {
fSamplerPoolManager.getNewDescriptorSet(gpu,
&fDescriptorSets[GrVkUniformHandler::kSamplerDescSet]);
}
fUniformPoolManager.getNewDescriptorSet(gpu,
&fDescriptorSets[GrVkUniformHandler::kUniformBufferDescSet]);
this->writeUniformBuffers(gpu);
this->writeSamplers(gpu, textureBindings);
@ -340,13 +344,21 @@ void GrVkProgram::setRenderTargetState(const GrPipeline& pipeline) {
void GrVkProgram::bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
commandBuffer->bindPipeline(gpu, fPipeline);
commandBuffer->bindDescriptorSets(gpu, this, fPipelineLayout, 0, 2, fDescriptorSets, 0,
nullptr);
if (fDSCount) {
commandBuffer->bindDescriptorSets(gpu, this, fPipelineLayout, fStartDS, fDSCount,
&fDescriptorSets[fStartDS], 0, nullptr);
}
}
void GrVkProgram::addUniformResources(GrVkCommandBuffer& commandBuffer) {
#if 1
commandBuffer.addResource(fDescriptorPool);
if (fSamplerPoolManager.fPool) {
commandBuffer.addResource(fSamplerPoolManager.fPool);
}
if (fUniformPoolManager.fPool) {
commandBuffer.addResource(fUniformPoolManager.fPool);
}
if (fVertexUniformBuffer.get()) {
commandBuffer.addResource(fVertexUniformBuffer->resource());
}
@ -364,5 +376,64 @@ void GrVkProgram::addUniformResources(GrVkCommandBuffer& commandBuffer) {
for (int i = 0; i < fTextures.count(); ++i) {
commandBuffer.addResource(fTextures[i]);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
void GrVkProgram::DescriptorPoolManager::getNewPool(GrVkGpu* gpu) {
if (fPool) {
fPool->unref(gpu);
SkASSERT(fMaxDescriptorSets < (SK_MaxU32 >> 1));
fMaxDescriptorSets = fMaxDescriptorSets << 1;
}
if (fMaxDescriptorSets) {
fPool = gpu->resourceProvider().findOrCreateCompatibleDescriptorPool(fDescType,
fMaxDescriptorSets);
}
SkASSERT(fPool || !fMaxDescriptorSets);
}
void GrVkProgram::DescriptorPoolManager::getNewDescriptorSet(GrVkGpu* gpu, VkDescriptorSet* ds) {
if (!fMaxDescriptorSets) {
return;
}
if (fCurrentDescriptorSet == fMaxDescriptorSets) {
this->getNewPool(gpu);
fCurrentDescriptorSet = 0;
}
fCurrentDescriptorSet++;
VkDescriptorSetAllocateInfo dsAllocateInfo;
memset(&dsAllocateInfo, 0, sizeof(VkDescriptorSetAllocateInfo));
dsAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
dsAllocateInfo.pNext = nullptr;
dsAllocateInfo.descriptorPool = fPool->descPool();
dsAllocateInfo.descriptorSetCount = 1;
dsAllocateInfo.pSetLayouts = &fDescLayout;
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), AllocateDescriptorSets(gpu->device(),
&dsAllocateInfo,
ds));
}
void GrVkProgram::DescriptorPoolManager::freeGPUResources(const GrVkGpu* gpu) {
if (fDescLayout) {
GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDescLayout,
nullptr));
fDescLayout = VK_NULL_HANDLE;
}
if (fPool) {
fPool->unref(gpu);
fPool = nullptr;
}
}
void GrVkProgram::DescriptorPoolManager::abandonGPUResources() {
fDescLayout = VK_NULL_HANDLE;
if (fPool) {
fPool->unrefAndAbandon();
fPool = nullptr;
}
}

View File

@ -55,8 +55,6 @@ private:
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
GrVkDescriptorPool* descriptorPool,
VkDescriptorSet descriptorSets[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
@ -66,6 +64,40 @@ private:
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors);
// Each pool will manage one type of descriptor. Thus each descriptor set we use will all be of
// one VkDescriptorType.
struct DescriptorPoolManager {
DescriptorPoolManager(VkDescriptorSetLayout layout, VkDescriptorType type,
uint32_t descCount, GrVkGpu* gpu)
: fDescLayout(layout)
, fDescType(type)
, fCurrentDescriptorSet(0)
, fPool(nullptr) {
SkASSERT(descCount < (SK_MaxU32 >> 2));
fMaxDescriptorSets = descCount << 2;
this->getNewPool(gpu);
}
~DescriptorPoolManager() {
SkASSERT(!fDescLayout);
SkASSERT(!fPool);
}
void getNewDescriptorSet(GrVkGpu* gpu, VkDescriptorSet* ds);
void freeGPUResources(const GrVkGpu* gpu);
void abandonGPUResources();
VkDescriptorSetLayout fDescLayout;
VkDescriptorType fDescType;
uint32_t fMaxDescriptorSets;
uint32_t fCurrentDescriptorSet;
GrVkDescriptorPool* fPool;
private:
void getNewPool(GrVkGpu* gpu);
};
void writeUniformBuffers(const GrVkGpu* gpu);
void writeSamplers(GrVkGpu* gpu, const SkTArray<const GrTextureAccess*>& textureBindings);
@ -110,28 +142,24 @@ private:
// Helper for setData() that sets the view matrix and loads the render target height uniform
void setRenderTargetState(const GrPipeline&);
// GrVkGpu* fGpu;
// GrVkResources
GrVkDescriptorPool* fDescriptorPool;
GrVkPipeline* fPipeline;
// Used for binding DescriptorSets to the command buffer but does not need to survive during
// command buffer execution. Thus this is not need to be a GrVkResource.
VkPipelineLayout fPipelineLayout;
// The first set (index 0) will be used for samplers and the second set (index 1) will be
// used for uniform buffers.
// The DSLayouts only are needed for allocating the descriptor sets and must survive until after
// descriptor sets have been updated. Thus the lifetime of the layouts will just be the life of
//the GrVkProgram.
VkDescriptorSetLayout fDSLayout[2];
// The DescriptorSets need to survive until the gpu has finished all draws that use them.
// However, they will only be freed by the descriptor pool. Thus by simply keeping the
// descriptor pool alive through the draw, the descritor sets will also stay alive. Thus we do
// not need a GrVkResource versions of VkDescriptorSet.
// not need a GrVkResource versions of VkDescriptorSet. We hold on to these in the program since
// we update the descriptor sets and bind them at separate times;
VkDescriptorSet fDescriptorSets[2];
// Meta data so we know which descriptor sets we are using and need to bind.
int fStartDS;
int fDSCount;
SkAutoTDelete<GrVkUniformBuffer> fVertexUniformBuffer;
SkAutoTDelete<GrVkUniformBuffer> fFragmentUniformBuffer;
@ -151,6 +179,9 @@ private:
GrVkProgramDataManager fProgramDataManager;
DescriptorPoolManager fSamplerPoolManager;
DescriptorPoolManager fUniformPoolManager;
#ifdef SK_DEBUG
int fNumSamplers;
#endif

View File

@ -272,33 +272,10 @@ GrVkProgram* GrVkProgramBuilder::finalize(GrPrimitiveType primitiveType,
return nullptr;
}
GrVkDescriptorPool::DescriptorTypeCounts typeCounts;
typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2);
SkASSERT(numSamplers < 256);
typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, (uint8_t)numSamplers);
GrVkDescriptorPool* descriptorPool =
fGpu->resourceProvider().findOrCreateCompatibleDescriptorPool(typeCounts);
VkDescriptorSetAllocateInfo dsAllocateInfo;
memset(&dsAllocateInfo, 0, sizeof(VkDescriptorSetAllocateInfo));
dsAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
dsAllocateInfo.pNext = nullptr;
dsAllocateInfo.descriptorPool = descriptorPool->descPool();
dsAllocateInfo.descriptorSetCount = 2;
dsAllocateInfo.pSetLayouts = dsLayout;
VkDescriptorSet descriptorSets[2];
GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), AllocateDescriptorSets(fGpu->device(),
&dsAllocateInfo,
descriptorSets));
return new GrVkProgram(fGpu,
pipeline,
pipelineLayout,
dsLayout,
descriptorPool,
descriptorSets,
fUniformHandles,
fUniformHandler.fUniforms,
fUniformHandler.fCurrentVertexUBOOffset,

View File

@ -79,8 +79,8 @@ GrVkResourceProvider::findOrCreateCompatibleRenderPass(const GrVkRenderTarget& t
}
GrVkDescriptorPool* GrVkResourceProvider::findOrCreateCompatibleDescriptorPool(
const GrVkDescriptorPool::DescriptorTypeCounts& typeCounts) {
return new GrVkDescriptorPool(fGpu, typeCounts);
VkDescriptorType type, uint32_t count) {
return new GrVkDescriptorPool(fGpu, type, count);
}
GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTextureParams& params) {

View File

@ -49,14 +49,13 @@ public:
GrVkCommandBuffer* createCommandBuffer();
void checkCommandBuffers();
// Finds or creates a compatible GrVkDescriptorPool for the requested DescriptorTypeCount.
// Finds or creates a compatible GrVkDescriptorPool for the requested type and count.
// The refcount is incremented and a pointer returned.
// TODO: Currently this will just create a descriptor pool without holding onto a ref itself
// so we currently do not reuse them. Rquires knowing if another draw is currently using
// the GrVkDescriptorPool, the ability to reset pools, and the ability to purge pools out
// of our cache of GrVkDescriptorPools.
GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(
const GrVkDescriptorPool::DescriptorTypeCounts& typeCounts);
GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count);
// Finds or creates a compatible GrVkSampler based on the GrTextureParams.
// The refcount is incremented and a pointer returned.