diff options
8 files changed, 514 insertions, 45 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 53b0e4cf20..51cf1886d3 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -648,27 +648,89 @@ bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) { return success; } -status_t GLESRenderEngine::drawLayers(const DisplaySettings& /*settings*/, - const std::vector<LayerSettings>& /*layers*/, - ANativeWindowBuffer* const /*buffer*/, - base::unique_fd* /*displayFence*/) const { +status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, + const std::vector<LayerSettings>& layers, + ANativeWindowBuffer* const buffer, + base::unique_fd* drawFence) { + if (layers.empty()) { + ALOGV("Drawing empty layer stack"); + return NO_ERROR; + } + + BindNativeBufferAsFramebuffer fbo(*this, buffer); + + if (fbo.getStatus() != NO_ERROR) { + ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", + buffer->handle); + checkErrors(); + return fbo.getStatus(); + } + + setViewportAndProjection(display.physicalDisplay, display.clip); + + setOutputDataSpace(display.outputDataspace); + setDisplayMaxLuminance(display.maxLuminance); + + mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform; + + Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2); + for (auto layer : layers) { + // for now, assume that all pixel sources are solid colors. + // TODO(alecmouri): support buffer sources + if (layer.source.buffer.buffer != nullptr) { + continue; + } + + setColorTransform(display.colorTransform * layer.colorTransform); + + mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; + + FloatRect bounds = layer.geometry.boundaries; + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + position[0] = vec2(bounds.left, bounds.top); + position[1] = vec2(bounds.left, bounds.bottom); + position[2] = vec2(bounds.right, bounds.bottom); + position[3] = vec2(bounds.right, bounds.top); + + half3 solidColor = layer.source.solidColor; + half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + setupLayerBlending(/*premultipliedAlpha=*/true, /*opaque=*/false, /*disableTexture=*/true, + color, /*cornerRadius=*/0.0); + setSourceDataSpace(layer.sourceDataspace); + + drawMesh(mesh); + } + + *drawFence = flush(); + // If flush failed or we don't support native fences, we need to force the + // gl command stream to be executed. + if (drawFence->get() < 0) { + bool success = finish(); + if (!success) { + ALOGE("Failed to flush RenderEngine commands"); + checkErrors(); + // Chances are, something illegal happened (either the caller passed + // us bad parameters, or we messed up our shader generation). + return INVALID_OPERATION; + } + } + + checkErrors(); return NO_ERROR; } void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, ui::Transform::orientation_flags rotation) { - int32_t l = sourceCrop.left; - int32_t r = sourceCrop.right; - int32_t b = sourceCrop.bottom; - int32_t t = sourceCrop.top; - std::swap(t, b); - mat4 m = mat4::ortho(l, r, b, t, 0, 1); + setViewportAndProjection(Rect(vpw, vph), sourceCrop); + + if (rotation == ui::Transform::ROT_0) { + return; + } // Apply custom rotation to the projection. float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; + mat4 m = mState.projectionMatrix; switch (rotation) { - case ui::Transform::ROT_0: - break; case ui::Transform::ROT_90: m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; break; @@ -681,11 +743,18 @@ void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sou default: break; } - - glViewport(0, 0, vpw, vph); mState.projectionMatrix = m; - mVpWidth = vpw; - mVpHeight = vph; +} + +void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { + mVpWidth = viewport.getWidth(); + mVpHeight = viewport.getHeight(); + + // We pass the the top left corner instead of the bottom left corner, + // because since we're rendering off-screen first. + glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight); + + mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1); } void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 07e5585c04..b6fff33061 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -72,9 +72,8 @@ public: bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; bool useProtectedContext(bool useProtectedContext) override; - status_t drawLayers(const DisplaySettings& settings, const std::vector<LayerSettings>& layers, - ANativeWindowBuffer* const buffer, - base::unique_fd* displayFence) const override; + status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers, + ANativeWindowBuffer* buffer, base::unique_fd* drawFence) override; // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } @@ -125,6 +124,9 @@ private: // with PQ or HLG transfer function. bool isHdrDataSpace(const ui::Dataspace dataSpace) const; bool needsXYZTransformMatrix() const; + // Defines the viewport, and sets the projection matrix to the projection + // defined by the clip. + void setViewportAndProjection(Rect viewport, Rect clip); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index aa4e3196c1..0c923535bb 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -41,7 +41,7 @@ struct DisplaySettings { mat4 globalTransform = mat4(); // Maximum luminance pulled from the display's HDR capabilities. - float maxLuminence = 1.0f; + float maxLuminance = 1.0f; // Output dataspace that will be populated if wide color gamut is used, or // DataSpace::UNKNOWN otherwise. diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 38dee40b3a..93abf5c458 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -85,7 +85,11 @@ struct LayerSettings { half alpha = half(0.0); // Color space describing how the source pixels should be interpreted. - ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN; + ui::Dataspace sourceDataspace; + + // Additional layer-specific color transform to be applied before the global + // transform. + mat4 colorTransform; }; } // namespace renderengine diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 5e88159207..20dd996ec2 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -161,12 +161,12 @@ public: // Renders layers for a particular display via GPU composition. This method // should be called for every display that needs to be rendered via the GPU. - // @param settings The display-wide settings that should be applied prior to + // @param display The display-wide settings that should be applied prior to // drawing any layers. // @param layers The layers to draw onto the display, in Z-order. // @param buffer The buffer which will be drawn to. This buffer will be // ready once displayFence fires. - // @param displayFence A pointer to a fence, which will fire when the buffer + // @param drawFence A pointer to a fence, which will fire when the buffer // has been drawn to and is ready to be examined. The fence will be // initialized by this method. The caller will be responsible for owning the // fence. @@ -174,10 +174,9 @@ public: // now, this always returns NO_ERROR. // TODO(alecmouri): Consider making this a multi-display API, so that the // caller deoes not need to handle multiple fences. - virtual status_t drawLayers(const DisplaySettings& settings, + virtual status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers, - ANativeWindowBuffer* const buffer, - base::unique_fd* displayFence) const = 0; + ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0; // TODO(alecmouri): Expose something like bindTexImage() so that devices // that don't support native sync fences can get rid of code duplicated diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index 051b8b6212..9b483ef51d 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -31,6 +31,7 @@ cc_test { "libgui", "liblog", "libnativewindow", + "libsync", "libui", "libutils", ], diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 345c7eacf5..a0542dd0cd 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -17,36 +17,430 @@ #include <gtest/gtest.h> #include <renderengine/RenderEngine.h> +#include <sync/sync.h> #include <ui/PixelFormat.h> +constexpr int DEFAULT_DISPLAY_WIDTH = 128; +constexpr int DEFAULT_DISPLAY_HEIGHT = 256; +constexpr int DEFAULT_DISPLAY_OFFSET = 64; + namespace android { -class RenderEngineTest : public ::testing::Test { -public: - RenderEngineTest() { - // Initialize with some sane defaults. - // TODO(alecmouri): This should probably be the same instance used by - // SurfaceFlinger eventually. - mRE = renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), - 0); +struct RenderEngineTest : public ::testing::Test { + 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, + "output"); + } + + RenderEngineTest() { mBuffer = allocateDefaultBuffer(); } + + 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); + } + + static 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(), &fence); + + int fd = fence.release(); + if (fd >= 0) { + sync_wait(fd, -1); + close(fd); + } + + ASSERT_EQ(NO_ERROR, status); } - status_t drawEmptyLayers() { + static void drawEmptyLayers() { renderengine::DisplaySettings settings; std::vector<renderengine::LayerSettings> layers; // Meaningless buffer since we don't do any drawing sp<GraphicBuffer> buffer = new GraphicBuffer(); - base::unique_fd fence; - return mRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence); + invokeDraw(settings, layers, buffer); } -private: - std::unique_ptr<renderengine::RenderEngine> mRE; + 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 fillBufferLayerTransform(); + + template <typename SourceVariant> + void fillBufferColorTransform(); + + // Dumb hack to get aroud the fact that tear-down for renderengine isn't + // well defined right now, so we can't create multiple instances + static std::unique_ptr<renderengine::RenderEngine> sRE; + + sp<GraphicBuffer> mBuffer; +}; + +std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE = + renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0); + +struct ColorSourceVariant { + static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b) { + layer.source.solidColor = half3(r, g, b); + } }; -TEST_F(RenderEngineTest, drawLayers_noLayersToDraw_works) { - status_t result = drawEmptyLayers(); - ASSERT_EQ(NO_ERROR, result); +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); + 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); + 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); + 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); + 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); + 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::fillBufferLayerTransform() { + 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); + layer.source.solidColor = half3(1.0f, 0.0f, 0.0f); + layer.alpha = 1.0f; + + layers.push_back(layer); + + invokeDraw(settings, layers, mBuffer); + + 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::fillBufferColorTransform() { + 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(); + layer.source.solidColor = half3(0.5f, 0.25f, 0.125f); + 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); + + layers.push_back(layer); + + invokeDraw(settings, layers, mBuffer); + + expectBufferColor(fullscreenRect(), 191, 0, 0, 255); +} + +TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) { + drawEmptyLayers(); +} + +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>(); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h index 1bee271865..81a7768cc6 100644 --- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h +++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h @@ -77,9 +77,9 @@ public: MOCK_CONST_METHOD0(isProtected, bool()); MOCK_CONST_METHOD0(supportsProtectedContent, bool()); MOCK_METHOD1(useProtectedContext, bool(bool)); - MOCK_CONST_METHOD4(drawLayers, - status_t(const DisplaySettings&, const std::vector<LayerSettings>&, - ANativeWindowBuffer* const, base::unique_fd*)); + MOCK_METHOD4(drawLayers, + status_t(const DisplaySettings&, const std::vector<LayerSettings>&, + ANativeWindowBuffer*, base::unique_fd*)); }; class Image : public renderengine::Image { |