| // | |
| // Copyright 2022 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // ProgramPipelineObjectPerfTest: | |
| // Performance tests switching program stages of a pipeline. | |
| // | |
| #include "ANGLEPerfTest.h" | |
| #include <array> | |
| #include "common/vector_utils.h" | |
| #include "util/shader_utils.h" | |
| using namespace angle; | |
| namespace | |
| { | |
| constexpr unsigned int kIterationsPerStep = 1024; | |
| struct ProgramPipelineObjectParams final : public RenderTestParams | |
| { | |
| ProgramPipelineObjectParams() | |
| { | |
| iterationsPerStep = kIterationsPerStep; | |
| majorVersion = 3; | |
| minorVersion = 1; | |
| windowWidth = 256; | |
| windowHeight = 256; | |
| } | |
| std::string story() const override | |
| { | |
| std::stringstream strstr; | |
| strstr << RenderTestParams::story(); | |
| if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) | |
| { | |
| strstr << "_null"; | |
| } | |
| return strstr.str(); | |
| } | |
| }; | |
| std::ostream &operator<<(std::ostream &os, const ProgramPipelineObjectParams ¶ms) | |
| { | |
| os << params.backendAndStory().substr(1); | |
| return os; | |
| } | |
| class ProgramPipelineObjectBenchmark | |
| : public ANGLERenderTest, | |
| public ::testing::WithParamInterface<ProgramPipelineObjectParams> | |
| { | |
| public: | |
| ProgramPipelineObjectBenchmark(); | |
| void initializeBenchmark() override; | |
| void destroyBenchmark() override; | |
| void drawBenchmark() override; | |
| protected: | |
| GLuint mVertProg1 = 0; | |
| GLuint mVertProg2 = 0; | |
| GLuint mFragProg1 = 0; | |
| GLuint mFragProg2 = 0; | |
| GLuint mPpo = 0; | |
| }; | |
| ProgramPipelineObjectBenchmark::ProgramPipelineObjectBenchmark() | |
| : ANGLERenderTest("ProgramPipelineObject", GetParam()) | |
| {} | |
| void ProgramPipelineObjectBenchmark::initializeBenchmark() | |
| { | |
| glGenProgramPipelines(1, &mPpo); | |
| glBindProgramPipeline(mPpo); | |
| // Create 2 separable vertex and fragment program objects from the same source. | |
| const GLchar *vertString = essl31_shaders::vs::Simple(); | |
| const GLchar *fragString = R"(#version 310 es | |
| precision highp float; | |
| uniform float redColorIn; | |
| uniform float greenColorIn; | |
| out vec4 my_FragColor; | |
| void main() | |
| { | |
| my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0); | |
| })"; | |
| mVertProg1 = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString); | |
| ASSERT_NE(mVertProg1, 0u); | |
| mVertProg2 = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString); | |
| ASSERT_NE(mVertProg2, 0u); | |
| mFragProg1 = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString); | |
| ASSERT_NE(mFragProg1, 0u); | |
| mFragProg2 = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString); | |
| ASSERT_NE(mFragProg2, 0u); | |
| } | |
| void ProgramPipelineObjectBenchmark::destroyBenchmark() | |
| { | |
| glDeleteProgramPipelines(1, &mPpo); | |
| glDeleteProgram(mVertProg1); | |
| glDeleteProgram(mVertProg2); | |
| glDeleteProgram(mFragProg1); | |
| glDeleteProgram(mFragProg2); | |
| } | |
| void ProgramPipelineObjectBenchmark::drawBenchmark() | |
| { | |
| glUseProgramStages(mPpo, GL_VERTEX_SHADER_BIT, mVertProg1); | |
| glUseProgramStages(mPpo, GL_FRAGMENT_SHADER_BIT, mFragProg1); | |
| // Set the output color to red | |
| GLint location = glGetUniformLocation(mFragProg1, "redColorIn"); | |
| glActiveShaderProgram(mPpo, mFragProg1); | |
| glUniform1f(location, 1.0); | |
| location = glGetUniformLocation(mFragProg1, "greenColorIn"); | |
| glActiveShaderProgram(mPpo, mFragProg1); | |
| glUniform1f(location, 0.0); | |
| // Change vertex and fragment programs of the pipeline before the draw. | |
| glUseProgramStages(mPpo, GL_VERTEX_SHADER_BIT, mVertProg2); | |
| glUseProgramStages(mPpo, GL_FRAGMENT_SHADER_BIT, mFragProg2); | |
| // Set the output color to green | |
| location = glGetUniformLocation(mFragProg2, "redColorIn"); | |
| glActiveShaderProgram(mPpo, mFragProg2); | |
| glUniform1f(location, 0.0); | |
| location = glGetUniformLocation(mFragProg2, "greenColorIn"); | |
| glActiveShaderProgram(mPpo, mFragProg2); | |
| glUniform1f(location, 1.0); | |
| // Draw | |
| const std::array<Vector3, 6> kQuadVertices = {{ | |
| Vector3(-1.0f, 1.0f, 0.5f), | |
| Vector3(-1.0f, -1.0f, 0.5f), | |
| Vector3(1.0f, -1.0f, 0.5f), | |
| Vector3(-1.0f, 1.0f, 0.5f), | |
| }}; | |
| GLint positionLocation = glGetAttribLocation(mVertProg2, "a_position"); | |
| glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, kQuadVertices.data()); | |
| glEnableVertexAttribArray(positionLocation); | |
| glDrawArrays(GL_TRIANGLES, 0, 6); | |
| glDisableVertexAttribArray(positionLocation); | |
| glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr); | |
| } | |
| using namespace egl_platform; | |
| ProgramPipelineObjectParams ProgramPipelineObjectVulkanParams() | |
| { | |
| ProgramPipelineObjectParams params; | |
| params.eglParameters = VULKAN(); | |
| return params; | |
| } | |
| ProgramPipelineObjectParams ProgramPipelineObjectVulkanNullParams() | |
| { | |
| ProgramPipelineObjectParams params; | |
| params.eglParameters = VULKAN_NULL(); | |
| return params; | |
| } | |
| // Test performance of switching programs before a draw. | |
| TEST_P(ProgramPipelineObjectBenchmark, Run) | |
| { | |
| run(); | |
| } | |
| ANGLE_INSTANTIATE_TEST(ProgramPipelineObjectBenchmark, | |
| ProgramPipelineObjectVulkanParams(), | |
| ProgramPipelineObjectVulkanNullParams()); | |
| } // anonymous namespace |