| /* |
| * 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<SkSL::Program> 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<SkSL::Program> 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; |
| } |