blob: 5ffd76c0685c0e65548f68df27d15b82ff47adb4 [file] [log] [blame]
//
// Copyright 2020 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.
//
// MultisampledRenderToTextureBenchmark:
// Performance test for rendering to multisampled-render-to-texture attachments.
//
#include "ANGLEPerfTest.h"
#include <iostream>
#include <random>
#include <sstream>
#include "test_utils/gl_raii.h"
#include "util/shader_utils.h"
using namespace angle;
namespace
{
constexpr uint32_t kMultipassPassCount = 5;
struct MultisampledRenderToTextureParams final : public RenderTestParams
{
MultisampledRenderToTextureParams()
{
iterationsPerStep = 1;
trackGpuTime = true;
textureWidth = 1920;
textureHeight = 1080;
multiplePasses = false;
withDepthStencil = false;
}
std::string story() const override;
GLsizei textureWidth;
GLsizei textureHeight;
bool multiplePasses;
bool withDepthStencil;
};
std::ostream &operator<<(std::ostream &os, const MultisampledRenderToTextureParams &params)
{
return os << params.backendAndStory().substr(1);
}
std::string MultisampledRenderToTextureParams::story() const
{
std::stringstream strstr;
strstr << RenderTestParams::story();
if (multiplePasses)
{
strstr << "_multipass";
}
if (withDepthStencil)
{
strstr << "_ds";
}
return strstr.str();
}
class MultisampledRenderToTextureBenchmark
: public ANGLERenderTest,
public ::testing::WithParamInterface<MultisampledRenderToTextureParams>
{
public:
MultisampledRenderToTextureBenchmark();
void initializeBenchmark() override;
void destroyBenchmark() override;
void drawBenchmark() override;
protected:
void initShaders();
GLuint mFramebuffer = 0;
GLuint mProgram = 0;
GLuint mColorTexture = 0;
GLuint mDepthStencilRenderbuffer = 0;
std::vector<uint8_t> mTextureData;
};
MultisampledRenderToTextureBenchmark::MultisampledRenderToTextureBenchmark()
: ANGLERenderTest("MultisampledRenderToTexture", GetParam())
{
if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
skipTest("http://crbug.com/945415 Crashes on nvidia+d3d11");
}
if (IsWindows7() && IsNVIDIA() &&
GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
{
skipTest(
"http://crbug.com/1096510 Fails on Windows7 NVIDIA Vulkan, presumably due to old "
"drivers");
}
if (IsPixel4() && GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
{
skipTest("http://anglebug.com/5120 Fails on Pixel 4 GLES");
}
if (IsLinux() && IsAMD() &&
GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE &&
GetParam().multiplePasses && GetParam().withDepthStencil)
{
skipTest("http://anglebug.com/5380");
}
if (IsLinux() && IsIntel() &&
GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
skipTest("http://anglebug.com/6319");
}
}
void MultisampledRenderToTextureBenchmark::initializeBenchmark()
{
if (!IsGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"))
{
skipTest("missing GL_EXT_multisampled_render_to_texture");
return;
}
const auto &params = GetParam();
initShaders();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
glGenFramebuffers(1, &mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glGenTextures(1, &mColorTexture);
glBindTexture(GL_TEXTURE_2D, mColorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, params.textureWidth, params.textureHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mColorTexture, 0, 4);
if (params.withDepthStencil)
{
glGenRenderbuffers(1, &mDepthStencilRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthStencilRenderbuffer);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8,
params.textureWidth, params.textureHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDepthStencilRenderbuffer);
}
ASSERT_GL_NO_ERROR();
}
void MultisampledRenderToTextureBenchmark::initShaders()
{
constexpr char kVS[] = R"(void main()
{
gl_Position = vec4(0, 0, 0, 1);
})";
constexpr char kFS[] = R"(precision mediump float;
void main()
{
gl_FragColor = vec4(0);
})";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
ASSERT_GL_NO_ERROR();
}
void MultisampledRenderToTextureBenchmark::destroyBenchmark()
{
glDeleteFramebuffers(1, &mFramebuffer);
glDeleteRenderbuffers(1, &mDepthStencilRenderbuffer);
glDeleteTextures(1, &mColorTexture);
glDeleteProgram(mProgram);
}
void MultisampledRenderToTextureBenchmark::drawBenchmark()
{
const auto &params = GetParam();
GLTexture mMockTexture;
glBindTexture(GL_TEXTURE_2D, mMockTexture);
startGpuTimer();
// Initially clear the color attachment to avoid having to load from the resolved image. The
// depth/stencil attachment doesn't need this as it's contents are always undefined between
// render passes.
glClear(GL_COLOR_BUFFER_BIT);
const uint32_t passCount = params.multiplePasses ? kMultipassPassCount : 1;
for (uint32_t pass = 0; pass < passCount; ++pass)
{
// Perform a draw just to have something in the render pass. With the position attributes
// not set, a constant default value is used, resulting in a very cheap draw.
glDrawArrays(GL_TRIANGLES, 0, 3);
// Force the render pass to break by cheaply reading back from the color attachment.
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
}
stopGpuTimer();
ASSERT_GL_NO_ERROR();
}
MultisampledRenderToTextureParams D3D11Params(bool multiplePasses, bool withDepthStencil)
{
MultisampledRenderToTextureParams params;
params.eglParameters = egl_platform::D3D11();
params.majorVersion = 3;
params.minorVersion = 0;
params.multiplePasses = multiplePasses;
params.withDepthStencil = withDepthStencil;
return params;
}
MultisampledRenderToTextureParams MetalParams(bool multiplePasses, bool withDepthStencil)
{
MultisampledRenderToTextureParams params;
params.eglParameters = egl_platform::METAL();
params.majorVersion = 3;
params.minorVersion = 0;
params.multiplePasses = multiplePasses;
params.withDepthStencil = withDepthStencil;
return params;
}
MultisampledRenderToTextureParams OpenGLOrGLESParams(bool multiplePasses, bool withDepthStencil)
{
MultisampledRenderToTextureParams params;
params.eglParameters = egl_platform::OPENGL_OR_GLES();
params.majorVersion = 3;
params.minorVersion = 0;
params.multiplePasses = multiplePasses;
params.withDepthStencil = withDepthStencil;
return params;
}
MultisampledRenderToTextureParams VulkanParams(bool multiplePasses, bool withDepthStencil)
{
MultisampledRenderToTextureParams params;
params.eglParameters = egl_platform::VULKAN();
params.majorVersion = 3;
params.minorVersion = 0;
params.multiplePasses = multiplePasses;
params.withDepthStencil = withDepthStencil;
return params;
}
} // anonymous namespace
TEST_P(MultisampledRenderToTextureBenchmark, Run)
{
run();
}
using namespace params;
ANGLE_INSTANTIATE_TEST(MultisampledRenderToTextureBenchmark,
D3D11Params(false, false),
D3D11Params(true, true),
MetalParams(false, false),
MetalParams(true, true),
OpenGLOrGLESParams(false, false),
OpenGLOrGLESParams(true, true),
VulkanParams(false, false),
VulkanParams(true, false),
VulkanParams(false, true),
VulkanParams(true, true));