summaryrefslogtreecommitdiffstats
path: root/gpu/perftests
diff options
context:
space:
mode:
authordcastagna <dcastagna@chromium.org>2015-03-18 22:10:16 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-19 05:10:58 +0000
commit1b9c0f6571baefe70dad41d504cbe3136ce41ae4 (patch)
treef8622347383fb146a6ea489c067912a6b7d7f804 /gpu/perftests
parent7d6166f4461ed1c2a31ae6d3fd5a941a5625203c (diff)
downloadchromium_src-1b9c0f6571baefe70dad41d504cbe3136ce41ae4.zip
chromium_src-1b9c0f6571baefe70dad41d504cbe3136ce41ae4.tar.gz
chromium_src-1b9c0f6571baefe70dad41d504cbe3136ce41ae4.tar.bz2
gpu: Measure texture uploads with glTexSubImage2D and glTexImage2D.
glTexImage2D and glTexSubImage2D could have different performance properties. With this patch we benchmark both of these upload techniques. When using glTexSubImage2D the texture storage is specified with glTexStorage2D when available, or glTexImage2D passing an empty pointer as data. BUG=423481 Review URL: https://codereview.chromium.org/1022603002 Cr-Commit-Position: refs/heads/master@{#321300}
Diffstat (limited to 'gpu/perftests')
-rw-r--r--gpu/perftests/texture_upload_perftest.cc122
1 files changed, 87 insertions, 35 deletions
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc
index add6343..d1192b5 100644
--- a/gpu/perftests/texture_upload_perftest.cc
+++ b/gpu/perftests/texture_upload_perftest.cc
@@ -20,14 +20,15 @@
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_version_info.h"
#include "ui/gl/gpu_timing.h"
#include "ui/gl/scoped_make_current.h"
namespace gpu {
namespace {
-const int kUploadPerfWarmupRuns = 10;
-const int kUploadPerfTestRuns = 100;
+const int kUploadPerfWarmupRuns = 5;
+const int kUploadPerfTestRuns = 30;
#define SHADER(Src) #Src
@@ -58,8 +59,8 @@ SHADER(
);
// clang-format on
-void CheckNoGlError() {
- CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+void CheckNoGlError(const std::string& msg) {
+ CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()) << " " << msg;
}
// Utility function to compile a shader from a string.
@@ -90,6 +91,20 @@ int GLFormatBytePerPixel(GLenum format) {
return format == GL_RGBA ? 4 : 1;
}
+GLenum GLFormatToStorageFormat(GLenum format) {
+ switch (format) {
+ case GL_RGBA:
+ return GL_RGBA8;
+ case GL_LUMINANCE:
+ return GL_LUMINANCE8;
+ case GL_RED_EXT:
+ return GL_R8;
+ default:
+ NOTREACHED();
+ }
+ return 0;
+}
+
void GenerateTextureData(const gfx::Size& size,
int bytes_per_pixel,
const int seed,
@@ -227,7 +242,12 @@ class TextureUploadPerfTest : public testing::Test {
reinterpret_cast<void*>(sizeof(GLfloat) * 2));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
- CheckNoGlError();
+ CheckNoGlError("glEnableVertexAttribArray");
+
+ has_texture_storage_ =
+ gl_context_->GetVersionInfo()->is_es3 ||
+ gl_context_->HasExtension("GL_EXT_texture_storage") ||
+ gl_context_->HasExtension("GL_ARB_texture_storage");
}
void GenerateVertexBuffer(const gfx::Size& size) {
@@ -249,7 +269,7 @@ class TextureUploadPerfTest : public testing::Test {
right, top, 1.f, 1.f};
// clang-format on
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
- CheckNoGlError();
+ CheckNoGlError("glBufferData");
}
void TearDown() override {
@@ -262,7 +282,7 @@ class TextureUploadPerfTest : public testing::Test {
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
glDeleteFramebuffersEXT(1, &framebuffer_object_);
glDeleteTextures(1, &color_texture_);
- CheckNoGlError();
+ CheckNoGlError("glDeleteTextures");
gpu_timing_client_ = nullptr;
gl_context_ = nullptr;
@@ -270,36 +290,57 @@ class TextureUploadPerfTest : public testing::Test {
}
protected:
- GLuint CreateGLTexture() {
+ GLuint CreateGLTexture(const GLenum format,
+ const gfx::Size& size,
+ const bool specify_storage) {
GLuint texture_id = 0;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (specify_storage) {
+ if (has_texture_storage_) {
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GLFormatToStorageFormat(format),
+ size.width(), size.height());
+ CheckNoGlError("glTexStorage2DEXT");
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0,
+ format, GL_UNSIGNED_BYTE, nullptr);
+ CheckNoGlError("glTexImage2D");
+ }
+ }
return texture_id;
}
void UploadTexture(GLuint texture_id,
const gfx::Size& size,
const std::vector<uint8>& pixels,
- GLenum format) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0,
- format, GL_UNSIGNED_BYTE, &pixels[0]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- CheckNoGlError();
+ GLenum format,
+ const bool subimage) {
+ if (subimage) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(),
+ format, GL_UNSIGNED_BYTE, &pixels[0]);
+ CheckNoGlError("glTexSubImage2D");
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0,
+ format, GL_UNSIGNED_BYTE, &pixels[0]);
+ CheckNoGlError("glTexImage2D");
+ }
}
// Upload and draw on the offscren surface.
// Return a list of pair. Each pair describe a gl operation and the wall
// time elapsed in milliseconds.
- std::vector<Measurement> UploadAndDraw(const gfx::Size& size,
+ std::vector<Measurement> UploadAndDraw(GLuint texture_id,
+ const gfx::Size& size,
const std::vector<uint8>& pixels,
- const GLenum format) {
- GLuint texture_id = CreateGLTexture();
+ const GLenum format,
+ const bool subimage) {
MeasurementTimers tex_timers(gpu_timing_client_.get());
- UploadTexture(texture_id, size, pixels, format);
+ UploadTexture(texture_id, size, pixels, format, subimage);
tex_timers.Record();
MeasurementTimers draw_timers(gpu_timing_client_.get());
@@ -309,15 +350,13 @@ class TextureUploadPerfTest : public testing::Test {
MeasurementTimers finish_timers(gpu_timing_client_.get());
glFinish();
- CheckNoGlError();
+ CheckNoGlError("glFinish");
finish_timers.Record();
- glDeleteTextures(1, &texture_id);
-
std::vector<uint8> pixels_rendered(size.GetArea() * 4);
glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
&pixels_rendered[0]);
- CheckNoGlError();
+ CheckNoGlError("glReadPixels");
EXPECT_TRUE(
CompareBufferToRGBABuffer(format, size, pixels, pixels_rendered))
<< "Format is: " << gfx::GLEnums::GetStringEnum(format);
@@ -327,7 +366,8 @@ class TextureUploadPerfTest : public testing::Test {
gpu_timing_client_->IsAvailable() &&
gpu_timing_client_->CheckAndResetTimerErrors();
if (!gpu_timer_errors) {
- measurements.push_back(tex_timers.GetAsMeasurement("teximage2d"));
+ measurements.push_back(tex_timers.GetAsMeasurement(
+ subimage ? "texsubimage2d" : "teximage2d"));
measurements.push_back(draw_timers.GetAsMeasurement("drawarrays"));
measurements.push_back(finish_timers.GetAsMeasurement("finish"));
}
@@ -335,14 +375,16 @@ class TextureUploadPerfTest : public testing::Test {
}
void RunUploadAndDrawMultipleTimes(const gfx::Size& size,
- const GLenum format) {
+ const GLenum format,
+ const bool subimage) {
std::vector<uint8> pixels;
base::SmallMap<std::map<std::string, Measurement>>
aggregates; // indexed by name
int successful_runs = 0;
+ GLuint texture_id = CreateGLTexture(format, size, subimage);
for (int i = 0; i < kUploadPerfWarmupRuns + kUploadPerfTestRuns; ++i) {
GenerateTextureData(size, GLFormatBytePerPixel(format), i + 1, &pixels);
- auto run = UploadAndDraw(size, pixels, format);
+ auto run = UploadAndDraw(texture_id, size, pixels, format, subimage);
if (i < kUploadPerfWarmupRuns || !run.size()) {
continue;
}
@@ -353,8 +395,14 @@ class TextureUploadPerfTest : public testing::Test {
aggregate.Increment(measurement);
}
}
+ glDeleteTextures(1, &texture_id);
+
std::string graph_name = base::StringPrintf(
"%d_%s", size.width(), gfx::GLEnums::GetStringEnum(format).c_str());
+ if (subimage) {
+ graph_name += "_sub";
+ }
+
if (successful_runs) {
for (const auto& entry : aggregates) {
const auto m = entry.second.Divide(successful_runs);
@@ -378,11 +426,13 @@ class TextureUploadPerfTest : public testing::Test {
GLint sampler_location_ = -1;
GLint translation_location_ = -1;
GLuint vertex_buffer_ = 0;
+
+ bool has_texture_storage_ = false;
};
// Perf test that generates, uploads and draws a texture on a surface repeatedly
// and prints out aggregated measurements for all the runs.
-TEST_F(TextureUploadPerfTest, glTexImage2d) {
+TEST_F(TextureUploadPerfTest, upload) {
int sizes[] = {21, 128, 256, 512, 1024};
std::vector<GLenum> formats;
formats.push_back(GL_RGBA);
@@ -390,21 +440,23 @@ TEST_F(TextureUploadPerfTest, glTexImage2d) {
formats.push_back(GL_LUMINANCE);
ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
- bool has_texture_rg = gl_context_->HasExtension("GL_EXT_texture_rg") ||
- gl_context_->HasExtension("GL_ARB_texture_rg");
+ const bool has_texture_rg = gl_context_->HasExtension("GL_EXT_texture_rg") ||
+ gl_context_->HasExtension("GL_ARB_texture_rg");
if (has_texture_rg) {
// Used as ResourceProvider::yuv_resource_format_ if
// {ARB,EXT}_texture_rg are available.
formats.push_back(GL_RED_EXT);
}
+
for (int side : sizes) {
ASSERT_GE(fbo_size_.width(), side);
ASSERT_GE(fbo_size_.height(), side);
gfx::Size size(side, side);
GenerateVertexBuffer(size);
for (GLenum format : formats) {
- RunUploadAndDrawMultipleTimes(size, format);
+ RunUploadAndDrawMultipleTimes(size, format, true); // use glTexSubImage2D
+ RunUploadAndDrawMultipleTimes(size, format, false); // use glTexImage2D
}
}
}
@@ -433,12 +485,12 @@ TEST_F(TextureUploadPerfTest, renaming) {
gfx::Vector2dF(1.f, 0.f),
gfx::Vector2dF(0.f, 1.f),
gfx::Vector2dF(1.f, 1.f)};
- GLuint texture_id = CreateGLTexture();
+ GLuint texture_id = CreateGLTexture(GL_RGBA, texture_size, true);
MeasurementTimers upload_and_draw_timers(gpu_timing_client_.get());
for (int i = 0; i < 4; ++i) {
- UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA);
+ UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA, true);
DCHECK_NE(-1, translation_location_);
glUniform2f(translation_location_, positions[i % 4].x(),
positions[i % 4].y());
@@ -452,7 +504,7 @@ TEST_F(TextureUploadPerfTest, renaming) {
upload_and_draw_timers.Record();
MeasurementTimers finish_timers(gpu_timing_client_.get());
glFinish();
- CheckNoGlError();
+ CheckNoGlError("glFinish");
finish_timers.Record();
glDeleteTextures(1, &texture_id);
@@ -463,7 +515,7 @@ TEST_F(TextureUploadPerfTest, renaming) {
texture_size.height() * positions[i].y(), texture_size.width(),
texture_size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
&pixels_rendered[0]);
- CheckNoGlError();
+ CheckNoGlError("glReadPixels");
ASSERT_EQ(pixels[i].size(), pixels_rendered.size());
EXPECT_EQ(pixels[i], pixels_rendered);
}