// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "main.h"
#include "testbase.h"
#include "utils.h"
#include <algorithm>
namespace glbench {
class FillRateTest : public DrawArraysTestFunc {
public:
FillRateTest() {}
virtual ~FillRateTest() {}
virtual bool Run();
virtual const char* Name() const { return "fill_rate"; }
private:
DISALLOW_COPY_AND_ASSIGN(FillRateTest);
};
class FboFillRateTest : public DrawArraysTestFunc {
public:
FboFillRateTest() {}
virtual ~FboFillRateTest() {}
virtual bool Run();
virtual const char* Name() const { return "fbo_fill_rate"; }
private:
DISALLOW_COPY_AND_ASSIGN(FboFillRateTest);
};
const char* kVertexShader1 =
"attribute vec4 position;"
"void main() {"
" gl_Position = position;"
"}";
const char* kFragmentShader1 =
"uniform vec4 color;"
"void main() {"
" gl_FragColor = color;"
"}";
const char* kVertexShader2 =
"attribute vec4 position;"
"attribute vec4 texcoord;"
"uniform float scale;"
"varying vec4 v1;"
"void main() {"
" gl_Position = position * vec4(scale, scale, 1., 1.);"
" v1 = texcoord;"
"}";
const char* kFragmentShader2 =
"uniform sampler2D texture;"
"varying vec4 v1;"
"void main() {"
" gl_FragColor = texture2D(texture, v1.xy);"
"}";
const GLfloat buffer_vertex[8] = {
-1.f, -1.f,
1.f, -1.f,
-1.f, 1.f,
1.f, 1.f,
};
const GLfloat buffer_texture[8] = {
0.f, 0.f,
1.f, 0.f,
0.f, 1.f,
1.f, 1.f,
};
const GLfloat red[4] = {1.f, 0.f, 0.f, 1.f};
bool FillRateTest::Run() {
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER,
sizeof(buffer_vertex), buffer_vertex);
GLuint program = InitShaderProgram(kVertexShader1, kFragmentShader1);
GLint position_attribute = glGetAttribLocation(program, "position");
glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(position_attribute);
GLint color_uniform = glGetUniformLocation(program, "color");
glUniform4fv(color_uniform, 1, red);
FillRateTestNormal("fill_solid");
FillRateTestBlendDepth("fill_solid");
glDeleteProgram(program);
program = InitShaderProgram(kVertexShader2, kFragmentShader2);
position_attribute = glGetAttribLocation(program, "position");
// Reusing vbo_vertex buffer from the previous test.
glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(position_attribute);
GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER,
sizeof(buffer_texture), buffer_texture);
GLuint texcoord_attribute = glGetAttribLocation(program, "texcoord");
glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(texcoord_attribute);
// Get a fractal looking source texture of size 512x512 and full levels
// of detail.
GLuint texture = SetupTexture(9);
GLuint texture_uniform = glGetUniformLocation(program, "texture");
glUniform1i(texture_uniform, 0);
GLuint scale_uniform = glGetUniformLocation(program, "scale");
glUniform1f(scale_uniform, 1.f);
FillRateTestNormal("fill_tex_nearest");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
FillRateTestNormal("fill_tex_bilinear");
// lod = 0.5
float scale = 0.7071f;
glUniform1f(scale_uniform, scale);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
FillRateTestNormalSubWindow("fill_tex_trilinear_linear_05",
g_width, g_height);
// lod = 0.4
scale = 0.758f;
glUniform1f(scale_uniform, scale);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
FillRateTestNormalSubWindow("fill_tex_trilinear_linear_04",
g_width, g_height);
// lod = 0.1
scale = 0.933f;
glUniform1f(scale_uniform, scale);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
FillRateTestNormalSubWindow("fill_tex_trilinear_linear_01",
g_width, g_height);
glDeleteProgram(program);
glDeleteBuffers(1, &vbo_vertex);
glDeleteBuffers(1, &vbo_texture);
glDeleteTextures(1, &texture);
return true;
}
bool FboFillRateTest::Run() {
char name[256];
CHECK(!glGetError());
GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER,
sizeof(buffer_vertex), buffer_vertex);
GLuint program = InitShaderProgram(kVertexShader2, kFragmentShader2);
GLint position_attribute = glGetAttribLocation(program, "position");
glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(position_attribute);
GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER,
sizeof(buffer_texture), buffer_texture);
GLuint texcoord_attribute = glGetAttribLocation(program, "texcoord");
glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(texcoord_attribute);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
CHECK(!glGetError());
// We don't care for tiny texture sizes. And why the 8K*8K reference is
// only 700kB in size in the failure case it could be huge to upload to GS.
// In hasty mode we ignore huge textures all together.
const int max_size = std::min(g_hasty ? 512 : 4096, g_max_texture_size);
// Start with 32x32 textures and go up from there.
int size_log2 = 5;
for (int size = 1 << size_log2; size <= max_size; size *= 2) {
sprintf(name, "fbofill_tex_bilinear_%d", size);
// Setup texture for FBO.
GLuint destination_texture = 0;
glGenTextures(1, &destination_texture);
glBindTexture(GL_TEXTURE_2D, destination_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
CHECK(!glGetError());
// Setup Framebuffer.
// TODO(fjhenigman): In WAFFLE_PLATFORM_NULL the default framebuffer
// is NOT zero, so we have to save the current binding and restore
// that value later. Fix this.
GLint save_fb;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &save_fb);
GLuint framebuffer = 0;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, destination_texture, 0);
CHECK(!glGetError());
// Attach texture and check for completeness.
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
CHECK(status == GL_FRAMEBUFFER_COMPLETE);
glViewport(0, 0, size, size);
// Get a fractal looking source texture of size size*size.
GLuint source_texture = SetupTexture(size_log2);
GLuint texture_uniform = glGetUniformLocation(program, "texture");
glUniform1i(texture_uniform, 0);
GLuint scale_uniform = glGetUniformLocation(program, "scale");
glUniform1f(scale_uniform, 1.f);
// Run the benchmark, save the images if desired.
FillRateTestNormalSubWindow(name, size, size);
// Clean up for this loop.
glBindFramebuffer(GL_FRAMEBUFFER, save_fb);
glDeleteFramebuffers(1, &framebuffer);
glDeleteTextures(1, &source_texture);
glDeleteTextures(1, &destination_texture);
CHECK(!glGetError());
size_log2++;
}
// Clean up invariants.
glDeleteProgram(program);
glDeleteBuffers(1, &vbo_vertex);
glDeleteBuffers(1, &vbo_texture);
// Just in case restore the viewport for all other tests.
glViewport(0, 0, g_width, g_height);
return true;
}
TestBase* GetFillRateTest() {
return new FillRateTest;
}
TestBase* GetFboFillRateTest() {
return new FboFillRateTest;
}
} // namespace glbench