/* * 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. */ #undef LOG_TAG #define LOG_TAG "RenderEngineTest" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" #include #include #include #include #include #include #include #include #include #include "../gl/GLESRenderEngine.h" #include "../skia/SkiaGLRenderEngine.h" #include "../threaded/RenderEngineThreaded.h" constexpr int DEFAULT_DISPLAY_WIDTH = 128; constexpr int DEFAULT_DISPLAY_HEIGHT = 256; constexpr int DEFAULT_DISPLAY_OFFSET = 64; constexpr bool WRITE_BUFFER_TO_FILE_ON_FAILURE = false; namespace android { namespace renderengine { class RenderEngineFactory { public: virtual ~RenderEngineFactory() = default; virtual std::string name() = 0; virtual renderengine::RenderEngine::RenderEngineType type() = 0; virtual std::unique_ptr createRenderEngine() = 0; virtual std::unique_ptr createGLESRenderEngine() { return nullptr; } virtual bool useColorManagement() const = 0; }; class GLESRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "GLESRenderEngineFactory"; } renderengine::RenderEngine::RenderEngineType type() { return renderengine::RenderEngine::RenderEngineType::GLES; } std::unique_ptr createRenderEngine() override { return createGLESRenderEngine(); } std::unique_ptr createGLESRenderEngine() { renderengine::RenderEngineCreationArgs reCreationArgs = renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) .setImageCacheSize(1) .setUseColorManagerment(false) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) .setUseColorManagerment(useColorManagement()) .build(); return renderengine::gl::GLESRenderEngine::create(reCreationArgs); } bool useColorManagement() const override { return false; } }; class GLESCMRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "GLESCMRenderEngineFactory"; } renderengine::RenderEngine::RenderEngineType type() { return renderengine::RenderEngine::RenderEngineType::GLES; } std::unique_ptr createRenderEngine() override { return createGLESRenderEngine(); } std::unique_ptr createGLESRenderEngine() override { renderengine::RenderEngineCreationArgs reCreationArgs = renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) .setImageCacheSize(1) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) .setUseColorManagerment(useColorManagement()) .build(); return renderengine::gl::GLESRenderEngine::create(reCreationArgs); } bool useColorManagement() const override { return true; } }; class SkiaGLESRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "SkiaGLRenderEngineFactory"; } renderengine::RenderEngine::RenderEngineType type() { return renderengine::RenderEngine::RenderEngineType::SKIA_GL; } std::unique_ptr createRenderEngine() override { renderengine::RenderEngineCreationArgs reCreationArgs = renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) .setImageCacheSize(1) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) .setUseColorManagerment(useColorManagement()) .build(); return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs); } bool useColorManagement() const override { return false; } }; class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "SkiaGLCMRenderEngineFactory"; } renderengine::RenderEngine::RenderEngineType type() { return renderengine::RenderEngine::RenderEngineType::SKIA_GL; } std::unique_ptr createRenderEngine() override { renderengine::RenderEngineCreationArgs reCreationArgs = renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) .setImageCacheSize(1) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) .setUseColorManagerment(useColorManagement()) .build(); return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs); } bool useColorManagement() const override { return true; } }; class RenderEngineTest : public ::testing::TestWithParam> { public: std::shared_ptr allocateDefaultBuffer() { return std::make_shared< renderengine:: ExternalTexture>(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 | GRALLOC_USAGE_HW_TEXTURE, "output"), *mRE, renderengine::ExternalTexture::Usage::READABLE | renderengine::ExternalTexture::Usage::WRITEABLE); } // Allocates a 1x1 buffer to fill with a solid color std::shared_ptr allocateSourceBuffer(uint32_t width, uint32_t height) { return std::make_shared< renderengine:: ExternalTexture>(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"), *mRE, renderengine::ExternalTexture::Usage::READABLE | renderengine::ExternalTexture::Usage::WRITEABLE); } RenderEngineTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); } ~RenderEngineTest() { if (WRITE_BUFFER_TO_FILE_ON_FAILURE && ::testing::Test::HasFailure()) { writeBufferToFile("/data/texture_out_"); } for (uint32_t texName : mTexNames) { mRE->deleteTextures(1, &texName); if (mGLESRE != nullptr) { EXPECT_FALSE(mGLESRE->isTextureNameKnownForTesting(texName)); } } const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } void writeBufferToFile(const char* basename) { std::string filename(basename); filename.append(::testing::UnitTest::GetInstance()->current_test_info()->name()); filename.append(".ppm"); std::ofstream file(filename.c_str(), std::ios::binary); if (!file.is_open()) { ALOGE("Unable to open file: %s", filename.c_str()); ALOGE("You may need to do: \"adb shell setenforce 0\" to enable " "surfaceflinger to write debug images"); return; } uint8_t* pixels; mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); file << "P6\n"; file << mBuffer->getBuffer()->getWidth() << "\n"; file << mBuffer->getBuffer()->getHeight() << "\n"; file << 255 << "\n"; std::vector outBuffer(mBuffer->getBuffer()->getWidth() * mBuffer->getBuffer()->getHeight() * 3); auto outPtr = reinterpret_cast(outBuffer.data()); for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) { const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4; for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) { // Only copy R, G and B components outPtr[0] = src[0]; outPtr[1] = src[1]; outPtr[2] = src[2]; outPtr += 3; src += 4; } } file.write(reinterpret_cast(outBuffer.data()), outBuffer.size()); mBuffer->getBuffer()->unlock(); } void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { size_t c; Rect const* rect = region.getArray(&c); for (size_t i = 0; i < c; i++, rect++) { expectBufferColor(*rect, r, g, b, a); } } void expectBufferColor(const Point& point, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t tolerance = 0) { expectBufferColor(Rect(point.x, point.y, point.x + 1, point.y + 1), r, g, b, a, tolerance); } void expectBufferColor(const Rect& rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t tolerance = 0) { auto colorCompare = [tolerance](const uint8_t* colorA, const uint8_t* colorB) { auto colorBitCompare = [tolerance](uint8_t a, uint8_t b) { uint8_t tmp = a >= b ? a - b : b - a; return tmp <= tolerance; }; return std::equal(colorA, colorA + 4, colorB, colorBitCompare); }; expectBufferColor(rect, r, g, b, a, colorCompare); } void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, std::function colorCompare) { uint8_t* pixels; mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); int32_t maxFails = 10; int32_t fails = 0; for (int32_t j = 0; j < region.getHeight(); j++) { const uint8_t* src = pixels + (mBuffer->getBuffer()->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 = colorCompare(src, expected); EXPECT_TRUE(equal) << GetParam()->name().c_str() << ": " << "pixel @ (" << region.left + i << ", " << region.top + j << "): " << "expected (" << static_cast(r) << ", " << static_cast(g) << ", " << static_cast(b) << ", " << static_cast(a) << "), " << "got (" << static_cast(src[0]) << ", " << static_cast(src[1]) << ", " << static_cast(src[2]) << ", " << static_cast(src[3]) << ")"; src += 4; if (!equal && ++fails >= maxFails) { break; } } if (fails >= maxFails) { break; } } mBuffer->getBuffer()->unlock(); } void expectAlpha(const Rect& rect, uint8_t a) { auto colorCompare = [](const uint8_t* colorA, const uint8_t* colorB) { return colorA[3] == colorB[3]; }; expectBufferColor(rect, 0.0f /* r */, 0.0f /*g */, 0.0f /* b */, a, colorCompare); } void expectShadowColor(const renderengine::LayerSettings& castingLayer, const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, const ubyte4& backgroundColor) { const Rect casterRect(castingLayer.geometry.boundaries); Region casterRegion = Region(casterRect); const float casterCornerRadius = castingLayer.geometry.roundedCornersRadius; if (casterCornerRadius > 0.0f) { // ignore the corners if a corner radius is set Rect cornerRect(casterCornerRadius, casterCornerRadius); casterRegion.subtractSelf(cornerRect.offsetTo(casterRect.left, casterRect.top)); casterRegion.subtractSelf( cornerRect.offsetTo(casterRect.right - casterCornerRadius, casterRect.top)); casterRegion.subtractSelf( cornerRect.offsetTo(casterRect.left, casterRect.bottom - casterCornerRadius)); casterRegion.subtractSelf(cornerRect.offsetTo(casterRect.right - casterCornerRadius, casterRect.bottom - casterCornerRadius)); } const float shadowInset = shadow.length * -1.0f; const Rect casterWithShadow = Rect(casterRect).inset(shadowInset, shadowInset, shadowInset, shadowInset); const Region shadowRegion = Region(casterWithShadow).subtractSelf(casterRect); const Region backgroundRegion = Region(fullscreenRect()).subtractSelf(casterWithShadow); // verify casting layer expectBufferColor(casterRegion, casterColor.r, casterColor.g, casterColor.b, casterColor.a); // verify shadows by testing just the alpha since its difficult to validate the shadow color size_t c; Rect const* r = shadowRegion.getArray(&c); for (size_t i = 0; i < c; i++, r++) { expectAlpha(*r, 255); } // verify background expectBufferColor(backgroundRegion, backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a); } void expectShadowColorWithoutCaster(const FloatRect& casterBounds, const renderengine::ShadowSettings& shadow, const ubyte4& backgroundColor) { const float shadowInset = shadow.length * -1.0f; const Rect casterRect(casterBounds); const Rect shadowRect = Rect(casterRect).inset(shadowInset, shadowInset, shadowInset, shadowInset); const Region backgroundRegion = Region(fullscreenRect()).subtractSelf(casterRect).subtractSelf(shadowRect); expectAlpha(shadowRect, 255); // (0, 0, 0) fill on the bounds of the layer should be ignored. expectBufferColor(casterRect, 255, 255, 255, 255, 254); // verify background expectBufferColor(backgroundRegion, backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a); } static renderengine::ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength, bool casterIsTranslucent) { renderengine::ShadowSettings shadow; shadow.ambientColor = {0.0f, 0.0f, 0.0f, 0.039f}; shadow.spotColor = {0.0f, 0.0f, 0.0f, 0.19f}; shadow.lightPos = vec3(casterPos.x, casterPos.y, 0); shadow.lightRadius = 0.0f; shadow.length = shadowLength; shadow.casterIsTranslucent = casterIsTranslucent; return shadow; } 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 layers) { base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence); int fd = fence.release(); if (fd >= 0) { sync_wait(fd, -1); close(fd); } ASSERT_EQ(NO_ERROR, status); if (layers.size() > 0 && mGLESRE != nullptr) { ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); } } void drawEmptyLayers() { renderengine::DisplaySettings settings; std::vector layers; invokeDraw(settings, layers); } template void fillBuffer(half r, half g, half b, half a); template void fillRedBuffer(); template void fillGreenBuffer(); template void fillBlueBuffer(); template void fillRedTransparentBuffer(); template void fillRedOffsetBuffer(); template void fillBufferPhysicalOffset(); template void fillBufferCheckers(uint32_t rotation); template void fillBufferCheckersRotate0(); template void fillBufferCheckersRotate90(); template void fillBufferCheckersRotate180(); template void fillBufferCheckersRotate270(); template void fillBufferWithLayerTransform(); template void fillBufferLayerTransform(); template void fillBufferWithColorTransform(); template void fillBufferColorTransform(); template void fillBufferWithColorTransformZeroLayerAlpha(); template void fillBufferColorTransformZeroLayerAlpha(); template void fillRedBufferWithRoundedCorners(); template void fillBufferWithRoundedCorners(); template void fillBufferAndBlurBackground(); template void fillSmallLayerAndBlurBackground(); template void overlayCorners(); void fillRedBufferTextureTransform(); void fillBufferTextureTransform(); void fillRedBufferWithPremultiplyAlpha(); void fillBufferWithPremultiplyAlpha(); void fillRedBufferWithoutPremultiplyAlpha(); void fillBufferWithoutPremultiplyAlpha(); void fillGreenColorBufferThenClearRegion(); void clearLeftRegion(); void clearRegion(); template void drawShadow(const renderengine::LayerSettings& castingLayer, const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, const ubyte4& backgroundColor); void drawShadowWithoutCaster(const FloatRect& castingBounds, const renderengine::ShadowSettings& shadow, const ubyte4& backgroundColor); void initializeRenderEngine(); std::unique_ptr mRE; std::shared_ptr mBuffer; // GLESRenderEngine for testing GLES-specific behavior. // Owened by mRE, but this is downcasted. renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; std::vector mTexNames; }; void RenderEngineTest::initializeRenderEngine() { const auto& renderEngineFactory = GetParam(); if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) { // Only GLESRenderEngine exposes test-only methods. Provide a pointer to the // GLESRenderEngine if we're using it so that we don't need to dynamic_cast // every time. std::unique_ptr renderEngine = renderEngineFactory->createGLESRenderEngine(); mGLESRE = renderEngine.get(); mRE = std::move(renderEngine); } else { mRE = renderEngineFactory->createRenderEngine(); } mBuffer = allocateDefaultBuffer(); } struct ColorSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* /*fixture*/) { layer.source.solidColor = half3(r, g, b); layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; } }; struct RelaxOpaqueBufferVariant { static void setOpaqueBit(renderengine::LayerSettings& layer) { layer.source.buffer.isOpaque = false; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; } static uint8_t getAlphaChannel() { return 255; } }; struct ForceOpaqueBufferVariant { static void setOpaqueBit(renderengine::LayerSettings& layer) { layer.source.buffer.isOpaque = true; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; } static uint8_t getAlphaChannel() { // The isOpaque bit will override the alpha channel, so this should be // arbitrary. return 50; } }; template struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { const auto buf = fixture->allocateSourceBuffer(1, 1); uint32_t texName; fixture->mRE->genTextures(1, &texName); fixture->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4; for (int32_t i = 0; i < buf->getBuffer()->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->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; OpaquenessVariant::setOpaqueBit(layer); } }; template void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(layer, r, g, b, this); layer.alpha = a; layers.push_back(&layer); invokeDraw(settings, layers); } template void RenderEngineTest::fillRedBuffer() { fillBuffer(1.0f, 0.0f, 0.0f, 1.0f); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } template void RenderEngineTest::fillGreenBuffer() { fillBuffer(0.0f, 1.0f, 0.0f, 1.0f); expectBufferColor(fullscreenRect(), 0, 255, 0, 255); } template void RenderEngineTest::fillBlueBuffer() { fillBuffer(0.0f, 0.0f, 1.0f, 1.0f); expectBufferColor(fullscreenRect(), 0, 0, 255, 255); } template void RenderEngineTest::fillRedTransparentBuffer() { fillBuffer(1.0f, 0.0f, 0.0f, .2f); expectBufferColor(fullscreenRect(), 51, 0, 0, 51); } template void RenderEngineTest::fillRedOffsetBuffer() { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = offsetRect(); settings.clip = offsetRectAtZero(); std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); } template void RenderEngineTest::fillBufferPhysicalOffset() { fillRedOffsetBuffer(); 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 void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); // Here logical space is 2x2 settings.clip = Rect(2, 2); settings.orientation = orientationFlag; std::vector layers; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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; layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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; layerThree.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); } template void RenderEngineTest::fillBufferCheckersRotate0() { fillBufferCheckers(ui::Transform::ROT_0); 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 void RenderEngineTest::fillBufferCheckersRotate90() { fillBufferCheckers(ui::Transform::ROT_90); 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 void RenderEngineTest::fillBufferCheckersRotate180() { fillBufferCheckers(ui::Transform::ROT_180); 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 void RenderEngineTest::fillBufferCheckersRotate270() { fillBufferCheckers(ui::Transform::ROT_270); 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 void RenderEngineTest::fillBufferWithLayerTransform() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); // Here logical space is 2x2 settings.clip = Rect(2, 2); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); } template void RenderEngineTest::fillBufferLayerTransform() { fillBufferWithLayerTransform(); 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 void RenderEngineTest::fillBufferWithColorTransform() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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(0.9f, 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); } template void RenderEngineTest::fillBufferColorTransform() { fillBufferWithColorTransform(); expectBufferColor(fullscreenRect(), 172, 0, 0, 255, 1); } template void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = Rect(1, 1); std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this); layer.alpha = 0; // construct a fake color matrix // simple inverse color settings.colorTransform = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 1, 1, 1, 1); layer.geometry.boundaries = Rect(1, 1).toFloatRect(); layers.push_back(&layer); invokeDraw(settings, layers); } template void RenderEngineTest::fillBufferColorTransformZeroLayerAlpha() { fillBufferWithColorTransformZeroLayerAlpha(); expectBufferColor(fullscreenRect(), 0, 0, 0, 0); } template void RenderEngineTest::fillRedBufferWithRoundedCorners() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); } template void RenderEngineTest::fillBufferWithRoundedCorners() { fillRedBufferWithRoundedCorners(); // 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 void RenderEngineTest::fillBufferAndBlurBackground() { auto blurRadius = 50; auto center = DEFAULT_DISPLAY_WIDTH / 2; renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; layers.push_back(&backgroundLayer); renderengine::LayerSettings leftLayer; leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; leftLayer.geometry.boundaries = Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect(); SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this); leftLayer.alpha = 1.0f; layers.push_back(&leftLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; blurLayer.geometry.boundaries = fullscreenRect().toFloatRect(); blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; layers.push_back(&blurLayer); invokeDraw(settings, layers); // solid color expectBufferColor(Rect(0, 0, 1, 1), 255, 0, 0, 255, 0 /* tolerance */); if (mRE->supportsBackgroundBlur()) { // blurred color (downsampling should result in the center color being close to 128) expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255, 50 /* tolerance */); } } template void RenderEngineTest::fillSmallLayerAndBlurBackground() { auto blurRadius = 50; renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; layers.push_back(&backgroundLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; blurLayer.geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f); blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; layers.push_back(&blurLayer); invokeDraw(settings, layers); // Give a generous tolerance - the blur rectangle is very small and this test is // mainly concerned with ensuring that there's no device failure. expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 255, 0, 0, 255, 40 /* tolerance */); } template void RenderEngineTest::overlayCorners() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layersFirst; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); 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 layersSecond; renderengine::LayerSettings layerTwo; layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; 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); 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); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. const auto buf = allocateSourceBuffer(2, 2); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&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->getBuffer()->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); } 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 layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; buf->getBuffer()->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); } 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 layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; buf->getBuffer()->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); } void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() { fillRedBufferWithoutPremultiplyAlpha(); expectBufferColor(fullscreenRect(), 128, 0, 0, 128, 1); } void RenderEngineTest::clearLeftRegion() { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); // Here logical space is 4x4 settings.clip = Rect(4, 4); settings.clearRegion = Region(Rect(2, 4)); std::vector layers; // fake layer, without bounds should not render anything renderengine::LayerSettings layer; layers.push_back(&layer); invokeDraw(settings, layers); } 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); } template void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLayer, const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, const ubyte4& backgroundColor) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; // add background layer renderengine::LayerSettings bgLayer; bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; bgLayer.geometry.boundaries = fullscreenRect().toFloatRect(); ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; layers.push_back(&bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; shadowLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries; shadowLayer.alpha = castingLayer.alpha; shadowLayer.shadow = shadow; layers.push_back(&shadowLayer); // add layer casting the shadow renderengine::LayerSettings layer = castingLayer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f, casterColor.b / 255.0f, this); layers.push_back(&layer); invokeDraw(settings, layers); } void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, const renderengine::ShadowSettings& shadow, const ubyte4& backgroundColor) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; // add background layer renderengine::LayerSettings bgLayer; bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; bgLayer.geometry.boundaries = fullscreenRect().toFloatRect(); ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; layers.push_back(&bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; shadowLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; shadowLayer.geometry.boundaries = castingBounds; shadowLayer.skipContentDraw = true; shadowLayer.alpha = 1.0f; ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this); shadowLayer.shadow = shadow; layers.push_back(&shadowLayer); invokeDraw(settings, layers); } INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest, testing::Values(std::make_shared(), std::make_shared(), std::make_shared(), std::make_shared())); TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { initializeRenderEngine(); drawEmptyLayers(); } TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); // 255, 255, 255, 255 is full opaque white. const ubyte4 backgroundColor(255.f, 255.f, 255.f, 255.f); // Create layer with given color. renderengine::LayerSettings bgLayer; bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; bgLayer.geometry.boundaries = fullscreenRect().toFloatRect(); bgLayer.source.solidColor = half3(backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f); bgLayer.alpha = backgroundColor.a / 255.0f; // Transform the red color. bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); std::vector layers; layers.push_back(&bgLayer); invokeDraw(settings, layers); // Expect to see full opaque pixel (with inverted red from the transform). expectBufferColor(Rect(0, 0, 10, 10), 0.f, backgroundColor.g, backgroundColor.b, backgroundColor.a); } TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layers.push_back(&layer); base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence); ASSERT_EQ(BAD_VALUE, status); } TEST_P(RenderEngineTest, drawLayers_nullOutputFence) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr); ASSERT_EQ(NO_ERROR, status); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { const auto& renderEngineFactory = GetParam(); if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { // GLES-specific test return; } initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr); ASSERT_EQ(NO_ERROR, status); ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) { initializeRenderEngine(); fillRedBuffer(); } TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) { initializeRenderEngine(); fillGreenBuffer(); } TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) { initializeRenderEngine(); fillBlueBuffer(); } TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) { initializeRenderEngine(); fillRedTransparentBuffer(); } TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) { initializeRenderEngine(); fillBufferPhysicalOffset(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) { initializeRenderEngine(); fillBufferCheckersRotate0(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) { initializeRenderEngine(); fillBufferCheckersRotate90(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) { initializeRenderEngine(); fillBufferCheckersRotate180(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) { initializeRenderEngine(); fillBufferCheckersRotate270(); } TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) { initializeRenderEngine(); fillBufferLayerTransform(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) { initializeRenderEngine(); fillBufferColorTransform(); } TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) { initializeRenderEngine(); fillBufferWithRoundedCorners(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) { initializeRenderEngine(); fillBufferColorTransformZeroLayerAlpha(); } TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) { initializeRenderEngine(); fillBufferAndBlurBackground(); } TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource) { initializeRenderEngine(); fillSmallLayerAndBlurBackground(); } TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) { initializeRenderEngine(); overlayCorners(); } TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) { initializeRenderEngine(); fillRedBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) { initializeRenderEngine(); fillGreenBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) { initializeRenderEngine(); fillBlueBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) { initializeRenderEngine(); fillRedTransparentBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) { initializeRenderEngine(); fillBufferPhysicalOffset>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) { initializeRenderEngine(); fillBufferCheckersRotate0>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) { initializeRenderEngine(); fillBufferCheckersRotate90>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) { initializeRenderEngine(); fillBufferCheckersRotate180>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) { initializeRenderEngine(); fillBufferCheckersRotate270>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) { initializeRenderEngine(); fillBufferLayerTransform>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) { initializeRenderEngine(); fillBufferColorTransform>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) { initializeRenderEngine(); fillBufferWithRoundedCorners>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) { initializeRenderEngine(); fillBufferColorTransformZeroLayerAlpha>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) { initializeRenderEngine(); fillBufferAndBlurBackground>(); } TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBufferSource) { initializeRenderEngine(); fillSmallLayerAndBlurBackground>(); } TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) { initializeRenderEngine(); overlayCorners>(); } TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) { initializeRenderEngine(); fillRedBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) { initializeRenderEngine(); fillGreenBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) { initializeRenderEngine(); fillBlueBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) { initializeRenderEngine(); fillRedTransparentBuffer>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) { initializeRenderEngine(); fillBufferPhysicalOffset>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) { initializeRenderEngine(); fillBufferCheckersRotate0>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) { initializeRenderEngine(); fillBufferCheckersRotate90>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) { initializeRenderEngine(); fillBufferCheckersRotate180>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) { initializeRenderEngine(); fillBufferCheckersRotate270>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) { initializeRenderEngine(); fillBufferLayerTransform>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) { initializeRenderEngine(); fillBufferColorTransform>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) { initializeRenderEngine(); fillBufferWithRoundedCorners>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) { initializeRenderEngine(); fillBufferColorTransformZeroLayerAlpha>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) { initializeRenderEngine(); fillBufferAndBlurBackground>(); } TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource) { initializeRenderEngine(); fillSmallLayerAndBlurBackground>(); } TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) { initializeRenderEngine(); overlayCorners>(); } TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) { initializeRenderEngine(); fillBufferTextureTransform(); } TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) { initializeRenderEngine(); fillBufferWithPremultiplyAlpha(); } TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) { initializeRenderEngine(); fillBufferWithoutPremultiplyAlpha(); } TEST_P(RenderEngineTest, drawLayers_clearRegion) { initializeRenderEngine(); clearRegion(); } TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, false /* casterIsTranslucent */); drawShadowWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor); expectShadowColorWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor); } TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) { initializeRenderEngine(); const ubyte4 casterColor(255, 0, 0, 255); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(1, 1); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, false /* casterIsTranslucent */); drawShadow(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); } TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) { initializeRenderEngine(); const ubyte4 casterColor(255, 0, 0, 255); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, false /* casterIsTranslucent */); drawShadow(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); } TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) { initializeRenderEngine(); const ubyte4 casterColor(255, 0, 0, 255); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, false /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); } TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { initializeRenderEngine(); const ubyte4 casterColor(255, 0, 0, 255); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.geometry.roundedCornersRadius = 3.0f; castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, false /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); } TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) { initializeRenderEngine(); const ubyte4 casterColor(255, 0, 0, 255); const ubyte4 backgroundColor(255, 255, 255, 255); const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 0.5f; renderengine::ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, true /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); // verify only the background since the shadow will draw behind the caster const float shadowInset = settings.length * -1.0f; const Rect casterWithShadow = Rect(casterBounds).inset(shadowInset, shadowInset, shadowInset, shadowInset); const Region backgroundRegion = Region(fullscreenRect()).subtractSelf(casterWithShadow); expectBufferColor(backgroundRegion, backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a); } TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; layers.push_back(&layer); base::unique_fd fenceOne; mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne); base::unique_fd fenceTwo; mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo); const int fd = fenceTwo.get(); if (fd >= 0) { sync_wait(fd, -1); } // Only cleanup the first time. EXPECT_FALSE(mRE->canSkipPostRenderCleanup()); mRE->cleanupPostRender(); EXPECT_TRUE(mRE->canSkipPostRenderCleanup()); } TEST_P(RenderEngineTest, testRoundedCornersCrop) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); redLayer.geometry.roundedCornersRadius = 5.0f; redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; layers.push_back(&redLayer); // Green layer with 1/3 size. renderengine::LayerSettings greenLayer; greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; greenLayer.geometry.boundaries = fullscreenRect().toFloatRect(); greenLayer.geometry.roundedCornersRadius = 5.0f; // Bottom right corner is not going to be rounded. greenLayer.geometry.roundedCornersCrop = Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_HEIGHT) .toFloatRect(); greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); greenLayer.alpha = 1.0f; layers.push_back(&greenLayer); invokeDraw(settings, layers); // Corners should be ignored... // Screen size: width is 128, height is 256. 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); // Bottom right corner is kept out of the clipping, and it's green. expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 0, 255, 0, 255); } TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { initializeRenderEngine(); renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); redLayer.geometry.roundedCornersRadius = 5.0f; redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; layers.push_back(&redLayer); // Green layer with 1/2 size with parent crop rect. renderengine::LayerSettings greenLayer = redLayer; greenLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2); greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); layers.push_back(&greenLayer); invokeDraw(settings, layers); // Due to roundedCornersRadius, the corners are untouched. expectBufferColor(Point(0, 0), 0, 0, 0, 0); expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0); expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); // top middle should be green and the bottom middle red expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 0), 0, 255, 0, 255); expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255); // the bottom edge of the green layer should not be rounded expectBufferColor(Point(0, (DEFAULT_DISPLAY_HEIGHT / 2) - 1), 0, 255, 0, 255); } TEST_P(RenderEngineTest, testClear) { initializeRenderEngine(); const auto rect = fullscreenRect(); const renderengine::DisplaySettings display{ .physicalDisplay = rect, .clip = rect, }; const renderengine::LayerSettings redLayer{ .geometry.boundaries = rect.toFloatRect(), .source.solidColor = half3(1.0f, 0.0f, 0.0f), .alpha = 1.0f, }; // This mimics prepareClearClientComposition. This layer should overwrite // the redLayer, so that the buffer is transparent, rather than red. const renderengine::LayerSettings clearLayer{ .geometry.boundaries = rect.toFloatRect(), .source.solidColor = half3(0.0f, 0.0f, 0.0f), .alpha = 0.0f, .disableBlending = true, }; std::vector layers{&redLayer, &clearLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 0, 0, 0); } TEST_P(RenderEngineTest, testDisableBlendingBuffer) { initializeRenderEngine(); const auto rect = Rect(0, 0, 1, 1); const renderengine::DisplaySettings display{ .physicalDisplay = rect, .clip = rect, }; const renderengine::LayerSettings redLayer{ .geometry.boundaries = rect.toFloatRect(), .source.solidColor = half3(1.0f, 0.0f, 0.0f), .alpha = 1.0f, }; // The next layer will overwrite redLayer with a GraphicBuffer that is green // applied with a translucent alpha. const auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 255; buf->getBuffer()->unlock(); } const renderengine::LayerSettings greenLayer{ .geometry.boundaries = rect.toFloatRect(), .source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = buf, .usePremultipliedAlpha = true, }, }, .alpha = 0.5f, .disableBlending = true, }; std::vector layers{&redLayer, &greenLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 128, 0, 128); } TEST_P(RenderEngineTest, test_isOpaque) { initializeRenderEngine(); const auto rect = Rect(0, 0, 1, 1); const renderengine::DisplaySettings display{ .physicalDisplay = rect, .clip = rect, .outputDataspace = ui::Dataspace::DISPLAY_P3, }; // Create an unpremul buffer that is green with no alpha. Using isOpaque // should make the green show. const auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, reinterpret_cast(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 0; buf->getBuffer()->unlock(); } const renderengine::LayerSettings greenLayer{ .geometry.boundaries = rect.toFloatRect(), .source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = buf, // Although the pixels are not // premultiplied in practice, this // matches the input we see. .usePremultipliedAlpha = true, .isOpaque = true, }, }, .alpha = 1.0f, }; std::vector layers{&greenLayer}; invokeDraw(display, layers); if (GetParam()->useColorManagement()) { expectBufferColor(rect, 117, 251, 76, 255); } else { expectBufferColor(rect, 0, 255, 0, 255); } } } // namespace renderengine } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"