diff options
author | dcastagna <dcastagna@chromium.org> | 2015-03-19 22:11:09 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-20 05:11:51 +0000 |
commit | e450ffd9dc792387272d5771fdec81639942655d (patch) | |
tree | 3c66bb93c43e8f99f0e2835c59c4b317c0dbf4bb /gpu | |
parent | a24bf43bfb8ea6f75109ba9eea841f92c164e3ae (diff) | |
download | chromium_src-e450ffd9dc792387272d5771fdec81639942655d.zip chromium_src-e450ffd9dc792387272d5771fdec81639942655d.tar.gz chromium_src-e450ffd9dc792387272d5771fdec81639942655d.tar.bz2 |
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.
Trying to re-land this patch after it broke the perfbots (crbug.com/468748).
BUG=468748
Review URL: https://codereview.chromium.org/1027623002
Cr-Commit-Position: refs/heads/master@{#321519}
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/perftests/texture_upload_perftest.cc | 119 |
1 files changed, 88 insertions, 31 deletions
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc index 4211084..c14a151 100644 --- a/gpu/perftests/texture_upload_perftest.cc +++ b/gpu/perftests/texture_upload_perftest.cc @@ -59,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. @@ -91,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, @@ -228,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) { @@ -250,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 { @@ -263,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; @@ -271,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()); @@ -310,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); @@ -328,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")); } @@ -336,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; } @@ -354,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); @@ -379,11 +432,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); @@ -403,13 +458,15 @@ TEST_F(TextureUploadPerfTest, glTexImage2d) { // {ARB,EXT}_texture_rg are available. 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 } } } @@ -438,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()); @@ -457,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); @@ -468,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); } |