cb7ba1eafc
BUG=skia: Review URL: https://codereview.chromium.org/1403373012
271 lines
9.3 KiB
C++
271 lines
9.3 KiB
C++
/*
|
|
* 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 "Benchmark.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkImageEncoder.h"
|
|
|
|
#if SK_SUPPORT_GPU
|
|
#include "GLBench.h"
|
|
#include "gl/GrGLContext.h"
|
|
#include "gl/GrGLInterface.h"
|
|
#include "gl/GrGLUtil.h"
|
|
#include "glsl/GrGLSL.h"
|
|
#include "glsl/GrGLSLCaps.h"
|
|
#include "glsl/GrGLSLShaderVar.h"
|
|
#include <stdio.h>
|
|
|
|
/*
|
|
* This is a native GL benchmark for determining the cost of uploading vertex attributes
|
|
*/
|
|
class GLVertexAttributesBench : public GLBench {
|
|
public:
|
|
GLVertexAttributesBench(uint32_t attribs)
|
|
: fTexture(0)
|
|
, fBuffers(0)
|
|
, fProgram(0)
|
|
, fVBO(0)
|
|
, fAttribs(attribs)
|
|
, fStride(2 * sizeof(SkPoint) + fAttribs * sizeof(GrGLfloat) * 4) {
|
|
fName.appendf("GLVertexAttributesBench_%d", fAttribs);
|
|
}
|
|
|
|
protected:
|
|
const char* onGetName() override { return fName.c_str(); }
|
|
void setup(const GrGLContext*) override;
|
|
void glDraw(int loops, const GrGLContext*) override;
|
|
void teardown(const GrGLInterface*) override;
|
|
|
|
static const GrGLuint kScreenWidth = 800;
|
|
static const GrGLuint kScreenHeight = 600;
|
|
static const uint32_t kNumTri = 10000;
|
|
static const uint32_t kVerticesPerTri = 3;
|
|
static const uint32_t kDrawMultiplier = 512;
|
|
static const uint32_t kMaxAttribs = 7;
|
|
|
|
private:
|
|
GrGLuint setupShader(const GrGLContext*, uint32_t attribs, uint32_t maxAttribs);
|
|
|
|
GrGLuint fTexture;
|
|
SkTArray<GrGLuint> fBuffers;
|
|
GrGLuint fProgram;
|
|
GrGLuint fVBO;
|
|
SkTArray<unsigned char> fVertices;
|
|
uint32_t fAttribs;
|
|
size_t fStride;
|
|
SkString fName;
|
|
typedef Benchmark INHERITED;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
GrGLuint GLVertexAttributesBench::setupShader(const GrGLContext* ctx, uint32_t attribs,
|
|
uint32_t maxAttribs) {
|
|
const GrGLSLCaps* glslCaps = ctx->caps()->glslCaps();
|
|
const char* version = glslCaps->versionDeclString();
|
|
|
|
// setup vertex shader
|
|
GrGLSLShaderVar aPosition("a_position", kVec4f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
|
|
SkTArray<GrGLSLShaderVar> aVars;
|
|
SkTArray<GrGLSLShaderVar> oVars;
|
|
|
|
SkString vshaderTxt(version);
|
|
aPosition.appendDecl(glslCaps, &vshaderTxt);
|
|
vshaderTxt.append(";\n");
|
|
|
|
for (uint32_t i = 0; i < attribs; i++) {
|
|
SkString aname;
|
|
aname.appendf("a_color_%d", i);
|
|
aVars.push_back(GrGLSLShaderVar(aname.c_str(),
|
|
kVec4f_GrSLType,
|
|
GrShaderVar::kAttribute_TypeModifier));
|
|
aVars.back().appendDecl(glslCaps, &vshaderTxt);
|
|
vshaderTxt.append(";\n");
|
|
|
|
}
|
|
|
|
for (uint32_t i = 0; i < maxAttribs; i++) {
|
|
SkString oname;
|
|
oname.appendf("o_color_%d", i);
|
|
oVars.push_back(GrGLSLShaderVar(oname.c_str(),
|
|
kVec4f_GrSLType,
|
|
GrShaderVar::kVaryingOut_TypeModifier));
|
|
oVars.back().appendDecl(glslCaps, &vshaderTxt);
|
|
vshaderTxt.append(";\n");
|
|
}
|
|
|
|
vshaderTxt.append(
|
|
"void main()\n"
|
|
"{\n"
|
|
"gl_Position = a_position;\n");
|
|
|
|
for (uint32_t i = 0; i < attribs; i++) {
|
|
vshaderTxt.appendf("%s = %s;\n", oVars[i].c_str(), aVars[i].c_str());
|
|
}
|
|
|
|
// Passthrough position as a dummy
|
|
for (uint32_t i = attribs; i < maxAttribs; i++) {
|
|
vshaderTxt.appendf("%s = vec4(0, 0, 0, 1);\n", oVars[i].c_str());
|
|
}
|
|
|
|
vshaderTxt.append("}\n");
|
|
|
|
const GrGLInterface* gl = ctx->interface();
|
|
|
|
// setup fragment shader
|
|
GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
|
|
SkString fshaderTxt(version);
|
|
GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, &fshaderTxt);
|
|
|
|
const char* fsOutName;
|
|
if (glslCaps->mustDeclareFragmentShaderOutput()) {
|
|
oFragColor.appendDecl(glslCaps, &fshaderTxt);
|
|
fshaderTxt.append(";\n");
|
|
fsOutName = oFragColor.c_str();
|
|
} else {
|
|
fsOutName = "gl_FragColor";
|
|
}
|
|
|
|
for (uint32_t i = 0; i < maxAttribs; i++) {
|
|
oVars[i].setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
|
|
oVars[i].appendDecl(glslCaps, &fshaderTxt);
|
|
fshaderTxt.append(";\n");
|
|
}
|
|
|
|
fshaderTxt.appendf(
|
|
"void main()\n"
|
|
"{\n"
|
|
"%s = ", fsOutName);
|
|
|
|
fshaderTxt.appendf("%s", oVars[0].c_str());
|
|
for (uint32_t i = 1; i < maxAttribs; i++) {
|
|
fshaderTxt.appendf(" + %s", oVars[i].c_str());
|
|
}
|
|
|
|
fshaderTxt.append(";\n"
|
|
"}\n");
|
|
|
|
return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str());
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void GLVertexAttributesBench::setup(const GrGLContext* ctx) {
|
|
const GrGLInterface* gl = ctx->interface();
|
|
fTexture = SetupFramebuffer(gl, kScreenWidth, kScreenHeight);
|
|
|
|
fProgram = setupShader(ctx, fAttribs, kMaxAttribs);
|
|
|
|
// setup matrices
|
|
SkMatrix viewMatrices[kNumTri];
|
|
for (uint32_t i = 0 ; i < kNumTri; i++) {
|
|
SkMatrix m = SkMatrix::I();
|
|
m.setScale(0.0001f, 0.0001f);
|
|
viewMatrices[i] = m;
|
|
}
|
|
|
|
// presetup vertex attributes, color is set to be a light gray no matter how many vertex
|
|
// attributes are used
|
|
float targetColor = 0.9f;
|
|
float colorContribution = targetColor / fAttribs;
|
|
fVertices.reset(static_cast<int>(kVerticesPerTri * kNumTri * fStride));
|
|
for (uint32_t i = 0; i < kNumTri; i++) {
|
|
unsigned char* ptr = &fVertices[static_cast<int>(i * kVerticesPerTri * fStride)];
|
|
SkPoint* p = reinterpret_cast<SkPoint*>(ptr);
|
|
p->set(-1.0f, -1.0f); p++; p->set( 0.0f, 1.0f);
|
|
p = reinterpret_cast<SkPoint*>(ptr + fStride);
|
|
p->set( 1.0f, -1.0f); p++; p->set( 0.0f, 1.0f);
|
|
p = reinterpret_cast<SkPoint*>(ptr + fStride * 2);
|
|
p->set( 1.0f, 1.0f); p++; p->set( 0.0f, 1.0f);
|
|
|
|
SkPoint* position = reinterpret_cast<SkPoint*>(ptr);
|
|
viewMatrices[i].mapPointsWithStride(position, fStride, kVerticesPerTri);
|
|
|
|
// set colors
|
|
for (uint32_t j = 0; j < kVerticesPerTri; j++) {
|
|
GrGLfloat* f = reinterpret_cast<GrGLfloat*>(ptr + 2 * sizeof(SkPoint) + fStride * j);
|
|
for (uint32_t k = 0; k < fAttribs * 4; k += 4) {
|
|
f[k] = colorContribution;
|
|
f[k + 1] = colorContribution;
|
|
f[k + 2] = colorContribution;
|
|
f[k + 3] = 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
GR_GL_CALL(gl, GenBuffers(1, &fVBO));
|
|
fBuffers.push_back(fVBO);
|
|
|
|
// clear screen
|
|
GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f));
|
|
GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT));
|
|
|
|
// set us up to draw
|
|
GR_GL_CALL(gl, UseProgram(fProgram));
|
|
}
|
|
|
|
void GLVertexAttributesBench::glDraw(int loops, const GrGLContext* ctx) {
|
|
const GrGLInterface* gl = ctx->interface();
|
|
|
|
// upload vertex attributes
|
|
GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVBO));
|
|
GR_GL_CALL(gl, EnableVertexAttribArray(0));
|
|
GR_GL_CALL(gl, VertexAttribPointer(0, 4, GR_GL_FLOAT, GR_GL_FALSE, (GrGLsizei)fStride,
|
|
(GrGLvoid*)0));
|
|
|
|
size_t runningStride = 2 * sizeof(SkPoint);
|
|
for (uint32_t i = 0; i < fAttribs; i++) {
|
|
int attribId = i + 1;
|
|
GR_GL_CALL(gl, EnableVertexAttribArray(attribId));
|
|
GR_GL_CALL(gl, VertexAttribPointer(attribId, 4, GR_GL_FLOAT, GR_GL_FALSE,
|
|
(GrGLsizei)fStride, (GrGLvoid*)(runningStride)));
|
|
runningStride += sizeof(GrGLfloat) * 4;
|
|
}
|
|
|
|
GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, fVertices.count(), fVertices.begin(),
|
|
GR_GL_STREAM_DRAW));
|
|
|
|
uint32_t maxTrianglesPerFlush = kNumTri;
|
|
uint32_t trianglesToDraw = loops * kDrawMultiplier;
|
|
|
|
while (trianglesToDraw > 0) {
|
|
uint32_t triangles = SkTMin(trianglesToDraw, maxTrianglesPerFlush);
|
|
GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * triangles));
|
|
trianglesToDraw -= triangles;
|
|
}
|
|
|
|
#if 0
|
|
//const char* filename = "/data/local/tmp/out.png";
|
|
SkString filename("out");
|
|
filename.appendf("_%s.png", this->getName());
|
|
DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str());
|
|
#endif
|
|
}
|
|
|
|
void GLVertexAttributesBench::teardown(const GrGLInterface* gl) {
|
|
// teardown
|
|
GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, 0));
|
|
GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0));
|
|
GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, 0));
|
|
GR_GL_CALL(gl, DeleteTextures(1, &fTexture));
|
|
GR_GL_CALL(gl, DeleteProgram(fProgram));
|
|
GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin()));
|
|
fBuffers.reset();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_BENCH( return new GLVertexAttributesBench(0) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(1) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(2) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(3) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(4) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(5) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(6) )
|
|
DEF_BENCH( return new GLVertexAttributesBench(7) )
|
|
#endif
|