Set up cache in vulkan to reuse GrVkPrograms (aka VkPipelines)

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

Review URL: https://codereview.chromium.org/1816153002
This commit is contained in:
egdaniel 2016-03-23 13:49:40 -07:00 committed by Commit bot
parent 297f7ce2bb
commit 22281c13a1
25 changed files with 888 additions and 398 deletions

View File

@ -464,12 +464,13 @@
'<(skia_src_path)/gpu/vk/GrVkMemory.h',
'<(skia_src_path)/gpu/vk/GrVkPipeline.cpp',
'<(skia_src_path)/gpu/vk/GrVkPipeline.h',
'<(skia_src_path)/gpu/vk/GrVkProgram.cpp',
'<(skia_src_path)/gpu/vk/GrVkProgram.h',
'<(skia_src_path)/gpu/vk/GrVkProgramBuilder.cpp',
'<(skia_src_path)/gpu/vk/GrVkProgramBuilder.h',
'<(skia_src_path)/gpu/vk/GrVkProgramDataManager.cpp',
'<(skia_src_path)/gpu/vk/GrVkProgramDataManager.h',
'<(skia_src_path)/gpu/vk/GrVkPipelineState.cpp',
'<(skia_src_path)/gpu/vk/GrVkPipelineState.h',
'<(skia_src_path)/gpu/vk/GrVkPipelineStateBuilder.cpp',
'<(skia_src_path)/gpu/vk/GrVkPipelineStateBuilder.h',
'<(skia_src_path)/gpu/vk/GrVkPipelineStateCache.cpp',
'<(skia_src_path)/gpu/vk/GrVkPipelineStateDataManager.cpp',
'<(skia_src_path)/gpu/vk/GrVkPipelineStateDataManager.h',
'<(skia_src_path)/gpu/vk/GrVkProgramDesc.cpp',
'<(skia_src_path)/gpu/vk/GrVkProgramDesc.h',
'<(skia_src_path)/gpu/vk/GrVkRenderPass.cpp',

View File

@ -9,6 +9,8 @@
#include "GrStencil.h"
#include "GrProcessor.h"
////////////////////////////////////////////////////////////////////////////////
// Stencil Rules for Merging user stencil space into clip
@ -393,3 +395,10 @@ bool GrStencilSettings::GetClipPasses(
}
return false;
}
void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
static const int kCount = sizeof(GrStencilSettings) / sizeof(uint32_t);
GR_STATIC_ASSERT(0 == sizeof(GrStencilSettings) % sizeof(uint32_t));
uint32_t* key = b->add32n(kCount);
memcpy(key, this, sizeof(GrStencilSettings));
}

View File

