1/*
2 * Copyright 2015 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 "GLBench.h"
9
10#if SK_SUPPORT_GPU
11#include "GrTest.h"
12#include <stdio.h>
13
14const GrGLContext* GLBench::getGLContext(SkCanvas* canvas) {
15    // This bench exclusively tests GL calls directly
16    if (nullptr == canvas->getGrContext()) {
17        return nullptr;
18    }
19    GrContext* context = canvas->getGrContext();
20    GrGpu* gpu = context->getGpu();
21    if (!gpu) {
22        SkDebugf("Couldn't get Gr gpu.");
23        return nullptr;
24    }
25
26    const GrGLContext* ctx = gpu->glContextForTesting();
27    if (!ctx) {
28        SkDebugf("Couldn't get an interface\n");
29        return nullptr;
30    }
31
32    return this->onGetGLContext(ctx);
33}
34
35void GLBench::onPreDraw(SkCanvas* canvas) {
36    // This bench exclusively tests GL calls directly
37    const GrGLContext* ctx = this->getGLContext(canvas);
38    if (!ctx) {
39        return;
40    }
41    this->setup(ctx);
42}
43
44void GLBench::onPostDraw(SkCanvas* canvas) {
45    // This bench exclusively tests GL calls directly
46    const GrGLContext* ctx = this->getGLContext(canvas);
47    if (!ctx) {
48        return;
49    }
50    this->teardown(ctx->interface());
51}
52
53void GLBench::onDraw(int loops, SkCanvas* canvas) {
54    const GrGLContext* ctx = this->getGLContext(canvas);
55    if (!ctx) {
56        return;
57    }
58    this->glDraw(loops, ctx);
59}
60
61GrGLuint GLBench::CompileShader(const GrGLInterface* gl, const char* shaderSrc, GrGLenum type) {
62    GrGLuint shader;
63    // Create the shader object
64    GR_GL_CALL_RET(gl, shader, CreateShader(type));
65
66    // Load the shader source
67    GR_GL_CALL(gl, ShaderSource(shader, 1, &shaderSrc, nullptr));
68
69    // Compile the shader
70    GR_GL_CALL(gl, CompileShader(shader));
71
72    // Check for compile time errors
73    GrGLint success = GR_GL_INIT_ZERO;
74    GrGLchar infoLog[512];
75    GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &success));
76    if (!success) {
77        GR_GL_CALL(gl, GetShaderInfoLog(shader, 512, nullptr, infoLog));
78        SkDebugf("ERROR::SHADER::COMPLIATION_FAILED: %s\n", infoLog);
79    }
80
81    return shader;
82}
83
84GrGLuint GLBench::CreateProgram(const GrGLInterface* gl, const char* vshader, const char* fshader) {
85
86    GrGLuint vertexShader = CompileShader(gl, vshader, GR_GL_VERTEX_SHADER);
87    GrGLuint fragmentShader = CompileShader(gl, fshader, GR_GL_FRAGMENT_SHADER);
88
89    GrGLuint shaderProgram;
90    GR_GL_CALL_RET(gl, shaderProgram, CreateProgram());
91    GR_GL_CALL(gl, AttachShader(shaderProgram, vertexShader));
92    GR_GL_CALL(gl, AttachShader(shaderProgram, fragmentShader));
93    GR_GL_CALL(gl, LinkProgram(shaderProgram));
94
95    // Check for linking errors
96    GrGLint success = GR_GL_INIT_ZERO;
97    GrGLchar infoLog[512];
98    GR_GL_CALL(gl, GetProgramiv(shaderProgram, GR_GL_LINK_STATUS, &success));
99    if (!success) {
100        GR_GL_CALL(gl, GetProgramInfoLog(shaderProgram, 512, nullptr, infoLog));
101        SkDebugf("Linker Error: %s\n", infoLog);
102    }
103    GR_GL_CALL(gl, DeleteShader(vertexShader));
104    GR_GL_CALL(gl, DeleteShader(fragmentShader));
105
106    return shaderProgram;
107}
108
109GrGLuint GLBench::SetupFramebuffer(const GrGLInterface* gl, int screenWidth, int screenHeight) {
110    //Setup framebuffer
111    GrGLuint texture;
112    GR_GL_CALL(gl, GenTextures(1, &texture));
113    GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE7));
114    GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texture));
115    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
116    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
117    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
118    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
119    GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D,
120                              0, //level
121                              GR_GL_RGBA, //internal format
122                              screenWidth, // width
123                              screenHeight, // height
124                              0, //border
125                              GR_GL_RGBA, //format
126                              GR_GL_UNSIGNED_BYTE, // type
127                              nullptr));
128
129    // bind framebuffer
130    GrGLuint framebuffer;
131    GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0));
132    GR_GL_CALL(gl, GenFramebuffers(1, &framebuffer));
133    GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, framebuffer));
134    GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER,
135                                        GR_GL_COLOR_ATTACHMENT0,
136                                        GR_GL_TEXTURE_2D,
137                                        texture, 0));
138    GR_GL_CALL(gl, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
139    GR_GL_CALL(gl, Viewport(0, 0, screenWidth, screenHeight));
140    return texture;
141}
142
143
144void GLBench::DumpImage(const GrGLInterface* gl, uint32_t screenWidth, uint32_t screenHeight,
145                        const char* filename) {
146    // read back pixels
147    SkAutoTArray<uint32_t> readback(screenWidth * screenHeight);
148    GR_GL_CALL(gl, ReadPixels(0, // x
149                              0, // y
150                              screenWidth, // width
151                              screenHeight, // height
152                              GR_GL_RGBA, //format
153                              GR_GL_UNSIGNED_BYTE, //type
154                              readback.get()));
155
156    // dump png
157    SkBitmap bm;
158    if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(screenWidth, screenHeight))) {
159        SkDebugf("couldn't allocate bitmap\n");
160        return;
161    }
162
163    bm.setPixels(readback.get());
164
165    if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) {
166        SkDebugf("------ failed to encode %s\n", filename);
167        remove(filename);   // remove any partial file
168        return;
169    }
170}
171
172#endif
173