Index: src/gpu/gl/GrGLShaderBuilder.cpp |
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp |
index 89f4cbf4a628f1a47ac5debe730d05c72b015a88..264bc3b0050eb8675b310c9ad2f040246475daf6 100644 |
--- a/src/gpu/gl/GrGLShaderBuilder.cpp |
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp |
@@ -572,7 +572,6 @@ const char* GrGLShaderBuilder::enableSecondaryOutput() { |
return dual_source_output_name(); |
} |
- |
bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) { |
SK_TRACE_EVENT0("GrGLShaderBuilder::finish"); |
@@ -582,7 +581,9 @@ bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) { |
return false; |
} |
- if (!this->compileAndAttachShaders(programId)) { |
+ SkTDArray<GrGLuint> shadersToDelete; |
+ |
+ if (!this->compileAndAttachShaders(programId, &shadersToDelete)) { |
GL_CALL(DeleteProgram(programId)); |
return false; |
} |
@@ -625,22 +626,27 @@ bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) { |
if (!fUniformManager.isUsingBindUniform()) { |
fUniformManager.getUniformLocations(programId, fUniforms); |
} |
+ |
+ for (int i = 0; i < shadersToDelete.count(); ++i) { |
+ GL_CALL(DeleteShader(shadersToDelete[i])); |
+ } |
+ |
*outProgramId = programId; |
return true; |
} |
-// Compiles a GL shader, attaches it to a program, and releases the shader's reference. |
-// (That way there's no need to hang on to the GL shader id and delete it later.) |
-static bool attach_shader(const GrGLContext& glCtx, |
- GrGLuint programId, |
- GrGLenum type, |
- const SkString& shaderSrc) { |
+// Compiles a GL shader and attaches it to a program. Returns the shader ID if |
+// successful, or 0 if not. |
+static GrGLuint attach_shader(const GrGLContext& glCtx, |
+ GrGLuint programId, |
+ GrGLenum type, |
+ const SkString& shaderSrc) { |
const GrGLInterface* gli = glCtx.interface(); |
GrGLuint shaderId; |
GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); |
if (0 == shaderId) { |
- return false; |
+ return 0; |
} |
const GrGLchar* sourceStr = shaderSrc.c_str(); |
@@ -672,7 +678,7 @@ static bool attach_shader(const GrGLContext& glCtx, |
} |
SkDEBUGFAIL("Shader compilation failed!"); |
GR_GL_CALL(gli, DeleteShader(shaderId)); |
- return false; |
+ return 0; |
} |
} |
if (c_PrintShaders) { |
@@ -680,12 +686,16 @@ static bool attach_shader(const GrGLContext& glCtx, |
GrPrintf("\n"); |
} |
+ // Attach the shader, but defer deletion until after we have linked the program. |
+ // This works around a bug in the Android emulator's GLES2 wrapper which |
+ // will immediately delete the shader object and free its memory even though it's |
+ // attached to a program, which then causes glLinkProgram to fail. |
GR_GL_CALL(gli, AttachShader(programId, shaderId)); |
- GR_GL_CALL(gli, DeleteShader(shaderId)); |
- return true; |
+ |
+ return shaderId; |
} |
-bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { |
+bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { |
SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); |
fragShaderSrc.append(fFSExtensions); |
append_default_precision_qualifier(kDefaultFragmentPrecision, |
@@ -700,10 +710,14 @@ bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { |
fragShaderSrc.append("void main() {\n"); |
fragShaderSrc.append(fFSCode); |
fragShaderSrc.append("}\n"); |
- if (!attach_shader(fGpu->glContext(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc)) { |
+ |
+ GrGLuint fragShaderId = attach_shader(fGpu->glContext(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc); |
+ if (!fragShaderId) { |
return false; |
} |
+ *shaderIds->append() = fragShaderId; |
+ |
return true; |
} |
@@ -870,7 +884,7 @@ GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects( |
return programEffectsBuilder.finish(); |
} |
-bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { |
+bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { |
const GrGLContext& glCtx = this->gpu()->glContext(); |
SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); |
this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc); |
@@ -879,9 +893,11 @@ bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { |
vertShaderSrc.append("void main() {\n"); |
vertShaderSrc.append(fVSCode); |
vertShaderSrc.append("}\n"); |
- if (!attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER, vertShaderSrc)) { |
+ GrGLuint vertShaderId = attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER, vertShaderSrc); |
+ if (!vertShaderId) { |
return false; |
} |
+ *shaderIds->append() = vertShaderId; |
#if GR_GL_EXPERIMENTAL_GS |
if (fDesc.getHeader().fExperimentalGS) { |
@@ -907,13 +923,15 @@ bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { |
"\t}\n" |
"\tEndPrimitive();\n"); |
geomShaderSrc.append("}\n"); |
- if (!attach_shader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc)) { |
+ GrGLuint geomShaderId = attach_shader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc); |
+ if (!geomShaderId) { |
return false; |
} |
+ *shaderIds->append() = geomShaderId; |
} |
#endif |
- return this->INHERITED::compileAndAttachShaders(programId); |
+ return this->INHERITED::compileAndAttachShaders(programId, shaderIds); |
} |
void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) const { |