Reland "Implement sample mask and sample locations support in Vulkan"
This is a reland of 8b915a0c27652d5932ff4013ba98c57baf553c3c
Original change's description:
> Implement sample mask and sample locations support in Vulkan
>
> Change-Id: I372695ec5360def42a8a997675993264740b0da4
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252038
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Chris Dalton <csmartdalton@google.com>
TBR=ethannicholas@google.com
Change-Id: I20de36719db52ad4dfc5290101d48a8fd9601c11
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252936
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index f5919b4..b6163f0 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -291,7 +291,8 @@
if (CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()) {
const SkTArray<SkPoint>& sampleLocations = fProgramBuilder->getSampleLocations();
- this->definitions().append("const float2 _sampleOffsets[] = float2[](");
+ this->definitions().appendf("const float2 _sampleOffsets[%i] = float2[%i](",
+ sampleLocations.count(), sampleLocations.count());
for (int i = 0; i < sampleLocations.count(); ++i) {
SkPoint offset = sampleLocations[i] - SkPoint::Make(.5f, .5f);
if (kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) {
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index a99f7f4..2e80834 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -473,6 +473,10 @@
static const uint32_t kMaxVertexAttributes = 64;
fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes);
+ if (properties.limits.standardSampleLocations) {
+ fSampleLocationsSupport = true;
+ }
+
if (extensions.hasExtension(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, 1)) {
// We "disable" multisample by colocating all samples at pixel center.
fMultisampleDisableSupport = true;
@@ -548,7 +552,7 @@
// to be true with Vulkan as well.
shaderCaps->fPreferFlatInterpolation = kQualcomm_VkVendor != properties.vendorID;
- // GrShaderCaps
+ shaderCaps->fSampleMaskSupport = true;
shaderCaps->fShaderDerivativeSupport = true;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index c0d6d1f..ea68320 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1814,6 +1814,59 @@
return GrBackendTexture(dimensions.width(), dimensions.height(), info);
}
+void GrVkGpu::querySampleLocations(GrRenderTarget* renderTarget,
+ SkTArray<SkPoint>* sampleLocations) {
+ // In Vulkan, sampleLocationsSupport() means that the platform uses the standard sample
+ // locations defined by the spec.
+ SkASSERT(this->caps()->sampleLocationsSupport());
+ static SkPoint kStandardSampleLocations_1[1] = {
+ {0.5f, 0.5f}};
+ static SkPoint kStandardSampleLocations_2[2] = {
+ {0.75f, 0.75f}, {0.25f, 0.25f}};
+ static SkPoint kStandardSampleLocations_4[4] = {
+ {0.375f, 0.125f}, {0.875f, 0.375f}, {0.125f, 0.625f}, {0.625f, 0.875f}};
+ static SkPoint kStandardSampleLocations_8[8] = {
+ {0.5625f, 0.3125f}, {0.4375f, 0.6875f}, {0.8125f, 0.5625f}, {0.3125f, 0.1875f},
+ {0.1875f, 0.8125f}, {0.0625f, 0.4375f}, {0.6875f, 0.9375f}, {0.9375f, 0.0625f}};
+ static SkPoint kStandardSampleLocations_16[16] = {
+ {0.5625f, 0.5625f}, {0.4375f, 0.3125f}, {0.3125f, 0.625f}, {0.75f, 0.4375f},
+ {0.1875f, 0.375f}, {0.625f, 0.8125f}, {0.8125f, 0.6875f}, {0.6875f, 0.1875f},
+ {0.375f, 0.875f}, {0.5f, 0.0625f}, {0.25f, 0.125f}, {0.125f, 0.75f},
+ {0.0f, 0.5f}, {0.9375f, 0.25f}, {0.875f, 0.9375f}, {0.0625f, 0.0f}};
+
+ int numSamples = renderTarget->numSamples();
+ if (1 == numSamples) {
+ SkASSERT(this->caps()->mixedSamplesSupport());
+ if (auto* stencil = renderTarget->renderTargetPriv().getStencilAttachment()) {
+ numSamples = stencil->numSamples();
+ }
+ }
+ SkASSERT(numSamples > 1);
+ SkASSERT(!renderTarget->renderTargetPriv().getStencilAttachment() ||
+ numSamples == renderTarget->renderTargetPriv().getStencilAttachment()->numSamples());
+
+ switch (numSamples) {
+ case 1:
+ sampleLocations->push_back_n(1, kStandardSampleLocations_1);
+ break;
+ case 2:
+ sampleLocations->push_back_n(2, kStandardSampleLocations_2);
+ break;
+ case 4:
+ sampleLocations->push_back_n(4, kStandardSampleLocations_4);
+ break;
+ case 8:
+ sampleLocations->push_back_n(8, kStandardSampleLocations_8);
+ break;
+ case 16:
+ sampleLocations->push_back_n(16, kStandardSampleLocations_16);
+ break;
+ default:
+ SK_ABORT("Invalid vulkan sample count.");
+ break;
+ }
+}
+
void GrVkGpu::deleteBackendTexture(const GrBackendTexture& tex) {
SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index d25fabe..42087fc 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -75,10 +75,7 @@
kSkip_SyncQueue
};
- void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override {
- SkASSERT(!this->caps()->sampleLocationsSupport());
- SK_ABORT("Sample locations not yet implemented for Vulkan.");
- }
+ void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override;
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index b7c4f17..2e78b99 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -1166,9 +1166,6 @@
case SK_HEIGHT_BUILTIN:
fInputs.fRTHeight = true;
break;
- case SK_SAMPLEMASK_BUILTIN:
- fUsesSampleMask = true;
- break;
#ifndef SKSL_STANDALONE
case SK_FRAGCOORD_BUILTIN:
fInputs.fFlipY = true;
@@ -2425,25 +2422,6 @@
}
}
-void IRGenerator::removeSampleMask(std::vector<std::unique_ptr<ProgramElement>>* out) {
- for (const auto& e : *out) {
- switch (e->fKind) {
- case ProgramElement::kVar_Kind: {
- VarDeclarations& vd = (VarDeclarations&) *e;
- for (auto iter = vd.fVars.begin(); iter != vd.fVars.end(); ++iter) {
- SkASSERT((*iter)->fKind == Statement::kVarDeclaration_Kind);
- const auto& v = (VarDeclaration&) **iter;
- if (v.fVar->fName == "sk_SampleMask") {
- vd.fVars.erase(iter);
- return;
- }
- }
- }
- default: break;
- }
- }
-}
-
void IRGenerator::convertProgram(Program::Kind kind,
const char* text,
size_t length,
@@ -2509,9 +2487,6 @@
ABORT("unsupported declaration: %s\n", decl.description().c_str());
}
}
- if (!fUsesSampleMask) {
- this->removeSampleMask(out);
- }
}
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index abb787c..6ca6248 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -169,7 +169,6 @@
Variable* fRTAdjustInterfaceBlock;
int fRTAdjustFieldIndex;
bool fStarted = false;
- bool fUsesSampleMask = false;
friend class AutoSymbolTable;
friend class AutoLoopLevel;
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index ce5d73b..858d8ca 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -2713,6 +2713,22 @@
}
}
+bool is_dead(const Variable& var) {
+ if (var.fReadCount || var.fWriteCount) {
+ return false;
+ }
+ // not entirely sure what the rules are for when it's safe to elide interface variables, but it
+ // causes various problems to elide some of them even when dead. But it also causes problems
+ // *not* to elide sk_SampleMask when it's not being used.
+ if (!(var.fModifiers.fFlags & (Modifiers::kIn_Flag |
+ Modifiers::kOut_Flag |
+ Modifiers::kUniform_Flag |
+ Modifiers::kBuffer_Flag))) {
+ return true;
+ }
+ return var.fModifiers.fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
+}
+
#define BUILTIN_IGNORE 9999
void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
OutputStream& out) {
@@ -2737,13 +2753,7 @@
SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
continue;
}
- if (!var->fReadCount && !var->fWriteCount &&
- !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
- Modifiers::kOut_Flag |
- Modifiers::kUniform_Flag |
- Modifiers::kBuffer_Flag))) {
- // variable is dead and not an input / output var (the Vulkan debug layers complain if
- // we elide an interface var, even if it's dead)
+ if (is_dead(*var)) {
continue;
}
SpvStorageClass_ storageClass;
@@ -3161,7 +3171,8 @@
SpvId id = this->writeInterfaceBlock(intf);
if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
(intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
- intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
+ intf.fVariable.fModifiers.fLayout.fBuiltin == -1 &&
+ !is_dead(intf.fVariable)) {
interfaceVars.insert(id);
}
}
@@ -3190,7 +3201,7 @@
const Variable* var = entry.first;
if (var->fStorage == Variable::kGlobal_Storage &&
((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
- (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
+ (var->fModifiers.fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
interfaceVars.insert(entry.second);
}
}