Implement multisample "disable" in Vulkan
Emulates multisample disable by colocating all samples at pixel
center. Multisample disable will be required in order for us to
integrate mixed samples.
Change-Id: I52b67e22c979584b5d001e737a08eef07bd7ffe2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/253282
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index a246c85..c03a8dd 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 GrCaps& caps) const {
+ // kSnapVerticesToPixelCenters is implemented in a shader.
+ InputFlags ignoredFlags = InputFlags::kSnapVerticesToPixelCenters;
+ if (!caps.multisampleDisableSupport()) {
+ // Ganesh will omit kHWAntialias regardless multisampleDisableSupport.
+ ignoredFlags |= InputFlags::kHWAntialias;
+ }
+ b->add32((uint32_t)fFlags & ~(uint32_t)ignoredFlags);
+
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..7854e82 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -197,7 +197,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 GrCaps&) const;
const GrSwizzle& outputSwizzle() const { return fOutputSwizzle; }
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 8e78d0c..63aad6c 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -468,7 +468,7 @@
b.add32((uint32_t)programInfo.pipeline().isStencilEnabled());
// Stencil samples don't seem to be tracked in the MTLRenderPipeline
- b.add32(programInfo.pipeline().getBlendInfoKey());
+ programInfo.pipeline().genKey(&b, *gpu->caps());
b.add32((uint32_t)programInfo.primitiveType());
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index cf21e67..4089ed5 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -461,29 +461,6 @@
}
}
-int get_max_sample_count(VkSampleCountFlags flags) {
- SkASSERT(flags & VK_SAMPLE_COUNT_1_BIT);
- if (!(flags & VK_SAMPLE_COUNT_2_BIT)) {
- return 0;
- }
- if (!(flags & VK_SAMPLE_COUNT_4_BIT)) {
- return 2;
- }
- if (!(flags & VK_SAMPLE_COUNT_8_BIT)) {
- return 4;
- }
- if (!(flags & VK_SAMPLE_COUNT_16_BIT)) {
- return 8;
- }
- if (!(flags & VK_SAMPLE_COUNT_32_BIT)) {
- return 16;
- }
- if (!(flags & VK_SAMPLE_COUNT_64_BIT)) {
- return 32;
- }
- return 64;
-}
-
void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
VkPhysicalDevice physDev,
const VkPhysicalDeviceProperties& properties,
@@ -497,6 +474,11 @@
static const uint32_t kMaxVertexAttributes = 64;
fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes);
+ if (extensions.hasExtension(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, 1)) {
+ // We "disable" multisample by colocating all samples at pixel center.
+ fMultisampleDisableSupport = 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);
@@ -1187,12 +1169,8 @@
if (flags & VK_SAMPLE_COUNT_16_BIT) {
fColorSampleCounts.push_back(16);
}
- if (flags & VK_SAMPLE_COUNT_32_BIT) {
- fColorSampleCounts.push_back(32);
- }
- if (flags & VK_SAMPLE_COUNT_64_BIT) {
- fColorSampleCounts.push_back(64);
- }
+ // Standard sample locations are not defined for more than 16 samples, and we don't need more
+ // than 16. Omit 32 and 64.
}
void GrVkCaps::FormatInfo::init(const GrVkInterface* interface,
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index 8e46591..da2765c 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -294,6 +294,29 @@
multisampleInfo->alphaToOneEnable = VK_FALSE;
}
+static void setup_all_sample_locations_at_pixel_center(
+ const GrProgramInfo& programInfo,
+ VkPipelineSampleLocationsStateCreateInfoEXT* sampleLocations) {
+ constexpr static VkSampleLocationEXT kCenteredSampleLocations[16] = {
+ {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f},
+ {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}, {.5f,.5f}};
+ memset(sampleLocations, 0, sizeof(VkPipelineSampleLocationsStateCreateInfoEXT));
+ sampleLocations->sType = VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT;
+ sampleLocations->pNext = nullptr;
+ sampleLocations->sampleLocationsEnable = VK_TRUE;
+ sampleLocations->sampleLocationsInfo.sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT;
+ sampleLocations->sampleLocationsInfo.pNext = nullptr;
+ SkAssertResult(GrSampleCountToVkSampleCount(
+ programInfo.numSamples(),
+ &sampleLocations->sampleLocationsInfo.sampleLocationsPerPixel));
+ sampleLocations->sampleLocationsInfo.sampleLocationGridSize.width = 1;
+ sampleLocations->sampleLocationsInfo.sampleLocationGridSize.height = 1;
+ SkASSERT(programInfo.numSamples() < (int)SK_ARRAY_COUNT(kCenteredSampleLocations));
+ sampleLocations->sampleLocationsInfo.sampleLocationsCount = std::min(
+ programInfo.numSamples(), (int)SK_ARRAY_COUNT(kCenteredSampleLocations));
+ sampleLocations->sampleLocationsInfo.pSampleLocations = kCenteredSampleLocations;
+}
+
static VkBlendFactor blend_coeff_to_vk_blend(GrBlendCoeff coeff) {
static const VkBlendFactor gTable[] = {
VK_BLEND_FACTOR_ZERO, // kZero_GrBlendCoeff
@@ -523,6 +546,15 @@
VkPipelineMultisampleStateCreateInfo multisampleInfo;
setup_multisample_state(programInfo, gpu->caps(), &multisampleInfo);
+ VkPipelineSampleLocationsStateCreateInfoEXT sampleLocations;
+ if (gpu->caps()->multisampleDisableSupport()) {
+ if (programInfo.numSamples() > 1 && !programInfo.pipeline().isHWAntialiasState()) {
+ setup_all_sample_locations_at_pixel_center(programInfo, &sampleLocations);
+ sampleLocations.pNext = multisampleInfo.pNext;
+ multisampleInfo.pNext = &sampleLocations;
+ }
+ }
+
// We will only have one color attachment per pipeline.
VkPipelineColorBlendAttachmentState attachmentStates[1];
VkPipelineColorBlendStateCreateInfo colorBlendInfo;
diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
index 578bdf1..ca72313 100644
--- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp
+++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp
@@ -346,7 +346,7 @@
stencil.genKey(&b);
- b.add32(programInfo.pipeline().getBlendInfoKey());
+ programInfo.pipeline().genKey(&b, *gpu->caps());
// Vulkan requires the full primitive type as part of its key
b.add32((uint32_t)programInfo.primitiveType());
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index a49dcea..4fb13ed 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -96,12 +96,6 @@
case 16:
*vkSamples = VK_SAMPLE_COUNT_16_BIT;
return true;
- case 32:
- *vkSamples = VK_SAMPLE_COUNT_32_BIT;
- return true;
- case 64:
- *vkSamples = VK_SAMPLE_COUNT_64_BIT;
- return true;
default:
return false;
}