// // Copyright 2018 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. // // DispatchComputePerf: // Performance tests for ANGLE DispatchCompute call overhead. // #include "ANGLEPerfTest.h" #include "util/shader_utils.h" namespace { unsigned int kIterationsPerStep = 50; struct DispatchComputePerfParams final : public RenderTestParams { DispatchComputePerfParams() { iterationsPerStep = kIterationsPerStep; majorVersion = 3; minorVersion = 1; } std::string story() const override; unsigned int localSizeX = 16; unsigned int localSizeY = 16; unsigned int textureWidth = 32; unsigned int textureHeight = 32; }; std::string DispatchComputePerfParams::story() const { std::stringstream storyStr; storyStr << RenderTestParams::story(); if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) { storyStr << "_null"; } return storyStr.str(); } std::ostream &operator<<(std::ostream &os, const DispatchComputePerfParams ¶ms) { os << params.backendAndStory().substr(1); return os; } class DispatchComputePerfBenchmark : public ANGLERenderTest, public ::testing::WithParamInterface { public: DispatchComputePerfBenchmark(); void initializeBenchmark() override; void destroyBenchmark() override; void drawBenchmark() override; private: void initComputeShader(); void initTextures(); GLuint mProgram = 0; GLuint mReadTexture = 0; GLuint mWriteTexture = 0; GLuint mDispatchX = 0; GLuint mDispatchY = 0; }; DispatchComputePerfBenchmark::DispatchComputePerfBenchmark() : ANGLERenderTest("DispatchComputePerf", GetParam()) {} void DispatchComputePerfBenchmark::initializeBenchmark() { const auto ¶ms = GetParam(); initComputeShader(); initTextures(); glUseProgram(mProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mReadTexture); glUniform1i(glGetUniformLocation(mProgram, "readTexture"), 0); glBindImageTexture(4, mWriteTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32F); mDispatchX = params.textureWidth / params.localSizeX; mDispatchY = params.textureHeight / params.localSizeY; ASSERT_GL_NO_ERROR(); } void DispatchComputePerfBenchmark::initComputeShader() { constexpr char kCS[] = R"(#version 310 es #define LOCAL_SIZE_X 16 #define LOCAL_SIZE_Y 16 layout(local_size_x=LOCAL_SIZE_X, local_size_y=LOCAL_SIZE_Y) in; precision highp float; uniform sampler2D readTexture; layout(r32f, binding = 4) writeonly uniform highp image2D outImage; void main() { float sum = 0.; sum += texelFetch(readTexture, ivec2(gl_GlobalInvocationID.xy), 0).r; imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(sum)); })"; mProgram = CompileComputeProgram(kCS, false); ASSERT_NE(0u, mProgram); } void DispatchComputePerfBenchmark::initTextures() { const auto ¶ms = GetParam(); unsigned int textureDataSize = params.textureWidth * params.textureHeight; std::vector textureInputData(textureDataSize, 0.2f); std::vector textureOutputData(textureDataSize, 0.1f); glGenTextures(1, &mReadTexture); glBindTexture(GL_TEXTURE_2D, mReadTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, params.textureWidth, params.textureHeight, 0, GL_RED, GL_FLOAT, textureInputData.data()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glGenTextures(1, &mWriteTexture); glBindTexture(GL_TEXTURE_2D, mWriteTexture); glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, params.textureWidth, params.textureHeight); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, params.textureWidth, params.textureHeight, GL_RED, GL_FLOAT, textureOutputData.data()); ASSERT_GL_NO_ERROR(); } void DispatchComputePerfBenchmark::destroyBenchmark() { glDeleteProgram(mProgram); glDeleteTextures(1, &mReadTexture); glDeleteTextures(1, &mWriteTexture); } void DispatchComputePerfBenchmark::drawBenchmark() { const auto ¶ms = GetParam(); for (unsigned int it = 0; it < params.iterationsPerStep; it++) { glDispatchCompute(mDispatchX, mDispatchY, 1); glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); } ASSERT_GL_NO_ERROR(); } DispatchComputePerfParams DispatchComputePerfOpenGLOrGLESParams(bool useNullDevice) { DispatchComputePerfParams params; params.eglParameters = useNullDevice ? angle::egl_platform::OPENGL_OR_GLES_NULL() : angle::egl_platform::OPENGL_OR_GLES(); return params; } TEST_P(DispatchComputePerfBenchmark, Run) { run(); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DispatchComputePerfBenchmark); ANGLE_INSTANTIATE_TEST(DispatchComputePerfBenchmark, DispatchComputePerfOpenGLOrGLESParams(true), DispatchComputePerfOpenGLOrGLESParams(false)); } // namespace