19f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 29f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// Use of this source code is governed by a BSD-style license that can be 39f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// found in the LICENSE file. 49f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 59f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev#include <stdio.h> 69f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 79f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev#include "main.h" 89f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev#include "testbase.h" 99f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev#include "utils.h" 109f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 119f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 129f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevnamespace glbench { 139f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 149f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst float kScreenScaleFactor = 1e6f * (WINDOW_WIDTH * WINDOW_HEIGHT) / 159f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev (1280.f * 768); 169f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 179f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevclass WindowManagerCompositingTest : public TestBase { 189f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev public: 199f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev WindowManagerCompositingTest(bool scissor) 209f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev : scissor_(scissor), 219f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev compositing_background_program_(0), 229f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev compositing_foreground_program_(0) {} 239f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev virtual ~WindowManagerCompositingTest() {} 24439ea14b8019a05cd4d3f038b4d32bca1d3fe5dcIlja H. Friedel virtual bool TestFunc(uint64_t iterations); 259f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev virtual bool Run(); 26f50ecb1b44db52db39768f55a03280e1fd8eeac7Alexey Marinichev virtual const char* Name() const { return "compositing"; } 27bcad4fb80e1115af4aad4558d93be6dabf7a3f26Daniel Kurtz virtual bool IsDrawTest() const { return true; } 28aace01b7d49e41d1bd26be3767305f57e036e0d7Daniel Kurtz virtual const char* Unit() const { return "1280x768_fps"; } 299f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 309f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev void InitializeCompositing(); 319f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev void TeardownCompositing(); 329f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev void InitBaseTexture(); 339f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev void UpdateTexture(); 349f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev void LoadTexture(); 359f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 369f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev private: 379f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev bool scissor_; 389f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev uint32_t texture_base_[WINDOW_HEIGHT*WINDOW_WIDTH]; 399f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev uint32_t texture_update_[WINDOW_HEIGHT*WINDOW_WIDTH]; 409f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint compositing_textures_[5]; 419f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint compositing_background_program_; 429f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint compositing_foreground_program_; 439f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev DISALLOW_COPY_AND_ASSIGN(WindowManagerCompositingTest); 449f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev}; 459f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 469f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey MarinichevTestBase* GetWindowManagerCompositingTest(bool enable_scissor) { 479f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return new WindowManagerCompositingTest(enable_scissor); 489f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 499f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 509f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevbool WindowManagerCompositingTest::Run() { 51aace01b7d49e41d1bd26be3767305f57e036e0d7Daniel Kurtz const char* testname = "compositing"; 529f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev if (scissor_) { 539f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glScissor(0, 0, 1, 1); 549f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnable(GL_SCISSOR_TEST); 55aace01b7d49e41d1bd26be3767305f57e036e0d7Daniel Kurtz testname = "compositing_no_fill"; 569f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 579f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev InitializeCompositing(); 583907fd1607fdc5ae5065adad80b35c7733fbbf7aIlja Friedel RunTest(this, testname, kScreenScaleFactor, WINDOW_WIDTH, WINDOW_HEIGHT, true); 599f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev TeardownCompositing(); 609f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return true; 619f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 629f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 63439ea14b8019a05cd4d3f038b4d32bca1d3fe5dcIlja H. Friedelbool WindowManagerCompositingTest::TestFunc(uint64_t iterations) { 64439ea14b8019a05cd4d3f038b4d32bca1d3fe5dcIlja H. Friedel for (uint64_t i = 0 ; i < iterations; ++i) { 659f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 669f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 679f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Draw the background 689f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDisable(GL_BLEND); 699f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDisable(GL_DEPTH_TEST); 709f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // We have to blend three textures, but we use multi-texture for this 719f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // blending, not fb blend, to avoid the external memory traffic 729f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 739f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]); 749f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE1); 759f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]); 769f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE2); 779f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]); 789f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Use the right shader 799f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUseProgram(compositing_background_program_); 809f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Draw the quad 819f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 829f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 839f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Use the right shader 849f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUseProgram(compositing_foreground_program_); 859f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 869f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Compositing is blending, so we shall blend. 879f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnable(GL_BLEND); 889f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Depth test is on for window occlusion 899f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnable(GL_DEPTH_TEST); 909f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 919f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Draw window number one 929f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // This update acts like a chrome webkit sw rendering update. 939f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 949f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]); 959f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 969f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // TODO(papakipos): this LoadTexture is likely doing more CPU memory copies 979f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // than we would like. 989f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 999f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // TODO(papakipos): add color interpolation here, and modulate 1009f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // texture against it. 1019f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 1029f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1039f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Draw window number two 1049f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // This is a static window, so we don't update it. 1059f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 1069f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]); 1079f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // TODO(papakipos): add color interpolation here, and modulate 1089f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // texture against it. 1099f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 1109f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 1119f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return true; 1129f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 1139f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1149f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *kBasicTextureVertexShader = 1159f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "attribute vec4 c1;" 1169f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "attribute vec4 c2;" 117a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v1;" 1189f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "void main() {" 1199f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev " gl_Position = c1;" 120b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " v1 = c2;" 1219f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "}"; 1229f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1239f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *kBasicTextureFragmentShader = 1249f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "uniform sampler2D texture_sampler;" 125a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v1;" 1269f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "void main() {" 127b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " gl_FragColor = texture2D(texture_sampler, v1.st);" 1289f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "}"; 1299f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1309f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey MarinichevGLuint BasicTextureShaderProgram(GLuint vertex_buffer, GLuint texture_buffer) { 1319f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint program = InitShaderProgram(kBasicTextureVertexShader, 1329f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev kBasicTextureFragmentShader); 1339f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1349f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up the texture sampler 1359f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler = glGetUniformLocation(program, "texture_sampler"); 1369f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler, 0); 1379f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1389f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up vertex attribute 1399f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int attribute_index = glGetAttribLocation(program, "c1"); 1409f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 1419f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 1429f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 1439f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1449f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up texture attribute 1459f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c2"); 1469f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer); 1479f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 1489f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 1499f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1509f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return program; 1519f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 1529f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1539f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *kDoubleTextureBlendVertexShader = 1549f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "attribute vec4 c1;" 1559f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "attribute vec4 c2;" 1569f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "attribute vec4 c3;" 157a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v1;" 158a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v2;" 1599f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "void main() {" 1609f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev " gl_Position = c1;" 161b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " v1 = c2;" 162b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " v2 = c3;" 1639f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "}"; 1649f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1659f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *kDoubleTextureBlendFragmentShader = 1669f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "uniform sampler2D texture_sampler_0;" 1679f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "uniform sampler2D texture_sampler_1;" 168a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v1;" 169a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters "varying vec4 v2;" 1709f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "void main() {" 171b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " vec4 one = texture2D(texture_sampler_0, v1.st);" 172b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie " vec4 two = texture2D(texture_sampler_1, v2.st);" 1739f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev " gl_FragColor = mix(one, two, 0.5);" 1749f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev "}"; 1759f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1769f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// This shader blends the three textures 1779f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey MarinichevGLuint DoubleTextureBlendShaderProgram(GLuint vertex_buffer, 1789f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint texture_buffer_0, 1799f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint texture_buffer_1) { 1809f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint program = InitShaderProgram(kDoubleTextureBlendVertexShader, 1819f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev kDoubleTextureBlendFragmentShader); 1829f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up the texture sampler 1839f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0"); 1849f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler0, 0); 1859f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1"); 1869f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler1, 1); 1879f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1889f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up vertex attribute 1899f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int attribute_index = glGetAttribLocation(program, "c1"); 1909f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 1919f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 1929f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 1939f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1949f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up texture attributes 1959f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c2"); 1969f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0); 1979f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 1989f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 1999f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2009f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c3"); 2019f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1); 2029f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 2039f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 2049f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2059f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return program; 2069f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 2079f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2089f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *triple_texture_blend_vertex_shader = 2099f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"attribute vec4 c1;" 2109f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"attribute vec4 c2;" 2119f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"attribute vec4 c3;" 2129f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"attribute vec4 c4;" 213a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v1;" 214a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v2;" 215a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v3;" 2169f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"void main() {" 2179f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev" gl_Position = c1;" 218b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" v1 = c2;" 219b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" v2 = c3;" 220b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" v3 = c4;" 2219f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"}"; 2229f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2239f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevconst char *triple_texture_blend_fragment_shader = 2249f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"uniform sampler2D texture_sampler_0;" 2259f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"uniform sampler2D texture_sampler_1;" 2269f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"uniform sampler2D texture_sampler_2;" 227a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v1;" 228a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v2;" 229a1a86cbb14725f46b095671263c04289935bc8e7Kenneth Waters"varying vec4 v3;" 2309f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"void main() {" 231b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" vec4 one = texture2D(texture_sampler_0, v1.st);" 232b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" vec4 two = texture2D(texture_sampler_1, v2.st);" 233b8f4e7a20cddf76c31f3e00438b46963365c8b97Stuart Abercrombie" vec4 three = texture2D(texture_sampler_2, v3.st);" 2349f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev" gl_FragColor = mix(mix(one, two, 0.5), three, 0.5);" 2359f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev"}"; 2369f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2379f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// This shader blends the three textures 2389f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey MarinichevGLuint TripleTextureBlendShaderProgram(GLuint vertex_buffer, 2399f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint texture_buffer_0, 2409f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint texture_buffer_1, 2419f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint texture_buffer_2) { 2429f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint program = 2439f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev InitShaderProgram(triple_texture_blend_vertex_shader, 2449f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev triple_texture_blend_fragment_shader); 2459f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2469f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up the texture sampler 2479f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0"); 2489f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler0, 0); 2499f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1"); 2509f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler1, 1); 2519f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int textureSampler2 = glGetUniformLocation(program, "texture_sampler_2"); 2529f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glUniform1i(textureSampler2, 2); 2539f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2549f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up vertex attribute 2559f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev int attribute_index = glGetAttribLocation(program, "c1"); 2569f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 2579f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 2589f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 2599f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2609f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up texture attributes 2619f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c2"); 2629f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0); 2639f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 2649f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 2659f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2669f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c3"); 2679f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1); 2689f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 2699f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 2709f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2719f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev attribute_index = glGetAttribLocation(program, "c4"); 2729f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_2); 2739f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 2749f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glEnableVertexAttribArray(attribute_index); 2759f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2769f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev return program; 2779f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 2789f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2799f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevvoid WindowManagerCompositingTest::InitializeCompositing() { 2809f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev InitBaseTexture(); 2819f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2829f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glClearColor(0.f, 0.f, 0.f, 0.f); 2839f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDisable(GL_DEPTH_TEST); 2849f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDisable(GL_BLEND); 2859f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 2869f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDepthFunc(GL_LEQUAL); 2879f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2889f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glGenTextures(5, compositing_textures_); 2899f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 2909f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev for (int i = 0; i < 5; i++) { 2919f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[i]); 2929f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 2939f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GL_LINEAR); 2949f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 2959f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GL_LINEAR); 2969f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 2979f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 2989f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up the vertex arrays for drawing textured quads later on. 2999f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLfloat buffer_vertex[8] = { 3009f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev -1.f, -1.f, 3019f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1.f, -1.f, 3029f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev -1.f, 1.f, 3039f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1.f, 1.f, 3049f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev }; 3059f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER, 3069f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev sizeof(buffer_vertex), buffer_vertex); 3079f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3089f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLfloat buffer_texture[8] = { 3099f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 0.f, 0.f, 3109f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1.f, 0.f, 3119f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 0.f, 1.f, 3129f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 1.f, 1.f, 3139f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev }; 3149f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER, 3159f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev sizeof(buffer_texture), buffer_texture); 3169f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3179f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up the static background textures. 3189f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 3199f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 3209f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 3219f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Load these textures into bound texture ids and keep using them 3229f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // from there to avoid having to reload this texture every frame 3239f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 3249f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]); 3259f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 3269f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE1); 3279f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]); 3289f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 3299f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE2); 3309f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]); 3319f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 3329f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3339f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 3349f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]); 3359f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 3369f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 3379f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3389f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glActiveTexture(GL_TEXTURE0); 3399f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]); 3409f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev UpdateTexture(); 3419f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev LoadTexture(); 3429f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3439f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Set up vertex & fragment shaders. 3449f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev compositing_background_program_ = 3459f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev TripleTextureBlendShaderProgram(vbo_vertex, 3469f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev vbo_texture, vbo_texture, vbo_texture); 3479f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev compositing_foreground_program_ = 3489f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev BasicTextureShaderProgram(vbo_vertex, vbo_texture); 3499f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev if (!compositing_background_program_ || !compositing_foreground_program_) { 3508faad30e5a44271d9e50c4d75e1271018d7439b5Ilja H. Friedel printf("# Warning: Could not set up compositing shader.\n"); 3519f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 3529f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 3539f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3549f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevvoid WindowManagerCompositingTest::TeardownCompositing() { 3559f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDeleteProgram(compositing_background_program_); 3569f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glDeleteProgram(compositing_foreground_program_); 3579f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 3589f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3599f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevvoid WindowManagerCompositingTest::InitBaseTexture() { 3609f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev for (int y = 0; y < WINDOW_HEIGHT; y++) { 3619f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev for (int x = 0; x < WINDOW_WIDTH; x++) { 3629f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // This color is gray, half alpha. 3639f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev texture_base_[y*WINDOW_WIDTH+x] = 0x80808080; 3649f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 3659f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev } 3669f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 3679f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3689f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// UpdateTexture simulates Chrome updating tab contents. 3699f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// We cause a bunch of read and write cpu memory bandwidth. 3709f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev// It's a very rough approximation. 3719f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevvoid WindowManagerCompositingTest::UpdateTexture() { 3729f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev memcpy(texture_update_, texture_base_, sizeof(texture_base_)); 3739f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 3749f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3759f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichevvoid WindowManagerCompositingTest::LoadTexture() { 3769f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev // Use GL_RGBA for compatibility with GLES2.0. 3779f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3789f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev WINDOW_WIDTH, WINDOW_HEIGHT, 0, 3799f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev GL_RGBA, GL_UNSIGNED_BYTE, texture_update_); 3809f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} 3819f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev 3829f9b873ae65c0a087ed3cd9856121a6d41e3410aAlexey Marinichev} // namespace glbench 383