@ -13,6 +13,8 @@
#include "GrTypes.h"
#include "SkRegion.h"
class GrProcessorKeyBuilder;
/**
* Gr uses the stencil buffer to implement complex clipping inside the
* GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
@ -285,6 +287,8 @@ public:
return fPassOps[0] < kStencilOpCount;
}
void genKey(GrProcessorKeyBuilder* b) const;
bool operator == (const GrStencilSettings& s) const {
static const size_t gCompareSize = sizeof(GrStencilSettings) -
sizeof(fFlags);

View File

@ -270,7 +270,6 @@ private:
ProgramCache(GrGLGpu* gpu);
~ProgramCache();
void reset();
void abandon();
GrGLProgram* refProgram(const GrGLGpu* gpu, const GrPipeline&, const GrPrimitiveProcessor&);

View File

@ -77,7 +77,7 @@ GrGLGpu::ProgramCache::~ProgramCache() {
#endif
}
void GrGLGpu::ProgramCache::reset() {
void GrGLGpu::ProgramCache::abandon() {
for (int i = 0; i < fCount; ++i) {
SkASSERT(fEntries[i]->fProgram.get());
fEntries[i]->fProgram->abandon();
@ -99,10 +99,6 @@ void GrGLGpu::ProgramCache::reset() {
#endif
}
void GrGLGpu::ProgramCache::abandon() {
this->reset();
}
int GrGLGpu::ProgramCache::search(const GrProgramDesc& desc) const {
ProgDescLess less;
return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);

View File

@ -224,6 +224,6 @@ protected:
friend class GrGLProgramBuilder;
friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
friend class GrGLPathProgramBuilder; // to access fInputs.
friend class GrVkProgramBuilder;
friend class GrVkPipelineStateBuilder;
};
#endif

View File

@ -12,7 +12,7 @@
#include "GrVkPipeline.h"
#include "GrVkRenderPass.h"
#include "GrVkRenderTarget.h"
#include "GrVkProgram.h"
#include "GrVkPipelineState.h"
#include "GrVkTransferBuffer.h"
#include "GrVkUtil.h"
@ -347,7 +347,7 @@ void GrVkCommandBuffer::clearAttachments(const GrVkGpu* gpu,
}
void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
GrVkProgram* program,
GrVkPipelineState* pipelineState,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t setCount,
@ -363,7 +363,7 @@ void GrVkCommandBuffer::bindDescriptorSets(const GrVkGpu* gpu,
descriptorSets,
dynamicOffsetCount,
dynamicOffsets));
program->addUniformResources(*this);
pipelineState->addUniformResources(*this);
}
void GrVkCommandBuffer::bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline) {

View File

@ -83,7 +83,7 @@ public:
}
void bindDescriptorSets(const GrVkGpu* gpu,
GrVkProgram*,
GrVkPipelineState*,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t setCount,

View File

@ -21,9 +21,7 @@
#include "GrVkIndexBuffer.h"
#include "GrVkMemory.h"
#include "GrVkPipeline.h"
#include "GrVkProgram.h"
#include "GrVkProgramBuilder.h"
#include "GrVkProgramDesc.h"
#include "GrVkPipelineState.h"
#include "GrVkRenderPass.h"
#include "GrVkResourceProvider.h"
#include "GrVkTexture.h"
@ -478,12 +476,6 @@ GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::Li
if (renderTarget) {
tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, desc, lifeCycle,
imageDesc);
#if 0
// This clear can be included to fix warning described in htttps://bugs.skia.org/5045
// Obviously we do not want to be clearling needlessly every time we create a render target.
SkIRect rect = SkIRect::MakeWH(tex->width(), tex->height());
this->clear(rect, GrColor_TRANSPARENT_BLACK, tex->asRenderTarget());
#endif
} else {
tex = GrVkTexture::CreateNewTexture(this, desc, lifeCycle, imageDesc);
}
@ -1291,32 +1283,22 @@ bool GrVkGpu::onReadPixels(GrSurface* surface,
return true;
}
bool GrVkGpu::prepareDrawState(const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass,
GrVkProgram** program) {
// Get GrVkProgramDesc
GrVkProgramDesc desc;
if (!GrVkProgramDescBuilder::Build(&desc, primProc, pipeline, *this->vkCaps().glslCaps())) {
GrCapsDebugf(this->caps(), "Failed to vk program descriptor!\n");
GrVkPipelineState** pipelineState) {
*pipelineState = fResourceProvider.findOrCreateCompatiblePipelineState(pipeline,
primProc,
primitiveType,
renderPass);
if (!pipelineState) {
return false;
}
*program = GrVkProgramBuilder::CreateProgram(this,
pipeline,
primProc,
primitiveType,
desc,
renderPass);
if (!program) {
return false;
}
(*pipelineState)->setData(this, primProc, pipeline);
(*program)->setData(this, primProc, pipeline);
(*program)->bind(this, fCurrentCmdBuffer);
(*pipelineState)->bind(this, fCurrentCmdBuffer);
GrVkPipeline::SetDynamicState(this, fCurrentCmdBuffer, pipeline);
@ -1337,9 +1319,9 @@ void GrVkGpu::onDraw(const GrPipeline& pipeline,
fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
GrVkProgram* program = nullptr;
GrVkPipelineState* pipelineState = nullptr;
GrPrimitiveType primitiveType = meshes[0].primitiveType();
if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass, &program)) {
if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass, &pipelineState)) {
return;
}
@ -1391,21 +1373,18 @@ void GrVkGpu::onDraw(const GrPipeline& pipeline,
do {
if (nonIdxMesh->primitiveType() != primitiveType) {
// Technically we don't have to call this here (since there is a safety check in
// program:setData but this will allow for quicker freeing of resources if the
// program sits in a cache for a while.
program->freeTempResources(this);
// This free will go away once we setup a program cache, and then the cache will be
// responsible for call freeGpuResources.
program->freeGPUResources(this);
program->unref();
SkDEBUGCODE(program = nullptr);
// pipelineState:setData but this will allow for quicker freeing of resources if the
// pipelineState sits in a cache for a while.
pipelineState->freeTempResources(this);
pipelineState->unref();
SkDEBUGCODE(pipelineState = nullptr);
primitiveType = nonIdxMesh->primitiveType();
if (!this->prepareDrawState(pipeline, primProc, primitiveType, *renderPass,
&program)) {
&pipelineState)) {
return;
}
}
SkASSERT(program);
SkASSERT(pipelineState);
this->bindGeometry(primProc, *nonIdxMesh);
if (nonIdxMesh->isIndexed()) {
@ -1429,14 +1408,11 @@ void GrVkGpu::onDraw(const GrPipeline& pipeline,
fCurrentCmdBuffer->endRenderPass(this);
// Technically we don't have to call this here (since there is a safety check in program:setData
// but this will allow for quicker freeing of resources if the program sits in a cache for a
// while.
program->freeTempResources(this);
// This free will go away once we setup a program cache, and then the cache will be responsible
// for call freeGpuResources.
program->freeGPUResources(this);
program->unref();
// Technically we don't have to call this here (since there is a safety check in
// pipelineState:setData but this will allow for quicker freeing of resources if the
// pipelineState sits in a cache for a while.
pipelineState->freeTempResources(this);
pipelineState->unref();
#if SWAP_PER_DRAW
glFlush();

View File

@ -13,7 +13,6 @@
#include "vk/GrVkBackendContext.h"
#include "GrVkCaps.h"
#include "GrVkIndexBuffer.h"
#include "GrVkProgram.h"
#include "GrVkResourceProvider.h"
#include "GrVkVertexBuffer.h"
#include "GrVkUtil.h"
@ -27,6 +26,7 @@ class GrNonInstancedMesh;
class GrVkBufferImpl;
class GrVkCommandBuffer;
class GrVkPipeline;
class GrVkPipelineState;
class GrVkRenderPass;
class GrVkTexture;
struct GrVkInterface;
@ -186,7 +186,7 @@ private:
const GrPrimitiveProcessor&,
GrPrimitiveType,
const GrVkRenderPass&,
GrVkProgram** program);
GrVkPipelineState** pipelineState);
// Bind vertex and index buffers
void bindGeometry(const GrPrimitiveProcessor&, const GrNonInstancedMesh&);

View File

@ -479,7 +479,6 @@ void GrVkPipeline::freeGPUData(const GrVkGpu* gpu) const {
GR_VK_CALL(gpu->vkInterface(), DestroyPipeline(gpu->device(), fPipeline, nullptr));
}
void set_dynamic_scissor_state(GrVkGpu* gpu,
GrVkCommandBuffer* cmdBuffer,
const GrPipeline& pipeline,
@ -544,8 +543,6 @@ void set_dynamic_blend_constant_state(GrVkGpu* gpu,
cmdBuffer->setBlendConstants(gpu, floatColors);
}
void GrVkPipeline::SetDynamicState(GrVkGpu* gpu,
GrVkCommandBuffer* cmdBuffer,
const GrPipeline& pipeline) {

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "GrVkProgram.h"
#include "GrVkPipelineState.h"
#include "GrPipeline.h"
#include "GrVkCommandBuffer.h"
@ -14,6 +14,7 @@
#include "GrVkImageView.h"
#include "GrVkMemory.h"
#include "GrVkPipeline.h"
#include "GrVkRenderTarget.h"
#include "GrVkSampler.h"
#include "GrVkTexture.h"
#include "GrVkUniformBuffer.h"
@ -21,25 +22,27 @@
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLXferProcessor.h"
GrVkProgram::GrVkProgram(GrVkGpu* gpu,
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize,
uint32_t numSamplers,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors)
GrVkPipelineState::GrVkPipelineState(GrVkGpu* gpu,
const GrVkPipelineState::Desc& desc,
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize,
uint32_t numSamplers,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
const GrGLSLFragProcs& fragmentProcessors)
: fPipeline(pipeline)
, fPipelineLayout(layout)
, fBuiltinUniformHandles(builtinUniformHandles)
, fGeometryProcessor(geometryProcessor)
, fXferProcessor(xferProcessor)
, fFragmentProcessors(fragmentProcessors)
, fProgramDataManager(uniforms, vertexUniformSize, fragmentUniformSize)
, fDesc(desc)
, fDataManager(uniforms, vertexUniformSize, fragmentUniformSize)
, fSamplerPoolManager(dsLayout[GrVkUniformHandler::kSamplerDescSet],
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numSamplers, gpu)
, fUniformPoolManager(dsLayout[GrVkUniformHandler::kUniformBufferDescSet],
@ -65,7 +68,7 @@ GrVkProgram::GrVkProgram(GrVkGpu* gpu,
fNumSamplers = numSamplers;
}
GrVkProgram::~GrVkProgram() {
GrVkPipelineState::~GrVkPipelineState() {
// Must of freed all GPU resources before this is destroyed
SkASSERT(!fPipeline);
SkASSERT(!fPipelineLayout);
@ -74,7 +77,7 @@ GrVkProgram::~GrVkProgram() {
SkASSERT(!fTextures.count());
}
void GrVkProgram::freeTempResources(const GrVkGpu* gpu) {
void GrVkPipelineState::freeTempResources(const GrVkGpu* gpu) {
for (int i = 0; i < fSamplers.count(); ++i) {
fSamplers[i]->unref(gpu);
}
@ -91,7 +94,7 @@ void GrVkProgram::freeTempResources(const GrVkGpu* gpu) {
fTextures.rewind();
}
void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
void GrVkPipelineState::freeGPUResources(const GrVkGpu* gpu) {
if (fPipeline) {
fPipeline->unref(gpu);
fPipeline = nullptr;
@ -118,7 +121,7 @@ void GrVkProgram::freeGPUResources(const GrVkGpu* gpu) {
this->freeTempResources(gpu);
}
void GrVkProgram::abandonGPUResources() {
void GrVkPipelineState::abandonGPUResources() {
fPipeline->unrefAndAbandon();
fPipeline = nullptr;
@ -157,9 +160,9 @@ static void append_texture_bindings(const GrProcessor& processor,
}
}
void GrVkProgram::setData(GrVkGpu* gpu,
const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline) {
void GrVkPipelineState::setData(GrVkGpu* gpu,
const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline) {
// This is here to protect against someone calling setData multiple times in a row without
// freeing the tempData between calls.
this->freeTempResources(gpu);
@ -168,18 +171,18 @@ void GrVkProgram::setData(GrVkGpu* gpu,
SkSTArray<8, const GrTextureAccess*> textureBindings;
fGeometryProcessor->setData(fProgramDataManager, primProc);
fGeometryProcessor->setData(fDataManager, primProc);
append_texture_bindings(primProc, &textureBindings);
for (int i = 0; i < fFragmentProcessors.count(); ++i) {
const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i);
fFragmentProcessors[i]->setData(fProgramDataManager, processor);
fGeometryProcessor->setTransformData(primProc, fProgramDataManager, i,
fFragmentProcessors[i]->setData(fDataManager, processor);
fGeometryProcessor->setTransformData(primProc, fDataManager, i,
processor.coordTransforms());
append_texture_bindings(processor, &textureBindings);
}
fXferProcessor->setData(fProgramDataManager, pipeline.getXferProcessor());
fXferProcessor->setData(fDataManager, pipeline.getXferProcessor());
append_texture_bindings(pipeline.getXferProcessor(), &textureBindings);
// Get new descriptor sets
@ -195,8 +198,8 @@ void GrVkProgram::setData(GrVkGpu* gpu,
this->writeSamplers(gpu, textureBindings);
}
void GrVkProgram::writeUniformBuffers(const GrVkGpu* gpu) {
fProgramDataManager.uploadUniformBuffers(gpu, fVertexUniformBuffer, fFragmentUniformBuffer);
void GrVkPipelineState::writeUniformBuffers(const GrVkGpu* gpu) {
fDataManager.uploadUniformBuffers(gpu, fVertexUniformBuffer, fFragmentUniformBuffer);
VkWriteDescriptorSet descriptorWrites[2];
memset(descriptorWrites, 0, 2 * sizeof(VkWriteDescriptorSet));
@ -223,6 +226,13 @@ void GrVkProgram::writeUniformBuffers(const GrVkGpu* gpu) {
descriptorWrites[0].pImageInfo = nullptr;
descriptorWrites[0].pBufferInfo = &vertBufferInfo;
descriptorWrites[0].pTexelBufferView = nullptr;
fVertexUniformBuffer->addMemoryBarrier(gpu,
VK_ACCESS_HOST_WRITE_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
false);
}
VkDescriptorBufferInfo fragBufferInfo;
@ -247,6 +257,13 @@ void GrVkProgram::writeUniformBuffers(const GrVkGpu* gpu) {
descriptorWrites[1].pImageInfo = nullptr;
descriptorWrites[1].pBufferInfo = &fragBufferInfo;
descriptorWrites[1].pTexelBufferView = nullptr;
fFragmentUniformBuffer->addMemoryBarrier(gpu,
VK_ACCESS_HOST_WRITE_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
false);
}
if (uniformBindingUpdateCount) {
@ -257,8 +274,8 @@ void GrVkProgram::writeUniformBuffers(const GrVkGpu* gpu) {
}
}
void GrVkProgram::writeSamplers(GrVkGpu* gpu,
const SkTArray<const GrTextureAccess*>& textureBindings) {
void GrVkPipelineState::writeSamplers(GrVkGpu* gpu,
const SkTArray<const GrTextureAccess*>& textureBindings) {
SkASSERT(fNumSamplers == textureBindings.count());
for (int i = 0; i < textureBindings.count(); ++i) {
@ -316,11 +333,11 @@ void GrVkProgram::writeSamplers(GrVkGpu* gpu,
}
}
void GrVkProgram::setRenderTargetState(const GrPipeline& pipeline) {
void GrVkPipelineState::setRenderTargetState(const GrPipeline& pipeline) {
// Load the RT height uniform if it is needed to y-flip gl_FragCoord.
if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) {
fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
SkIntToScalar(pipeline.getRenderTarget()->height()));
}
@ -336,11 +353,11 @@ void GrVkProgram::setRenderTargetState(const GrPipeline& pipeline) {
float rtAdjustmentVec[4];
fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
}
}
void GrVkProgram::bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
void GrVkPipelineState::bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
commandBuffer->bindPipeline(gpu, fPipeline);
if (fDSCount) {
@ -349,7 +366,7 @@ void GrVkProgram::bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
}
}
void GrVkProgram::addUniformResources(GrVkCommandBuffer& commandBuffer) {
void GrVkPipelineState::addUniformResources(GrVkCommandBuffer& commandBuffer) {
if (fSamplerPoolManager.fPool) {
commandBuffer.addResource(fSamplerPoolManager.fPool);
}
@ -378,7 +395,7 @@ void GrVkProgram::addUniformResources(GrVkCommandBuffer& commandBuffer) {
////////////////////////////////////////////////////////////////////////////////
void GrVkProgram::DescriptorPoolManager::getNewPool(GrVkGpu* gpu) {
void GrVkPipelineState::DescriptorPoolManager::getNewPool(GrVkGpu* gpu) {
if (fPool) {
fPool->unref(gpu);
SkASSERT(fMaxDescriptorSets < (SK_MaxU32 >> 1));
@ -392,7 +409,7 @@ void GrVkProgram::DescriptorPoolManager::getNewPool(GrVkGpu* gpu) {
SkASSERT(fPool || !fMaxDescriptorSets);
}
void GrVkProgram::DescriptorPoolManager::getNewDescriptorSet(GrVkGpu* gpu, VkDescriptorSet* ds) {
void GrVkPipelineState::DescriptorPoolManager::getNewDescriptorSet(GrVkGpu* gpu, VkDescriptorSet* ds) {
if (!fMaxDescriptorSets) {
return;
}
@ -409,13 +426,12 @@ void GrVkProgram::DescriptorPoolManager::getNewDescriptorSet(GrVkGpu* gpu, VkDes
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) {
void GrVkPipelineState::DescriptorPoolManager::freeGPUResources(const GrVkGpu* gpu) {
if (fDescLayout) {
GR_VK_CALL(gpu->vkInterface(), DestroyDescriptorSetLayout(gpu->device(), fDescLayout,
nullptr));
@ -428,10 +444,53 @@ void GrVkProgram::DescriptorPoolManager::freeGPUResources(const GrVkGpu* gpu) {
}
}
void GrVkProgram::DescriptorPoolManager::abandonGPUResources() {
void GrVkPipelineState::DescriptorPoolManager::abandonGPUResources() {
fDescLayout = VK_NULL_HANDLE;
if (fPool) {
fPool->unrefAndAbandon();
fPool = nullptr;
}
}
uint32_t get_blend_info_key(const GrPipeline& pipeline) {
GrXferProcessor::BlendInfo blendInfo;
pipeline.getXferProcessor().getBlendInfo(&blendInfo);
static const uint32_t kBlendWriteShift = 1;
static const uint32_t kBlendCoeffShift = 5;
GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift));
GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4);
uint32_t key = blendInfo.fWriteColor;
key |= (blendInfo.fSrcBlend << kBlendWriteShift);
key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
return key;
}
void GrVkPipelineState::BuildStateKey(const GrPipeline& pipeline, GrPrimitiveType primitiveType,
SkTArray<uint8_t, true>* key) {
// Save room for the key length and key header
key->reset();
key->push_back_n(kData_StateKeyOffset);
GrProcessorKeyBuilder b(key);
GrVkRenderTarget* vkRT = (GrVkRenderTarget*)pipeline.getRenderTarget();
vkRT->simpleRenderPass()->genKey(&b);
pipeline.getStencil().genKey(&b);
SkASSERT(sizeof(GrPipelineBuilder::DrawFace) <= sizeof(uint32_t));
b.add32(pipeline.getDrawFace());
b.add32(get_blend_info_key(pipeline));
b.add32(primitiveType);
// Set key length
int keyLength = key->count();
SkASSERT(0 == (keyLength % 4));
*reinterpret_cast<uint32_t*>(key->begin()) = SkToU32(keyLength);
}

View File

@ -0,0 +1,286 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrVkPipelineState_DEFINED
#define GrVkPipelineState_DEFINED
#include "GrVkImage.h"
#include "GrVkProgramDesc.h"
#include "GrVkPipelineStateDataManager.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "vulkan/vulkan.h"
class GrPipeline;
class GrVkCommandBuffer;
class GrVkDescriptorPool;
class GrVkGpu;
class GrVkImageView;
class GrVkPipeline;
class GrVkSampler;
class GrVkUniformBuffer;
/**
* This class holds onto a GrVkPipeline object that we use for draws. Besides storing the acutal
* GrVkPipeline object, this class is also responsible handling all uniforms, descriptors, samplers,
* and other similar objects that are used along with the VkPipeline in the draw. This includes both
* allocating and freeing these objects, as well as updating their values.
*/
class GrVkPipelineState : public SkRefCnt {
public:
typedef GrGLSLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles;
~GrVkPipelineState();
GrVkPipeline* vkPipeline() const { return fPipeline; }
void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);
void addUniformResources(GrVkCommandBuffer&);
void freeGPUResources(const GrVkGpu* gpu);
// This releases resources that only a given instance of a GrVkPipelineState needs to hold onto
// and don't need to survive across new uses of the GrVkPipelineState.
void freeTempResources(const GrVkGpu* gpu);
void abandonGPUResources();
// The key is composed of two parts:
// 1. uint32_t for total key length
// 2. Pipeline state data
enum StateKeyOffsets {
// Part 1.
kLength_StateKeyOffset = 0,
// Part 2.
kData_StateKeyOffset = kLength_StateKeyOffset + sizeof(uint32_t),
};
static void BuildStateKey(const GrPipeline&, GrPrimitiveType primitiveType,
SkTArray<unsigned char, true>* key);
/**
* For Vulkan we want to cache the entire VkPipeline for reuse of draws. The Desc here holds all
* the information needed to differentiate one pipeline from another.
*
* The GrVkProgramDesc contains all the information need to create the actual shaders for the
* pipeline.
*
* The fStateKey is used to store all the inputs for the rest of the state stored on the
* pipeline. This includes stencil settings, blending information, render pass format, draw face
* information, and primitive type. Note that some state is set dynamically on the pipeline for
* each draw and thus is not included in this descriptor. This includes the viewport, scissor,
* and blend constant.
*
* A checksum which includes the fProgramDesc and fStateKey is included at the top of the Desc
* for caching purposes and faster equality checks.
*/
struct Desc {
uint32_t fChecksum;
GrVkProgramDesc fProgramDesc;
enum {
kRenderPassKeyAlloc = 12, // This is typical color attachment with no stencil or msaa
kStencilKeyAlloc = sizeof(GrStencilSettings),
kDrawFaceKeyAlloc = 4,
kBlendingKeyAlloc = 4,
kPrimitiveTypeKeyAlloc = 4,
kPreAllocSize = kData_StateKeyOffset + kRenderPassKeyAlloc + kStencilKeyAlloc +
kDrawFaceKeyAlloc + kBlendingKeyAlloc + kPrimitiveTypeKeyAlloc,
};
SkSTArray<kPreAllocSize, uint8_t, true> fStateKey;
bool operator== (const Desc& that) const {
if (fChecksum != that.fChecksum || fProgramDesc != that.fProgramDesc) {
return false;
}
// We store the keyLength at the start of fVkKey. Thus we don't have to worry about
// different length keys since we will fail on the comparison immediately. Therefore we
// just use this PipelineDesc to get the length to iterate over.
int keyLength = fStateKey.count();
SkASSERT(SkIsAlign4(keyLength));
int l = keyLength >> 2;
const uint32_t* aKey = reinterpret_cast<const uint32_t*>(fStateKey.begin());
const uint32_t* bKey = reinterpret_cast<const uint32_t*>(that.fStateKey.begin());
for (int i = 0; i < l; ++i) {
if (aKey[i] != bKey[i]) {
return false;
}
}
return true;
}
static bool Less(const Desc& a, const Desc& b) {
if (a.fChecksum != b.fChecksum) {
return a.fChecksum < b.fChecksum ? true : false;
}
bool progDescLess = GrProgramDesc::Less(a.fProgramDesc, b.fProgramDesc);
if (progDescLess || a.fProgramDesc != b.fProgramDesc) {
return progDescLess;
}
int keyLength = a.fStateKey.count();
SkASSERT(SkIsAlign4(keyLength));
int l = keyLength >> 2;
const uint32_t* aKey = reinterpret_cast<const uint32_t*>(a.fStateKey.begin());
const uint32_t* bKey = reinterpret_cast<const uint32_t*>(b.fStateKey.begin());
for (int i = 0; i < l; ++i) {
if (aKey[i] != bKey[i]) {
return aKey[i] < bKey[i] ? true : false;
}
}
return false;
}
};
const Desc& getDesc() { return fDesc; }
private:
typedef GrVkPipelineStateDataManager::UniformInfoArray UniformInfoArray;
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
GrVkPipelineState(GrVkGpu* gpu,
const GrVkPipelineState::Desc&,
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize,
uint32_t numSamplers,
GrGLSLPrimitiveProcessor* geometryProcessor,
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);
/**
* We use the RT's size and origin to adjust from Skia device space to vulkan normalized device
* space and to make device space positions have the correct origin for processors that require
* them.
*/
struct RenderTargetState {
SkISize fRenderTargetSize;
GrSurfaceOrigin fRenderTargetOrigin;
RenderTargetState() { this->invalidate(); }
void invalidate() {
fRenderTargetSize.fWidth = -1;
fRenderTargetSize.fHeight = -1;
fRenderTargetOrigin = (GrSurfaceOrigin)-1;
}
/**
* Gets a vec4 that adjusts the position from Skia device coords to Vulkans normalized device
* coords. Assuming the transformed position, pos, is a homogeneous vec3, the vec, v, is
* applied as such:
* pos.x = dot(v.xy, pos.xz)
* pos.y = dot(v.zw, pos.yz)
*/
void getRTAdjustmentVec(float* destVec) {
destVec[0] = 2.f / fRenderTargetSize.fWidth;
destVec[1] = -1.f;
if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
destVec[2] = -2.f / fRenderTargetSize.fHeight;
destVec[3] = 1.f;
} else {
destVec[2] = 2.f / fRenderTargetSize.fHeight;
destVec[3] = -1.f;
}
}
};
// Helper for setData() that sets the view matrix and loads the render target height uniform
void setRenderTargetState(const GrPipeline&);
// GrVkResources
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 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. We hold on to these in the
// GrVkPipelineState 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;
// GrVkResources used for sampling textures
SkTDArray<GrVkSampler*> fSamplers;
SkTDArray<const GrVkImageView*> fTextureViews;
SkTDArray<const GrVkImage::Resource*> fTextures;
// Tracks the current render target uniforms stored in the vertex buffer.
RenderTargetState fRenderTargetState;
BuiltinUniformHandles fBuiltinUniformHandles;
// Processors in the GrVkPipelineState
SkAutoTDelete<GrGLSLPrimitiveProcessor> fGeometryProcessor;
SkAutoTDelete<GrGLSLXferProcessor> fXferProcessor;
GrGLSLFragProcs fFragmentProcessors;
Desc fDesc;
GrVkPipelineStateDataManager fDataManager;
DescriptorPoolManager fSamplerPoolManager;
DescriptorPoolManager fUniformPoolManager;
int fNumSamplers;
friend class GrVkPipelineStateBuilder;
};
#endif

