1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrGLProgramBuilder.h" 9 10#include "GrAutoLocaleSetter.h" 11#include "GrContext.h" 12#include "GrCoordTransform.h" 13#include "GrGLProgramBuilder.h" 14#include "GrProgramDesc.h" 15#include "GrShaderCaps.h" 16#include "GrSwizzle.h" 17#include "SkAutoMalloc.h" 18#include "SkATrace.h" 19#include "SkTraceEvent.h" 20#include "gl/GrGLGpu.h" 21#include "gl/GrGLProgram.h" 22#include "gl/builders/GrGLShaderStringBuilder.h" 23#include "glsl/GrGLSLFragmentProcessor.h" 24#include "glsl/GrGLSLGeometryProcessor.h" 25#include "glsl/GrGLSLProgramDataManager.h" 26#include "glsl/GrGLSLXferProcessor.h" 27 28#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) 29#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) 30 31GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline, 32 const GrPrimitiveProcessor& primProc, 33 GrProgramDesc* desc, 34 GrGLGpu* gpu) { 35 SkASSERT(!pipeline.isBad() && primProc.instantiate(gpu->getContext()->resourceProvider())); 36 37 ATRACE_ANDROID_FRAMEWORK("Shader Compile"); 38 GrAutoLocaleSetter als("C"); 39 40 // create a builder. This will be handed off to effects so they can use it to add 41 // uniforms, varyings, textures, etc 42 GrGLProgramBuilder builder(gpu, pipeline, primProc, desc); 43 44 if (!builder.emitAndInstallProcs()) { 45 builder.cleanupFragmentProcessors(); 46 return nullptr; 47 } 48 49 return builder.finalize(); 50} 51 52///////////////////////////////////////////////////////////////////////////// 53 54GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, 55 const GrPipeline& pipeline, 56 const GrPrimitiveProcessor& primProc, 57 GrProgramDesc* desc) 58 : INHERITED(pipeline, primProc, desc) 59 , fGpu(gpu) 60 , fVaryingHandler(this) 61 , fUniformHandler(this) { 62} 63 64const GrCaps* GrGLProgramBuilder::caps() const { 65 return fGpu->caps(); 66} 67 68bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, 69 GrGLuint programId, 70 GrGLenum type, 71 SkTDArray<GrGLuint>* shaderIds, 72 const SkSL::Program::Settings& settings, 73 SkSL::Program::Inputs* outInputs) { 74 GrGLGpu* gpu = this->gpu(); 75 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(), 76 programId, 77 type, 78 shader.fCompilerStrings.begin(), 79 shader.fCompilerStringLengths.begin(), 80 shader.fCompilerStrings.count(), 81 gpu->stats(), 82 settings, 83 outInputs); 84 85 if (!shaderId) { 86 return false; 87 } 88 89 *shaderIds->append() = shaderId; 90 if (outInputs->fFlipY) { 91 GrProgramDesc* d = this->desc(); 92 d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( 93 this->pipeline().getRenderTarget()->origin())); 94 d->finalize(); 95 } 96 97 return true; 98} 99 100GrGLProgram* GrGLProgramBuilder::finalize() { 101 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia"), "GrGLProgramBuilder::finalize()"); 102 103 // verify we can get a program id 104 GrGLuint programID; 105 GL_CALL_RET(programID, CreateProgram()); 106 if (0 == programID) { 107 this->cleanupFragmentProcessors(); 108 return nullptr; 109 } 110 111 this->finalizeShaders(); 112 113 // compile shaders and bind attributes / uniforms 114 SkSL::Program::Settings settings; 115 settings.fCaps = this->gpu()->glCaps().shaderCaps(); 116 settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin; 117 SkSL::Program::Inputs inputs; 118 SkTDArray<GrGLuint> shadersToDelete; 119 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete, 120 settings, &inputs)) { 121 this->cleanupProgram(programID, shadersToDelete); 122 return nullptr; 123 } 124 125 // NVPR actually requires a vertex shader to compile 126 const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); 127 bool useNvpr = primProc.isPathRendering(); 128 if (!useNvpr) { 129 int vaCount = primProc.numAttribs(); 130 for (int i = 0; i < vaCount; i++) { 131 GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName)); 132 } 133 } 134 135 if (primProc.willUseGeoShader() && 136 !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete, 137 settings, &inputs)) { 138 this->cleanupProgram(programID, shadersToDelete); 139 return nullptr; 140 } 141 142 if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete, 143 settings, &inputs)) { 144 this->cleanupProgram(programID, shadersToDelete); 145 return nullptr; 146 } 147 148 if (inputs.fRTHeight) { 149 this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); 150 } 151 152 this->bindProgramResourceLocations(programID); 153 154 GL_CALL(LinkProgram(programID)); 155 156 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. 157 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver(); 158#ifdef SK_DEBUG 159 checkLinked = true; 160#endif 161 if (checkLinked) { 162 if (!this->checkLinkStatus(programID)) { 163 SkDebugf("VS:\n"); 164 GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(), 165 fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(), 166 settings); 167 if (primProc.willUseGeoShader()) { 168 SkDebugf("\nGS:\n"); 169 GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER, 170 fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(), 171 fGS.fCompilerStrings.count(), settings); 172 } 173 SkDebugf("\nFS:\n"); 174 GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(), 175 fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(), 176 settings); 177 SkDEBUGFAIL(""); 178 return nullptr; 179 } 180 } 181 this->resolveProgramResourceLocations(programID); 182 183 this->cleanupShaders(shadersToDelete); 184 185 return this->createProgram(programID); 186} 187 188void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) { 189 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps()); 190 191 const GrGLCaps& caps = this->gpu()->glCaps(); 192 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) { 193 GL_CALL(BindFragDataLocation(programID, 0, 194 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName())); 195 } 196 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) { 197 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, 198 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName())); 199 } 200 201 // handle NVPR separable varyings 202 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() || 203 !fGpu->glPathRendering()->shouldBindFragmentInputs()) { 204 return; 205 } 206 int count = fVaryingHandler.fPathProcVaryingInfos.count(); 207 for (int i = 0; i < count; ++i) { 208 GL_CALL(BindFragmentInputLocation(programID, i, 209 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str())); 210 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i; 211 } 212} 213 214bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) { 215 GrGLint linked = GR_GL_INIT_ZERO; 216 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked)); 217 if (!linked) { 218 SkDebugf("Program linking failed.\n"); 219 GrGLint infoLen = GR_GL_INIT_ZERO; 220 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen)); 221 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 222 if (infoLen > 0) { 223 // retrieve length even though we don't need it to workaround 224 // bug in chrome cmd buffer param validation. 225 GrGLsizei length = GR_GL_INIT_ZERO; 226 GL_CALL(GetProgramInfoLog(programID, 227 infoLen+1, 228 &length, 229 (char*)log.get())); 230 SkDebugf("%s", (char*)log.get()); 231 } 232 GL_CALL(DeleteProgram(programID)); 233 programID = 0; 234 } 235 return SkToBool(linked); 236} 237 238void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) { 239 fUniformHandler.getUniformLocations(programID, fGpu->glCaps()); 240 241 // handle NVPR separable varyings 242 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() || 243 fGpu->glPathRendering()->shouldBindFragmentInputs()) { 244 return; 245 } 246 int count = fVaryingHandler.fPathProcVaryingInfos.count(); 247 for (int i = 0; i < count; ++i) { 248 GrGLint location; 249 GL_CALL_RET(location, GetProgramResourceLocation( 250 programID, 251 GR_GL_FRAGMENT_INPUT, 252 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str())); 253 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location; 254 } 255} 256 257void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) { 258 GL_CALL(DeleteProgram(programID)); 259 this->cleanupShaders(shaderIDs); 260 this->cleanupFragmentProcessors(); 261} 262void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { 263 for (int i = 0; i < shaderIDs.count(); ++i) { 264 GL_CALL(DeleteShader(shaderIDs[i])); 265 } 266} 267 268GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { 269 return new GrGLProgram(fGpu, 270 *this->desc(), 271 fUniformHandles, 272 programID, 273 fUniformHandler.fUniforms, 274 fUniformHandler.fSamplers, 275 fUniformHandler.fTexelBuffers, 276 fUniformHandler.fImageStorages, 277 fVaryingHandler.fPathProcVaryingInfos, 278 fGeometryProcessor, 279 fXferProcessor, 280 fFragmentProcessors); 281} 282