decoder_perftest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <memory>
  5. #include "base/command_line.h"
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/process/process.h"
  8. #include "base/threading/platform_thread.h"
  9. #include "base/time/time.h"
  10. #include "gpu/command_buffer/client/gles2_cmd_helper.h"
  11. #include "gpu/command_buffer/client/gles2_implementation.h"
  12. #include "gpu/command_buffer/client/gpu_control.h"
  13. #include "gpu/command_buffer/client/shared_memory_limits.h"
  14. #include "gpu/command_buffer/client/transfer_buffer.h"
  15. #include "gpu/command_buffer/common/constants.h"
  16. #include "gpu/command_buffer/common/context_creation_attribs.h"
  17. #include "gpu/command_buffer/common/sync_token.h"
  18. #include "gpu/command_buffer/service/command_buffer_direct.h"
  19. #include "gpu/command_buffer/service/context_group.h"
  20. #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
  21. #include "gpu/command_buffer/service/gpu_switches.h"
  22. #include "gpu/command_buffer/service/gpu_tracer.h"
  23. #include "gpu/command_buffer/service/logger.h"
  24. #include "gpu/command_buffer/service/mailbox_manager_impl.h"
  25. #include "gpu/command_buffer/service/memory_tracking.h"
  26. #include "gpu/command_buffer/service/passthrough_discardable_manager.h"
  27. #include "gpu/command_buffer/service/service_discardable_manager.h"
  28. #include "gpu/command_buffer/service/service_utils.h"
  29. #include "gpu/command_buffer/service/shared_image/shared_image_manager.h"
  30. #include "gpu/command_buffer/service/sync_point_manager.h"
  31. #include "gpu/command_buffer/service/transfer_buffer_manager.h"
  32. #include "testing/gtest/include/gtest/gtest.h"
  33. #include "testing/perf/perf_result_reporter.h"
  34. #include "ui/gfx/geometry/size.h"
  35. #include "ui/gl/gl_context_stub.h"
  36. #include "ui/gl/gl_share_group.h"
  37. #include "ui/gl/gl_surface_stub.h"
  38. #include "ui/gl/gl_utils.h"
  39. #include "ui/gl/init/gl_factory.h"
  40. namespace gpu {
  41. namespace {
  42. constexpr int kDefaultRuns = 8;
  43. constexpr int kDefaultIterations = 50000;
  44. // A command buffer that can record and replay commands
  45. // This goes through 3 states, allowing setting up of initial state before
  46. // record/replay a tight loop:
  47. // - kDirect directly sends commands to the service on Flush
  48. // - kRecord doesn't send anything on Flush, but keeps track of the put pointer
  49. // - kReplay allows replaying of commands recorded in the kRecord state
  50. //
  51. // The initial state is kDirect. AdvanceMode is used to transition from one
  52. // state to the next. The transition from kDirect to kRecord requires the
  53. // GetBuffer to have been freed, allowing a fresh start for record.
  54. class RecordReplayCommandBuffer : public CommandBufferDirect {
  55. public:
  56. enum Mode { kDirect, kRecord, kReplay };
  57. RecordReplayCommandBuffer() = default;
  58. ~RecordReplayCommandBuffer() override = default;
  59. void AdvanceMode() {
  60. switch (mode_) {
  61. case kDirect:
  62. mode_ = kRecord;
  63. DCHECK_EQ(current_get_buffer_, -1);
  64. DCHECK_EQ(service()->GetState().get_offset, 0);
  65. break;
  66. case kRecord:
  67. mode_ = kReplay;
  68. DCHECK_NE(saved_get_buffer_, -1);
  69. CommandBufferDirect::SetGetBuffer(saved_get_buffer_);
  70. break;
  71. case kReplay:
  72. mode_ = kDirect;
  73. break;
  74. }
  75. }
  76. void Flush(int32_t put_offset) override {
  77. DCHECK_NE(mode_, kReplay);
  78. if (mode_ == kDirect) {
  79. CommandBufferDirect::Flush(put_offset);
  80. } else {
  81. DCHECK_GE(put_offset, saved_put_offset_);
  82. saved_put_offset_ = put_offset;
  83. }
  84. }
  85. CommandBuffer::State WaitForTokenInRange(int32_t start,
  86. int32_t end) override {
  87. DCHECK_EQ(mode_, kDirect);
  88. return CommandBufferDirect::WaitForTokenInRange(start, end);
  89. }
  90. CommandBuffer::State WaitForGetOffsetInRange(uint32_t set_get_buffer_count,
  91. int32_t start,
  92. int32_t end) override {
  93. DCHECK_EQ(mode_, kDirect);
  94. return CommandBufferDirect::WaitForGetOffsetInRange(set_get_buffer_count,
  95. start, end);
  96. }
  97. void SetGetBuffer(int32_t transfer_buffer_id) override {
  98. switch (mode_) {
  99. case kDirect:
  100. current_get_buffer_ = transfer_buffer_id;
  101. CommandBufferDirect::SetGetBuffer(transfer_buffer_id);
  102. break;
  103. case kRecord:
  104. DCHECK_EQ(saved_get_buffer_, -1);
  105. saved_get_buffer_ = transfer_buffer_id;
  106. break;
  107. case kReplay:
  108. NOTREACHED();
  109. break;
  110. }
  111. }
  112. void OnParseError() override {
  113. ASSERT_EQ(service()->GetState().error, error::kNoError);
  114. }
  115. void Replay() {
  116. DCHECK_EQ(mode_, kReplay);
  117. SetGetOffsetForTest(0);
  118. CommandBufferDirect::Flush(saved_put_offset_);
  119. }
  120. int32_t saved_put_offset() const { return saved_put_offset_; }
  121. Mode mode() const { return mode_; }
  122. private:
  123. Mode mode_ = kDirect;
  124. int32_t saved_put_offset_ = 0;
  125. int32_t saved_get_buffer_ = -1;
  126. int32_t current_get_buffer_ = -1;
  127. };
  128. GpuPreferences GetGpuPreferences() {
  129. GpuPreferences preferences;
  130. if (gles2::UsePassthroughCommandDecoder(
  131. base::CommandLine::ForCurrentProcess()))
  132. preferences.use_passthrough_cmd_decoder = true;
  133. return preferences;
  134. }
  135. // This wraps a RecordReplayCommandBuffer and gives it a back-end decoder, as
  136. // well as a front-end GLES2Implementation. This allows recording commands at
  137. // the GL level and replaying them to the driver (or a stub).
  138. class RecordReplayContext : public GpuControl {
  139. public:
  140. RecordReplayContext()
  141. : gpu_preferences_(GetGpuPreferences()),
  142. share_group_(new gl::GLShareGroup),
  143. discardable_manager_(gpu::GpuPreferences()),
  144. passthrough_discardable_manager_(gpu::GpuPreferences()),
  145. translator_cache_(gpu_preferences_) {
  146. bool bind_generates_resource = false;
  147. if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-stub")) {
  148. surface_ = new gl::GLSurfaceStub;
  149. scoped_refptr<gl::GLContextStub> context_stub =
  150. new gl::GLContextStub(share_group_.get());
  151. context_stub->SetGLVersionString("OpenGL ES 3.1");
  152. context_stub->SetUseStubApi(true);
  153. context_ = context_stub;
  154. } else {
  155. gl::GLContextAttribs attribs;
  156. if (gpu_preferences_.use_passthrough_cmd_decoder)
  157. attribs.bind_generates_resource = bind_generates_resource;
  158. surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(),
  159. gfx::Size());
  160. context_ = gl::init::CreateGLContext(share_group_.get(), surface_.get(),
  161. attribs);
  162. }
  163. context_->MakeCurrent(surface_.get());
  164. scoped_refptr<gles2::FeatureInfo> feature_info = new gles2::FeatureInfo();
  165. scoped_refptr<gles2::ContextGroup> context_group = new gles2::ContextGroup(
  166. gpu_preferences_, true, &mailbox_manager_, nullptr /* memory_tracker */,
  167. &translator_cache_, &completeness_cache_, feature_info,
  168. bind_generates_resource, nullptr /* image_factory */,
  169. nullptr /* progress_reporter */, GpuFeatureInfo(),
  170. &discardable_manager_, &passthrough_discardable_manager_,
  171. &shared_image_manager_);
  172. command_buffer_ = std::make_unique<RecordReplayCommandBuffer>();
  173. decoder_.reset(gles2::GLES2Decoder::Create(
  174. command_buffer_.get(), command_buffer_->service(), &outputter_,
  175. context_group.get()));
  176. command_buffer_->set_handler(decoder_.get());
  177. decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
  178. ContextCreationAttribs attrib_helper;
  179. attrib_helper.offscreen_framebuffer_size = gfx::Size(16, 16);
  180. attrib_helper.red_size = 8;
  181. attrib_helper.green_size = 8;
  182. attrib_helper.blue_size = 8;
  183. attrib_helper.alpha_size = 8;
  184. attrib_helper.depth_size = 0;
  185. attrib_helper.stencil_size = 0;
  186. attrib_helper.context_type = CONTEXT_TYPE_OPENGLES3;
  187. ContextResult result =
  188. decoder_->Initialize(surface_.get(), context_.get(), true,
  189. gles2::DisallowedFeatures(), attrib_helper);
  190. DCHECK_EQ(result, ContextResult::kSuccess);
  191. capabilities_ = decoder_->GetCapabilities();
  192. const SharedMemoryLimits limits;
  193. gles2_helper_ =
  194. std::make_unique<gles2::GLES2CmdHelper>(command_buffer_.get());
  195. result = gles2_helper_->Initialize(limits.command_buffer_size);
  196. DCHECK_EQ(result, ContextResult::kSuccess);
  197. // Create a transfer buffer.
  198. transfer_buffer_ = std::make_unique<TransferBuffer>(gles2_helper_.get());
  199. // Create the object exposing the OpenGL API.
  200. const bool lose_context_when_out_of_memory = false;
  201. const bool support_client_side_arrays = false;
  202. gles2_implementation_ = std::make_unique<gles2::GLES2Implementation>(
  203. gles2_helper_.get(), nullptr, transfer_buffer_.get(),
  204. bind_generates_resource, lose_context_when_out_of_memory,
  205. support_client_side_arrays, this);
  206. result = gles2_implementation_->Initialize(limits);
  207. DCHECK_EQ(result, ContextResult::kSuccess);
  208. }
  209. ~RecordReplayContext() override {
  210. while (command_buffer_->mode() != RecordReplayCommandBuffer::kDirect)
  211. command_buffer_->AdvanceMode();
  212. gles2_implementation_.reset();
  213. transfer_buffer_.reset();
  214. gles2_helper_.reset();
  215. decoder_->Destroy(true);
  216. decoder_.reset();
  217. command_buffer_.reset();
  218. }
  219. void StartRecord() {
  220. DCHECK_EQ(command_buffer_->mode(), RecordReplayCommandBuffer::kDirect);
  221. gles2_helper_->FreeRingBuffer();
  222. command_buffer_->AdvanceMode();
  223. }
  224. void StartReplay() {
  225. DCHECK_EQ(command_buffer_->mode(), RecordReplayCommandBuffer::kRecord);
  226. gles2_helper_->FlushLazy();
  227. command_buffer_->AdvanceMode();
  228. }
  229. void Replay() { command_buffer_->Replay(); }
  230. gles2::GLES2Implementation* gl() { return gles2_implementation_.get(); }
  231. private:
  232. // GpuControl implementation;
  233. void SetGpuControlClient(GpuControlClient*) override {}
  234. const Capabilities& GetCapabilities() const override { return capabilities_; }
  235. void SignalQuery(uint32_t query, base::OnceClosure callback) override {
  236. NOTREACHED();
  237. }
  238. void CreateGpuFence(uint32_t gpu_fence_id, ClientGpuFence source) override {
  239. NOTREACHED();
  240. }
  241. void GetGpuFence(uint32_t gpu_fence_id,
  242. base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)>
  243. callback) override {
  244. NOTREACHED();
  245. }
  246. void SetLock(base::Lock*) override { NOTREACHED(); }
  247. void EnsureWorkVisible() override { NOTREACHED(); }
  248. gpu::CommandBufferNamespace GetNamespaceID() const override {
  249. return gpu::CommandBufferNamespace::INVALID;
  250. }
  251. CommandBufferId GetCommandBufferID() const override {
  252. return gpu::CommandBufferId();
  253. }
  254. void FlushPendingWork() override { NOTREACHED(); }
  255. uint64_t GenerateFenceSyncRelease() override {
  256. NOTREACHED();
  257. return 0;
  258. }
  259. bool IsFenceSyncReleased(uint64_t release) override {
  260. NOTREACHED();
  261. return true;
  262. }
  263. void SignalSyncToken(const gpu::SyncToken& sync_token,
  264. base::OnceClosure callback) override {
  265. NOTREACHED();
  266. }
  267. void WaitSyncToken(const gpu::SyncToken& sync_token) override {
  268. NOTREACHED();
  269. }
  270. bool CanWaitUnverifiedSyncToken(const gpu::SyncToken& sync_token) override {
  271. NOTREACHED();
  272. return true;
  273. }
  274. GpuPreferences gpu_preferences_;
  275. gles2::MailboxManagerImpl mailbox_manager_;
  276. scoped_refptr<gl::GLShareGroup> share_group_;
  277. ServiceDiscardableManager discardable_manager_;
  278. PassthroughDiscardableManager passthrough_discardable_manager_;
  279. SharedImageManager shared_image_manager_;
  280. scoped_refptr<gl::GLSurface> surface_;
  281. scoped_refptr<gl::GLContext> context_;
  282. gles2::ShaderTranslatorCache translator_cache_;
  283. gles2::FramebufferCompletenessCache completeness_cache_;
  284. std::unique_ptr<RecordReplayCommandBuffer> command_buffer_;
  285. gles2::TraceOutputter outputter_;
  286. std::unique_ptr<gles2::GLES2Decoder> decoder_;
  287. gpu::Capabilities capabilities_;
  288. std::unique_ptr<gles2::GLES2CmdHelper> gles2_helper_;
  289. std::unique_ptr<TransferBuffer> transfer_buffer_;
  290. std::unique_ptr<gles2::GLES2Implementation> gles2_implementation_;
  291. };
  292. // This abstracts the performance capture loop, iterating through a warmup run
  293. // and then a number of performance capturing runs.
  294. class PerfIterator {
  295. public:
  296. PerfIterator(std::string story, int runs, int iterations)
  297. : story_(std::move(story)), runs_(runs), iterations_(iterations) {
  298. // When running under linux-perf, we try to isolate the microbenchmark
  299. // performance:
  300. // 1- sleep 1 second after warmup so that one can skip perf for
  301. // intitialization with 'perf record -D 1000'
  302. // 2- exit immediately after the capture loop is finished to skip teardown.
  303. // 3- avoid unneeded syscalls (time, print).
  304. for_linux_perf_ =
  305. base::CommandLine::ForCurrentProcess()->HasSwitch("for-linux-perf");
  306. if (base::CommandLine::ForCurrentProcess()->HasSwitch("fast-run")) {
  307. runs_ = 1;
  308. iterations_ = 100;
  309. }
  310. }
  311. PerfIterator(const PerfIterator&) = delete;
  312. PerfIterator& operator=(const PerfIterator&) = delete;
  313. bool Iterate() {
  314. if (--current_iterations_ > 0)
  315. return true;
  316. return NextOuter();
  317. }
  318. private:
  319. bool NextOuter() {
  320. base::TimeTicks time;
  321. if (warmup_) {
  322. warmup_ = false;
  323. if (for_linux_perf_)
  324. base::PlatformThread::Sleep(base::Seconds(1));
  325. else
  326. time = base::TimeTicks::Now();
  327. } else if (!for_linux_perf_) {
  328. time = base::TimeTicks::Now();
  329. double ns = (time - run_start_time_).InNanoseconds() / iterations_;
  330. perf_test::PerfResultReporter reporter("Decoder.", story_);
  331. reporter.RegisterImportantMetric("draw_wall_time", "ns");
  332. reporter.AddResult("draw_wall_time", ns);
  333. }
  334. if (runs_ == 0) {
  335. if (for_linux_perf_)
  336. base::Process::TerminateCurrentProcessImmediately(0);
  337. return false;
  338. }
  339. --runs_;
  340. current_iterations_ = iterations_;
  341. run_start_time_ = time;
  342. return true;
  343. }
  344. static constexpr int kWarmupIterations = 2;
  345. std::string story_;
  346. base::TimeTicks run_start_time_;
  347. int runs_;
  348. int iterations_;
  349. int current_iterations_ = 1 + kWarmupIterations;
  350. bool warmup_ = true;
  351. bool for_linux_perf_ = false;
  352. };
  353. class DecoderPerfTest : public testing::Test {
  354. public:
  355. ~DecoderPerfTest() override = default;
  356. void SetUp() override {
  357. context_ = std::make_unique<RecordReplayContext>();
  358. gl_ = context_->gl();
  359. gl_->GenRenderbuffers(1, &renderbuffer_);
  360. gl_->BindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
  361. gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 256, 256);
  362. gl_->GenFramebuffers(1, &framebuffer_);
  363. gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
  364. gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  365. GL_RENDERBUFFER, renderbuffer_);
  366. gl_->Viewport(0, 0, 256, 256);
  367. }
  368. void TearDown() override { context_.reset(); }
  369. void StartRecord() { context_->StartRecord(); }
  370. void StartReplay() { context_->StartReplay(); }
  371. void Replay() { context_->Replay(); }
  372. GLuint CompileShader(GLenum type, const char* source) {
  373. GLuint shader = gl_->CreateShader(type);
  374. GLint length = base::checked_cast<GLint>(strlen(source));
  375. gl_->ShaderSource(shader, 1, &source, &length);
  376. gl_->CompileShader(shader);
  377. GLint compile_status = 0;
  378. gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
  379. if (!compile_status) {
  380. GLint log_length = 0;
  381. gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
  382. if (log_length) {
  383. std::unique_ptr<GLchar[]> log(new GLchar[log_length]);
  384. GLsizei returned_log_length = 0;
  385. gl_->GetShaderInfoLog(shader, log_length, &returned_log_length,
  386. log.get());
  387. LOG(ERROR) << std::string(log.get(), returned_log_length);
  388. }
  389. gl_->DeleteShader(shader);
  390. return 0;
  391. }
  392. return shader;
  393. }
  394. struct AttribBinding {
  395. const char* name;
  396. GLuint location;
  397. };
  398. GLuint CreateAndLinkProgram(
  399. const char* vertex_shader,
  400. const char* fragment_shader,
  401. const std::initializer_list<AttribBinding>& attrib_bindings) {
  402. GLuint program = gl_->CreateProgram();
  403. GLuint vshader = CompileShader(GL_VERTEX_SHADER, vertex_shader);
  404. DCHECK_NE(0u, vshader);
  405. gl_->AttachShader(program, vshader);
  406. gl_->DeleteShader(vshader);
  407. GLuint fshader = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
  408. DCHECK_NE(0u, fshader);
  409. gl_->AttachShader(program, fshader);
  410. gl_->DeleteShader(fshader);
  411. for (const auto& attrib : attrib_bindings)
  412. gl_->BindAttribLocation(program, attrib.location, attrib.name);
  413. gl_->LinkProgram(program);
  414. GLint link_status = 0;
  415. gl_->GetProgramiv(program, GL_LINK_STATUS, &link_status);
  416. DCHECK_EQ(link_status, GL_TRUE);
  417. return program;
  418. }
  419. void CreateBasicTexture(GLuint texture) {
  420. gl_->BindTexture(GL_TEXTURE_2D, texture);
  421. gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  422. gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  423. gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  424. gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  425. gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA,
  426. GL_UNSIGNED_BYTE, nullptr);
  427. }
  428. protected:
  429. std::unique_ptr<RecordReplayContext> context_;
  430. raw_ptr<gles2::GLES2Implementation> gl_;
  431. GLuint renderbuffer_ = 0;
  432. GLuint framebuffer_ = 0;
  433. };
  434. constexpr const char kVertexShader[] =
  435. "attribute vec2 position;\n"
  436. "uniform vec2 scale;\n"
  437. "uniform vec2 offset;\n"
  438. "varying vec2 texcoords;\n"
  439. "void main () {\n"
  440. " gl_Position = vec4(position * scale + offset, 0.0, 1.0);\n"
  441. " texcoords = position;\n"
  442. "}\n";
  443. constexpr const char kFragmentShader[] =
  444. "precision mediump float;\n"
  445. "varying vec2 texcoords;\n"
  446. "uniform sampler2D texture;\n"
  447. "void main() {\n"
  448. " gl_FragColor = texture2D(texture, texcoords);\n"
  449. "}\n";
  450. constexpr const float kVertices[] = {
  451. 0.f, 0.f, 0.f, 1.f, 1.f, 0.f, 1.f, 1.f,
  452. };
  453. // Measures a loop with Uniform2f and DrawArrays.
  454. TEST_F(DecoderPerfTest, BasicDraw) {
  455. GLuint program =
  456. CreateAndLinkProgram(kVertexShader, kFragmentShader, {{"postition", 0}});
  457. gl_->UseProgram(program);
  458. GLint scale_location = gl_->GetUniformLocation(program, "scale");
  459. GLint offset_location = gl_->GetUniformLocation(program, "offset");
  460. GLint texture_location = gl_->GetUniformLocation(program, "texture");
  461. GLuint texture;
  462. gl_->GenTextures(1, &texture);
  463. CreateBasicTexture(texture);
  464. GLuint buffer;
  465. gl_->GenBuffers(1, &buffer);
  466. gl_->BindBuffer(GL_ARRAY_BUFFER, buffer);
  467. gl_->BufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices,
  468. GL_STATIC_DRAW);
  469. gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
  470. nullptr);
  471. gl_->EnableVertexAttribArray(0);
  472. gl_->Uniform1i(texture_location, 0);
  473. constexpr int N = 10;
  474. gl_->Uniform2f(scale_location, 2.f / N, 2.f / N);
  475. StartRecord();
  476. for (int x = 0; x < N; ++x) {
  477. float xpos = 2.f * x / N - 1.f;
  478. for (int y = 0; y < N; ++y) {
  479. float ypos = 2.f * y / N - 1.f;
  480. gl_->Uniform2f(offset_location, xpos, ypos);
  481. gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  482. }
  483. }
  484. StartReplay();
  485. PerfIterator iterator("basic_draw_100", kDefaultRuns, kDefaultIterations);
  486. while (iterator.Iterate())
  487. Replay();
  488. }
  489. // Measures a loop with changing the texture binding between draws.
  490. TEST_F(DecoderPerfTest, TextureDraw) {
  491. GLuint program =
  492. CreateAndLinkProgram(kVertexShader, kFragmentShader, {{"position", 0}});
  493. gl_->UseProgram(program);
  494. GLint scale_location = gl_->GetUniformLocation(program, "scale");
  495. GLint offset_location = gl_->GetUniformLocation(program, "offset");
  496. GLint texture_location = gl_->GetUniformLocation(program, "texture");
  497. constexpr size_t kTextures = 16;
  498. GLuint textures[kTextures];
  499. gl_->GenTextures(kTextures, textures);
  500. for (GLuint texture : textures)
  501. CreateBasicTexture(texture);
  502. GLuint buffer;
  503. gl_->GenBuffers(1, &buffer);
  504. gl_->BindBuffer(GL_ARRAY_BUFFER, buffer);
  505. gl_->BufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices,
  506. GL_STATIC_DRAW);
  507. gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
  508. nullptr);
  509. gl_->EnableVertexAttribArray(0);
  510. gl_->Uniform1i(texture_location, 0);
  511. constexpr int N = 10;
  512. gl_->Uniform2f(scale_location, 2.f / N, 2.f / N);
  513. StartRecord();
  514. size_t texture = 0;
  515. for (int x = 0; x < N; ++x) {
  516. float xpos = 2.f * x / N - 1.f;
  517. for (int y = 0; y < N; ++y) {
  518. float ypos = 2.f * y / N - 1.f;
  519. gl_->BindTexture(GL_TEXTURE_2D, textures[texture]);
  520. gl_->Uniform2f(offset_location, xpos, ypos);
  521. gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  522. texture = (texture + 1) % kTextures;
  523. }
  524. }
  525. StartReplay();
  526. PerfIterator iterator("texture_draw_100", kDefaultRuns, kDefaultIterations);
  527. while (iterator.Iterate())
  528. Replay();
  529. }
  530. // Measures a loop with changing the program between draws.
  531. TEST_F(DecoderPerfTest, ProgramDraw) {
  532. const char kVertexShader2[] =
  533. "attribute vec2 position;\n"
  534. "uniform vec2 scale;\n"
  535. "uniform vec2 offset;\n"
  536. "void main () {\n"
  537. " gl_Position = vec4(position * scale + offset, 0.0, 1.0);\n"
  538. "}\n";
  539. const char kFragmentShader2[] =
  540. "precision mediump float;\n"
  541. "uniform vec4 color;\n"
  542. "void main() {\n"
  543. " gl_FragColor = color;\n"
  544. "}\n";
  545. GLuint programs[2];
  546. programs[0] =
  547. CreateAndLinkProgram(kVertexShader, kFragmentShader, {{"position", 0}});
  548. GLint scale_location1 = gl_->GetUniformLocation(programs[0], "scale");
  549. GLint texture_location1 = gl_->GetUniformLocation(programs[0], "texture");
  550. programs[1] =
  551. CreateAndLinkProgram(kVertexShader2, kFragmentShader2, {{"position", 0}});
  552. GLint scale_location2 = gl_->GetUniformLocation(programs[1], "scale");
  553. GLint color_location2 = gl_->GetUniformLocation(programs[1], "color");
  554. GLuint texture;
  555. gl_->GenTextures(1, &texture);
  556. CreateBasicTexture(texture);
  557. GLuint buffer;
  558. gl_->GenBuffers(1, &buffer);
  559. gl_->BindBuffer(GL_ARRAY_BUFFER, buffer);
  560. gl_->BufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices,
  561. GL_STATIC_DRAW);
  562. gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
  563. nullptr);
  564. gl_->EnableVertexAttribArray(0);
  565. constexpr int N = 10;
  566. gl_->UseProgram(programs[0]);
  567. gl_->Uniform1i(texture_location1, 0);
  568. gl_->Uniform2f(scale_location1, 2.f / N, 2.f / N);
  569. gl_->UseProgram(programs[1]);
  570. gl_->Uniform2f(scale_location2, 2.f / N, 2.f / N);
  571. gl_->Uniform4f(color_location2, 1.f, 0.f, 0.f, 1.f);
  572. GLint offset_locations[2] = {gl_->GetUniformLocation(programs[0], "offset"),
  573. gl_->GetUniformLocation(programs[1], "offset")};
  574. StartRecord();
  575. size_t program = 0;
  576. for (int x = 0; x < N; ++x) {
  577. float xpos = 2.f * x / N - 1.f;
  578. for (int y = 0; y < N; ++y) {
  579. float ypos = 2.f * y / N - 1.f;
  580. gl_->UseProgram(programs[program]);
  581. gl_->Uniform2f(offset_locations[program], xpos, ypos);
  582. gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  583. program = 1 - program;
  584. }
  585. }
  586. StartReplay();
  587. PerfIterator iterator("program_draw_100", kDefaultRuns, kDefaultIterations);
  588. while (iterator.Iterate())
  589. Replay();
  590. }
  591. } // anonymous namespace
  592. } // namespace gpu