View File

@ -5,21 +5,21 @@
* found in the LICENSE file.
*/
#include "vk/GrVkProgramBuilder.h"
#include "vk/GrVkPipelineStateBuilder.h"
#include "vk/GrVkGpu.h"
#include "vk/GrVkRenderPass.h"
#include "vk/GrVkProgram.h"
GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu,
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
GrPrimitiveType primitiveType,
const GrVkProgramDesc& desc,
const GrVkRenderPass& renderPass) {
GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState(
GrVkGpu* gpu,
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
GrPrimitiveType primitiveType,
const GrVkPipelineState::Desc& desc,
const GrVkRenderPass& renderPass) {
// create a builder. This will be handed off to effects so they can use it to add
// uniforms, varyings, textures, etc
GrVkProgramBuilder builder(gpu, pipeline, primProc, desc);
GrVkPipelineStateBuilder builder(gpu, pipeline, primProc, desc.fProgramDesc);
GrGLSLExpr4 inputColor;
GrGLSLExpr4 inputCoverage;
@ -29,27 +29,27 @@ GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu,
return nullptr;
}
return builder.finalize(primitiveType, renderPass);
return builder.finalize(primitiveType, renderPass, desc);
}
GrVkProgramBuilder::GrVkProgramBuilder(GrVkGpu* gpu,
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
const GrVkProgramDesc& desc)
GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu,
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
const GrVkProgramDesc& desc)
: INHERITED(pipeline, primProc, desc)
, fGpu(gpu)
, fVaryingHandler(this)
, fUniformHandler(this) {
}
const GrCaps* GrVkProgramBuilder::caps() const {
const GrCaps* GrVkPipelineStateBuilder::caps() const {
return fGpu->caps();
}
const GrGLSLCaps* GrVkProgramBuilder::glslCaps() const {
const GrGLSLCaps* GrVkPipelineStateBuilder::glslCaps() const {
return fGpu->vkCaps().glslCaps();
}
void GrVkProgramBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) {
void GrVkPipelineStateBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) {
outputColor.setLayoutQualifier("location = 0");
}
@ -76,11 +76,11 @@ shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage)
return shaderc_glsl_fragment_shader;
}
bool GrVkProgramBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
VkShaderStageFlagBits stage,
const GrGLSLShaderBuilder& builder,
VkShaderModule* shaderModule,
VkPipelineShaderStageCreateInfo* stageInfo) {
bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
VkShaderStageFlagBits stage,
const GrGLSLShaderBuilder& builder,
VkShaderModule* shaderModule,
VkPipelineShaderStageCreateInfo* stageInfo) {
SkString shaderString;
for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
if (builder.fCompilerStrings[i]) {
@ -140,8 +140,9 @@ bool GrVkProgramBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
return true;
}
GrVkProgram* GrVkProgramBuilder::finalize(GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass) {
GrVkPipelineState* GrVkPipelineStateBuilder::finalize(GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass,
const GrVkPipelineState::Desc& desc) {
VkDescriptorSetLayout dsLayout[2];
VkPipelineLayout pipelineLayout;
VkShaderModule vertShaderModule;
@ -272,16 +273,17 @@ GrVkProgram* GrVkProgramBuilder::finalize(GrPrimitiveType primitiveType,
return nullptr;
}
return new GrVkProgram(fGpu,
pipeline,
pipelineLayout,
dsLayout,
fUniformHandles,
fUniformHandler.fUniforms,
fUniformHandler.fCurrentVertexUBOOffset,
fUniformHandler.fCurrentFragmentUBOOffset,
numSamplers,
fGeometryProcessor,
fXferProcessor,
fFragmentProcessors);
return new GrVkPipelineState(fGpu,
desc,
pipeline,
pipelineLayout,
dsLayout,
fUniformHandles,
fUniformHandler.fUniforms,
fUniformHandler.fCurrentVertexUBOOffset,
fUniformHandler.fCurrentFragmentUBOOffset,
numSamplers,
fGeometryProcessor,
fXferProcessor,
fFragmentProcessors);
}

View File

@ -5,38 +5,37 @@
* found in the LICENSE file.
*/
#ifndef GrVkProgramBuilder_DEFINED
#define GrVkProgramBuilder_DEFINED
#ifndef GrVkPipelineStateBuilder_DEFINED
#define GrVkPipelineStateBuilder_DEFINED
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrPipeline.h"
#include "vk/GrVkUniformHandler.h"
#include "vk/GrVkVaryingHandler.h"
#include "GrVkPipelineState.h"
#include "GrVkUniformHandler.h"
#include "GrVkVaryingHandler.h"
#include "shaderc/shaderc.h"
#include "vulkan/vulkan.h"
class GrVkGpu;
class GrVkRenderPass;
class GrVkProgram;
class GrVkProgramDesc;
class GrVkProgramBuilder : public GrGLSLProgramBuilder {
class GrVkPipelineStateBuilder : public GrGLSLProgramBuilder {
public:
/** Generates a shader program.
/** Generates a pipeline state.
*
* The program implements what is specified in the stages given as input.
* After successful generation, the builder result objects are available
* to be used.
* The GrVkPipelineState implements what is specified in the GrPipeline and GrPrimitiveProcessor
* as input. After successful generation, the builder result objects are available to be used.
* @return true if generation was successful.
*/
static GrVkProgram* CreateProgram(GrVkGpu*,
const GrPipeline&,
const GrPrimitiveProcessor&,
GrPrimitiveType,
const GrVkProgramDesc&,
const GrVkRenderPass& renderPass);
static GrVkPipelineState* CreatePipelineState(GrVkGpu*,
const GrPipeline&,
const GrPrimitiveProcessor&,
GrPrimitiveType,
const GrVkPipelineState::Desc&,
const GrVkRenderPass& renderPass);
const GrCaps* caps() const override;
const GrGLSLCaps* glslCaps() const override;
@ -46,12 +45,14 @@ public:
void finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) override;
private:
GrVkProgramBuilder(GrVkGpu*,
const GrPipeline&,
const GrPrimitiveProcessor&,
const GrVkProgramDesc&);
GrVkPipelineStateBuilder(GrVkGpu*,
const GrPipeline&,
const GrPrimitiveProcessor&,
const GrVkProgramDesc&);
GrVkProgram* finalize(GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass);
GrVkPipelineState* finalize(GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass,
const GrVkPipelineState::Desc&);
static bool CreateVkShaderModule(const GrVkGpu* gpu,
VkShaderStageFlagBits stage,

View File

@ -0,0 +1,249 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrVkResourceProvider.h"
#include "GrVkGpu.h"
#include "GrProcessor.h"
#include "GrVkPipelineState.h"
#include "GrVkPipelineStateBuilder.h"
#include "SkRTConf.h"
#include "SkTSearch.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#ifdef PIPELINE_STATE_CACHE_STATS
SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false,
"Display pipeline state cache usage.");
#endif
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
struct GrVkResourceProvider::PipelineStateCache::Entry {
Entry() : fPipelineState(nullptr), fLRUStamp(0) {}
SkAutoTUnref<GrVkPipelineState> fPipelineState;
unsigned int fLRUStamp;
};
struct GrVkResourceProvider::PipelineStateCache::PipelineDescLess {
bool operator() (const GrVkPipelineState::Desc& desc, const Entry* entry) {
SkASSERT(entry->fPipelineState.get());
return GrVkPipelineState::Desc::Less(desc, entry->fPipelineState->getDesc());
}
bool operator() (const Entry* entry, const GrVkPipelineState::Desc& desc) {
SkASSERT(entry->fPipelineState.get());
return GrVkPipelineState::Desc::Less(entry->fPipelineState->getDesc(), desc);
}
};
GrVkResourceProvider::PipelineStateCache::PipelineStateCache(GrVkGpu* gpu)
: fCount(0)
, fCurrLRUStamp(0)
, fGpu(gpu)
#ifdef PIPELINE_STATE_CACHE_STATS
, fTotalRequests(0)
, fCacheMisses(0)
, fHashMisses(0)
#endif
{
for (int i = 0; i < 1 << kHashBits; ++i) {
fHashTable[i] = nullptr;
}
}
GrVkResourceProvider::PipelineStateCache::~PipelineStateCache() {
SkASSERT(0 == fCount);
// dump stats
#ifdef PIPELINE_STATE_CACHE_STATS
if (c_DisplayCache) {
SkDebugf("--- Pipeline State Cache ---\n");
SkDebugf("Total requests: %d\n", fTotalRequests);
SkDebugf("Cache misses: %d\n", fCacheMisses);
SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
100.f * fCacheMisses / fTotalRequests :
0.f);
int cacheHits = fTotalRequests - fCacheMisses;
SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
SkDebugf("---------------------\n");
}
#endif
}
void GrVkResourceProvider::PipelineStateCache::reset() {
for (int i = 0; i < fCount; ++i) {
delete fEntries[i];
fEntries[i] = nullptr;
}
fCount = 0;
// zero out hash table
for (int i = 0; i < 1 << kHashBits; i++) {
fHashTable[i] = nullptr;
}
fCurrLRUStamp = 0;
}
void GrVkResourceProvider::PipelineStateCache::abandon() {
for (int i = 0; i < fCount; ++i) {
SkASSERT(fEntries[i]->fPipelineState.get());
fEntries[i]->fPipelineState->abandonGPUResources();
}
this->reset();
}
void GrVkResourceProvider::PipelineStateCache::release() {
for (int i = 0; i < fCount; ++i) {
SkASSERT(fEntries[i]->fPipelineState.get());
fEntries[i]->fPipelineState->freeGPUResources(fGpu);
}
this->reset();
}
int GrVkResourceProvider::PipelineStateCache::search(const GrVkPipelineState::Desc& desc) const {
PipelineDescLess less;
return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
}
GrVkPipelineState* GrVkResourceProvider::PipelineStateCache::refPipelineState(
const GrPipeline& pipeline,
const GrPrimitiveProcessor& primProc,
GrPrimitiveType primiteType,
const GrVkRenderPass& renderPass) {
#ifdef PIPELINE_STATE_CACHE_STATS
++fTotalRequests;
#endif
Entry* entry = nullptr;
// Get GrVkProgramDesc
GrVkPipelineState::Desc desc;
if (!GrVkProgramDescBuilder::Build(&desc.fProgramDesc,
primProc,
pipeline,
*fGpu->vkCaps().glslCaps())) {
GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
return false;
}
// Get vulkan specific descriptor key
GrVkPipelineState::BuildStateKey(pipeline, primiteType, &desc.fStateKey);
// Get checksum of entire PipelineDesc
int keyLength = desc.fStateKey.count();
SkASSERT(0 == (keyLength % 4));
// Seed the checksum with the checksum of the programDesc then add the vulkan key to it.
desc.fChecksum = SkChecksum::Murmur3(desc.fStateKey.begin(), keyLength,
desc.fProgramDesc.getChecksum());
uint32_t hashIdx = desc.fChecksum;
hashIdx ^= hashIdx >> 16;
if (kHashBits <= 8) {
hashIdx ^= hashIdx >> 8;
}
hashIdx &= ((1 << kHashBits) - 1);
Entry* hashedEntry = fHashTable[hashIdx];
if (hashedEntry && hashedEntry->fPipelineState->getDesc() == desc) {
SkASSERT(hashedEntry->fPipelineState);
entry = hashedEntry;
}
int entryIdx;
if (nullptr == entry) {
entryIdx = this->search(desc);
if (entryIdx >= 0) {
entry = fEntries[entryIdx];
#ifdef PIPELINE_STATE_CACHE_STATS
++fHashMisses;
#endif
}
}
if (nullptr == entry) {
// We have a cache miss
#ifdef PIPELINE_STATE_CACHE_STATS
++fCacheMisses;
#endif
GrVkPipelineState* pipelineState =
GrVkPipelineStateBuilder::CreatePipelineState(fGpu,
pipeline,
primProc,
primiteType,
desc,
renderPass);
if (nullptr == pipelineState) {
return nullptr;
}
int purgeIdx = 0;
if (fCount < kMaxEntries) {
entry = new Entry;
purgeIdx = fCount++;
fEntries[purgeIdx] = entry;
} else {
SkASSERT(fCount == kMaxEntries);
purgeIdx = 0;
for (int i = 1; i < kMaxEntries; ++i) {
if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) {
purgeIdx = i;
}
}
entry = fEntries[purgeIdx];
int purgedHashIdx = entry->fPipelineState->getDesc().fChecksum & ((1 << kHashBits) - 1);
if (fHashTable[purgedHashIdx] == entry) {
fHashTable[purgedHashIdx] = nullptr;
}
entry->fPipelineState->freeGPUResources(fGpu);
}
SkASSERT(fEntries[purgeIdx] == entry);
entry->fPipelineState.reset(pipelineState);
// We need to shift fEntries around so that the entry currently at purgeIdx is placed
// just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor).
entryIdx = ~entryIdx;
if (entryIdx < purgeIdx) {
// Let E and P be the entries at index entryIdx and purgeIdx, respectively.
// If the entries array looks like this:
// aaaaEbbbbbPccccc
// we rearrange it to look like this:
// aaaaPEbbbbbccccc
size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*);
memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize);
fEntries[entryIdx] = entry;
} else if (purgeIdx < entryIdx) {
// If the entries array looks like this:
// aaaaPbbbbbEccccc
// we rearrange it to look like this:
// aaaabbbbbPEccccc
size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*);
memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize);
fEntries[entryIdx - 1] = entry;
}
#ifdef SK_DEBUG
SkASSERT(fEntries[0]->fPipelineState.get());
for (int i = 0; i < fCount - 1; ++i) {
SkASSERT(fEntries[i + 1]->fPipelineState.get());
const GrVkPipelineState::Desc& a = fEntries[i]->fPipelineState->getDesc();
const GrVkPipelineState::Desc& b = fEntries[i + 1]->fPipelineState->getDesc();
SkASSERT(GrVkPipelineState::Desc::Less(a, b));
SkASSERT(!GrVkPipelineState::Desc::Less(b, a));
}
#endif
}
fHashTable[hashIdx] = entry;
entry->fLRUStamp = fCurrLRUStamp;
if (SK_MaxU32 == fCurrLRUStamp) {
// wrap around! just trash our LRU, one time hit.
for (int i = 0; i < fCount; ++i) {
fEntries[i]->fLRUStamp = 0;
}
}
++fCurrLRUStamp;
return SkRef(entry->fPipelineState.get());
}

