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