130ba436f04e61d4505fb854d5fc56079636e0788joshualitt/*
230ba436f04e61d4505fb854d5fc56079636e0788joshualitt * Copyright 2014 Google Inc.
330ba436f04e61d4505fb854d5fc56079636e0788joshualitt *
430ba436f04e61d4505fb854d5fc56079636e0788joshualitt * Use of this source code is governed by a BSD-style license that can be
530ba436f04e61d4505fb854d5fc56079636e0788joshualitt * found in the LICENSE file.
630ba436f04e61d4505fb854d5fc56079636e0788joshualitt */
730ba436f04e61d4505fb854d5fc56079636e0788joshualitt
830ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "GrGLShaderStringBuilder.h"
9e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon#include "GrSKSLPrettyPrint.h"
1095e3c058ef633782f7549e9e1c2727d60dbc8ee5Hal Canary#include "SkAutoMalloc.h"
11c456b73fef9589bbdc5eb83eaa83e53c357bb3daKevin Lubick#include "SkSLCompiler.h"
12c456b73fef9589bbdc5eb83eaa83e53c357bb3daKevin Lubick#include "SkSLGLSLCodeGenerator.h"
1395e3c058ef633782f7549e9e1c2727d60dbc8ee5Hal Canary#include "SkTraceEvent.h"
1495e3c058ef633782f7549e9e1c2727d60dbc8ee5Hal Canary#include "gl/GrGLGpu.h"
155961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#include "ir/SkSLProgram.h"
1630ba436f04e61d4505fb854d5fc56079636e0788joshualitt
1730ba436f04e61d4505fb854d5fc56079636e0788joshualitt#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
1830ba436f04e61d4505fb854d5fc56079636e0788joshualitt#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
1930ba436f04e61d4505fb854d5fc56079636e0788joshualitt
204e44efe50474d4eebcb30b762e784b3ef2126750halcanary// Print the source code for all shaders generated.
2106ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomonstatic const bool gPrintSKSL = false;
2206ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomonstatic const bool gPrintGLSL = false;
2330ba436f04e61d4505fb854d5fc56079636e0788joshualitt
247bd55c2149cf70a2bf17743ecdfe74332daa276cChris Daltonstatic void print_source_lines_with_numbers(const char* source,
257bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton                                            std::function<void(const char*)> println) {
26e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    SkTArray<SkString> lines;
27e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines);
287bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton    for (int i = 0; i < lines.count(); ++i) {
297bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton        SkString& line = lines[i];
307bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton        line.prependf("%4i\t", i + 1);
317bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton        println(line.c_str());
32e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    }
33e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon}
3430ba436f04e61d4505fb854d5fc56079636e0788joshualitt
357bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton// Prints shaders one line at the time. This ensures they don't get truncated by the adb log.
36d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholasstatic void print_sksl_line_by_line(const char** skslStrings, int* lengths, int count,
37d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    std::function<void(const char*)> println = [](const char* ln) {
38d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                        SkDebugf("%s\n", ln);
39d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    }) {
4093ba0a4fc85f04bc1be9429983df1e57473b49a7Brian Osman    SkSL::String sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
417bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton    println("SKSL:");
427bd55c2149cf70a2bf17743ecdfe74332daa276cChris Dalton    print_source_lines_with_numbers(sksl.c_str(), println);
43e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon}
4430ba436f04e61d4505fb854d5fc56079636e0788joshualitt
45d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholasstatic void print_glsl_line_by_line(const SkSL::String& glsl,
46d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    std::function<void(const char*)> println = [](const char* ln) {
47d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                        SkDebugf("%s\n", ln);
48d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    }) {
49d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    println("GLSL:");
50d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    print_source_lines_with_numbers(glsl.c_str(), println);
51d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas}
52d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas
5306ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomonvoid print_shader_banner(GrGLenum type) {
5406ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    const char* typeName = "Unknown";
5506ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    switch (type) {
5606ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        case GR_GL_VERTEX_SHADER: typeName = "Vertex"; break;
5706ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        case GR_GL_GEOMETRY_SHADER: typeName = "Geometry"; break;
5806ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break;
5906ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    }
6006ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    SkDebugf("---- %s shader ----------------------------------------------------\n", typeName);
6106ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon}
6206ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon
63d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholasstd::unique_ptr<SkSL::Program> GrSkSLtoGLSL(const GrGLContext& context, GrGLenum type,
64d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                            const char** skslStrings, int* lengths, int count,
65d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                            const SkSL::Program::Settings& settings,
66d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                            SkSL::String* glsl) {
67d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    // Trace event for shader preceding driver compilation
68d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    bool traceShader;
69d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    TRACE_EVENT_CATEGORY_GROUP_ENABLED("skia.gpu", &traceShader);
70d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    if (traceShader) {
71d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        SkString shaderDebugString;
72d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        print_sksl_line_by_line(skslStrings, lengths, count, [&](const char* ln) {
73d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas            shaderDebugString.append(ln);
74d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas            shaderDebugString.append("\n");
75d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        });
76d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        TRACE_EVENT_INSTANT1("skia.gpu", "skia_gpu::GLShader",
77d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                             TRACE_EVENT_SCOPE_THREAD, "shader",
78d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                             TRACE_STR_COPY(shaderDebugString.c_str()));
79d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    }
80d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas
8193ba0a4fc85f04bc1be9429983df1e57473b49a7Brian Osman    SkSL::String sksl;
82754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips#ifdef SK_DEBUG
83e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
84754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips#else
855961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    for (int i = 0; i < count; i++) {
86e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon        sksl.append(skslStrings[i], lengths[i]);
875961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    }
88754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips#endif
89068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    SkSL::Compiler* compiler = context.compiler();
90068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    std::unique_ptr<SkSL::Program> program;
91068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    SkSL::Program::Kind programKind;
92068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    switch (type) {
93068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        case GR_GL_VERTEX_SHADER:   programKind = SkSL::Program::kVertex_Kind;   break;
94068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        case GR_GL_FRAGMENT_SHADER: programKind = SkSL::Program::kFragment_Kind; break;
95068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        case GR_GL_GEOMETRY_SHADER: programKind = SkSL::Program::kGeometry_Kind; break;
96898d5b20348784fdf65f0decf96fc5d40d99bd95Ethan Nicholas        default: SK_ABORT("unsupported shader kind");
97068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    }
98068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    program = compiler->convertProgram(programKind, sksl, settings);
99068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    if (!program || !compiler->toGLSL(*program, glsl)) {
100068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        SkDebugf("SKSL compilation error\n----------------------\n");
101d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        print_sksl_line_by_line(skslStrings, lengths, count);
102068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str());
103068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas        SkDEBUGFAIL("SKSL compilation failed!\n");
104e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon        return nullptr;
105276cc4113a6440b842c0dacb6d668ee3b45a3b7dcsmartdalton    }
10606ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    if (gPrintSKSL) {
10706ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        print_shader_banner(type);
10806ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        print_sksl_line_by_line(skslStrings, lengths, count);
10906ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    }
110068acd5cf930212510c69f7909c8b999be7965e2Ethan Nicholas    return program;
111e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon}
1125961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas
113e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian SalomonGrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
114e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon                                    GrGLuint programId,
115e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon                                    GrGLenum type,
116d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    const char* glsl,
117d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    int glslLength,
118e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon                                    GrGpu::Stats* stats,
119d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas                                    const SkSL::Program::Settings& settings) {
120e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    const GrGLInterface* gli = glCtx.interface();
121e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon
122e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    // Specify GLSL source to the driver.
123e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    GrGLuint shaderId;
124e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    GR_GL_CALL_RET(gli, shaderId, CreateShader(type));
125e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    if (0 == shaderId) {
126e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon        return 0;
127e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    }
128d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glsl, &glslLength));
12943466a1ade066f96823dbc7963767da3973afd91joshualitt
130b9eb4ac0f1c29d6fe10ad7ff81ed8326ac1ea043mtklein    stats->incShaderCompilations();
131754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    GR_GL_CALL(gli, CompileShader(shaderId));
13230ba436f04e61d4505fb854d5fc56079636e0788joshualitt
133754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds.
1341acea86914797bc33856ff62b5cdfbe82c58dd67cdalton    bool checkCompiled = kChromium_GrGLDriver != glCtx.driver();
135754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips#ifdef SK_DEBUG
136754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    checkCompiled = true;
137754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips#endif
138754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    if (checkCompiled) {
139754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips        GrGLint compiled = GR_GL_INIT_ZERO;
140754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips        GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));
14130ba436f04e61d4505fb854d5fc56079636e0788joshualitt
142754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips        if (!compiled) {
143e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon            SkDebugf("GLSL compilation error\n----------------------\n");
144d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas            print_glsl_line_by_line(glsl);
145754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            GrGLint infoLen = GR_GL_INIT_ZERO;
146754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen));
147754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
148754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            if (infoLen > 0) {
149754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips                // retrieve length even though we don't need it to workaround bug in Chromium cmd
150754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips                // buffer param validation.
151754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips                GrGLsizei length = GR_GL_INIT_ZERO;
15243466a1ade066f96823dbc7963767da3973afd91joshualitt                GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get()));
1535961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas                SkDebugf("Errors:\n%s\n", (const char*) log.get());
154754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            }
155020dbe7917f7616bfbdff9128124e0c09d3f0f2dBrian Salomon            // In Chrome we may have failed due to context-loss. So we should just continue along
156020dbe7917f7616bfbdff9128124e0c09d3f0f2dBrian Salomon            // wihthout asserting until the GrContext gets abandoned.
157020dbe7917f7616bfbdff9128124e0c09d3f0f2dBrian Salomon            if (kChromium_GrGLDriver != glCtx.driver()) {
158020dbe7917f7616bfbdff9128124e0c09d3f0f2dBrian Salomon                SkDEBUGFAIL("GLSL compilation failed!");
159020dbe7917f7616bfbdff9128124e0c09d3f0f2dBrian Salomon            }
160754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            GR_GL_CALL(gli, DeleteShader(shaderId));
161754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips            return 0;
162754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips        }
163754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    }
16430ba436f04e61d4505fb854d5fc56079636e0788joshualitt
16506ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon    if (gPrintGLSL) {
16606ab3836f779dbcbcd067a9261300616ff7cc594Brian Salomon        print_shader_banner(type);
167d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        print_glsl_line_by_line(glsl);
168754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    }
16930ba436f04e61d4505fb854d5fc56079636e0788joshualitt
170754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    // Attach the shader, but defer deletion until after we have linked the program.
171754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    // This works around a bug in the Android emulator's GLES2 wrapper which
172754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    // will immediately delete the shader object and free its memory even though it's
173754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    // attached to a program, which then causes glLinkProgram to fail.
174754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    GR_GL_CALL(gli, AttachShader(programId, shaderId));
175754f4e98d94d7c9ed76cd128cf983f9323a1885brobertphillips    return shaderId;
17630ba436f04e61d4505fb854d5fc56079636e0788joshualitt}
177b3772dcb306241f53fe10ba62117ed67f89f24b2csmartdalton
178e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomonvoid GrGLPrintShader(const GrGLContext& context, GrGLenum type, const char** skslStrings,
179e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon                     int* lengths, int count, const SkSL::Program::Settings& settings) {
180d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    print_sksl_line_by_line(skslStrings, lengths, count);
181e334c596546c7ec79f2b0e55b3a1c2839a94f352Brian Salomon    SkSL::String glsl;
182d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas    if (GrSkSLtoGLSL(context, type, skslStrings, lengths, count, settings, &glsl)) {
183d1b2eec0d0f95977b52669025cb25038618c0335Ethan Nicholas        print_glsl_line_by_line(glsl);
184b3772dcb306241f53fe10ba62117ed67f89f24b2csmartdalton    }
185b3772dcb306241f53fe10ba62117ed67f89f24b2csmartdalton}
186