Add a workaround for platforms with broken geo shader invocations

BUG=skia:

Change-Id: I9105b65b522d9ffac5a90ca7126bfd4ae88f8069
Reviewed-on: https://skia-review.googlesource.com/8422
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
csmartdalton 2017-02-15 10:41:27 -07:00 committed by Skia Commit-Bot
parent e14349a754
commit 2e777ead12
5 changed files with 37 additions and 5 deletions

View File

@ -176,6 +176,9 @@ public:
bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; }
// On MacBook, geometry shaders break if they have more than one invocation.
bool mustImplementGSInvocationsWithLoop() const { return fMustImplementGSInvocationsWithLoop; }
// Returns the string of an extension that must be enabled in the shader to support
// derivatives. If nullptr is returned then no extension needs to be enabled. Before calling
// this function, the caller should check that shaderDerivativeSupport exists.
@ -304,6 +307,7 @@ private:
bool fMustForceNegatedAtanParamToFloat : 1;
bool fAtan2ImplementedAsAtanYOverX : 1;
bool fRequiresLocalOutputColorForFBFetch : 1;
bool fMustImplementGSInvocationsWithLoop : 1;
PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount];
int fPixelLocalStorageSize;

View File

@ -58,6 +58,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fMustForceNegatedAtanParamToFloat = false;
fAtan2ImplementedAsAtanYOverX = false;
fRequiresLocalOutputColorForFBFetch = false;
fMustImplementGSInvocationsWithLoop = false;
fFlatInterpolationSupport = false;
fNoPerspectiveInterpolationSupport = false;
fMultisampleInterpolationSupport = false;
@ -144,6 +145,8 @@ SkString GrShaderCaps::dump() const {
"YES" : "NO"));
r.appendf("Must use local out color for FBFetch: %s\n", (fRequiresLocalOutputColorForFBFetch ?
"YES" : "NO"));
r.appendf("Must implement geo shader invocations with loop : %s\n",
(fMustImplementGSInvocationsWithLoop ? "YES" : "NO"));
r.appendf("Flat interpolation support: %s\n", (fFlatInterpolationSupport ? "YES" : "NO"));
r.appendf("No perspective interpolation support: %s\n", (fNoPerspectiveInterpolationSupport ?
"YES" : "NO"));

View File

@ -870,6 +870,13 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) {
if (shaderCaps->fFBFetchSupport && kQualcomm_GrGLVendor == ctxInfo.vendor()) {
shaderCaps->fRequiresLocalOutputColorForFBFetch = true;
}
#ifdef SK_BUILD_FOR_MAC
// On at least some MacBooks, geometry shaders fall apart if we use more than one invocation. To
// work around this, we always use a single invocation and wrap the shader in a loop. The long-
// term plan for this WAR is for it to eventually be baked into SkSL.
shaderCaps->fMustImplementGSInvocationsWithLoop = true;
#endif
}
bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {

View File

@ -35,22 +35,39 @@ static const char* output_type_name(GrGLSLGeometryBuilder::OutputType out) {
GrGLSLGeometryBuilder::GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program)
: INHERITED(program)
, fIsConfigured(false) {
, fNumInvocations(0) {
}
void GrGLSLGeometryBuilder::configure(InputType inputType, OutputType outputType, int maxVertices,
int numInvocations) {
SkASSERT(!fIsConfigured);
SkASSERT(!this->isConfigured());
fNumInvocations = numInvocations;
if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) {
maxVertices *= numInvocations;
numInvocations = 1;
}
this->addLayoutQualifier(input_type_name(inputType), kIn_InterfaceQualifier);
this->addLayoutQualifier(SkStringPrintf("invocations = %i", numInvocations).c_str(),
kIn_InterfaceQualifier);
this->addLayoutQualifier(output_type_name(outputType), kOut_InterfaceQualifier);
this->addLayoutQualifier(SkStringPrintf("max_vertices = %i", maxVertices).c_str(),
kOut_InterfaceQualifier);
fIsConfigured = true;
}
void GrGLSLGeometryBuilder::onFinalize() {
SkASSERT(fIsConfigured);
SkASSERT(this->isConfigured());
fProgramBuilder->varyingHandler()->getGeomDecls(&this->inputs(), &this->outputs());
GrShaderVar sk_InvocationID("sk_InvocationID", kInt_GrSLType);
this->declareGlobal(sk_InvocationID);
SkASSERT(sk_InvocationID.getName() == SkString("sk_InvocationID"));
if (this->getProgramBuilder()->shaderCaps()->mustImplementGSInvocationsWithLoop()) {
SkString invokeFn;
this->emitFunction(kVoid_GrSLType, "invoke", 0, nullptr, this->code().c_str(), &invokeFn);
this->code().printf("for (sk_InvocationID = 0; sk_InvocationID < %i; ++sk_InvocationID) {"
"%s();"
"EndPrimitive();"
"}", fNumInvocations, invokeFn.c_str());
} else {
this->codePrependf("sk_InvocationID = gl_InvocationID;");
}
}

View File

@ -31,11 +31,12 @@ public:
};
void configure(InputType, OutputType, int maxVertices, int numInvocations = 1);
bool isConfigured() const { return fNumInvocations; }
private:
void onFinalize() override;
bool fIsConfigured;
int fNumInvocations;
friend class GrGLProgramBuilder;