Add a "conservative raster" flag to GrPipeline and implement in Vulkan
This flag is not yet used or tested. Both will come next when we
enable mixed sampled ccpr.
Change-Id: Ic242010b1f0b8d81b83731960283e4231f301fd1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252258
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index dd2aa36..4941e85 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -26,6 +26,7 @@
fMultisampleDisableSupport = false;
fInstanceAttribSupport = false;
fMixedSamplesSupport = false;
+ fConservativeRasterSupport = false;
fMSAAResolvesAutomatically = false;
fUsePrimitiveRestart = false;
fPreferClientSideDynamicBuffers = false;
@@ -174,6 +175,7 @@
writer->appendBool("Multisample disable support", fMultisampleDisableSupport);
writer->appendBool("Instance Attrib Support", fInstanceAttribSupport);
writer->appendBool("Mixed Samples Support", fMixedSamplesSupport);
+ writer->appendBool("Conservative Raster Support", fConservativeRasterSupport);
writer->appendBool("MSAA Resolves Automatically", fMSAAResolvesAutomatically);
writer->appendBool("Use primitive restart", fUsePrimitiveRestart);
writer->appendBool("Prefer client-side dynamic buffers", fPreferClientSideDynamicBuffers);
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index 27f0ec4..23d9f44 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -48,6 +48,7 @@
bool multisampleDisableSupport() const { return fMultisampleDisableSupport; }
bool instanceAttribSupport() const { return fInstanceAttribSupport; }
bool mixedSamplesSupport() const { return fMixedSamplesSupport; }
+ bool conservativeRasterSupport() const { return fConservativeRasterSupport; }
// This flag indicates that we never have to resolve MSAA. In practice, it means that we have
// an MSAA-render-to-texture extension: Any render target we create internally will use the
// extension, and any wrapped render target is the client's responsibility.
@@ -465,6 +466,7 @@
bool fMultisampleDisableSupport : 1;
bool fInstanceAttribSupport : 1;
bool fMixedSamplesSupport : 1;
+ bool fConservativeRasterSupport : 1;
bool fMSAAResolvesAutomatically : 1;
bool fUsePrimitiveRestart : 1;
bool fPreferClientSideDynamicBuffers : 1;
diff --git a/src/gpu/GrOpsRenderPass.cpp b/src/gpu/GrOpsRenderPass.cpp
index 1b8ebea..680c013 100644
--- a/src/gpu/GrOpsRenderPass.cpp
+++ b/src/gpu/GrOpsRenderPass.cpp
@@ -18,6 +18,7 @@
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrRenderTargetPriv.h"
+#include "src/gpu/GrStencilAttachment.h"
#include "src/gpu/GrTexturePriv.h"
void GrOpsRenderPass::clear(const GrFixedClip& clip, const SkPMColor4f& color) {
@@ -44,6 +45,8 @@
#ifdef SK_DEBUG
SkASSERT(!programInfo.primProc().hasInstanceAttributes() ||
this->gpu()->caps()->instanceAttribSupport());
+ SkASSERT(!programInfo.pipeline().usesConservativeRaster() ||
+ this->gpu()->caps()->conservativeRasterSupport());
programInfo.compatibleWithMeshes(meshes, meshCount);
programInfo.checkAllInstantiated();
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index a246c85..8f3eaa9 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -99,7 +99,15 @@
}
}
-uint32_t GrPipeline::getBlendInfoKey() const {
+void GrPipeline::genKey(GrProcessorKeyBuilder* b) const {
+ // Currently kHWAntialias and kSnapVerticesToPixelCenters don't affect the pipeline key:
+ // You can't disable msaa on vulkan or metal, and kSnapVerticesToPixelCenters is implemented
+ // in a shader. Ideally, the client would not set kHWAntialias without
+ // multisampleDisableSupport, but this is not currently the case.
+ constexpr static uint32_t kFlagsMask = ~(uint32_t)(
+ InputFlags::kHWAntialias | InputFlags::kSnapVerticesToPixelCenters);
+ b->add32((uint32_t)fFlags & kFlagsMask);
+
const GrXferProcessor::BlendInfo& blendInfo = this->getXferProcessor().getBlendInfo();
static const uint32_t kBlendWriteShift = 1;
@@ -107,10 +115,10 @@
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));
+ uint32_t blendKey = blendInfo.fWriteColor;
+ blendKey |= (blendInfo.fSrcBlend << kBlendWriteShift);
+ blendKey |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
+ blendKey |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
- return key;
+ b->add32(blendKey);
}
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index ea409c1..1d36bc5 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -50,9 +50,16 @@
*/
kHWAntialias = (1 << 0),
/**
+ * Cause every pixel to be rasterized that is touched by the triangle anywhere (not just at
+ * pixel center). Additionally, if using MSAA, the sample mask will always have 100%
+ * coverage.
+ * NOTE: The primitive type must be a triangle type.
+ */
+ kConservativeRaster = (1 << 1),
+ /**
* Modifies the vertex shader so that vertices will be positioned at pixel centers.
*/
- kSnapVerticesToPixelCenters = (1 << 1), // This value must be last. (See kLastInputFlag.)
+ kSnapVerticesToPixelCenters = (1 << 2), // This value must be last. (See kLastInputFlag.)
};
struct InitArgs {
@@ -182,9 +189,10 @@
const GrWindowRectsState& getWindowRectsState() const { return fWindowRectsState; }
- bool isHWAntialiasState() const { return SkToBool(fFlags & InputFlags::kHWAntialias); }
+ bool isHWAntialiasState() const { return fFlags & InputFlags::kHWAntialias; }
+ bool usesConservativeRaster() const { return fFlags & InputFlags::kConservativeRaster; }
bool snapVerticesToPixelCenters() const {
- return SkToBool(fFlags & InputFlags::kSnapVerticesToPixelCenters);
+ return fFlags & InputFlags::kSnapVerticesToPixelCenters;
}
bool hasStencilClip() const {
return SkToBool(fFlags & Flags::kHasStencilClip);
@@ -197,7 +205,7 @@
GrXferBarrierType xferBarrierType(GrTexture*, const GrCaps&) const;
// Used by Vulkan and Metal to cache their respective pipeline objects
- uint32_t getBlendInfoKey() const;
+ void genKey(GrProcessorKeyBuilder*) const;
const GrSwizzle& outputSwizzle() const { return fOutputSwizzle; }
diff --git a/src/gpu/GrProgramInfo.cpp b/src/gpu/GrProgramInfo.cpp
index 3391b61..0adecb0 100644
--- a/src/gpu/GrProgramInfo.cpp
+++ b/src/gpu/GrProgramInfo.cpp
@@ -115,6 +115,12 @@
for (int i = 0; i < meshCount; ++i) {
SkASSERT(fPrimProc.hasVertexAttributes() == meshes[i].hasVertexData());
SkASSERT(fPrimProc.hasInstanceAttributes() == meshes[i].hasInstanceData());
+ if (fPipeline.usesConservativeRaster()) {
+ // Conservative raster, by default, only supports triangles. Implementations can
+ // optionally indicate that they also support points and lines, but we don't currently
+ // query or track that info.
+ SkASSERT(GrIsPrimTypeTris(meshes[i].primitiveType()));
+ }
}
}
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 854d50e..7a20531 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -457,6 +457,8 @@
GrProcessorKeyBuilder b(&desc->key());
+ programInfo.pipeline().genKey(&b);
+
int keyLength = desc->key().count();
SkASSERT(0 == (keyLength % 4));
desc->fShaderKeyLength = SkToU32(keyLength);
@@ -469,8 +471,6 @@
b.add32((uint32_t)programInfo.pipeline().isStencilEnabled());
// Stencil samples don't seem to be tracked in the MTLRenderPipeline
- b.add32(programInfo.pipeline().getBlendInfoKey());
-
b.add32((uint32_t)primitiveType);
return true;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 4e6c77c..6d19fc6 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -501,6 +501,10 @@
fSampleLocationsSupport = true;
}
+ if (extensions.hasExtension(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, 1)) {
+ fConservativeRasterSupport = true;
+ }
+
// We could actually query and get a max size for each config, however maxImageDimension2D will
// give the minimum max size across all configs. So for simplicity we will use that for now.
fMaxRenderTargetSize = SkTMin(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index 6868ff5..effcfba 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -482,6 +482,19 @@
rasterInfo->lineWidth = 1.0f;
}
+static void setup_conservative_raster_info(
+ VkPipelineRasterizationConservativeStateCreateInfoEXT* conservativeRasterInfo) {
+ memset(conservativeRasterInfo, 0,
+ sizeof(VkPipelineRasterizationConservativeStateCreateInfoEXT));
+ conservativeRasterInfo->sType =
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT;
+ conservativeRasterInfo->pNext = nullptr;
+ conservativeRasterInfo->flags = 0;
+ conservativeRasterInfo->conservativeRasterizationMode =
+ VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
+ conservativeRasterInfo->extraPrimitiveOverestimationSize = 0;
+}
+
static void setup_dynamic_state(VkPipelineDynamicStateCreateInfo* dynamicInfo,
VkDynamicState* dynamicStates) {
memset(dynamicInfo, 0, sizeof(VkPipelineDynamicStateCreateInfo));
@@ -531,6 +544,14 @@
VkPipelineRasterizationStateCreateInfo rasterInfo;
setup_raster_state(programInfo.pipeline(), gpu->caps(), &rasterInfo);
+ VkPipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterInfo;
+ if (programInfo.pipeline().usesConservativeRaster()) {
+ SkASSERT(gpu->caps()->conservativeRasterSupport());
+ setup_conservative_raster_info(&conservativeRasterInfo);
+ conservativeRasterInfo.pNext = rasterInfo.pNext;
+ rasterInfo.pNext = &conservativeRasterInfo;
+ }
+
VkDynamicState dynamicStates[3];
VkPipelineDynamicStateCreateInfo dynamicInfo;
setup_dynamic_state(&dynamicInfo, dynamicStates);
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 52c7c52..0cd3c8b 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -337,6 +337,8 @@
GrProcessorKeyBuilder b(&desc->key());
+ programInfo.pipeline().genKey(&b);
+
b.add32(GrVkGpu::kShader_PersistentCacheKeyType);
int keyLength = desc->key().count();
SkASSERT(0 == (keyLength % 4));
@@ -347,8 +349,6 @@
stencil.genKey(&b);
- b.add32(programInfo.pipeline().getBlendInfoKey());
-
b.add32((uint32_t)primitiveType);
return true;