Index: gpu/perftests/texture_upload_perftest.cc |
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc |
index 89e901aea0839719b6eb76a2c07ba0875fdeba14..c14a15129a3a2e91f99a72ffb7433330e9a3e5e0 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 |
@@ -44,9 +45,12 @@ SHADER( |
v_texCoord = a_texCoord; |
} |
); |
-const char kFragmentShader[] = |
+const char kShaderDefaultFloatPrecision[] = |
SHADER( |
precision mediump float; |
+); |
+const char kFragmentShader[] = |
+SHADER( |
uniform sampler2D a_texture; |
varying vec2 v_texCoord; |
void main() { |
@@ -55,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. |
@@ -87,6 +91,24 @@ int GLFormatBytePerPixel(GLenum format) { |
return format == GL_RGBA ? 4 : 1; |
} |
+GLenum GLFormatToInternalFormat(GLenum format) { |
+ return format == GL_RED ? GL_R8 : format; |
+} |
+ |
+GLenum GLFormatToStorageFormat(GLenum format) { |
+ switch (format) { |
+ case GL_RGBA: |
+ return GL_RGBA8; |
+ case GL_LUMINANCE: |
+ return GL_LUMINANCE8; |
+ case GL_RED: |
+ return GL_R8; |
+ default: |
+ NOTREACHED(); |
+ } |
+ return 0; |
+} |
+ |
void GenerateTextureData(const gfx::Size& size, |
int bytes_per_pixel, |
const int seed, |
@@ -123,7 +145,7 @@ bool CompareBufferToRGBABuffer(GLenum format, |
case GL_LUMINANCE: // (L_t, L_t, L_t, 1) |
expected[1] = pixels[pixels_index]; |
expected[2] = pixels[pixels_index]; |
- case GL_RED_EXT: // (R_t, 0, 0, 1)n |
+ case GL_RED: // (R_t, 0, 0, 1) |
expected[0] = pixels[pixels_index]; |
expected[3] = 255; |
break; |
@@ -187,7 +209,12 @@ class TextureUploadPerfTest : public testing::Test { |
// Prepare a simple program and a vertex buffer that will be |
// used to draw a quad on the offscreen surface. |
vertex_shader_ = LoadShader(GL_VERTEX_SHADER, kVertexShader); |
- fragment_shader_ = LoadShader(GL_FRAGMENT_SHADER, kFragmentShader); |
+ |
+ bool is_gles = gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2; |
+ fragment_shader_ = LoadShader( |
+ GL_FRAGMENT_SHADER, |
+ base::StringPrintf("%s%s", is_gles ? kShaderDefaultFloatPrecision : "", |
+ kFragmentShader).c_str()); |
program_object_ = glCreateProgram(); |
CHECK_NE(0u, program_object_); |
@@ -219,7 +246,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) { |
@@ -241,7 +273,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 { |
@@ -254,7 +286,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; |
@@ -262,36 +294,59 @@ 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, GLFormatToInternalFormat(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, GLFormatToInternalFormat(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()); |
@@ -301,15 +356,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); |
@@ -319,7 +372,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")); |
} |
@@ -327,14 +381,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; |
} |
@@ -345,8 +401,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); |
@@ -370,33 +432,41 @@ 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); |
- // Used by default for ResourceProvider::yuv_resource_format_. |
- formats.push_back(GL_LUMINANCE); |
+ |
+ if (!gl_context_->GetVersionInfo()->is_es3) { |
+ // Used by default for ResourceProvider::yuv_resource_format_. |
+ 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_->GetVersionInfo()->is_es3 || |
+ 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); |
+ formats.push_back(GL_RED); |
} |
+ |
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 |
} |
} |
} |
@@ -425,12 +495,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()); |
@@ -444,7 +514,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); |
@@ -455,7 +525,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); |
} |