| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "GLBench.h" |
| |
| #if SK_SUPPORT_GPU |
| #include "GrGpu.h" |
| #include "GrTest.h" |
| #include "gl/GrGLContext.h" |
| #include "gl/builders/GrGLShaderStringBuilder.h" |
| #include "SkSLCompiler.h" |
| #include <stdio.h> |
| |
| #include "sk_tool_utils.h" |
| |
| const GrGLContext* GLBench::getGLContext(SkCanvas* canvas) { |
| // This bench exclusively tests GL calls directly |
| if (nullptr == canvas->getGrContext()) { |
| return nullptr; |
| } |
| GrContext* context = canvas->getGrContext(); |
| GrGpu* gpu = context->getGpu(); |
| if (!gpu) { |
| SkDebugf("Couldn't get Gr gpu."); |
| return nullptr; |
| } |
| |
| const GrGLContext* ctx = gpu->glContextForTesting(); |
| if (!ctx) { |
| SkDebugf("Couldn't get an interface\n"); |
| return nullptr; |
| } |
| |
| return this->onGetGLContext(ctx); |
| } |
| |
| void GLBench::onPreDraw(SkCanvas* canvas) { |
| // This bench exclusively tests GL calls directly |
| const GrGLContext* ctx = this->getGLContext(canvas); |
| if (!ctx) { |
| return; |
| } |
| this->setup(ctx); |
| } |
| |
| void GLBench::onPostDraw(SkCanvas* canvas) { |
| // This bench exclusively tests GL calls directly |
| const GrGLContext* ctx = this->getGLContext(canvas); |
| if (!ctx) { |
| return; |
| } |
| this->teardown(ctx->interface()); |
| } |
| |
| void GLBench::onDraw(int loops, SkCanvas* canvas) { |
| const GrGLContext* ctx = this->getGLContext(canvas); |
| if (!ctx) { |
| return; |
| } |
| this->glDraw(loops, ctx); |
| canvas->getGrContext()->resetContext(); |
| } |
| |
| GrGLuint GLBench::CompileShader(const GrGLContext* context, const char* sksl, GrGLenum type) { |
| const GrGLInterface* gl = context->interface(); |
| SkString glsl; |
| bool result = context->compiler()->toGLSL(type == GR_GL_VERTEX_SHADER |
| ? SkSL::Program::kVertex_Kind |
| : SkSL::Program::kFragment_Kind, |
| SkString(sksl), |
| *context->caps()->shaderCaps(), |
| &glsl); |
| if (!result) { |
| SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl, |
| context->compiler()->errorText().c_str()); |
| } |
| GrGLuint shader; |
| // Create the shader object |
| GR_GL_CALL_RET(gl, shader, CreateShader(type)); |
| |
| // Load the shader source |
| const char* glslPtr = glsl.c_str(); |
| GR_GL_CALL(gl, ShaderSource(shader, 1, (const char**) &glslPtr, nullptr)); |
| |
| // Compile the shader |
| GR_GL_CALL(gl, CompileShader(shader)); |
| |
| // Check for compile time errors |
| GrGLint success = GR_GL_INIT_ZERO; |
| GrGLchar infoLog[512]; |
| GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &success)); |
| if (!success) { |
| GR_GL_CALL(gl, GetShaderInfoLog(shader, 512, nullptr, infoLog)); |
| SkDebugf("ERROR::SHADER::COMPLIATION_FAILED: %s\n", infoLog); |
| } |
| |
| return shader; |
| } |
| |
| GrGLuint GLBench::CreateProgram(const GrGLContext* context, const char* vshader, |
| const char* fshader) { |
| const GrGLInterface* gl = context->interface(); |
| GrGLuint vertexShader = CompileShader(context, vshader, GR_GL_VERTEX_SHADER); |
| GrGLuint fragmentShader = CompileShader(context, fshader, GR_GL_FRAGMENT_SHADER); |
| |
| GrGLuint shaderProgram; |
| GR_GL_CALL_RET(gl, shaderProgram, CreateProgram()); |
| GR_GL_CALL(gl, AttachShader(shaderProgram, vertexShader)); |
| GR_GL_CALL(gl, AttachShader(shaderProgram, fragmentShader)); |
| GR_GL_CALL(gl, LinkProgram(shaderProgram)); |
| |
| // Check for linking errors |
| GrGLint success = GR_GL_INIT_ZERO; |
| GrGLchar infoLog[512]; |
| GR_GL_CALL(gl, GetProgramiv(shaderProgram, GR_GL_LINK_STATUS, &success)); |
| if (!success) { |
| GR_GL_CALL(gl, GetProgramInfoLog(shaderProgram, 512, nullptr, infoLog)); |
| SkDebugf("Linker Error: %s\n", infoLog); |
| } |
| GR_GL_CALL(gl, DeleteShader(vertexShader)); |
| GR_GL_CALL(gl, DeleteShader(fragmentShader)); |
| |
| return shaderProgram; |
| } |
| |
| GrGLuint GLBench::SetupFramebuffer(const GrGLInterface* gl, int screenWidth, int screenHeight) { |
| //Setup framebuffer |
| GrGLuint texture; |
| GR_GL_CALL(gl, GenTextures(1, &texture)); |
| GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE7)); |
| GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texture)); |
| GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST)); |
| GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST)); |
| GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE)); |
| GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE)); |
| GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, |
| 0, //level |
| GR_GL_RGBA, //internal format |
| screenWidth, // width |
| screenHeight, // height |
| 0, //border |
| GR_GL_RGBA, //format |
| GR_GL_UNSIGNED_BYTE, // type |
| nullptr)); |
| |
| // bind framebuffer |
| GrGLuint framebuffer; |
| GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); |
| GR_GL_CALL(gl, GenFramebuffers(1, &framebuffer)); |
| GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, framebuffer)); |
| GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, |
| GR_GL_COLOR_ATTACHMENT0, |
| GR_GL_TEXTURE_2D, |
| texture, 0)); |
| GR_GL_CALL(gl, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); |
| GR_GL_CALL(gl, Viewport(0, 0, screenWidth, screenHeight)); |
| return texture; |
| } |
| |
| |
| void GLBench::DumpImage(const GrGLInterface* gl, uint32_t screenWidth, uint32_t screenHeight, |
| const char* filename) { |
| // read back pixels |
| SkAutoTArray<uint32_t> readback(screenWidth * screenHeight); |
| GR_GL_CALL(gl, ReadPixels(0, // x |
| 0, // y |
| screenWidth, // width |
| screenHeight, // height |
| GR_GL_RGBA, //format |
| GR_GL_UNSIGNED_BYTE, //type |
| readback.get())); |
| |
| // dump png |
| SkBitmap bm; |
| if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(screenWidth, screenHeight))) { |
| SkDebugf("couldn't allocate bitmap\n"); |
| return; |
| } |
| |
| bm.setPixels(readback.get()); |
| |
| if (!sk_tool_utils::EncodeImageToFile(filename, bm, SkEncodedImageFormat::kPNG, 100)) { |
| SkDebugf("------ failed to encode %s\n", filename); |
| remove(filename); // remove any partial file |
| return; |
| } |
| } |
| |
| #endif |