/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/core/SkAutoMalloc.h" #include "src/gpu/GrShaderUtils.h" #include "src/gpu/gl/GrGLGpu.h" #include "src/gpu/gl/builders/GrGLShaderStringBuilder.h" #include "src/sksl/SkSLCompiler.h" #include "src/sksl/SkSLGLSLCodeGenerator.h" #include "src/sksl/ir/SkSLProgram.h" // Print the source code for all shaders generated. static const bool gPrintSKSL = false; static const bool gPrintGLSL = false; void print_shader_banner(SkSL::Program::Kind programKind) { const char* typeName = "Unknown"; switch (programKind) { case SkSL::Program::kVertex_Kind: typeName = "Vertex"; break; case SkSL::Program::kGeometry_Kind: typeName = "Geometry"; break; case SkSL::Program::kFragment_Kind: typeName = "Fragment"; break; default: break; } SkDebugf("---- %s shader ----------------------------------------------------\n", typeName); } std::unique_ptr GrSkSLtoGLSL(const GrGLContext& context, SkSL::Program::Kind programKind, const SkSL::String& sksl, const SkSL::Program::Settings& settings, SkSL::String* glsl, GrContextOptions::ShaderErrorHandler* errorHandler) { SkSL::Compiler* compiler = context.compiler(); std::unique_ptr program; #ifdef SK_DEBUG SkSL::String src = GrShaderUtils::PrettyPrint(sksl); #else const SkSL::String& src = sksl; #endif program = compiler->convertProgram(programKind, src, settings); if (!program || !compiler->toGLSL(*program, glsl)) { errorHandler->compileError(src.c_str(), compiler->errorText().c_str()); return nullptr; } if (gPrintSKSL || gPrintGLSL) { print_shader_banner(programKind); if (gPrintSKSL) { GrShaderUtils::PrintLineByLine("SKSL:", GrShaderUtils::PrettyPrint(sksl)); } if (gPrintGLSL) { GrShaderUtils::PrintLineByLine("GLSL:", GrShaderUtils::PrettyPrint(*glsl)); } } return program; } GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx, GrGLuint programId, GrGLenum type, const SkSL::String& glsl, GrGpu::Stats* stats, GrContextOptions::ShaderErrorHandler* errorHandler) { const GrGLInterface* gli = glCtx.interface(); // Specify GLSL source to the driver. GrGLuint shaderId; GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); if (0 == shaderId) { return 0; } const GrGLchar* source = glsl.c_str(); GrGLint sourceLength = glsl.size(); GR_GL_CALL(gli, ShaderSource(shaderId, 1, &source, &sourceLength)); stats->incShaderCompilations(); GR_GL_CALL(gli, CompileShader(shaderId)); // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds. bool checkCompiled = kChromium_GrGLDriver != glCtx.driver(); #ifdef SK_DEBUG checkCompiled = true; #endif if (checkCompiled) { GrGLint compiled = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); if (!compiled) { GrGLint infoLen = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen)); SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger if (infoLen > 0) { // retrieve length even though we don't need it to workaround bug in Chromium cmd // buffer param validation. GrGLsizei length = GR_GL_INIT_ZERO; GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get())); } errorHandler->compileError(glsl.c_str(), infoLen > 0 ? (const char*)log.get() : ""); GR_GL_CALL(gli, DeleteShader(shaderId)); return 0; } } // 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)); return shaderId; }