Recycle small uniform buffers.
BUG=skia:5031
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2159333002
Review-Url: https://codereview.chromium.org/2159333002
diff --git a/src/gpu/vk/GrVkBuffer.cpp b/src/gpu/vk/GrVkBuffer.cpp
index 3b9cbc7..75f3901 100644
--- a/src/gpu/vk/GrVkBuffer.cpp
+++ b/src/gpu/vk/GrVkBuffer.cpp
@@ -108,7 +108,7 @@
void GrVkBuffer::vkRelease(const GrVkGpu* gpu) {
VALIDATE();
- fResource->unref(gpu);
+ fResource->recycle(const_cast<GrVkGpu*>(gpu));
fResource = nullptr;
fMapPtr = nullptr;
VALIDATE();
diff --git a/src/gpu/vk/GrVkBuffer.h b/src/gpu/vk/GrVkBuffer.h
index 232de17..b400e09 100644
--- a/src/gpu/vk/GrVkBuffer.h
+++ b/src/gpu/vk/GrVkBuffer.h
@@ -53,7 +53,7 @@
bool fDynamic;
};
- class Resource : public GrVkResource {
+ class Resource : public GrVkRecycledResource {
public:
Resource(VkBuffer buf, const GrVkAlloc& alloc, Type type)
: INHERITED(), fBuffer(buf), fAlloc(alloc), fType(type) {}
@@ -70,7 +70,9 @@
private:
void freeGPUData(const GrVkGpu* gpu) const override;
- typedef GrVkResource INHERITED;
+ void onRecycle(GrVkGpu* gpu) const override { this->unref(gpu); }
+
+ typedef GrVkRecycledResource INHERITED;
};
// convenience routine for raw buffer creation
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index a09a805..7fddd4b 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -151,7 +151,7 @@
fHeaps[kSmallOptimalImage_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 2*1024*1024));
fHeaps[kVertexBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
fHeaps[kIndexBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
- fHeaps[kUniformBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 64*1024));
+ fHeaps[kUniformBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 256*1024));
fHeaps[kCopyReadBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSingleAlloc_Strategy, 0));
fHeaps[kCopyWriteBuffer_Heap].reset(new GrVkHeap(this, GrVkHeap::kSubAlloc_Strategy, 16*1024*1024));
}
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index b9aa826..ab9cff8 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -68,8 +68,8 @@
fStartDS = SkTMin(fStartDS, (int)GrVkUniformHandler::kSamplerDescSet);
}
- fVertexUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, vertexUniformSize, true));
- fFragmentUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, fragmentUniformSize, true));
+ fVertexUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, vertexUniformSize));
+ fFragmentUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, fragmentUniformSize));
fNumSamplers = numSamplers;
}
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index ccf4716..abe07bd 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -12,6 +12,7 @@
#include "GrVkPipeline.h"
#include "GrVkRenderTarget.h"
#include "GrVkSampler.h"
+#include "GrVkUniformBuffer.h"
#include "GrVkUtil.h"
#ifdef SK_TRACE_VK_RESOURCES
@@ -267,6 +268,22 @@
fAvailableSecondaryCommandBuffers.push_back(cb);
}
+const GrVkResource* GrVkResourceProvider::findOrCreateStandardUniformBufferResource() {
+ const GrVkResource* resource = nullptr;
+ int count = fAvailableUniformBufferResources.count();
+ if (count > 0) {
+ resource = fAvailableUniformBufferResources[count - 1];
+ fAvailableUniformBufferResources.removeShuffle(count - 1);
+ } else {
+ resource = GrVkUniformBuffer::CreateResource(fGpu, GrVkUniformBuffer::kStandardSize);
+ }
+ return resource;
+}
+
+void GrVkResourceProvider::recycleStandardUniformBufferResource(const GrVkResource* resource) {
+ fAvailableUniformBufferResources.push_back(resource);
+}
+
void GrVkResourceProvider::destroyResources() {
// release our active command buffers
for (int i = 0; i < fActiveCommandBuffers.count(); ++i) {
@@ -322,6 +339,13 @@
fDescriptorSetManagers[i].release(fGpu);
}
fDescriptorSetManagers.reset();
+
+ // release our uniform buffers
+ for (int i = 0; i < fAvailableUniformBufferResources.count(); ++i) {
+ SkASSERT(fAvailableUniformBufferResources[i]->unique());
+ fAvailableUniformBufferResources[i]->unref(fGpu);
+ }
+ fAvailableUniformBufferResources.reset();
}
void GrVkResourceProvider::abandonResources() {
@@ -371,6 +395,12 @@
}
fDescriptorSetManagers.reset();
+ // release our uniform buffers
+ for (int i = 0; i < fAvailableUniformBufferResources.count(); ++i) {
+ SkASSERT(fAvailableUniformBufferResources[i]->unique());
+ fAvailableUniformBufferResources[i]->unrefAndAbandon();
+ }
+ fAvailableUniformBufferResources.reset();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index cd0411b..0660e91 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -128,6 +128,14 @@
void recycleDescriptorSet(const GrVkDescriptorSet* descSet,
const GrVkDescriptorSetManager::Handle&);
+ // Creates or finds free uniform buffer resources of size GrVkUniformBuffer::kStandardSize.
+ // Anything larger will need to be created and released by the client.
+ const GrVkResource* findOrCreateStandardUniformBufferResource();
+
+ // Signals that the resource passed to it (which should be a uniform buffer resource)
+ // can be reused by the next uniform buffer resource request.
+ void recycleStandardUniformBufferResource(const GrVkResource*);
+
// Destroy any cached resources. To be called before destroying the VkDevice.
// The assumption is that all queues are idle and all command buffers are finished.
// For resource tracing to work properly, this should be called after unrefing all other
@@ -226,6 +234,9 @@
// Array of available secondary command buffers
SkSTArray<16, GrVkSecondaryCommandBuffer*> fAvailableSecondaryCommandBuffers;
+ // Array of available uniform buffer resources
+ SkSTArray<16, const GrVkResource*> fAvailableUniformBufferResources;
+
// Stores GrVkSampler objects that we've already created so we can reuse them across multiple
// GrVkPipelineStates
SkTDynamicHash<GrVkSampler, uint16_t> fSamplers;
diff --git a/src/gpu/vk/GrVkUniformBuffer.cpp b/src/gpu/vk/GrVkUniformBuffer.cpp
index 022e2e3..c3899b0 100644
--- a/src/gpu/vk/GrVkUniformBuffer.cpp
+++ b/src/gpu/vk/GrVkUniformBuffer.cpp
@@ -8,24 +8,84 @@
#include "GrVkUniformBuffer.h"
#include "GrVkGpu.h"
+#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
-GrVkUniformBuffer* GrVkUniformBuffer::Create(GrVkGpu* gpu, size_t size, bool dynamic) {
+GrVkUniformBuffer* GrVkUniformBuffer::Create(GrVkGpu* gpu, size_t size) {
if (0 == size) {
return nullptr;
}
- GrVkBuffer::Desc desc;
- desc.fDynamic = dynamic;
- desc.fType = GrVkBuffer::kUniform_Type;
- desc.fSizeInBytes = size;
-
- const GrVkBuffer::Resource* bufferResource = GrVkBuffer::Create(gpu, desc);
- if (!bufferResource) {
+ const GrVkResource* resource = nullptr;
+ if (size <= GrVkUniformBuffer::kStandardSize) {
+ resource = gpu->resourceProvider().findOrCreateStandardUniformBufferResource();
+ } else {
+ resource = CreateResource(gpu, size);
+ }
+ if (!resource) {
return nullptr;
}
- GrVkUniformBuffer* buffer = new GrVkUniformBuffer(desc, bufferResource);
+ GrVkBuffer::Desc desc;
+ desc.fDynamic = true;
+ desc.fType = GrVkBuffer::kUniform_Type;
+ desc.fSizeInBytes = size;
+ GrVkUniformBuffer* buffer = new GrVkUniformBuffer(gpu, desc,
+ (const GrVkUniformBuffer::Resource*) resource);
if (!buffer) {
- bufferResource->unref(gpu);
+ // this will destroy anything we got from the resource provider,
+ // but this avoids a conditional
+ resource->unref(gpu);
}
return buffer;
-}
\ No newline at end of file
+}
+
+// We implement our own creation function for special buffer resource type
+const GrVkResource* GrVkUniformBuffer::CreateResource(GrVkGpu* gpu, size_t size) {
+ if (0 == size) {
+ return nullptr;
+ }
+
+ VkBuffer buffer;
+ GrVkAlloc alloc;
+
+ // create the buffer object
+ VkBufferCreateInfo bufInfo;
+ memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufInfo.flags = 0;
+ bufInfo.size = size;
+ bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ bufInfo.queueFamilyIndexCount = 0;
+ bufInfo.pQueueFamilyIndices = nullptr;
+
+ VkResult err;
+ err = VK_CALL(gpu, CreateBuffer(gpu->device(), &bufInfo, nullptr, &buffer));
+ if (err) {
+ return nullptr;
+ }
+
+ if (!GrVkMemory::AllocAndBindBufferMemory(gpu,
+ buffer,
+ kUniform_Type,
+ true, // dynamic
+ &alloc)) {
+ return nullptr;
+ }
+
+ const GrVkResource* resource = new GrVkUniformBuffer::Resource(buffer, alloc);
+ if (!resource) {
+ VK_CALL(gpu, DestroyBuffer(gpu->device(), buffer, nullptr));
+ GrVkMemory::FreeBufferMemory(gpu, kUniform_Type, alloc);
+ return nullptr;
+ }
+
+ return resource;
+}
+
+void GrVkUniformBuffer::Resource::onRecycle(GrVkGpu* gpu) const {
+ if (fAlloc.fSize <= GrVkUniformBuffer::kStandardSize) {
+ gpu->resourceProvider().recycleStandardUniformBufferResource(this);
+ } else {
+ this->unref(gpu);
+ }
+}
diff --git a/src/gpu/vk/GrVkUniformBuffer.h b/src/gpu/vk/GrVkUniformBuffer.h
index ed6c8a0..7aa3af6 100644
--- a/src/gpu/vk/GrVkUniformBuffer.h
+++ b/src/gpu/vk/GrVkUniformBuffer.h
@@ -15,7 +15,9 @@
class GrVkUniformBuffer : public GrVkBuffer {
public:
- static GrVkUniformBuffer* Create(GrVkGpu* gpu, size_t size, bool dynamic);
+ static GrVkUniformBuffer* Create(GrVkGpu* gpu, size_t size);
+ static const GrVkResource* CreateResource(GrVkGpu* gpu, size_t size);
+ static const size_t kStandardSize = 256;
void* map(const GrVkGpu* gpu) {
return this->vkMap(gpu);
@@ -29,18 +31,27 @@
bool* createdNewBuffer) {
return this->vkUpdateData(gpu, src, srcSizeInBytes, createdNewBuffer);
}
- void release(const GrVkGpu* gpu) {
- this->vkRelease(gpu);
- }
- void abandon() {
- this->vkAbandon();
- }
+ void release(const GrVkGpu* gpu) { this->vkRelease(gpu); }
+ void abandon() { this->vkAbandon(); }
private:
- GrVkUniformBuffer(const GrVkBuffer::Desc& desc, const GrVkBuffer::Resource* resource)
- : INHERITED(desc, resource) {
+ class Resource : public GrVkBuffer::Resource {
+ public:
+ Resource(VkBuffer buf, const GrVkAlloc& alloc)
+ : INHERITED(buf, alloc, kUniform_Type) {}
+
+ void onRecycle(GrVkGpu* gpu) const override;
+
+ typedef GrVkBuffer::Resource INHERITED;
};
+ GrVkUniformBuffer(GrVkGpu* gpu, const GrVkBuffer::Desc& desc,
+ const GrVkUniformBuffer::Resource* resource)
+ : INHERITED(desc, resource)
+ , fGpu(gpu) {}
+
+ GrVkGpu* fGpu;
+
typedef GrVkBuffer INHERITED;
};