Add support for immuatable samplers in vulkan.
For ycbcr conversions we need add immutable samplers to the creation of
the VkPipeline via the descriptor set layout.
Bug: skia:
Change-Id: I5eea6037191fd34d26d49f58533035316158cacd
Reviewed-on: https://skia-review.googlesource.com/c/171642
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 028f1da..cb8b2e9 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -406,6 +406,18 @@
}
}
+ /**
+ * Returns a key that represents the sampler that will be created for the passed in parameters.
+ * Currently this key is only used when we are building a vulkan pipeline with immutable
+ * samplers. In that case, we need our cache key to also contain this key.
+ *
+ * A return value of 0 indicates that the program/pipeline we are creating is not affected by
+ * the sampler.
+ */
+ virtual uint32_t getExtraSamplerKeyForProgram(const GrSamplerState&, const GrBackendFormat&) {
+ return 0;
+ }
+
protected:
// Handles cases where a surface will be updated without a call to flushRenderTarget.
void didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp
index b84af68..672056c 100644
--- a/src/gpu/GrPrimitiveProcessor.cpp
+++ b/src/gpu/GrPrimitiveProcessor.cpp
@@ -55,8 +55,9 @@
GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
GrPixelConfig config,
- const GrSamplerState& samplerState) {
- this->reset(textureType, config, samplerState);
+ const GrSamplerState& samplerState,
+ uint32_t extraSamplerKey) {
+ this->reset(textureType, config, samplerState, extraSamplerKey);
}
GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
@@ -68,12 +69,15 @@
void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
GrPixelConfig config,
- const GrSamplerState& samplerState) {
+ const GrSamplerState& samplerState,
+ uint32_t extraSamplerKey) {
SkASSERT(kUnknown_GrPixelConfig != config);
fSamplerState = samplerState;
fSamplerState.setFilterMode(clamp_filter(textureType, samplerState.filter()));
fTextureType = textureType;
fConfig = config;
+ fExtraSamplerKey = extraSamplerKey;
+ SkASSERT(!fExtraSamplerKey || textureType == GrTextureType::kExternal);
}
void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index ffb7ac0..be3d86a 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -244,7 +244,7 @@
public:
TextureSampler() = default;
- TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&);
+ TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&, uint32_t extraSamplerKey);
explicit TextureSampler(GrTextureType, GrPixelConfig,
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
@@ -253,22 +253,25 @@
TextureSampler(const TextureSampler&) = delete;
TextureSampler& operator=(const TextureSampler&) = delete;
- void reset(GrTextureType, GrPixelConfig, const GrSamplerState&);
+ void reset(GrTextureType, GrPixelConfig, const GrSamplerState&, uint32_t extraSamplerKey = 0);
void reset(GrTextureType, GrPixelConfig,
- GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
- GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp);
+ GrSamplerState::Filter,
+ GrSamplerState::WrapMode wrapXAndY);
GrTextureType textureType() const { return fTextureType; }
GrPixelConfig config() const { return fConfig; }
const GrSamplerState& samplerState() const { return fSamplerState; }
+ uint32_t extraSamplerKey() const { return fExtraSamplerKey; }
+
bool isInitialized() const { return fConfig != kUnknown_GrPixelConfig; }
private:
GrSamplerState fSamplerState;
GrTextureType fTextureType = GrTextureType::k2D;
GrPixelConfig fConfig = kUnknown_GrPixelConfig;
+ uint32_t fExtraSamplerKey = 0;
};
const GrPrimitiveProcessor::TextureSampler& GrPrimitiveProcessor::IthTextureSampler(int i) {
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 5c10b9f..aa84c98 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -50,7 +50,7 @@
}
static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrFragmentProcessor& fp,
- const GrShaderCaps& caps) {
+ GrGpu* gpu, const GrShaderCaps& caps) {
int numTextureSamplers = fp.numTextureSamplers();
// Need two bytes per key.
int word32Count = (numTextureSamplers + 1) / 2;
@@ -62,6 +62,16 @@
const GrFragmentProcessor::TextureSampler& sampler = fp.textureSampler(i);
const GrTexture* tex = sampler.peekTexture();
k16[i] = sampler_key(tex->texturePriv().textureType(), tex->config(), caps);
+ uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
+ sampler.samplerState(), sampler.proxy()->backendFormat());
+ if (extraSamplerKey) {
+ SkASSERT(sampler.proxy()->textureType() == GrTextureType::kExternal);
+ // We first mark the normal sampler key with last bit to flag that it has an extra
+ // sampler key. We then add all the extraSamplerKeys to the end of the normal ones.
+ SkASSERT((k16[i] & (1 << 15)) == 0);
+ k16[i] = k16[i] | (1 << 15);
+ b->add32(extraSamplerKey);
+ }
}
// zero the last 16 bits if the number of uniforms for samplers is odd.
if (numTextureSamplers & 0x1) {
@@ -70,7 +80,7 @@
}
static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcessor& pp,
- const GrShaderCaps& caps) {
+ const GrShaderCaps& caps) {
int numTextureSamplers = pp.numTextureSamplers();
// Need two bytes per key.
int word32Count = (numTextureSamplers + 1) / 2;
@@ -81,6 +91,15 @@
for (int i = 0; i < numTextureSamplers; ++i) {
const GrPrimitiveProcessor::TextureSampler& sampler = pp.textureSampler(i);
k16[i] = sampler_key(sampler.textureType(), sampler.config(), caps);
+ uint32_t extraSamplerKey = sampler.extraSamplerKey();
+ if (extraSamplerKey) {
+ SkASSERT(sampler.textureType() == GrTextureType::kExternal);
+ // We first mark the normal sampler key with last bit to flag that it has an extra
+ // sampler key. We then add all the extraSamplerKeys to the end of the normal ones.
+ SkASSERT((k16[i] & (1 << 15)) == 0);
+ k16[i] = k16[i] | (1 << 15);
+ b->add32(extraSamplerKey);
+ }
}
// zero the last 16 bits if the number of uniforms for samplers is odd.
if (numTextureSamplers & 0x1) {
@@ -98,6 +117,7 @@
* function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
*/
static bool gen_meta_key(const GrFragmentProcessor& fp,
+ GrGpu* gpu,
const GrShaderCaps& shaderCaps,
uint32_t transformKey,
GrProcessorKeyBuilder* b) {
@@ -110,7 +130,7 @@
return false;
}
- add_sampler_keys(b, fp, shaderCaps);
+ add_sampler_keys(b, fp, gpu, shaderCaps);
uint32_t* key = b->add32n(2);
key[0] = (classID << 16) | SkToU32(processorKeySize);
@@ -157,30 +177,33 @@
static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
const GrFragmentProcessor& fp,
+ GrGpu* gpu,
const GrShaderCaps& shaderCaps,
GrProcessorKeyBuilder* b) {
for (int i = 0; i < fp.numChildProcessors(); ++i) {
- if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), shaderCaps, b)) {
+ if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), gpu, shaderCaps, b)) {
return false;
}
}
fp.getGLSLProcessorKey(shaderCaps, b);
- return gen_meta_key(fp, shaderCaps, primProc.getTransformKey(fp.coordTransforms(),
- fp.numCoordTransforms()), b);
+ return gen_meta_key(fp, gpu, shaderCaps, primProc.getTransformKey(fp.coordTransforms(),
+ fp.numCoordTransforms()), b);
}
bool GrProgramDesc::Build(GrProgramDesc* desc,
const GrPrimitiveProcessor& primProc,
bool hasPointSize,
const GrPipeline& pipeline,
- const GrShaderCaps& shaderCaps) {
+ GrGpu* gpu) {
// The descriptor is used as a cache key. Thus when a field of the
// descriptor will not affect program generation (because of the attribute
// bindings in use or other descriptor field settings) it should be set
// to a canonical value to avoid duplicate programs with different keys.
+ const GrShaderCaps& shaderCaps = *gpu->caps()->shaderCaps();
+
GR_STATIC_ASSERT(0 == kProcessorKeysOffset % sizeof(uint32_t));
// Make room for everything up to the effect keys.
desc->key().reset();
@@ -196,7 +219,7 @@
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
- if (!gen_frag_proc_and_meta_keys(primProc, fp, shaderCaps, &b)) {
+ if (!gen_frag_proc_and_meta_keys(primProc, fp, gpu, shaderCaps, &b)) {
desc->key().reset();
return false;
}
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index f687876..0a634cb 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -36,14 +36,14 @@
* general draw information, as well as the specific color, geometry,
* and coverage stages which will be used to generate the GL Program for
* this optstate.
- * @param GrShaderCaps Capabilities of the shading language.
+ * @param GrGpu Ptr to the GrGpu object the program will be used with.
* @param GrProgramDesc The built and finalized descriptor
**/
static bool Build(GrProgramDesc*,
const GrPrimitiveProcessor&,
bool hasPointSize,
const GrPipeline&,
- const GrShaderCaps&);
+ GrGpu*);
// Returns this as a uint32_t array to be used as a key in the program cache.
const uint32_t* asKey() const {
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index aa5d847..eb920db 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -309,7 +309,7 @@
~ProgramCache();
void abandon();
- GrGLProgram* refProgram(const GrGLGpu*, const GrPrimitiveProcessor&,
+ GrGLProgram* refProgram(GrGLGpu*, const GrPrimitiveProcessor&,
const GrTextureProxy* const primProcProxies[],
const GrPipeline&, bool hasPointSize);
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index fa738cd..851640a 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -68,7 +68,7 @@
fMap.reset();
}
-GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu,
+GrGLProgram* GrGLGpu::ProgramCache::refProgram(GrGLGpu* gpu,
const GrPrimitiveProcessor& primProc,
const GrTextureProxy* const primProcProxies[],
const GrPipeline& pipeline,
@@ -79,7 +79,7 @@
// Get GrGLProgramDesc
GrProgramDesc desc;
- if (!GrProgramDesc::Build(&desc, primProc, isPoints, pipeline, *gpu->caps()->shaderCaps())) {
+ if (!GrProgramDesc::Build(&desc, primProc, isPoints, pipeline, gpu)) {
GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n");
return nullptr;
}
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
index 34f02bb..0eb4230 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
@@ -119,7 +119,7 @@
}
}
GrProgramDesc desc;
- if (!GrProgramDesc::Build(&desc, primProc, hasPoints, pipeline, *fGpu->caps()->shaderCaps())) {
+ if (!GrProgramDesc::Build(&desc, primProc, hasPoints, pipeline, fGpu)) {
return nullptr;
}
desc.finalize();
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index 19f9d72..0975025 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -8,9 +8,11 @@
#include "GrLatticeOp.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
+#include "GrGpu.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrResourceProvider.h"
+#include "GrResourceProviderPriv.h"
#include "GrSimpleMeshDrawOpHelper.h"
#include "GrVertexWriter.h"
#include "SkBitmap.h"
@@ -25,10 +27,11 @@
class LatticeGP : public GrGeometryProcessor {
public:
- static sk_sp<GrGeometryProcessor> Make(const GrTextureProxy* proxy,
+ static sk_sp<GrGeometryProcessor> Make(GrGpu* gpu,
+ const GrTextureProxy* proxy,
sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter) {
- return sk_sp<GrGeometryProcessor>(new LatticeGP(proxy, std::move(csxf), filter));
+ return sk_sp<GrGeometryProcessor>(new LatticeGP(gpu, proxy, std::move(csxf), filter));
}
const char* name() const override { return "LatticeGP"; }
@@ -86,10 +89,17 @@
}
private:
- LatticeGP(const GrTextureProxy* proxy, sk_sp<GrColorSpaceXform> csxf,
+ LatticeGP(GrGpu* gpu, const GrTextureProxy* proxy, sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter)
: INHERITED(kLatticeGP_ClassID), fColorSpaceXform(std::move(csxf)) {
- fSampler.reset(proxy->textureType(), proxy->config(), filter);
+
+ GrSamplerState samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp,
+ filter);
+ uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(samplerState,
+ proxy->backendFormat());
+
+ fSampler.reset(proxy->textureType(), proxy->config(), samplerState,
+ extraSamplerKey);
this->setTextureSamplerCnt(1);
fInPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
@@ -193,7 +203,8 @@
private:
void onPrepareDraws(Target* target) override {
- auto gp = LatticeGP::Make(fProxy.get(), fColorSpaceXform, fFilter);
+ GrGpu* gpu = target->resourceProvider()->priv().gpu();
+ auto gp = LatticeGP::Make(gpu, fProxy.get(), fColorSpaceXform, fFilter);
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index 2849e29..f893a91 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -472,10 +472,11 @@
static sk_sp<GrGeometryProcessor> Make(const VertexSpec& vertexSpec, const GrShaderCaps& caps,
GrTextureType textureType, GrPixelConfig textureConfig,
- const GrSamplerState::Filter filter,
+ const GrSamplerState& samplerState,
+ uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(
- vertexSpec, caps, textureType, textureConfig, filter,
+ vertexSpec, caps, textureType, textureConfig, samplerState, extraSamplerKey,
std::move(textureColorSpaceXform)));
}
@@ -634,11 +635,12 @@
QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec, const GrShaderCaps& caps,
GrTextureType textureType, GrPixelConfig textureConfig,
- GrSamplerState::Filter filter,
+ const GrSamplerState& samplerState,
+ uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform)
: INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
- , fSampler(textureType, textureConfig, filter) {
+ , fSampler(textureType, textureConfig, samplerState, extraSamplerKey) {
SkASSERT(spec.hasVertexColors() && spec.hasLocalCoords());
this->initializeAttrs(spec);
this->setTextureSamplerCnt(1);
@@ -696,8 +698,10 @@
sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec, const GrShaderCaps& caps,
GrTextureType textureType, GrPixelConfig textureConfig,
- const GrSamplerState::Filter filter, sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
- return QuadPerEdgeAAGeometryProcessor::Make(spec, caps, textureType, textureConfig, filter,
+ const GrSamplerState& samplerState, uint32_t extraSamplerKey,
+ sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
+ return QuadPerEdgeAAGeometryProcessor::Make(spec, caps, textureType, textureConfig,
+ samplerState, extraSamplerKey,
std::move(textureColorSpaceXform));
}
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index 9d1b650..68e798c 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -69,7 +69,8 @@
sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec,
const GrShaderCaps& caps, GrTextureType textureType, GrPixelConfig textureConfig,
- const GrSamplerState::Filter filter, sk_sp<GrColorSpaceXform> textureColorSpaceXform);
+ const GrSamplerState& samplerState, uint32_t extraSamplerKey,
+ sk_sp<GrColorSpaceXform> textureColorSpaceXform);
// Fill vertices with the vertex data needed to represent the given quad. The device position,
// local coords, vertex color, domain, and edge coefficients will be written and/or computed
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 6fe8c15..255f937 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -13,12 +13,14 @@
#include "GrContextPriv.h"
#include "GrDrawOpTest.h"
#include "GrGeometryProcessor.h"
+#include "GrGpu.h"
#include "GrMemoryPool.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrQuad.h"
#include "GrQuadPerEdgeAA.h"
#include "GrResourceProvider.h"
+#include "GrResourceProviderPriv.h"
#include "GrShaderCaps.h"
#include "GrTexture.h"
#include "GrTexturePriv.h"
@@ -352,9 +354,17 @@
VertexSpec vertexSpec(quadType, wideColor ? ColorType::kHalf : ColorType::kByte,
GrQuadType::kRect, /* hasLocal */ true, domain, aaType);
+ GrSamplerState samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp,
+ this->filter());
+ GrGpu* gpu = target->resourceProvider()->priv().gpu();
+ uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
+ samplerState, fProxies[0].fProxy->backendFormat());
+
sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeTexturedProcessor(
vertexSpec, *target->caps().shaderCaps(),
- textureType, config, this->filter(), std::move(fTextureColorSpaceXform));
+ textureType, config, samplerState, extraSamplerKey,
+ std::move(fTextureColorSpaceXform));
+
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
diff --git a/src/gpu/vk/GrVkDescriptorSetManager.cpp b/src/gpu/vk/GrVkDescriptorSetManager.cpp
index b032584..ba0a060 100644
--- a/src/gpu/vk/GrVkDescriptorSetManager.cpp
+++ b/src/gpu/vk/GrVkDescriptorSetManager.cpp
@@ -23,31 +23,56 @@
}
visibilities.push_back(geomStages);
visibilities.push_back(kFragment_GrShaderFlag);
- return new GrVkDescriptorSetManager(gpu, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, visibilities);
+
+ SkTArray<const GrVkSampler*> samplers;
+ return new GrVkDescriptorSetManager(gpu, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, visibilities,
+ samplers);
}
GrVkDescriptorSetManager* GrVkDescriptorSetManager::CreateSamplerManager(
GrVkGpu* gpu, VkDescriptorType type, const GrVkUniformHandler& uniformHandler) {
SkSTArray<4, uint32_t> visibilities;
+ SkSTArray<4, const GrVkSampler*> immutableSamplers;
SkASSERT(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
for (int i = 0 ; i < uniformHandler.numSamplers(); ++i) {
visibilities.push_back(uniformHandler.samplerVisibility(i));
+ immutableSamplers.push_back(uniformHandler.immutableSampler(i));
}
- return CreateSamplerManager(gpu, type, visibilities);
+ return new GrVkDescriptorSetManager(gpu, type, visibilities, immutableSamplers);
}
GrVkDescriptorSetManager* GrVkDescriptorSetManager::CreateSamplerManager(
GrVkGpu* gpu, VkDescriptorType type, const SkTArray<uint32_t>& visibilities) {
- return new GrVkDescriptorSetManager(gpu, type, visibilities);
+ SkSTArray<4, const GrVkSampler*> immutableSamplers;
+ SkASSERT(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
+ for (int i = 0 ; i < visibilities.count(); ++i) {
+ immutableSamplers.push_back(nullptr);
+ }
+ return new GrVkDescriptorSetManager(gpu, type, visibilities, immutableSamplers);
}
-GrVkDescriptorSetManager::GrVkDescriptorSetManager(GrVkGpu* gpu,
- VkDescriptorType type,
- const SkTArray<uint32_t>& visibilities)
- : fPoolManager(type, gpu, visibilities) {
+GrVkDescriptorSetManager::GrVkDescriptorSetManager(
+ GrVkGpu* gpu, VkDescriptorType type,
+ const SkTArray<uint32_t>& visibilities,
+ const SkTArray<const GrVkSampler*>& immutableSamplers)
+ : fPoolManager(type, gpu, visibilities, immutableSamplers) {
+#ifdef SK_DEBUG
+ if (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
+ SkASSERT(visibilities.count() == immutableSamplers.count());
+ } else {
+ SkASSERT(immutableSamplers.count() == 0);
+ }
+#endif
for (int i = 0; i < visibilities.count(); ++i) {
fBindingVisibilities.push_back(visibilities[i]);
}
+ for (int i = 0; i < immutableSamplers.count(); ++i) {
+ const GrVkSampler* sampler = immutableSamplers[i];
+ if (sampler) {
+ sampler->ref();
+ }
+ fImmutableSamplers.push_back(sampler);
+ }
}
const GrVkDescriptorSet* GrVkDescriptorSetManager::getDescriptorSet(GrVkGpu* gpu,
@@ -79,6 +104,13 @@
fFreeSets[i]->unref(gpu);
}
fFreeSets.reset();
+
+ for (int i = 0; i < fImmutableSamplers.count(); ++i) {
+ if (fImmutableSamplers[i]) {
+ fImmutableSamplers[i]->unref(gpu);
+ }
+ }
+ fImmutableSamplers.reset();
}
void GrVkDescriptorSetManager::abandon() {
@@ -88,6 +120,13 @@
fFreeSets[i]->unrefAndAbandon();
}
fFreeSets.reset();
+
+ for (int i = 0; i < fImmutableSamplers.count(); ++i) {
+ if (fImmutableSamplers[i]) {
+ fImmutableSamplers[i]->unrefAndAbandon();
+ }
+ }
+ fImmutableSamplers.reset();
}
bool GrVkDescriptorSetManager::isCompatible(VkDescriptorType type,
@@ -102,7 +141,8 @@
return false;
}
for (int i = 0; i < uniHandler->numSamplers(); ++i) {
- if (uniHandler->samplerVisibility(i) != fBindingVisibilities[i]) {
+ if (uniHandler->samplerVisibility(i) != fBindingVisibilities[i] ||
+ uniHandler->immutableSampler(i) != fImmutableSamplers[i]) {
return false;
}
}
@@ -121,7 +161,7 @@
return false;
}
for (int i = 0; i < visibilities.count(); ++i) {
- if (visibilities[i] != fBindingVisibilities[i]) {
+ if (visibilities[i] != fBindingVisibilities[i] || fImmutableSamplers[i] != nullptr) {
return false;
}
}
@@ -149,7 +189,8 @@
GrVkDescriptorSetManager::DescriptorPoolManager::DescriptorPoolManager(
VkDescriptorType type,
GrVkGpu* gpu,
- const SkTArray<uint32_t>& visibilities)
+ const SkTArray<uint32_t>& visibilities,
+ const SkTArray<const GrVkSampler*>& immutableSamplers)
: fDescType(type)
, fCurrentDescriptorCount(0)
, fPool(nullptr) {
@@ -166,7 +207,13 @@
dsSamplerBindings[i].descriptorType = type;
dsSamplerBindings[i].descriptorCount = 1;
dsSamplerBindings[i].stageFlags = visibility_to_vk_stage_flags(visibility);
- dsSamplerBindings[i].pImmutableSamplers = nullptr;
+ if (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER == type) {
+ if (immutableSamplers[i]) {
+ dsSamplerBindings[i].pImmutableSamplers = immutableSamplers[i]->samplerPtr();
+ } else {
+ dsSamplerBindings[i].pImmutableSamplers = nullptr;
+ }
+ }
}
VkDescriptorSetLayoutCreateInfo dsSamplerLayoutCreateInfo;
diff --git a/src/gpu/vk/GrVkDescriptorSetManager.h b/src/gpu/vk/GrVkDescriptorSetManager.h
index 9afb272..f9ee7b2 100644
--- a/src/gpu/vk/GrVkDescriptorSetManager.h
+++ b/src/gpu/vk/GrVkDescriptorSetManager.h
@@ -12,6 +12,7 @@
#include "GrResourceHandle.h"
#include "GrVkDescriptorPool.h"
+#include "GrVkSampler.h"
#include "SkRefCnt.h"
#include "SkTArray.h"
@@ -51,7 +52,8 @@
private:
struct DescriptorPoolManager {
DescriptorPoolManager(VkDescriptorType type, GrVkGpu* gpu,
- const SkTArray<uint32_t>& visibilities);
+ const SkTArray<uint32_t>& visibilities,
+ const SkTArray<const GrVkSampler*>& immutableSamplers);
~DescriptorPoolManager() {
@@ -83,12 +85,14 @@
GrVkDescriptorSetManager(GrVkGpu* gpu,
VkDescriptorType,
- const SkTArray<uint32_t>& visibilities);
+ const SkTArray<uint32_t>& visibilities,
+ const SkTArray<const GrVkSampler*>& immutableSamplers);
DescriptorPoolManager fPoolManager;
SkTArray<const GrVkDescriptorSet*, true> fFreeSets;
SkSTArray<4, uint32_t> fBindingVisibilities;
+ SkSTArray<4, const GrVkSampler*> fImmutableSamplers;
};
#endif
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 87af8dc..ca48271 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -2165,3 +2165,17 @@
fDrawables.emplace_back(std::move(drawable));
}
+uint32_t GrVkGpu::getExtraSamplerKeyForProgram(const GrSamplerState& samplerState,
+ const GrBackendFormat& format) {
+ const GrVkYcbcrConversionInfo* ycbcrInfo = format.getVkYcbcrConversionInfo();
+ SkASSERT(ycbcrInfo);
+ if (!ycbcrInfo->isValid()) {
+ return 0;
+ }
+
+ const GrVkSampler* sampler = this->resourceProvider().findOrCreateCompatibleSampler(
+ samplerState, *ycbcrInfo);
+
+ return sampler->uniqueID();
+}
+
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 298c4c5..c195d3b 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -156,6 +156,9 @@
VkDeviceSize dstOffset, VkDeviceSize size);
bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
+ uint32_t getExtraSamplerKeyForProgram(const GrSamplerState&,
+ const GrBackendFormat& format) override;
+
private:
GrVkGpu(GrContext*, const GrContextOptions&, const GrVkBackendContext&,
sk_sp<const GrVkInterface>);
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 53a5a3a..9f18b1a 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -37,7 +37,7 @@
const UniformInfoArray& uniforms,
uint32_t geometryUniformSize,
uint32_t fragmentUniformSize,
- uint32_t numSamplers,
+ const UniformInfoArray& samplers,
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
@@ -60,7 +60,13 @@
fGeometryUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, geometryUniformSize));
fFragmentUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, fragmentUniformSize));
- fNumSamplers = numSamplers;
+ fNumSamplers = samplers.count();
+
+ for (int i = 0; i < fNumSamplers; ++i) {
+ // We store the immutable samplers here and take ownership of the ref from the
+ // GrVkUnformHandler.
+ fImmutableSamplers.push_back(samplers[i].fImmutableSampler);
+ }
}
GrVkPipelineState::~GrVkPipelineState() {
@@ -243,8 +249,14 @@
GrVkTexture* texture = samplerBindings[i].fTexture;
const GrVkImageView* textureView = texture->textureView();
- GrVkSampler* sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(
+ const GrVkSampler* sampler = nullptr;
+ if (fImmutableSamplers[i]) {
+ sampler = fImmutableSamplers[i];
+ } else {
+ sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(
state, texture->ycbcrConversionInfo());
+ }
+ SkASSERT(sampler);
VkDescriptorImageInfo imageInfo;
memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
@@ -268,7 +280,9 @@
GR_VK_CALL(gpu->vkInterface(),
UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr));
commandBuffer->addResource(sampler);
- sampler->unref(gpu);
+ if (!fImmutableSamplers[i]) {
+ sampler->unref(gpu);
+ }
commandBuffer->addResource(samplerBindings[i].fTexture->textureView());
commandBuffer->addResource(samplerBindings[i].fTexture->resource());
}
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index 232b4f3..e8a1b39 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -49,7 +49,7 @@
const UniformInfoArray& uniforms,
uint32_t geometryUniformSize,
uint32_t fragmentUniformSize,
- uint32_t numSamplers,
+ const UniformInfoArray& samplers,
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
@@ -136,6 +136,8 @@
const GrVkDescriptorSetManager::Handle fSamplerDSHandle;
+ SkSTArray<4, const GrVkSampler*> fImmutableSamplers;
+
std::unique_ptr<GrVkUniformBuffer> fGeometryUniformBuffer;
std::unique_ptr<GrVkUniformBuffer> fFragmentUniformBuffer;
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 486bd73..e2ccbda 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -197,7 +197,7 @@
fUniformHandler.fUniforms,
fUniformHandler.fCurrentGeometryUBOOffset,
fUniformHandler.fCurrentFragmentUBOOffset,
- (uint32_t)fUniformHandler.numSamplers(),
+ fUniformHandler.fSamplers,
std::move(fGeometryProcessor),
std::move(fXferProcessor),
std::move(fFragmentProcessors),
@@ -228,9 +228,9 @@
const GrPipeline& pipeline,
const GrStencilSettings& stencil,
GrPrimitiveType primitiveType,
- const GrShaderCaps& caps) {
+ GrVkGpu* gpu) {
if (!INHERITED::Build(desc, primProc, primitiveType == GrPrimitiveType::kPoints, pipeline,
- caps)) {
+ gpu)) {
return false;
}
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.h b/src/gpu/vk/GrVkPipelineStateBuilder.h
index 8f7b00b..b70539e 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.h
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.h
@@ -43,7 +43,7 @@
const GrPipeline&,
const GrStencilSettings&,
GrPrimitiveType primitiveType,
- const GrShaderCaps&);
+ GrVkGpu* gpu);
private:
typedef GrProgramDesc INHERITED;
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index bb07827..7b0f9f8 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -96,7 +96,7 @@
// Get GrVkProgramDesc
GrVkPipelineStateBuilder::Desc desc;
if (!GrVkPipelineStateBuilder::Desc::Build(&desc, primProc, pipeline, stencil, primitiveType,
- *fGpu->caps()->shaderCaps())) {
+ fGpu)) {
GrCapsDebugf(fGpu->caps(), "Failed to build vk program descriptor!\n");
return nullptr;
}
diff --git a/src/gpu/vk/GrVkSampler.h b/src/gpu/vk/GrVkSampler.h
index 713bdbc..9d74d8f 100644
--- a/src/gpu/vk/GrVkSampler.h
+++ b/src/gpu/vk/GrVkSampler.h
@@ -12,6 +12,7 @@
#include "GrVkResource.h"
#include "GrVkSamplerYcbcrConversion.h"
+#include "SkAtomics.h"
#include "SkOpts.h"
#include "vk/GrVkTypes.h"
@@ -23,6 +24,7 @@
static GrVkSampler* Create(GrVkGpu* gpu, const GrSamplerState&, const GrVkYcbcrConversionInfo&);
VkSampler sampler() const { return fSampler; }
+ const VkSampler* samplerPtr() const { return &fSampler; }
struct Key {
Key(uint16_t samplerKey, const GrVkSamplerYcbcrConversion::Key& ycbcrKey) {
@@ -49,6 +51,8 @@
return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
}
+ uint32_t uniqueID() const { return fUniqueID; }
+
#ifdef SK_TRACE_VK_RESOURCES
void dumpInfo() const override {
SkDebugf("GrVkSampler: %d (%d refs)\n", fSampler, this->getRefCnt());
@@ -57,14 +61,28 @@
private:
GrVkSampler(VkSampler sampler, GrVkSamplerYcbcrConversion* ycbcrConversion, Key key)
- : INHERITED(), fSampler(sampler), fYcbcrConversion(ycbcrConversion), fKey(key) {}
+ : INHERITED()
+ , fSampler(sampler)
+ , fYcbcrConversion(ycbcrConversion)
+ , fKey(key)
+ , fUniqueID(GenID()) {}
void freeGPUData(const GrVkGpu* gpu) const override;
void abandonGPUData() const override;
+ static uint32_t GenID() {
+ static int32_t gUniqueID = SK_InvalidUniqueID;
+ uint32_t id;
+ do {
+ id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
+ } while (id == SK_InvalidUniqueID);
+ return id;
+ }
+
VkSampler fSampler;
GrVkSamplerYcbcrConversion* fYcbcrConversion;
Key fKey;
+ uint32_t fUniqueID;
typedef GrVkResource INHERITED;
};