View File

@ -5,14 +5,14 @@
* found in the LICENSE file.
*/
#include "GrVkProgramDataManager.h"
#include "GrVkPipelineStateDataManager.h"
#include "GrVkGpu.h"
#include "GrVkUniformBuffer.h"
GrVkProgramDataManager::GrVkProgramDataManager(const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize)
GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize)
: fVertexUniformSize(vertexUniformSize)
, fFragmentUniformSize(fragmentUniformSize)
, fVertexUniformsDirty(false)
@ -40,7 +40,7 @@ GrVkProgramDataManager::GrVkProgramDataManager(const UniformInfoArray& uniforms,
}
}
void* GrVkProgramDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
void* GrVkPipelineStateDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
@ -55,7 +55,7 @@ void* GrVkProgramDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const
return buffer;
}
void GrVkProgramDataManager::set1f(UniformHandle u, float v0) const {
void GrVkPipelineStateDataManager::set1f(UniformHandle u, float v0) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
@ -65,9 +65,9 @@ void GrVkProgramDataManager::set1f(UniformHandle u, float v0) const {
memcpy(buffer, &v0, sizeof(float));
}
void GrVkProgramDataManager::set1fv(UniformHandle u,
int arrayCount,
const float v[]) const {
void GrVkPipelineStateDataManager::set1fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat_GrSLType);
SkASSERT(arrayCount > 0);
@ -84,7 +84,7 @@ void GrVkProgramDataManager::set1fv(UniformHandle u,
}
}
void GrVkProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
void GrVkPipelineStateDataManager::set2f(UniformHandle u, float v0, float v1) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec2f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
@ -95,9 +95,9 @@ void GrVkProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
memcpy(buffer, v, 2 * sizeof(float));
}
void GrVkProgramDataManager::set2fv(UniformHandle u,
int arrayCount,
const float v[]) const {
void GrVkPipelineStateDataManager::set2fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec2f_GrSLType);
SkASSERT(arrayCount > 0);
@ -114,7 +114,7 @@ void GrVkProgramDataManager::set2fv(UniformHandle u,
}
}
void GrVkProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
void GrVkPipelineStateDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec3f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
@ -125,9 +125,9 @@ void GrVkProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2
memcpy(buffer, v, 3 * sizeof(float));
}
void GrVkProgramDataManager::set3fv(UniformHandle u,
int arrayCount,
const float v[]) const {
void GrVkPipelineStateDataManager::set3fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec3f_GrSLType);
SkASSERT(arrayCount > 0);
@ -144,7 +144,11 @@ void GrVkProgramDataManager::set3fv(UniformHandle u,
}
}
void GrVkProgramDataManager::set4f(UniformHandle u, float v0, float v1, float v2, float v3) const {
void GrVkPipelineStateDataManager::set4f(UniformHandle u,
float v0,
float v1,
float v2,
float v3) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec4f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
@ -155,9 +159,9 @@ void GrVkProgramDataManager::set4f(UniformHandle u, float v0, float v1, float v2
memcpy(buffer, v, 4 * sizeof(float));
}
void GrVkProgramDataManager::set4fv(UniformHandle u,
int arrayCount,
const float v[]) const {
void GrVkPipelineStateDataManager::set4fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kVec4f_GrSLType);
SkASSERT(arrayCount > 0);
@ -170,35 +174,41 @@ void GrVkProgramDataManager::set4fv(UniformHandle u,
memcpy(buffer, v, arrayCount * 4 * sizeof(float));
}
void GrVkProgramDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
void GrVkPipelineStateDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
this->setMatrices<2>(u, 1, matrix);
}
void GrVkProgramDataManager::setMatrix2fv(UniformHandle u, int arrayCount, const float m[]) const {
void GrVkPipelineStateDataManager::setMatrix2fv(UniformHandle u,
int arrayCount,
const float m[]) const {
this->setMatrices<2>(u, arrayCount, m);
}
void GrVkProgramDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
void GrVkPipelineStateDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
this->setMatrices<3>(u, 1, matrix);
}
void GrVkProgramDataManager::setMatrix3fv(UniformHandle u, int arrayCount, const float m[]) const {
void GrVkPipelineStateDataManager::setMatrix3fv(UniformHandle u,
int arrayCount,
const float m[]) const {
this->setMatrices<3>(u, arrayCount, m);
}
void GrVkProgramDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
void GrVkPipelineStateDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
this->setMatrices<4>(u, 1, matrix);
}
void GrVkProgramDataManager::setMatrix4fv(UniformHandle u, int arrayCount, const float m[]) const {
void GrVkPipelineStateDataManager::setMatrix4fv(UniformHandle u,
int arrayCount,
const float m[]) const {
this->setMatrices<4>(u, arrayCount, m);
}
template<int N> struct set_uniform_matrix;
template<int N> inline void GrVkProgramDataManager::setMatrices(UniformHandle u,
int arrayCount,
const float matrices[]) const {
template<int N> inline void GrVkPipelineStateDataManager::setMatrices(UniformHandle u,
int arrayCount,
const float matrices[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kMat22f_GrSLType + (N - 2));
SkASSERT(arrayCount > 0);
@ -243,9 +253,9 @@ template<> struct set_uniform_matrix<4> {
}
};
void GrVkProgramDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
GrVkUniformBuffer* vertexBuffer,
GrVkUniformBuffer* fragmentBuffer) const {
void GrVkPipelineStateDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
GrVkUniformBuffer* vertexBuffer,
GrVkUniformBuffer* fragmentBuffer) const {
if (vertexBuffer && fVertexUniformsDirty) {
vertexBuffer->addMemoryBarrier(gpu,
VK_ACCESS_UNIFORM_READ_BIT,

View File

@ -5,8 +5,8 @@
* found in the LICENSE file.
*/
#ifndef GrVkProgramDataManager_DEFINED
#define GrVkProgramDataManager_DEFINED
#ifndef GrVkPipelineStateDataManager_DEFINED
#define GrVkPipelineStateDataManager_DEFINED
#include "glsl/GrGLSLProgramDataManager.h"
@ -15,13 +15,13 @@
class GrVkGpu;
class GrVkUniformBuffer;
class GrVkProgramDataManager : public GrGLSLProgramDataManager {
class GrVkPipelineStateDataManager : public GrGLSLProgramDataManager {
public:
typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray;
GrVkProgramDataManager(const UniformInfoArray&,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize);
GrVkPipelineStateDataManager(const UniformInfoArray&,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize);
void set1f(UniformHandle, float v0) const override;
void set1fv(UniformHandle, int arrayCount, const float v[]) const override;

View File

@ -1,190 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrVkProgram_DEFINED
#define GrVkProgram_DEFINED
#include "GrVkImage.h"
#include "GrVkProgramDesc.h"
#include "GrVkProgramDataManager.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "vulkan/vulkan.h"
class GrPipeline;
class GrVkCommandBuffer;
class GrVkDescriptorPool;
class GrVkGpu;
class GrVkImageView;
class GrVkPipeline;
class GrVkSampler;
class GrVkUniformBuffer;
class GrVkProgram : public SkRefCnt {
public:
typedef GrGLSLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles;
~GrVkProgram();
GrVkPipeline* vkPipeline() const { return fPipeline; }
void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);
void addUniformResources(GrVkCommandBuffer&);
void freeGPUResources(const GrVkGpu* gpu);
// This releases resources the only a given instance of a GrVkProgram needs to hold onto and do
// don't need to survive across new uses of the program.
void freeTempResources(const GrVkGpu* gpu);
void abandonGPUResources();
private:
typedef GrVkProgramDataManager::UniformInfoArray UniformInfoArray;
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
GrVkProgram(GrVkGpu* gpu,
GrVkPipeline* pipeline,
VkPipelineLayout layout,
VkDescriptorSetLayout dsLayout[2],
const BuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize,
uint32_t numSamplers,
GrGLSLPrimitiveProcessor* geometryProcessor,
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);
/**
* We use the RT's size and origin to adjust from Skia device space to OpenGL normalized device
* space and to make device space positions have the correct origin for processors that require
* them.
*/
struct RenderTargetState {
SkISize fRenderTargetSize;
GrSurfaceOrigin fRenderTargetOrigin;
RenderTargetState() { this->invalidate(); }
void invalidate() {
fRenderTargetSize.fWidth = -1;
fRenderTargetSize.fHeight = -1;
fRenderTargetOrigin = (GrSurfaceOrigin)-1;
}
/**
* Gets a vec4 that adjusts the position from Skia device coords to GL's normalized device
* coords. Assuming the transformed position, pos, is a homogeneous vec3, the vec, v, is
* applied as such:
* pos.x = dot(v.xy, pos.xz)
* pos.y = dot(v.zw, pos.yz)
*/
void getRTAdjustmentVec(float* destVec) {
destVec[0] = 2.f / fRenderTargetSize.fWidth;
destVec[1] = -1.f;
if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
destVec[2] = -2.f / fRenderTargetSize.fHeight;
destVec[3] = 1.f;
} else {
destVec[2] = 2.f / fRenderTargetSize.fHeight;
destVec[3] = -1.f;
}
}
};
// Helper for setData() that sets the view matrix and loads the render target height uniform
void setRenderTargetState(const GrPipeline&);
// GrVkResources
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 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. 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;
// GrVkResources used for sampling textures
SkTDArray<GrVkSampler*> fSamplers;
SkTDArray<const GrVkImageView*> fTextureViews;
SkTDArray<const GrVkImage::Resource*> fTextures;
// Tracks the current render target uniforms stored in the vertex buffer.
RenderTargetState fRenderTargetState;
BuiltinUniformHandles fBuiltinUniformHandles;
// Processors in the program
SkAutoTDelete<GrGLSLPrimitiveProcessor> fGeometryProcessor;
SkAutoTDelete<GrGLSLXferProcessor> fXferProcessor;
GrGLSLFragProcs fFragmentProcessors;
GrVkProgramDataManager fProgramDataManager;
DescriptorPoolManager fSamplerPoolManager;
DescriptorPoolManager fUniformPoolManager;
int fNumSamplers;
friend class GrVkProgramBuilder;
};
#endif

View File

@ -7,6 +7,7 @@
#include "GrVkRenderPass.h"
#include "GrProcessor.h"
#include "GrVkFramebuffer.h"
#include "GrVkGpu.h"
#include "GrVkRenderTarget.h"
@ -218,3 +219,20 @@ bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
return true;
}
void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const {
b->add32(fAttachmentFlags);
if (fAttachmentFlags & kColor_AttachmentFlag) {
b->add32(fAttachmentsDescriptor.fColor.fFormat);
b->add32(fAttachmentsDescriptor.fColor.fSamples);
}
if (fAttachmentFlags & kResolve_AttachmentFlag) {
b->add32(fAttachmentsDescriptor.fResolve.fFormat);
b->add32(fAttachmentsDescriptor.fResolve.fSamples);
}
if (fAttachmentFlags & kStencil_AttachmentFlag) {
b->add32(fAttachmentsDescriptor.fStencil.fFormat);
b->add32(fAttachmentsDescriptor.fStencil.fSamples);
}
}

View File

@ -14,6 +14,7 @@
#include "vulkan/vulkan.h"
class GrProcessorKeyBuilder;
class GrVkGpu;
class GrVkRenderTarget;
@ -72,6 +73,8 @@ public:
VkRenderPass vkRenderPass() const { return fRenderPass; }
void genKey(GrProcessorKeyBuilder* b) const;
private:
GrVkRenderPass(const GrVkRenderPass&);
GrVkRenderPass& operator=(const GrVkRenderPass&);

View File

@ -21,11 +21,13 @@ SkRandom GrVkResource::fRandom;
GrVkResourceProvider::GrVkResourceProvider(GrVkGpu* gpu) : fGpu(gpu)
, fPipelineCache(VK_NULL_HANDLE) {
fPipelineStateCache = new PipelineStateCache(gpu);
}
GrVkResourceProvider::~GrVkResourceProvider() {
SkASSERT(0 == fSimpleRenderPasses.count());
SkASSERT(VK_NULL_HANDLE == fPipelineCache);
delete fPipelineStateCache;
}
void GrVkResourceProvider::init() {
@ -94,6 +96,14 @@ GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrTexture
return sampler;
}
GrVkPipelineState* GrVkResourceProvider::findOrCreateCompatiblePipelineState(
const GrPipeline& pipeline,
const GrPrimitiveProcessor& proc,
GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass) {
return fPipelineStateCache->refPipelineState(pipeline, proc, primitiveType, renderPass);
}
GrVkCommandBuffer* GrVkResourceProvider::createCommandBuffer() {
GrVkCommandBuffer* cmdBuffer = GrVkCommandBuffer::Create(fGpu, fGpu->cmdPool());
fActiveCommandBuffers.push_back(cmdBuffer);
@ -132,6 +142,8 @@ void GrVkResourceProvider::destroyResources() {
}
fSamplers.reset();
fPipelineStateCache->release();
#ifdef SK_TRACE_VK_RESOURCES
SkASSERT(0 == GrVkResource::fTrace.count());
#endif
@ -160,6 +172,8 @@ void GrVkResourceProvider::abandonResources() {
}
fSamplers.reset();
fPipelineStateCache->abandon();
#ifdef SK_TRACE_VK_RESOURCES
SkASSERT(0 == GrVkResource::fTrace.count());
#endif

View File

@ -8,7 +8,9 @@
#ifndef GrVkResourceProvider_DEFINED
#define GrVkResourceProvider_DEFINED
#include "GrGpu.h"
#include "GrVkDescriptorPool.h"
#include "GrVkPipelineState.h"
#include "GrVkResource.h"
#include "GrVkUtil.h"
#include "SkTArray.h"
@ -61,6 +63,11 @@ public:
// The refcount is incremented and a pointer returned.
GrVkSampler* findOrCreateCompatibleSampler(const GrTextureParams&);
GrVkPipelineState* findOrCreateCompatiblePipelineState(const GrPipeline&,
const GrPrimitiveProcessor&,
GrPrimitiveType,
const GrVkRenderPass& renderPass);
// 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
@ -73,6 +80,52 @@ public:
void abandonResources();
private:
class PipelineStateCache : public ::SkNoncopyable {
public:
PipelineStateCache(GrVkGpu* gpu);
~PipelineStateCache();
void abandon();
void release();
GrVkPipelineState* refPipelineState(const GrPipeline&,
const GrPrimitiveProcessor&,
GrPrimitiveType,
const GrVkRenderPass& renderPass);
private:
enum {
// We may actually have kMaxEntries+1 PipelineStates in context because we create a new
// PipelineState before evicting from the cache.
kMaxEntries = 128,
kHashBits = 6,
};
struct Entry;
struct PipelineDescLess;
void reset();
// binary search for entry matching desc. returns index into fEntries that matches desc or ~
// of the index of where it should be inserted.
int search(const GrVkPipelineState::Desc& desc) const;
// sorted array of all the entries
Entry* fEntries[kMaxEntries];
// hash table based on lowest kHashBits bits of the pipeline state key. Used to avoid binary
// searching fEntries.
Entry* fHashTable[1 << kHashBits];
int fCount;
unsigned int fCurrLRUStamp;
GrVkGpu* fGpu;
#ifdef PIPELINE_STATE_CACHE_STATS
int fTotalRequests;
int fCacheMisses;
int fHashMisses; // cache hit but hash table missed
#endif
};
GrVkGpu* fGpu;
// Central cache for creating pipelines
@ -86,8 +139,11 @@ private:
SkSTArray<4, GrVkCommandBuffer*> fActiveCommandBuffers;
// Stores GrVkSampler objects that we've already created so we can reuse them across multiple
// programs
// GrVkPipelineStates
SkTDynamicHash<GrVkSampler, uint8_t> fSamplers;
// Cache of GrVkPipelineStates
PipelineStateCache* fPipelineStateCache;
};
#endif

View File

@ -77,7 +77,7 @@ private:
uint32_t fCurrentFragmentUBOOffset;
uint32_t fCurrentSamplerBinding;
friend class GrVkProgramBuilder;
friend class GrVkPipelineStateBuilder;
typedef GrGLSLUniformHandler INHERITED;
};

View File

@ -19,9 +19,9 @@ public:
private:
void onFinalize() override;
friend class GrVkProgramBuilder;
friend class GrVkPipelineStateBuilder;
typedef GrGLSLVaryingHandler INHERITED;
};
#endif
#endif