| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 #include <vector> | 6 #include <vector> |
| 7 | 7 |
| 8 #include "base/containers/small_map.h" | 8 #include "base/containers/small_map.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "gpu/perftests/measurements.h" | 13 #include "gpu/perftests/measurements.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 #include "testing/perf/perf_test.h" | 16 #include "testing/perf/perf_test.h" |
| 17 #include "ui/gfx/geometry/size.h" | 17 #include "ui/gfx/geometry/size.h" |
| 18 #include "ui/gfx/geometry/vector2d_f.h" | 18 #include "ui/gfx/geometry/vector2d_f.h" |
| 19 #include "ui/gl/gl_bindings.h" | 19 #include "ui/gl/gl_bindings.h" |
| 20 #include "ui/gl/gl_context.h" | 20 #include "ui/gl/gl_context.h" |
| 21 #include "ui/gl/gl_enums.h" | 21 #include "ui/gl/gl_enums.h" |
| 22 #include "ui/gl/gl_surface.h" | 22 #include "ui/gl/gl_surface.h" |
| 23 #include "ui/gl/gl_version_info.h" | |
| 24 #include "ui/gl/gpu_timing.h" | 23 #include "ui/gl/gpu_timing.h" |
| 25 #include "ui/gl/scoped_make_current.h" | 24 #include "ui/gl/scoped_make_current.h" |
| 26 | 25 |
| 27 namespace gpu { | 26 namespace gpu { |
| 28 namespace { | 27 namespace { |
| 29 | 28 |
| 30 const int kUploadPerfWarmupRuns = 5; | 29 const int kUploadPerfWarmupRuns = 10; |
| 31 const int kUploadPerfTestRuns = 30; | 30 const int kUploadPerfTestRuns = 100; |
| 32 | 31 |
| 33 #define SHADER(Src) #Src | 32 #define SHADER(Src) #Src |
| 34 | 33 |
| 35 // clang-format off | 34 // clang-format off |
| 36 const char kVertexShader[] = | 35 const char kVertexShader[] = |
| 37 SHADER( | 36 SHADER( |
| 38 uniform vec2 translation; | 37 uniform vec2 translation; |
| 39 attribute vec2 a_position; | 38 attribute vec2 a_position; |
| 40 attribute vec2 a_texCoord; | 39 attribute vec2 a_texCoord; |
| 41 varying vec2 v_texCoord; | 40 varying vec2 v_texCoord; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 52 const char kFragmentShader[] = | 51 const char kFragmentShader[] = |
| 53 SHADER( | 52 SHADER( |
| 54 uniform sampler2D a_texture; | 53 uniform sampler2D a_texture; |
| 55 varying vec2 v_texCoord; | 54 varying vec2 v_texCoord; |
| 56 void main() { | 55 void main() { |
| 57 gl_FragColor = texture2D(a_texture, v_texCoord); | 56 gl_FragColor = texture2D(a_texture, v_texCoord); |
| 58 } | 57 } |
| 59 ); | 58 ); |
| 60 // clang-format on | 59 // clang-format on |
| 61 | 60 |
| 62 void CheckNoGlError(const std::string& msg) { | 61 void CheckNoGlError() { |
| 63 CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()) << " " << msg; | 62 CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
| 64 } | 63 } |
| 65 | 64 |
| 66 // Utility function to compile a shader from a string. | 65 // Utility function to compile a shader from a string. |
| 67 GLuint LoadShader(const GLenum type, const char* const src) { | 66 GLuint LoadShader(const GLenum type, const char* const src) { |
| 68 GLuint shader = 0; | 67 GLuint shader = 0; |
| 69 shader = glCreateShader(type); | 68 shader = glCreateShader(type); |
| 70 CHECK_NE(0u, shader); | 69 CHECK_NE(0u, shader); |
| 71 glShaderSource(shader, 1, &src, NULL); | 70 glShaderSource(shader, 1, &src, NULL); |
| 72 glCompileShader(shader); | 71 glCompileShader(shader); |
| 73 | 72 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 84 } | 83 } |
| 85 CHECK_NE(0, compiled); | 84 CHECK_NE(0, compiled); |
| 86 return shader; | 85 return shader; |
| 87 } | 86 } |
| 88 | 87 |
| 89 int GLFormatBytePerPixel(GLenum format) { | 88 int GLFormatBytePerPixel(GLenum format) { |
| 90 DCHECK(format == GL_RGBA || format == GL_LUMINANCE || format == GL_RED_EXT); | 89 DCHECK(format == GL_RGBA || format == GL_LUMINANCE || format == GL_RED_EXT); |
| 91 return format == GL_RGBA ? 4 : 1; | 90 return format == GL_RGBA ? 4 : 1; |
| 92 } | 91 } |
| 93 | 92 |
| 94 GLenum GLFormatToStorageFormat(GLenum format) { | |
| 95 switch (format) { | |
| 96 case GL_RGBA: | |
| 97 return GL_RGBA8; | |
| 98 case GL_LUMINANCE: | |
| 99 return GL_LUMINANCE8; | |
| 100 case GL_RED_EXT: | |
| 101 return GL_R8; | |
| 102 default: | |
| 103 NOTREACHED(); | |
| 104 } | |
| 105 return 0; | |
| 106 } | |
| 107 | |
| 108 void GenerateTextureData(const gfx::Size& size, | 93 void GenerateTextureData(const gfx::Size& size, |
| 109 int bytes_per_pixel, | 94 int bytes_per_pixel, |
| 110 const int seed, | 95 const int seed, |
| 111 std::vector<uint8>* const pixels) { | 96 std::vector<uint8>* const pixels) { |
| 112 // Row bytes has to be multiple of 4 (GL_PACK_ALIGNMENT defaults to 4). | 97 // Row bytes has to be multiple of 4 (GL_PACK_ALIGNMENT defaults to 4). |
| 113 int stride = ((size.width() * bytes_per_pixel) + 3) & ~0x3; | 98 int stride = ((size.width() * bytes_per_pixel) + 3) & ~0x3; |
| 114 pixels->resize(size.height() * stride); | 99 pixels->resize(size.height() * stride); |
| 115 for (int y = 0; y < size.height(); ++y) { | 100 for (int y = 0; y < size.height(); ++y) { |
| 116 for (int x = 0; x < size.width(); ++x) { | 101 for (int x = 0; x < size.width(); ++x) { |
| 117 for (int channel = 0; channel < bytes_per_pixel; ++channel) { | 102 for (int channel = 0; channel < bytes_per_pixel; ++channel) { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 | 220 |
| 236 glGenBuffersARB(1, &vertex_buffer_); | 221 glGenBuffersARB(1, &vertex_buffer_); |
| 237 CHECK_NE(0u, vertex_buffer_); | 222 CHECK_NE(0u, vertex_buffer_); |
| 238 DCHECK_NE(0u, vertex_buffer_); | 223 DCHECK_NE(0u, vertex_buffer_); |
| 239 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); | 224 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); |
| 240 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, 0); | 225 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, 0); |
| 241 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, | 226 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, |
| 242 reinterpret_cast<void*>(sizeof(GLfloat) * 2)); | 227 reinterpret_cast<void*>(sizeof(GLfloat) * 2)); |
| 243 glEnableVertexAttribArray(0); | 228 glEnableVertexAttribArray(0); |
| 244 glEnableVertexAttribArray(1); | 229 glEnableVertexAttribArray(1); |
| 245 CheckNoGlError("glEnableVertexAttribArray"); | 230 CheckNoGlError(); |
| 246 | |
| 247 has_texture_storage_ = | |
| 248 gl_context_->GetVersionInfo()->is_es3 || | |
| 249 gl_context_->HasExtension("GL_EXT_texture_storage") || | |
| 250 gl_context_->HasExtension("GL_ARB_texture_storage"); | |
| 251 } | 231 } |
| 252 | 232 |
| 253 void GenerateVertexBuffer(const gfx::Size& size) { | 233 void GenerateVertexBuffer(const gfx::Size& size) { |
| 254 DCHECK_NE(0u, vertex_buffer_); | 234 DCHECK_NE(0u, vertex_buffer_); |
| 255 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); | 235 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); |
| 256 // right and top are in clipspace | 236 // right and top are in clipspace |
| 257 float right = -1.f + 2.f * size.width() / fbo_size_.width(); | 237 float right = -1.f + 2.f * size.width() / fbo_size_.width(); |
| 258 float top = -1.f + 2.f * size.height() / fbo_size_.height(); | 238 float top = -1.f + 2.f * size.height() / fbo_size_.height(); |
| 259 // Four vertexes, one per line. Each vertex has two components per | 239 // Four vertexes, one per line. Each vertex has two components per |
| 260 // position and two per texcoord. | 240 // position and two per texcoord. |
| 261 // It represents a quad formed by two triangles if interpreted | 241 // It represents a quad formed by two triangles if interpreted |
| 262 // as a tristrip. | 242 // as a tristrip. |
| 263 | 243 |
| 264 // clang-format off | 244 // clang-format off |
| 265 GLfloat data[16] = { | 245 GLfloat data[16] = { |
| 266 -1.f, -1.f, 0.f, 0.f, | 246 -1.f, -1.f, 0.f, 0.f, |
| 267 right, -1.f, 1.f, 0.f, | 247 right, -1.f, 1.f, 0.f, |
| 268 -1.f, top, 0.f, 1.f, | 248 -1.f, top, 0.f, 1.f, |
| 269 right, top, 1.f, 1.f}; | 249 right, top, 1.f, 1.f}; |
| 270 // clang-format on | 250 // clang-format on |
| 271 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); | 251 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| 272 CheckNoGlError("glBufferData"); | 252 CheckNoGlError(); |
| 273 } | 253 } |
| 274 | 254 |
| 275 void TearDown() override { | 255 void TearDown() override { |
| 276 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); | 256 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); |
| 277 glDeleteProgram(program_object_); | 257 glDeleteProgram(program_object_); |
| 278 glDeleteShader(vertex_shader_); | 258 glDeleteShader(vertex_shader_); |
| 279 glDeleteShader(fragment_shader_); | 259 glDeleteShader(fragment_shader_); |
| 280 glDeleteBuffersARB(1, &vertex_buffer_); | 260 glDeleteBuffersARB(1, &vertex_buffer_); |
| 281 | 261 |
| 282 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | 262 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| 283 glDeleteFramebuffersEXT(1, &framebuffer_object_); | 263 glDeleteFramebuffersEXT(1, &framebuffer_object_); |
| 284 glDeleteTextures(1, &color_texture_); | 264 glDeleteTextures(1, &color_texture_); |
| 285 CheckNoGlError("glDeleteTextures"); | 265 CheckNoGlError(); |
| 286 | 266 |
| 287 gpu_timing_client_ = nullptr; | 267 gpu_timing_client_ = nullptr; |
| 288 gl_context_ = nullptr; | 268 gl_context_ = nullptr; |
| 289 surface_ = nullptr; | 269 surface_ = nullptr; |
| 290 } | 270 } |
| 291 | 271 |
| 292 protected: | 272 protected: |
| 293 GLuint CreateGLTexture(const GLenum format, | 273 GLuint CreateGLTexture() { |
| 294 const gfx::Size& size, | |
| 295 const bool specify_storage) { | |
| 296 GLuint texture_id = 0; | 274 GLuint texture_id = 0; |
| 297 glActiveTexture(GL_TEXTURE0); | 275 glActiveTexture(GL_TEXTURE0); |
| 298 glGenTextures(1, &texture_id); | 276 glGenTextures(1, &texture_id); |
| 299 glBindTexture(GL_TEXTURE_2D, texture_id); | 277 glBindTexture(GL_TEXTURE_2D, texture_id); |
| 300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 304 if (specify_storage) { | |
| 305 if (has_texture_storage_) { | |
| 306 glTexStorage2DEXT(GL_TEXTURE_2D, 1, GLFormatToStorageFormat(format), | |
| 307 size.width(), size.height()); | |
| 308 CheckNoGlError("glTexStorage2DEXT"); | |
| 309 } else { | |
| 310 glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, | |
| 311 format, GL_UNSIGNED_BYTE, nullptr); | |
| 312 CheckNoGlError("glTexImage2D"); | |
| 313 } | |
| 314 } | |
| 315 return texture_id; | 278 return texture_id; |
| 316 } | 279 } |
| 317 | 280 |
| 318 void UploadTexture(GLuint texture_id, | 281 void UploadTexture(GLuint texture_id, |
| 319 const gfx::Size& size, | 282 const gfx::Size& size, |
| 320 const std::vector<uint8>& pixels, | 283 const std::vector<uint8>& pixels, |
| 321 GLenum format, | 284 GLenum format) { |
| 322 const bool subimage) { | 285 glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, |
| 323 if (subimage) { | 286 format, GL_UNSIGNED_BYTE, &pixels[0]); |
| 324 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), | 287 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 325 format, GL_UNSIGNED_BYTE, &pixels[0]); | 288 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 326 CheckNoGlError("glTexSubImage2D"); | 289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 327 } else { | 290 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 328 glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, | 291 CheckNoGlError(); |
| 329 format, GL_UNSIGNED_BYTE, &pixels[0]); | |
| 330 CheckNoGlError("glTexImage2D"); | |
| 331 } | |
| 332 } | 292 } |
| 333 | 293 |
| 334 // Upload and draw on the offscren surface. | 294 // Upload and draw on the offscren surface. |
| 335 // Return a list of pair. Each pair describe a gl operation and the wall | 295 // Return a list of pair. Each pair describe a gl operation and the wall |
| 336 // time elapsed in milliseconds. | 296 // time elapsed in milliseconds. |
| 337 std::vector<Measurement> UploadAndDraw(GLuint texture_id, | 297 std::vector<Measurement> UploadAndDraw(const gfx::Size& size, |
| 338 const gfx::Size& size, | |
| 339 const std::vector<uint8>& pixels, | 298 const std::vector<uint8>& pixels, |
| 340 const GLenum format, | 299 const GLenum format) { |
| 341 const bool subimage) { | 300 GLuint texture_id = CreateGLTexture(); |
| 342 MeasurementTimers tex_timers(gpu_timing_client_.get()); | 301 MeasurementTimers tex_timers(gpu_timing_client_.get()); |
| 343 UploadTexture(texture_id, size, pixels, format, subimage); | 302 UploadTexture(texture_id, size, pixels, format); |
| 344 tex_timers.Record(); | 303 tex_timers.Record(); |
| 345 | 304 |
| 346 MeasurementTimers draw_timers(gpu_timing_client_.get()); | 305 MeasurementTimers draw_timers(gpu_timing_client_.get()); |
| 347 | 306 |
| 348 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 307 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 349 draw_timers.Record(); | 308 draw_timers.Record(); |
| 350 | 309 |
| 351 MeasurementTimers finish_timers(gpu_timing_client_.get()); | 310 MeasurementTimers finish_timers(gpu_timing_client_.get()); |
| 352 glFinish(); | 311 glFinish(); |
| 353 CheckNoGlError("glFinish"); | 312 CheckNoGlError(); |
| 354 finish_timers.Record(); | 313 finish_timers.Record(); |
| 355 | 314 |
| 315 glDeleteTextures(1, &texture_id); |
| 316 |
| 356 std::vector<uint8> pixels_rendered(size.GetArea() * 4); | 317 std::vector<uint8> pixels_rendered(size.GetArea() * 4); |
| 357 glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE, | 318 glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE, |
| 358 &pixels_rendered[0]); | 319 &pixels_rendered[0]); |
| 359 CheckNoGlError("glReadPixels"); | 320 CheckNoGlError(); |
| 360 EXPECT_TRUE( | 321 EXPECT_TRUE( |
| 361 CompareBufferToRGBABuffer(format, size, pixels, pixels_rendered)) | 322 CompareBufferToRGBABuffer(format, size, pixels, pixels_rendered)) |
| 362 << "Format is: " << gfx::GLEnums::GetStringEnum(format); | 323 << "Format is: " << gfx::GLEnums::GetStringEnum(format); |
| 363 | 324 |
| 364 std::vector<Measurement> measurements; | 325 std::vector<Measurement> measurements; |
| 365 bool gpu_timer_errors = | 326 bool gpu_timer_errors = |
| 366 gpu_timing_client_->IsAvailable() && | 327 gpu_timing_client_->IsAvailable() && |
| 367 gpu_timing_client_->CheckAndResetTimerErrors(); | 328 gpu_timing_client_->CheckAndResetTimerErrors(); |
| 368 if (!gpu_timer_errors) { | 329 if (!gpu_timer_errors) { |
| 369 measurements.push_back(tex_timers.GetAsMeasurement( | 330 measurements.push_back(tex_timers.GetAsMeasurement("teximage2d")); |
| 370 subimage ? "texsubimage2d" : "teximage2d")); | |
| 371 measurements.push_back(draw_timers.GetAsMeasurement("drawarrays")); | 331 measurements.push_back(draw_timers.GetAsMeasurement("drawarrays")); |
| 372 measurements.push_back(finish_timers.GetAsMeasurement("finish")); | 332 measurements.push_back(finish_timers.GetAsMeasurement("finish")); |
| 373 } | 333 } |
| 374 return measurements; | 334 return measurements; |
| 375 } | 335 } |
| 376 | 336 |
| 377 void RunUploadAndDrawMultipleTimes(const gfx::Size& size, | 337 void RunUploadAndDrawMultipleTimes(const gfx::Size& size, |
| 378 const GLenum format, | 338 const GLenum format) { |
| 379 const bool subimage) { | |
| 380 std::vector<uint8> pixels; | 339 std::vector<uint8> pixels; |
| 381 base::SmallMap<std::map<std::string, Measurement>> | 340 base::SmallMap<std::map<std::string, Measurement>> |
| 382 aggregates; // indexed by name | 341 aggregates; // indexed by name |
| 383 int successful_runs = 0; | 342 int successful_runs = 0; |
| 384 GLuint texture_id = CreateGLTexture(format, size, subimage); | |
| 385 for (int i = 0; i < kUploadPerfWarmupRuns + kUploadPerfTestRuns; ++i) { | 343 for (int i = 0; i < kUploadPerfWarmupRuns + kUploadPerfTestRuns; ++i) { |
| 386 GenerateTextureData(size, GLFormatBytePerPixel(format), i + 1, &pixels); | 344 GenerateTextureData(size, GLFormatBytePerPixel(format), i + 1, &pixels); |
| 387 auto run = UploadAndDraw(texture_id, size, pixels, format, subimage); | 345 auto run = UploadAndDraw(size, pixels, format); |
| 388 if (i < kUploadPerfWarmupRuns || !run.size()) { | 346 if (i < kUploadPerfWarmupRuns || !run.size()) { |
| 389 continue; | 347 continue; |
| 390 } | 348 } |
| 391 successful_runs++; | 349 successful_runs++; |
| 392 for (const Measurement& measurement : run) { | 350 for (const Measurement& measurement : run) { |
| 393 auto& aggregate = aggregates[measurement.name]; | 351 auto& aggregate = aggregates[measurement.name]; |
| 394 aggregate.name = measurement.name; | 352 aggregate.name = measurement.name; |
| 395 aggregate.Increment(measurement); | 353 aggregate.Increment(measurement); |
| 396 } | 354 } |
| 397 } | 355 } |
| 398 glDeleteTextures(1, &texture_id); | |
| 399 | |
| 400 std::string graph_name = base::StringPrintf( | 356 std::string graph_name = base::StringPrintf( |
| 401 "%d_%s", size.width(), gfx::GLEnums::GetStringEnum(format).c_str()); | 357 "%d_%s", size.width(), gfx::GLEnums::GetStringEnum(format).c_str()); |
| 402 if (subimage) { | |
| 403 graph_name += "_sub"; | |
| 404 } | |
| 405 | |
| 406 if (successful_runs) { | 358 if (successful_runs) { |
| 407 for (const auto& entry : aggregates) { | 359 for (const auto& entry : aggregates) { |
| 408 const auto m = entry.second.Divide(successful_runs); | 360 const auto m = entry.second.Divide(successful_runs); |
| 409 m.PrintResult(graph_name); | 361 m.PrintResult(graph_name); |
| 410 } | 362 } |
| 411 } | 363 } |
| 412 perf_test::PrintResult("sample_runs", "", graph_name, | 364 perf_test::PrintResult("sample_runs", "", graph_name, |
| 413 static_cast<size_t>(successful_runs), "laps", true); | 365 static_cast<size_t>(successful_runs), "laps", true); |
| 414 } | 366 } |
| 415 | 367 |
| 416 const gfx::Size fbo_size_; // for the fbo | 368 const gfx::Size fbo_size_; // for the fbo |
| 417 scoped_refptr<gfx::GLContext> gl_context_; | 369 scoped_refptr<gfx::GLContext> gl_context_; |
| 418 scoped_refptr<gfx::GLSurface> surface_; | 370 scoped_refptr<gfx::GLSurface> surface_; |
| 419 scoped_refptr<gfx::GPUTimingClient> gpu_timing_client_; | 371 scoped_refptr<gfx::GPUTimingClient> gpu_timing_client_; |
| 420 | 372 |
| 421 GLuint color_texture_ = 0; | 373 GLuint color_texture_ = 0; |
| 422 GLuint framebuffer_object_ = 0; | 374 GLuint framebuffer_object_ = 0; |
| 423 GLuint vertex_shader_ = 0; | 375 GLuint vertex_shader_ = 0; |
| 424 GLuint fragment_shader_ = 0; | 376 GLuint fragment_shader_ = 0; |
| 425 GLuint program_object_ = 0; | 377 GLuint program_object_ = 0; |
| 426 GLint sampler_location_ = -1; | 378 GLint sampler_location_ = -1; |
| 427 GLint translation_location_ = -1; | 379 GLint translation_location_ = -1; |
| 428 GLuint vertex_buffer_ = 0; | 380 GLuint vertex_buffer_ = 0; |
| 429 | |
| 430 bool has_texture_storage_ = false; | |
| 431 }; | 381 }; |
| 432 | 382 |
| 433 // Perf test that generates, uploads and draws a texture on a surface repeatedly | 383 // Perf test that generates, uploads and draws a texture on a surface repeatedly |
| 434 // and prints out aggregated measurements for all the runs. | 384 // and prints out aggregated measurements for all the runs. |
| 435 TEST_F(TextureUploadPerfTest, upload) { | 385 TEST_F(TextureUploadPerfTest, glTexImage2d) { |
| 436 int sizes[] = {21, 128, 256, 512, 1024}; | 386 int sizes[] = {21, 128, 256, 512, 1024}; |
| 437 std::vector<GLenum> formats; | 387 std::vector<GLenum> formats; |
| 438 formats.push_back(GL_RGBA); | 388 formats.push_back(GL_RGBA); |
| 439 // Used by default for ResourceProvider::yuv_resource_format_. | 389 // Used by default for ResourceProvider::yuv_resource_format_. |
| 440 formats.push_back(GL_LUMINANCE); | 390 formats.push_back(GL_LUMINANCE); |
| 441 | 391 |
| 442 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); | 392 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); |
| 443 const bool has_texture_rg = gl_context_->HasExtension("GL_EXT_texture_rg") || | 393 bool has_texture_rg = gl_context_->HasExtension("GL_EXT_texture_rg") || |
| 444 gl_context_->HasExtension("GL_ARB_texture_rg"); | 394 gl_context_->HasExtension("GL_ARB_texture_rg"); |
| 445 | 395 |
| 446 if (has_texture_rg) { | 396 if (has_texture_rg) { |
| 447 // Used as ResourceProvider::yuv_resource_format_ if | 397 // Used as ResourceProvider::yuv_resource_format_ if |
| 448 // {ARB,EXT}_texture_rg are available. | 398 // {ARB,EXT}_texture_rg are available. |
| 449 formats.push_back(GL_RED_EXT); | 399 formats.push_back(GL_RED_EXT); |
| 450 } | 400 } |
| 451 | |
| 452 for (int side : sizes) { | 401 for (int side : sizes) { |
| 453 ASSERT_GE(fbo_size_.width(), side); | 402 ASSERT_GE(fbo_size_.width(), side); |
| 454 ASSERT_GE(fbo_size_.height(), side); | 403 ASSERT_GE(fbo_size_.height(), side); |
| 455 gfx::Size size(side, side); | 404 gfx::Size size(side, side); |
| 456 GenerateVertexBuffer(size); | 405 GenerateVertexBuffer(size); |
| 457 for (GLenum format : formats) { | 406 for (GLenum format : formats) { |
| 458 RunUploadAndDrawMultipleTimes(size, format, true); // use glTexSubImage2D | 407 RunUploadAndDrawMultipleTimes(size, format); |
| 459 RunUploadAndDrawMultipleTimes(size, format, false); // use glTexImage2D | |
| 460 } | 408 } |
| 461 } | 409 } |
| 462 } | 410 } |
| 463 | 411 |
| 464 // Perf test to check if the driver is doing texture renaming. | 412 // Perf test to check if the driver is doing texture renaming. |
| 465 // This test creates one GL texture_id and four different images. For | 413 // This test creates one GL texture_id and four different images. For |
| 466 // every image it uploads it using texture_id and it draws multiple | 414 // every image it uploads it using texture_id and it draws multiple |
| 467 // times. The cpu/wall time and the gpu time for all the uploads and | 415 // times. The cpu/wall time and the gpu time for all the uploads and |
| 468 // draws, but before glFinish, is computed and is printed out at the end as | 416 // draws, but before glFinish, is computed and is printed out at the end as |
| 469 // "upload_and_draw". If the gpu time is >> than the cpu/wall time we expect the | 417 // "upload_and_draw". If the gpu time is >> than the cpu/wall time we expect the |
| 470 // driver to do texture renaming: this means that while the gpu is drawing using | 418 // driver to do texture renaming: this means that while the gpu is drawing using |
| 471 // texture_id it didn't block cpu side the texture upload using the same | 419 // texture_id it didn't block cpu side the texture upload using the same |
| 472 // texture_id. | 420 // texture_id. |
| 473 TEST_F(TextureUploadPerfTest, renaming) { | 421 TEST_F(TextureUploadPerfTest, renaming) { |
| 474 gfx::Size texture_size(fbo_size_.width() / 2, fbo_size_.height() / 2); | 422 gfx::Size texture_size(fbo_size_.width() / 2, fbo_size_.height() / 2); |
| 475 | 423 |
| 476 std::vector<uint8> pixels[4]; | 424 std::vector<uint8> pixels[4]; |
| 477 for (int i = 0; i < 4; ++i) { | 425 for (int i = 0; i < 4; ++i) { |
| 478 GenerateTextureData(texture_size, 4, i + 1, &pixels[i]); | 426 GenerateTextureData(texture_size, 4, i + 1, &pixels[i]); |
| 479 } | 427 } |
| 480 | 428 |
| 481 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); | 429 ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get()); |
| 482 GenerateVertexBuffer(texture_size); | 430 GenerateVertexBuffer(texture_size); |
| 483 | 431 |
| 484 gfx::Vector2dF positions[] = {gfx::Vector2dF(0.f, 0.f), | 432 gfx::Vector2dF positions[] = {gfx::Vector2dF(0.f, 0.f), |
| 485 gfx::Vector2dF(1.f, 0.f), | 433 gfx::Vector2dF(1.f, 0.f), |
| 486 gfx::Vector2dF(0.f, 1.f), | 434 gfx::Vector2dF(0.f, 1.f), |
| 487 gfx::Vector2dF(1.f, 1.f)}; | 435 gfx::Vector2dF(1.f, 1.f)}; |
| 488 GLuint texture_id = CreateGLTexture(GL_RGBA, texture_size, true); | 436 GLuint texture_id = CreateGLTexture(); |
| 489 | 437 |
| 490 MeasurementTimers upload_and_draw_timers(gpu_timing_client_.get()); | 438 MeasurementTimers upload_and_draw_timers(gpu_timing_client_.get()); |
| 491 | 439 |
| 492 for (int i = 0; i < 4; ++i) { | 440 for (int i = 0; i < 4; ++i) { |
| 493 UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA, true); | 441 UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA); |
| 494 DCHECK_NE(-1, translation_location_); | 442 DCHECK_NE(-1, translation_location_); |
| 495 glUniform2f(translation_location_, positions[i % 4].x(), | 443 glUniform2f(translation_location_, positions[i % 4].x(), |
| 496 positions[i % 4].y()); | 444 positions[i % 4].y()); |
| 497 // Draw the same quad multiple times to make sure that the time spent on the | 445 // Draw the same quad multiple times to make sure that the time spent on the |
| 498 // gpu is more than the cpu time. | 446 // gpu is more than the cpu time. |
| 499 for (int draw = 0; draw < 128; ++draw) { | 447 for (int draw = 0; draw < 128; ++draw) { |
| 500 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 448 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 501 } | 449 } |
| 502 } | 450 } |
| 503 | 451 |
| 504 upload_and_draw_timers.Record(); | 452 upload_and_draw_timers.Record(); |
| 505 MeasurementTimers finish_timers(gpu_timing_client_.get()); | 453 MeasurementTimers finish_timers(gpu_timing_client_.get()); |
| 506 glFinish(); | 454 glFinish(); |
| 507 CheckNoGlError("glFinish"); | 455 CheckNoGlError(); |
| 508 finish_timers.Record(); | 456 finish_timers.Record(); |
| 509 | 457 |
| 510 glDeleteTextures(1, &texture_id); | 458 glDeleteTextures(1, &texture_id); |
| 511 | 459 |
| 512 for (int i = 0; i < 4; ++i) { | 460 for (int i = 0; i < 4; ++i) { |
| 513 std::vector<uint8> pixels_rendered(texture_size.GetArea() * 4); | 461 std::vector<uint8> pixels_rendered(texture_size.GetArea() * 4); |
| 514 glReadPixels(texture_size.width() * positions[i].x(), | 462 glReadPixels(texture_size.width() * positions[i].x(), |
| 515 texture_size.height() * positions[i].y(), texture_size.width(), | 463 texture_size.height() * positions[i].y(), texture_size.width(), |
| 516 texture_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, | 464 texture_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, |
| 517 &pixels_rendered[0]); | 465 &pixels_rendered[0]); |
| 518 CheckNoGlError("glReadPixels"); | 466 CheckNoGlError(); |
| 519 ASSERT_EQ(pixels[i].size(), pixels_rendered.size()); | 467 ASSERT_EQ(pixels[i].size(), pixels_rendered.size()); |
| 520 EXPECT_EQ(pixels[i], pixels_rendered); | 468 EXPECT_EQ(pixels[i], pixels_rendered); |
| 521 } | 469 } |
| 522 | 470 |
| 523 bool gpu_timer_errors = gpu_timing_client_->IsAvailable() && | 471 bool gpu_timer_errors = gpu_timing_client_->IsAvailable() && |
| 524 gpu_timing_client_->CheckAndResetTimerErrors(); | 472 gpu_timing_client_->CheckAndResetTimerErrors(); |
| 525 if (!gpu_timer_errors) { | 473 if (!gpu_timer_errors) { |
| 526 upload_and_draw_timers.GetAsMeasurement("upload_and_draw") | 474 upload_and_draw_timers.GetAsMeasurement("upload_and_draw") |
| 527 .PrintResult("renaming"); | 475 .PrintResult("renaming"); |
| 528 finish_timers.GetAsMeasurement("finish").PrintResult("renaming"); | 476 finish_timers.GetAsMeasurement("finish").PrintResult("renaming"); |
| 529 } | 477 } |
| 530 } | 478 } |
| 531 | 479 |
| 532 } // namespace | 480 } // namespace |
| 533 } // namespace gpu | 481 } // namespace gpu |
| OLD | NEW |