Path: blob/main_old/src/tests/perf_tests/DrawCallPerf.cpp
1693 views
//1// Copyright 2014 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// DrawCallPerf:6// Performance tests for ANGLE draw call overhead.7//89#include "ANGLEPerfTest.h"10#include "DrawCallPerfParams.h"11#include "common/PackedEnums.h"12#include "test_utils/draw_call_perf_utils.h"13#include "util/shader_utils.h"1415namespace16{17enum class StateChange18{19NoChange,20VertexAttrib,21VertexBuffer,22ManyVertexBuffers,23Texture,24Program,25VertexBufferCycle,26Scissor,27InvalidEnum,28EnumCount = InvalidEnum,29};3031constexpr size_t kCycleVBOPoolSize = 200;3233struct DrawArraysPerfParams : public DrawCallPerfParams34{35DrawArraysPerfParams() = default;36DrawArraysPerfParams(const DrawCallPerfParams &base) : DrawCallPerfParams(base) {}3738std::string story() const override;3940StateChange stateChange = StateChange::NoChange;41};4243std::string DrawArraysPerfParams::story() const44{45std::stringstream strstr;4647strstr << DrawCallPerfParams::story();4849switch (stateChange)50{51case StateChange::VertexAttrib:52strstr << "_attrib_change";53break;54case StateChange::VertexBuffer:55strstr << "_vbo_change";56break;57case StateChange::ManyVertexBuffers:58strstr << "_manyvbos_change";59break;60case StateChange::Texture:61strstr << "_tex_change";62break;63case StateChange::Program:64strstr << "_prog_change";65break;66case StateChange::VertexBufferCycle:67strstr << "_vbo_cycle";68break;69case StateChange::Scissor:70strstr << "_scissor_change";71break;72default:73break;74}7576return strstr.str();77}7879std::ostream &operator<<(std::ostream &os, const DrawArraysPerfParams ¶ms)80{81os << params.backendAndStory().substr(1);82return os;83}8485GLuint CreateSimpleTexture2D()86{87// Use tightly packed data88glPixelStorei(GL_UNPACK_ALIGNMENT, 1);8990// Generate a texture object91GLuint texture;92glGenTextures(1, &texture);9394// Bind the texture object95glBindTexture(GL_TEXTURE_2D, texture);9697// Load the texture: 2x2 Image, 3 bytes per pixel (R, G, B)98constexpr size_t width = 2;99constexpr size_t height = 2;100GLubyte pixels[width * height * 3] = {101255, 0, 0, // Red1020, 255, 0, // Green1030, 0, 255, // Blue104255, 255, 0, // Yellow105};106glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);107108// Set the filtering mode109glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);110glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);111112return texture;113}114115class DrawCallPerfBenchmark : public ANGLERenderTest,116public ::testing::WithParamInterface<DrawArraysPerfParams>117{118public:119DrawCallPerfBenchmark();120121void initializeBenchmark() override;122void destroyBenchmark() override;123void drawBenchmark() override;124125private:126GLuint mProgram1 = 0;127GLuint mProgram2 = 0;128GLuint mBuffer1 = 0;129GLuint mBuffer2 = 0;130GLuint mFBO = 0;131GLuint mFBOTexture = 0;132GLuint mTexture1 = 0;133GLuint mTexture2 = 0;134int mNumTris = GetParam().numTris;135std::vector<GLuint> mVBOPool;136size_t mCurrentVBO = 0;137};138139DrawCallPerfBenchmark::DrawCallPerfBenchmark() : ANGLERenderTest("DrawCallPerf", GetParam()) {}140141void DrawCallPerfBenchmark::initializeBenchmark()142{143const auto ¶ms = GetParam();144145if (params.stateChange == StateChange::Texture)146{147mProgram1 = SetupSimpleTextureProgram();148}149if (params.stateChange == StateChange::Program)150{151mProgram1 = SetupSimpleTextureProgram();152mProgram2 = SetupDoubleTextureProgram();153154ASSERT_NE(0u, mProgram2);155}156else if (params.stateChange == StateChange::ManyVertexBuffers)157{158constexpr char kVS[] = R"(attribute vec2 vPosition;159attribute vec2 v0;160attribute vec2 v1;161attribute vec2 v2;162attribute vec2 v3;163const float scale = 0.5;164const float offset = -0.5;165166varying vec2 v;167168void main()169{170gl_Position = vec4(vPosition * vec2(scale) + vec2(offset), 0, 1);171v = (v0 + v1 + v2 + v3) * 0.25;172})";173174constexpr char kFS[] = R"(precision mediump float;175varying vec2 v;176void main()177{178gl_FragColor = vec4(v, 0, 1);179})";180181mProgram1 = CompileProgram(kVS, kFS);182glBindAttribLocation(mProgram1, 1, "v0");183glBindAttribLocation(mProgram1, 2, "v1");184glBindAttribLocation(mProgram1, 3, "v2");185glBindAttribLocation(mProgram1, 4, "v3");186glEnableVertexAttribArray(1);187glEnableVertexAttribArray(2);188glEnableVertexAttribArray(3);189glEnableVertexAttribArray(4);190}191else if (params.stateChange == StateChange::VertexBufferCycle)192{193mProgram1 = SetupSimpleDrawProgram();194195for (size_t bufferIndex = 0; bufferIndex < kCycleVBOPoolSize; ++bufferIndex)196{197GLuint buffer = Create2DTriangleBuffer(mNumTris, GL_STATIC_DRAW);198mVBOPool.push_back(buffer);199}200}201else202{203mProgram1 = SetupSimpleDrawProgram();204}205206ASSERT_NE(0u, mProgram1);207208// Re-link program to ensure the attrib bindings are used.209glBindAttribLocation(mProgram1, 0, "vPosition");210glLinkProgram(mProgram1);211glUseProgram(mProgram1);212213if (mProgram2)214{215glBindAttribLocation(mProgram2, 0, "vPosition");216glLinkProgram(mProgram2);217}218219glClearColor(0.0f, 0.0f, 0.0f, 0.0f);220221mBuffer1 = Create2DTriangleBuffer(mNumTris, GL_STATIC_DRAW);222mBuffer2 = Create2DTriangleBuffer(mNumTris, GL_STATIC_DRAW);223224glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);225glEnableVertexAttribArray(0);226227// Set the viewport228glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());229230if (params.surfaceType == SurfaceType::Offscreen)231{232CreateColorFBO(getWindow()->getWidth(), getWindow()->getHeight(), &mFBOTexture, &mFBO);233}234235mTexture1 = CreateSimpleTexture2D();236mTexture2 = CreateSimpleTexture2D();237238if (params.stateChange == StateChange::Program)239{240// Bind the textures as appropriate, they are not modified during the test.241GLint program1Tex1Loc = glGetUniformLocation(mProgram1, "tex");242GLint program2Tex1Loc = glGetUniformLocation(mProgram2, "tex1");243GLint program2Tex2Loc = glGetUniformLocation(mProgram2, "tex2");244245glUseProgram(mProgram1);246glUniform1i(program1Tex1Loc, 0);247248glUseProgram(mProgram2);249glUniform1i(program2Tex1Loc, 0);250glUniform1i(program2Tex2Loc, 1);251252glActiveTexture(GL_TEXTURE0);253glBindTexture(GL_TEXTURE_2D, mTexture1);254255glActiveTexture(GL_TEXTURE1);256glBindTexture(GL_TEXTURE_2D, mTexture2);257}258259ASSERT_GL_NO_ERROR();260}261262void DrawCallPerfBenchmark::destroyBenchmark()263{264glDeleteProgram(mProgram1);265glDeleteProgram(mProgram2);266glDeleteBuffers(1, &mBuffer1);267glDeleteBuffers(1, &mBuffer2);268glDeleteTextures(1, &mFBOTexture);269glDeleteTextures(1, &mTexture1);270glDeleteTextures(1, &mTexture2);271glDeleteFramebuffers(1, &mFBO);272273if (!mVBOPool.empty())274{275glDeleteBuffers(mVBOPool.size(), mVBOPool.data());276}277}278279void ClearThenDraw(unsigned int iterations, GLsizei numElements)280{281glClear(GL_COLOR_BUFFER_BIT);282283for (unsigned int it = 0; it < iterations; it++)284{285glDrawArrays(GL_TRIANGLES, 0, numElements);286}287}288289void JustDraw(unsigned int iterations, GLsizei numElements)290{291for (unsigned int it = 0; it < iterations; it++)292{293glDrawArrays(GL_TRIANGLES, 0, numElements);294}295}296297template <int kArrayBufferCount>298void ChangeVertexAttribThenDraw(unsigned int iterations, GLsizei numElements, GLuint buffer)299{300glBindBuffer(GL_ARRAY_BUFFER, buffer);301for (unsigned int it = 0; it < iterations; it++)302{303for (int arrayIndex = 0; arrayIndex < kArrayBufferCount; ++arrayIndex)304{305glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);306}307glDrawArrays(GL_TRIANGLES, 0, numElements);308309for (int arrayIndex = 0; arrayIndex < kArrayBufferCount; ++arrayIndex)310{311glVertexAttribPointer(arrayIndex, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);312}313glDrawArrays(GL_TRIANGLES, 0, numElements);314}315}316template <int kArrayBufferCount>317void ChangeArrayBuffersThenDraw(unsigned int iterations,318GLsizei numElements,319GLuint buffer1,320GLuint buffer2)321{322for (unsigned int it = 0; it < iterations; it++)323{324glBindBuffer(GL_ARRAY_BUFFER, buffer1);325for (int arrayIndex = 0; arrayIndex < kArrayBufferCount; ++arrayIndex)326{327glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);328}329glDrawArrays(GL_TRIANGLES, 0, numElements);330331glBindBuffer(GL_ARRAY_BUFFER, buffer2);332for (int arrayIndex = 0; arrayIndex < kArrayBufferCount; ++arrayIndex)333{334glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);335}336glDrawArrays(GL_TRIANGLES, 0, numElements);337}338}339340void ChangeTextureThenDraw(unsigned int iterations,341GLsizei numElements,342GLuint texture1,343GLuint texture2)344{345for (unsigned int it = 0; it < iterations; it++)346{347glBindTexture(GL_TEXTURE_2D, texture1);348glDrawArrays(GL_TRIANGLES, 0, numElements);349350glBindTexture(GL_TEXTURE_2D, texture2);351glDrawArrays(GL_TRIANGLES, 0, numElements);352}353}354355void ChangeProgramThenDraw(unsigned int iterations,356GLsizei numElements,357GLuint program1,358GLuint program2)359{360for (unsigned int it = 0; it < iterations; it++)361{362glUseProgram(program1);363glDrawArrays(GL_TRIANGLES, 0, numElements);364365glUseProgram(program2);366glDrawArrays(GL_TRIANGLES, 0, numElements);367}368}369370void CycleVertexBufferThenDraw(unsigned int iterations,371GLsizei numElements,372const std::vector<GLuint> &vbos,373size_t *currentVBO)374{375for (unsigned int it = 0; it < iterations; it++)376{377GLuint vbo = vbos[*currentVBO];378glBindBuffer(GL_ARRAY_BUFFER, vbo);379glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);380glDrawArrays(GL_TRIANGLES, 0, numElements);381*currentVBO = (*currentVBO + 1) % vbos.size();382}383}384385void ChangeScissorThenDraw(unsigned int iterations,386GLsizei numElements,387unsigned int windowWidth,388unsigned int windowHeight)389{390// Change scissor as such:391//392// - Start with a narrow vertical bar:393//394// Scissor395// |396// V397// +-----+-+-----+398// | | | | <-- Window399// | | | |400// | | | |401// | | | |402// | | | |403// | | | |404// +-----+-+-----+405//406// - Gradually reduce height and increase width, to end up with a narrow horizontal bar:407//408// +-------------+409// | |410// | |411// +-------------+ <-- Scissor412// +-------------+413// | |414// | |415// +-------------+416//417// - If more iterations left, restart, but shift the initial bar left to cover more area:418//419// +---+-+-------+ +-------------+420// | | | | | |421// | | | | +-------------+422// | | | | ---> | |423// | | | | | |424// | | | | +-------------+425// | | | | | |426// +---+-+-------+ +-------------+427//428// +-+-+---------+ +-------------+429// | | | | +-------------+430// | | | | | |431// | | | | ---> | |432// | | | | | |433// | | | | | |434// | | | | +-------------+435// +-+-+---------+ +-------------+436437glEnable(GL_SCISSOR_TEST);438439constexpr unsigned int kScissorStep = 2;440unsigned int scissorX = windowWidth / 2 - 1;441unsigned int scissorY = 0;442unsigned int scissorWidth = 2;443unsigned int scissorHeight = windowHeight;444unsigned int scissorPatternIteration = 0;445446for (unsigned int it = 0; it < iterations; it++)447{448glScissor(scissorX, scissorY, scissorWidth, scissorHeight);449glDrawArrays(GL_TRIANGLES, 0, numElements);450451if (scissorX < kScissorStep || scissorHeight < kScissorStep * 2)452{453++scissorPatternIteration;454scissorX = windowWidth / 2 - 1 - scissorPatternIteration * 2;455scissorY = 0;456scissorWidth = 2;457scissorHeight = windowHeight;458}459else460{461scissorX -= kScissorStep;462scissorY += kScissorStep;463scissorWidth += kScissorStep * 2;464scissorHeight -= kScissorStep * 2;465}466}467}468469void DrawCallPerfBenchmark::drawBenchmark()470{471// This workaround fixes a huge queue of graphics commands accumulating on the GL472// back-end. The GL back-end doesn't have a proper NULL device at the moment.473// TODO(jmadill): Remove this when/if we ever get a proper OpenGL NULL device.474const auto &eglParams = GetParam().eglParameters;475const auto ¶ms = GetParam();476GLsizei numElements = static_cast<GLsizei>(3 * mNumTris);477478switch (params.stateChange)479{480case StateChange::VertexAttrib:481ChangeVertexAttribThenDraw<1>(params.iterationsPerStep, numElements, mBuffer1);482break;483case StateChange::VertexBuffer:484ChangeArrayBuffersThenDraw<1>(params.iterationsPerStep, numElements, mBuffer1,485mBuffer2);486break;487case StateChange::ManyVertexBuffers:488ChangeArrayBuffersThenDraw<5>(params.iterationsPerStep, numElements, mBuffer1,489mBuffer2);490break;491case StateChange::Texture:492ChangeTextureThenDraw(params.iterationsPerStep, numElements, mTexture1, mTexture2);493break;494case StateChange::Program:495ChangeProgramThenDraw(params.iterationsPerStep, numElements, mProgram1, mProgram2);496break;497case StateChange::NoChange:498if (eglParams.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE ||499(eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE &&500eglParams.renderer != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE))501{502ClearThenDraw(params.iterationsPerStep, numElements);503}504else505{506JustDraw(params.iterationsPerStep, numElements);507}508break;509case StateChange::VertexBufferCycle:510CycleVertexBufferThenDraw(params.iterationsPerStep, numElements, mVBOPool,511&mCurrentVBO);512break;513case StateChange::Scissor:514ChangeScissorThenDraw(params.iterationsPerStep, numElements, getWindow()->getWidth(),515getWindow()->getHeight());516break;517case StateChange::InvalidEnum:518ADD_FAILURE() << "Invalid state change.";519break;520}521522ASSERT_GL_NO_ERROR();523}524525TEST_P(DrawCallPerfBenchmark, Run)526{527run();528}529530using namespace params;531532DrawArraysPerfParams CombineStateChange(const DrawArraysPerfParams &in, StateChange stateChange)533{534DrawArraysPerfParams out = in;535out.stateChange = stateChange;536537// Crank up iteration count to ensure we cycle through all VBs before a swap.538if (stateChange == StateChange::VertexBufferCycle)539{540out.iterationsPerStep = kCycleVBOPoolSize * 2;541}542543return out;544}545546using P = DrawArraysPerfParams;547548std::vector<P> gTestsWithStateChange =549CombineWithValues({P()}, angle::AllEnums<StateChange>(), CombineStateChange);550std::vector<P> gTestsWithRenderer =551CombineWithFuncs(gTestsWithStateChange, {D3D11<P>, GL<P>, Vulkan<P>, WGL<P>});552std::vector<P> gTestsWithDevice =553CombineWithFuncs(gTestsWithRenderer, {Passthrough<P>, Offscreen<P>, NullDevice<P>});554555ANGLE_INSTANTIATE_TEST_ARRAY(DrawCallPerfBenchmark, gTestsWithDevice);556557} // anonymous namespace558559560