blob: a2f6938afb8d77b3a5901fc8bd1628d83cd5d474 [file] [log] [blame]
//
// Copyright 2017 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.
//
// BlitFramebufferPerf:
// Performance tests for glBlitFramebuffer in ES3. Includes tests for
// color, depth, and stencil blit, as well as the mutlisample versions.
// The test works by clearing a framebuffer, then blitting it to a second.
#include "ANGLEPerfTest.h"
namespace
{
enum class BufferType
{
COLOR,
DEPTH,
STENCIL,
DEPTH_STENCIL
};
const char *BufferTypeString(BufferType type)
{
switch (type)
{
case BufferType::COLOR:
return "color";
case BufferType::DEPTH:
return "depth";
case BufferType::STENCIL:
return "stencil";
case BufferType::DEPTH_STENCIL:
return "depth_stencil";
default:
return "error";
}
}
GLbitfield BufferTypeMask(BufferType type)
{
switch (type)
{
case BufferType::COLOR:
return GL_COLOR_BUFFER_BIT;
case BufferType::DEPTH:
return GL_DEPTH_BUFFER_BIT;
case BufferType::STENCIL:
return GL_STENCIL_BUFFER_BIT;
case BufferType::DEPTH_STENCIL:
return (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
default:
return 0;
}
}
GLenum BufferTypeFormat(BufferType type)
{
switch (type)
{
case BufferType::COLOR:
return GL_RGBA8;
case BufferType::DEPTH:
return GL_DEPTH_COMPONENT24;
case BufferType::STENCIL:
return GL_STENCIL_INDEX8;
case BufferType::DEPTH_STENCIL:
return GL_DEPTH24_STENCIL8;
default:
return GL_NONE;
}
}
GLenum BufferTypeAttachment(BufferType type)
{
switch (type)
{
case BufferType::COLOR:
return GL_COLOR_ATTACHMENT0;
case BufferType::DEPTH:
return GL_DEPTH_ATTACHMENT;
case BufferType::STENCIL:
return GL_STENCIL_ATTACHMENT;
case BufferType::DEPTH_STENCIL:
return GL_DEPTH_STENCIL_ATTACHMENT;
default:
return GL_NONE;
}
}
struct BlitFramebufferParams final : public RenderTestParams
{
BlitFramebufferParams()
{
majorVersion = 3;
minorVersion = 0;
windowWidth = 256;
windowHeight = 256;
}
std::string suffix() const override
{
std::stringstream suffixStr;
suffixStr << RenderTestParams::suffix();
suffixStr << "_" << BufferTypeString(type);
if (samples > 1)
{
suffixStr << "_" << samples << "_samples";
}
return suffixStr.str();
}
BufferType type = BufferType::COLOR;
unsigned int framebufferSize = 512;
unsigned int samples = 0;
unsigned int iterations = 5;
};
std::ostream &operator<<(std::ostream &os, const BlitFramebufferParams &params)
{
os << params.suffix().substr(1);
return os;
}
class BlitFramebufferPerf : public ANGLERenderTest,
public ::testing::WithParamInterface<BlitFramebufferParams>
{
public:
BlitFramebufferPerf() : ANGLERenderTest("BlitFramebufferPerf", GetParam()) {}
void initializeBenchmark() override;
void destroyBenchmark() override;
void drawBenchmark() override;
private:
GLuint mReadFramebuffer = 0;
GLuint mReadRenderbuffer = 0;
GLuint mDrawFramebuffer = 0;
GLuint mDrawRenderbuffer = 0;
};
void BlitFramebufferPerf::initializeBenchmark()
{
const auto &param = GetParam();
glGenFramebuffers(1, &mReadFramebuffer);
glGenFramebuffers(1, &mDrawFramebuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
// Create source and destination Renderbuffers.
glGenRenderbuffers(1, &mReadRenderbuffer);
glGenRenderbuffers(1, &mDrawRenderbuffer);
ASSERT_GL_NO_ERROR();
GLenum format = BufferTypeFormat(param.type);
GLuint size = param.framebufferSize;
GLenum attachment = BufferTypeAttachment(param.type);
glBindRenderbuffer(GL_RENDERBUFFER, mReadRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.samples, format, size, size);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, mReadRenderbuffer);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
glBindRenderbuffer(GL_RENDERBUFFER, mDrawRenderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, size, size);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, mDrawRenderbuffer);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
void BlitFramebufferPerf::destroyBenchmark()
{
glDeleteFramebuffers(1, &mReadFramebuffer);
glDeleteRenderbuffers(1, &mReadRenderbuffer);
glDeleteFramebuffers(1, &mDrawFramebuffer);
glDeleteRenderbuffers(1, &mDrawRenderbuffer);
}
void BlitFramebufferPerf::drawBenchmark()
{
const auto &param = GetParam();
auto size = param.framebufferSize;
auto mask = BufferTypeMask(param.type);
// We don't read from the draw buffer (ie rendering) to simplify the test, but we could.
// This might trigger a flush, or we could trigger a flush manually to ensure the blit happens.
// TODO(jmadill): Investigate performance on Vulkan, and placement of Clear call.
switch (param.type)
{
case BufferType::COLOR:
{
GLfloat clearValues[4] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, clearValues);
break;
}
case BufferType::DEPTH:
{
GLfloat clearDepthValue = 0.5f;
glClearBufferfv(GL_DEPTH, 0, &clearDepthValue);
break;
}
case BufferType::STENCIL:
{
GLint clearStencilValue = 1;
glClearBufferiv(GL_STENCIL, 0, &clearStencilValue);
break;
}
case BufferType::DEPTH_STENCIL:
glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.5f, 1);
break;
}
for (unsigned int iteration = 0; iteration < param.iterations; ++iteration)
{
glBlitFramebuffer(0, 0, size, size, 0, 0, size, size, mask, GL_NEAREST);
}
}
TEST_P(BlitFramebufferPerf, Run)
{
run();
}
BlitFramebufferParams D3D11(BufferType type, unsigned int samples)
{
BlitFramebufferParams params;
params.eglParameters = angle::egl_platform::D3D11();
params.type = type;
params.samples = samples;
return params;
}
} // anonymous namespace
// TODO(jmadill): Programatically generate these combinations.
ANGLE_INSTANTIATE_TEST(BlitFramebufferPerf,
D3D11(BufferType::COLOR, 0),
D3D11(BufferType::DEPTH, 0),
D3D11(BufferType::STENCIL, 0),
D3D11(BufferType::DEPTH_STENCIL, 0),
D3D11(BufferType::COLOR, 2),
D3D11(BufferType::DEPTH, 2),
D3D11(BufferType::STENCIL, 2),
D3D11(BufferType::DEPTH_STENCIL, 2))