Reland "Implement sample mask and sample locations support in Vulkan"
This is a reland of 8b915a0c27
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>
Change-Id: Idd0d8f63c7bb1cdd4d905c483f2fe7ed2b34b05f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252306
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
5625412f02
commit
2245bf8313
@ -291,7 +291,8 @@ void GrGLSLFragmentShaderBuilder::onFinalize() {
|
||||
|
||||
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()) {
|
||||
|
@ -497,6 +497,10 @@ void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
|
||||
static const uint32_t kMaxVertexAttributes = 64;
|
||||
fMaxVertexAttributes = SkTMin(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes);
|
||||
|
||||
if (properties.limits.standardSampleLocations) {
|
||||
fSampleLocationsSupport = 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);
|
||||
@ -563,7 +567,7 @@ void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties,
|
||||
// to be true with Vulkan as well.
|
||||
shaderCaps->fPreferFlatInterpolation = kQualcomm_VkVendor != properties.vendorID;
|
||||
|
||||
// GrShaderCaps
|
||||
shaderCaps->fSampleMaskSupport = true;
|
||||
|
||||
shaderCaps->fShaderDerivativeSupport = true;
|
||||
|
||||
@ -1187,12 +1191,7 @@ void GrVkCaps::FormatInfo::initSampleCounts(const GrVkInterface* interface,
|
||||
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 32 or 64 samples, so we omit these options.
|
||||
}
|
||||
|
||||
void GrVkCaps::FormatInfo::init(const GrVkInterface* interface,
|
||||
|
@ -1814,6 +1814,48 @@ GrBackendTexture GrVkGpu::onCreateBackendTexture(SkISize dimensions,
|
||||
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}};
|
||||
|
||||
switch (renderTarget->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);
|
||||
|
||||
|
@ -72,10 +72,7 @@ public:
|
||||
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 {}
|
||||
|
||||
|
@ -1166,9 +1166,6 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTNode& identi
|
||||
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::setRefKind(const Expression& expr, VariableReference::RefKind
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void IRGenerator::convertProgram(Program::Kind kind,
|
||||
ABORT("unsupported declaration: %s\n", decl.description().c_str());
|
||||
}
|
||||
}
|
||||
if (!fUsesSampleMask) {
|
||||
this->removeSampleMask(out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,7 +169,6 @@ private:
|
||||
Variable* fRTAdjustInterfaceBlock;
|
||||
int fRTAdjustFieldIndex;
|
||||
bool fStarted = false;
|
||||
bool fUsesSampleMask = false;
|
||||
|
||||
friend class AutoSymbolTable;
|
||||
friend class AutoLoopLevel;
|
||||
|
@ -2713,6 +2713,22 @@ void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio
|
||||
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 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream&
|
||||
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 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream&
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user