/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
#include "../gl/GLESRenderEngine.h"
constexpr int DEFAULT_DISPLAY_WIDTH = 128;
constexpr int DEFAULT_DISPLAY_HEIGHT = 256;
constexpr int DEFAULT_DISPLAY_OFFSET = 64;
namespace android {
struct RenderEngineTest : public ::testing::Test {
static void SetUpTestSuite() {
sRE = renderengine::gl::GLESRenderEngine::create(static_cast<int32_t>(
ui::PixelFormat::RGBA_8888),
0, 1);
}
static void TearDownTestSuite() {
// The ordering here is important - sCurrentBuffer must live longer
// than RenderEngine to avoid a null reference on tear-down.
sRE = nullptr;
sCurrentBuffer = nullptr;
}
static sp<GraphicBuffer> allocateDefaultBuffer() {
return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER,
"output");
}
// Allocates a 1x1 buffer to fill with a solid color
static sp<GraphicBuffer> allocateSourceBuffer(uint32_t width, uint32_t height) {
return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_TEXTURE,
"input");
}
RenderEngineTest() { mBuffer = allocateDefaultBuffer(); }
~RenderEngineTest() {
for (uint32_t texName : mTexNames) {
sRE->deleteTextures(1, &texName);
}
}
void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
uint8_t tolerance = 0) {
uint8_t* pixels;
mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&pixels));
auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
uint8_t tmp = a >= b ? a - b : b - a;
return tmp <= tolerance;
};
int32_t maxFails = 10;
int32_t fails = 0;
for (int32_t j = 0; j < region.getHeight(); j++) {
const uint8_t* src =
pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4;
for (int32_t i = 0; i < region.getWidth(); i++) {
const uint8_t expected[4] = {r, g, b, a};
bool equal = std::equal(src, src + 4, expected, colorCompare);
EXPECT_TRUE(equal)
<< "pixel @ (" << region.left + i << ", " << region.top + j << "): "
<< "expected (" << static_cast<uint32_t>(r) << ", "
<< static_cast<uint32_t>(g) << ", " << static_cast<uint32_t>(b) << ", "
<< static_cast<uint32_t>(a) << "), "
<< "got (" << static_cast<uint32_t>(src[0]) << ", "
<< static_cast<uint32_t>(src[1]) << ", " << static_cast<uint32_t>(src[2])
<< ", " << static_cast<uint32_t>(src[3]) << ")";
src += 4;
if (!equal && ++fails >= maxFails) {
break;
}
}
if (fails >= maxFails) {
break;
}
}
mBuffer->unlock();
}
static Rect fullscreenRect() { return Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); }
static Rect offsetRect() {
return Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT);
}
static Rect offsetRectAtZero() {
return Rect(DEFAULT_DISPLAY_WIDTH - DEFAULT_DISPLAY_OFFSET,
DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET);
}
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
base::unique_fd(), &fence);
sCurrentBuffer = buffer;
int fd = fence.release();
if (fd >= 0) {
sync_wait(fd, -1);
close(fd);
}
ASSERT_EQ(NO_ERROR, status);
if (layers.size() > 0) {
ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
}
}
void drawEmptyLayers() {
renderengine::DisplaySettings settings;
std::vector<renderengine::LayerSettings> layers;
// Meaningless buffer since we don't do any drawing
sp<GraphicBuffer> buffer = new GraphicBuffer();
invokeDraw(settings, layers, buffer);
}
template <typename SourceVariant>
void fillBuffer(half r, half g, half b, half a);
template <typename SourceVariant>
void fillRedBuffer();
template <typename SourceVariant>
void fillGreenBuffer();
template <typename SourceVariant>
void fillBlueBuffer();
template <typename SourceVariant>
void fillRedTransparentBuffer();
template <typename SourceVariant>
void fillRedOffsetBuffer();
template <typename SourceVariant>
void fillBufferPhysicalOffset();
template <typename SourceVariant>
void fillBufferCheckers(mat4 transform);
template <typename SourceVariant>
void fillBufferCheckersRotate0();
template <typename SourceVariant>
void fillBufferCheckersRotate90();
template <typename SourceVariant>
void fillBufferCheckersRotate180();
template <typename SourceVariant>
void fillBufferCheckersRotate270();
template <typename SourceVariant>
void fillBufferWithLayerTransform();
template <typename SourceVariant>
void fillBufferLayerTransform();
template <typename SourceVariant>
void fillBufferWithColorTransform();
template <typename SourceVariant>
void fillBufferColorTransform();
template <typename SourceVariant>
void fillRedBufferWithRoundedCorners();
template <typename SourceVariant>
void fillBufferWithRoundedCorners();
template <typename SourceVariant>
void overlayCorners();
void fillRedBufferTextureTransform();
void fillBufferTextureTransform();
void fillRedBufferWithPremultiplyAlpha();
void fillBufferWithPremultiplyAlpha();
void fillRedBufferWithoutPremultiplyAlpha();
void fillBufferWithoutPremultiplyAlpha();
void fillGreenColorBufferThenClearRegion();
void clearLeftRegion();
void clearRegion();
// Keep around the same renderengine object to save on initialization time.
// For now, exercise the GL backend directly so that some caching specifics
// can be tested without changing the interface.
static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRE;
// Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
// be freed *after* RenderEngine is destroyed, so that the EGL image is
// destroyed first.
static sp<GraphicBuffer> sCurrentBuffer;
sp<GraphicBuffer> mBuffer;
std::vector<uint32_t> mTexNames;
};
std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRE = nullptr;
sp<GraphicBuffer> RenderEngineTest::sCurrentBuffer = nullptr;
struct ColorSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
RenderEngineTest* /*fixture*/) {
layer.source.solidColor = half3(r, g, b);
}
};
struct RelaxOpaqueBufferVariant {
static void setOpaqueBit(renderengine::LayerSettings& layer) {
layer.source.buffer.isOpaque = false;
}
static uint8_t getAlphaChannel() { return 255; }
};
struct ForceOpaqueBufferVariant {
static void setOpaqueBit(renderengine::LayerSettings& layer) {
layer.source.buffer.isOpaque = true;
}
static uint8_t getAlphaChannel() {
// The isOpaque bit will override the alpha channel, so this should be
// arbitrary.
return 10;
}
};
template <typename OpaquenessVariant>
struct BufferSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
RenderEngineTest* fixture) {
sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
uint32_t texName;
fixture->sRE->genTextures(1, &texName);
fixture->mTexNames.push_back(texName);
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&pixels));
for (int32_t j = 0; j < buf->getHeight(); j++) {
uint8_t* iter = pixels + (buf->getStride() * j) * 4;
for (int32_t i = 0; i < buf->getWidth(); i++) {
iter[0] = uint8_t(r * 255);
iter[1] = uint8_t(g * 255);
iter[2] = uint8_t(b * 255);
iter[3] = OpaquenessVariant::getAlphaChannel();
iter += 4;
}
}
buf->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
OpaquenessVariant::setOpaqueBit(layer);
}
};
template <typename SourceVariant>
void RenderEngineTest::fillBuffer(half r, half g, half b, half a) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillRedBuffer() {
fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, 1.0f);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillGreenBuffer() {
fillBuffer<SourceVariant>(0.0f, 1.0f, 0.0f, 1.0f);
expectBufferColor(fullscreenRect(), 0, 255, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillBlueBuffer() {
fillBuffer<SourceVariant>(0.0f, 0.0f, 1.0f, 1.0f);
expectBufferColor(fullscreenRect(), 0, 0, 255, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillRedTransparentBuffer() {
fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, .2f);
expectBufferColor(fullscreenRect(), 51, 0, 0, 51);
}
template <typename SourceVariant>
void RenderEngineTest::fillRedOffsetBuffer() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = offsetRect();
settings.clip = offsetRectAtZero();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferPhysicalOffset() {
fillRedOffsetBuffer<SourceVariant>();
expectBufferColor(Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT),
255, 0, 0, 255);
Rect offsetRegionLeft(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_HEIGHT);
Rect offsetRegionTop(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_OFFSET);
expectBufferColor(offsetRegionLeft, 0, 0, 0, 0);
expectBufferColor(offsetRegionTop, 0, 0, 0, 0);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckers(mat4 transform) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 2x2
settings.clip = Rect(2, 2);
settings.globalTransform = transform;
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layerOne;
Rect rectOne(0, 0, 1, 1);
layerOne.geometry.boundaries = rectOne.toFloatRect();
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 1.0f;
renderengine::LayerSettings layerTwo;
Rect rectTwo(0, 1, 1, 2);
layerTwo.geometry.boundaries = rectTwo.toFloatRect();
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
renderengine::LayerSettings layerThree;
Rect rectThree(1, 0, 2, 1);
layerThree.geometry.boundaries = rectThree.toFloatRect();
SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
layerThree.alpha = 1.0f;
layers.push_back(layerOne);
layers.push_back(layerTwo);
layers.push_back(layerThree);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckersRotate0() {
fillBufferCheckers<SourceVariant>(mat4());
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0,
255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT / 2),
0, 0, 255, 255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
DEFAULT_DISPLAY_HEIGHT),
0, 255, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckersRotate90() {
mat4 matrix = mat4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1);
fillBufferCheckers<SourceVariant>(matrix);
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 255, 0,
255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT / 2),
255, 0, 0, 255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 255, 255);
expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckersRotate180() {
mat4 matrix = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 2, 2, 0, 1);
fillBufferCheckers<SourceVariant>(matrix);
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0,
0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT / 2),
0, 255, 0, 255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
255, 0, 0, 255);
expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
DEFAULT_DISPLAY_HEIGHT),
0, 0, 255, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferCheckersRotate270() {
mat4 matrix = mat4(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1);
fillBufferCheckers<SourceVariant>(matrix);
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 255,
255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT / 2),
0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 255, 0, 255);
expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
DEFAULT_DISPLAY_HEIGHT),
255, 0, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferWithLayerTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 2x2
settings.clip = Rect(2, 2);
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
// Translate one pixel diagonally
layer.geometry.positionTransform = mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1);
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
layer.alpha = 1.0f;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferLayerTransform() {
fillBufferWithLayerTransform<SourceVariant>();
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0, 0);
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
255, 0, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferWithColorTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
layer.alpha = 1.0f;
// construct a fake color matrix
// annihilate green and blue channels
settings.colorTransform = mat4::scale(vec4(1, 0, 0, 1));
// set red channel to red + green
layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferColorTransform() {
fillBufferWithColorTransform<SourceVariant>();
expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
}
template <typename SourceVariant>
void RenderEngineTest::fillRedBufferWithRoundedCorners() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
layer.geometry.roundedCornersRadius = 5.0f;
layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferWithRoundedCorners() {
fillRedBufferWithRoundedCorners<SourceVariant>();
// Corners should be ignored...
expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, 0, DEFAULT_DISPLAY_WIDTH, 1), 0, 0, 0, 0);
expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT - 1, 1, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
// ...And the non-rounded portion should be red.
// Other pixels may be anti-aliased, so let's not check those.
expectBufferColor(Rect(5, 5, DEFAULT_DISPLAY_WIDTH - 5, DEFAULT_DISPLAY_HEIGHT - 5), 255, 0, 0,
255);
}
template <typename SourceVariant>
void RenderEngineTest::overlayCorners() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layersFirst;
renderengine::LayerSettings layerOne;
layerOne.geometry.boundaries =
FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 0.2;
layersFirst.push_back(layerOne);
invokeDraw(settings, layersFirst, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
std::vector<renderengine::LayerSettings> layersSecond;
renderengine::LayerSettings layerTwo;
layerTwo.geometry.boundaries =
FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
layersSecond.push_back(layerTwo);
invokeDraw(settings, layersSecond, mBuffer);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 255, 0, 255);
}
void RenderEngineTest::fillRedBufferTextureTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
// Here will allocate a checker board texture, but transform texture
// coordinates so that only the upper left is applied.
sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2);
uint32_t texName;
RenderEngineTest::sRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&pixels));
// Red top left, Green top right, Blue bottom left, Black bottom right
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
pixels[4] = 0;
pixels[5] = 255;
pixels[6] = 0;
pixels[7] = 255;
pixels[8] = 0;
pixels[9] = 0;
pixels[10] = 255;
pixels[11] = 255;
buf->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
// Transform coordinates to only be inside the red quadrant.
layer.source.buffer.textureTransform = mat4::scale(vec4(0.2, 0.2, 1, 1));
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
void RenderEngineTest::fillBufferTextureTransform() {
fillRedBufferTextureTransform();
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 1x1
settings.clip = Rect(1, 1);
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint32_t texName;
RenderEngineTest::sRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&pixels));
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
buf->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
layer.source.buffer.usePremultipliedAlpha = true;
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
void RenderEngineTest::fillBufferWithPremultiplyAlpha() {
fillRedBufferWithPremultiplyAlpha();
expectBufferColor(fullscreenRect(), 128, 0, 0, 128);
}
void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 1x1
settings.clip = Rect(1, 1);
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint32_t texName;
RenderEngineTest::sRE->genTextures(1, &texName);
this->mTexNames.push_back(texName);
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&pixels));
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
buf->unlock();
layer.source.buffer.buffer = buf;
layer.source.buffer.textureName = texName;
layer.source.buffer.usePremultipliedAlpha = false;
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
fillRedBufferWithoutPremultiplyAlpha();
expectBufferColor(fullscreenRect(), 128, 0, 0, 64, 1);
}
void RenderEngineTest::clearLeftRegion() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 4x4
settings.clip = Rect(4, 4);
settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
settings.clearRegion = Region(Rect(1, 1));
std::vector<renderengine::LayerSettings> layers;
// dummy layer, without bounds should not render anything
renderengine::LayerSettings layer;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
}
void RenderEngineTest::clearRegion() {
// Reuse mBuffer
clearLeftRegion();
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
}
TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
drawEmptyLayers();
}
TEST_F(RenderEngineTest, drawLayers_nullOutputBuffer) {
renderengine::DisplaySettings settings;
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(layer);
base::unique_fd fence;
status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
ASSERT_EQ(BAD_VALUE, status);
}
TEST_F(RenderEngineTest, drawLayers_nullOutputFence) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
layers.push_back(layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
base::unique_fd(), nullptr);
sCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
layers.push_back(layer);
status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
base::unique_fd(), nullptr);
sCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
fillRedBuffer<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
fillGreenBuffer<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
fillBlueBuffer<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
fillRedTransparentBuffer<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
fillBufferPhysicalOffset<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
fillBufferCheckersRotate0<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
fillBufferCheckersRotate90<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
fillBufferCheckersRotate180<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
fillBufferCheckersRotate270<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
fillBufferLayerTransform<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
fillBufferLayerTransform<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
overlayCorners<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
fillBufferTextureTransform();
}
TEST_F(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
fillBufferWithPremultiplyAlpha();
}
TEST_F(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
fillBufferWithoutPremultiplyAlpha();
}
TEST_F(RenderEngineTest, drawLayers_clearRegion) {
clearRegion();
}
TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
sRE->unbindExternalTextureBuffer(bufferId);
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
status_t result = sRE->bindExternalTextureBuffer(0, nullptr, nullptr);
ASSERT_EQ(BAD_VALUE, result);
}
TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) {
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint32_t texName;
sRE->genTextures(1, &texName);
mTexNames.push_back(texName);
sRE->bindExternalTextureBuffer(texName, buf, nullptr);
uint64_t bufferId = buf->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
sRE->unbindExternalTextureBuffer(bufferId);
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
status_t result = sRE->cacheExternalTextureBuffer(nullptr);
ASSERT_EQ(BAD_VALUE, result);
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint64_t bufferId = buf->getId();
sRE->cacheExternalTextureBuffer(buf);
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
sRE->unbindExternalTextureBuffer(bufferId);
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
} // namespace android