Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15f7cf31 authored by Ana Krulec's avatar Ana Krulec
Browse files

RenderEngineThreaded takes a function as an argument to create

In order to simplify testing and implementation of threaded RE,
RenderEngineThreaded::create can takes a std::function argument to
call to create the RE instance. RenderEngineThreaded::threadMain
then call the function.
- RenderEngine::create() uses it to create the production instance.
- The test uses it to create the mock instance.

Test: Unit tests
Change-Id: Ic1af134979d4449c34d9ad86d07673367eb16896
parent 9bc9dc69
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@
namespace android {
namespace renderengine {

std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
    RenderEngineType renderEngineType = args.renderEngineType;

    // Keep the ability to override by PROPERTIES:
@@ -41,7 +41,9 @@ std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreat
    switch (renderEngineType) {
        case RenderEngineType::THREADED:
            ALOGD("Threaded RenderEngine with GLES Backend");
            return renderengine::threaded::RenderEngineThreaded::create(args);
            return renderengine::threaded::RenderEngineThreaded::create([&args]() {
                return android::renderengine::gl::GLESRenderEngine::create(args);
            });
        case RenderEngineType::GLES:
        default:
            ALOGD("RenderEngine with GLES Backend");
+1 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ public:
        THREADED = 2,
    };

    static std::unique_ptr<impl::RenderEngine> create(const RenderEngineCreationArgs& args);
    static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);

    virtual ~RenderEngine() = 0;

+29 −41
Original line number Diff line number Diff line
@@ -28,56 +28,44 @@ using testing::Mock;
using testing::Return;

struct RenderEngineThreadedTest : public ::testing::Test {
    RenderEngineThreadedTest() {
        sThreadedRE->setRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
    }

    ~RenderEngineThreadedTest() {}

    static void SetUpTestSuite() {
        sThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
                renderengine::RenderEngineCreationArgs::Builder()
                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::THREADED)
                        .build());
    void SetUp() override {
        mThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
                [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); });
    }

    static void TearDownTestSuite() { sThreadedRE = nullptr; }

    // To avoid creating RE on every instantiation of the test, it is kept as a static variable.
    static std::unique_ptr<renderengine::threaded::RenderEngineThreaded> sThreadedRE;
    std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE;
    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
};

std::unique_ptr<renderengine::threaded::RenderEngineThreaded>
        RenderEngineThreadedTest::sThreadedRE = nullptr;

TEST_F(RenderEngineThreadedTest, dump) {
    std::string testString = "XYZ";
    EXPECT_CALL(*mRenderEngine, dump(_));
    sThreadedRE->dump(testString);
    mThreadedRE->dump(testString);
}

TEST_F(RenderEngineThreadedTest, primeCache) {
    EXPECT_CALL(*mRenderEngine, primeCache());
    sThreadedRE->primeCache();
    mThreadedRE->primeCache();
}

TEST_F(RenderEngineThreadedTest, genTextures) {
    uint32_t texName;
    EXPECT_CALL(*mRenderEngine, genTextures(1, &texName));
    sThreadedRE->genTextures(1, &texName);
    mThreadedRE->genTextures(1, &texName);
}

TEST_F(RenderEngineThreadedTest, deleteTextures) {
    uint32_t texName;
    EXPECT_CALL(*mRenderEngine, deleteTextures(1, &texName));
    sThreadedRE->deleteTextures(1, &texName);
    mThreadedRE->deleteTextures(1, &texName);
}

TEST_F(RenderEngineThreadedTest, bindExternalBuffer_nullptrBuffer) {
    EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, Eq(nullptr), Eq(nullptr)))
            .WillOnce(Return(BAD_VALUE));
    status_t result = sThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
    status_t result = mThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
    ASSERT_EQ(BAD_VALUE, result);
}

@@ -85,119 +73,119 @@ TEST_F(RenderEngineThreadedTest, bindExternalBuffer_withBuffer) {
    sp<GraphicBuffer> buf = new GraphicBuffer();
    EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, buf, Eq(nullptr)))
            .WillOnce(Return(NO_ERROR));
    status_t result = sThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
    status_t result = mThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
    ASSERT_EQ(NO_ERROR, result);
}

TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_nullptr) {
    EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(Eq(nullptr)));
    sThreadedRE->cacheExternalTextureBuffer(nullptr);
    mThreadedRE->cacheExternalTextureBuffer(nullptr);
}

TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_withBuffer) {
    sp<GraphicBuffer> buf = new GraphicBuffer();
    EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(buf));
    sThreadedRE->cacheExternalTextureBuffer(buf);
    mThreadedRE->cacheExternalTextureBuffer(buf);
}

TEST_F(RenderEngineThreadedTest, unbindExternalTextureBuffer) {
    EXPECT_CALL(*mRenderEngine, unbindExternalTextureBuffer(0x0));
    sThreadedRE->unbindExternalTextureBuffer(0x0);
    mThreadedRE->unbindExternalTextureBuffer(0x0);
}

TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsBadValue) {
    std::unique_ptr<renderengine::Framebuffer> framebuffer;
    EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(BAD_VALUE));
    status_t result = sThreadedRE->bindFrameBuffer(framebuffer.get());
    status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
    ASSERT_EQ(BAD_VALUE, result);
}

TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsNoError) {
    std::unique_ptr<renderengine::Framebuffer> framebuffer;
    EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(NO_ERROR));
    status_t result = sThreadedRE->bindFrameBuffer(framebuffer.get());
    status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
    ASSERT_EQ(NO_ERROR, result);
}

TEST_F(RenderEngineThreadedTest, unbindFrameBuffer) {
    std::unique_ptr<renderengine::Framebuffer> framebuffer;
    EXPECT_CALL(*mRenderEngine, unbindFrameBuffer(framebuffer.get()));
    sThreadedRE->unbindFrameBuffer(framebuffer.get());
    mThreadedRE->unbindFrameBuffer(framebuffer.get());
}

TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns20) {
    size_t size = 20;
    EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
    size_t result = sThreadedRE->getMaxTextureSize();
    size_t result = mThreadedRE->getMaxTextureSize();
    ASSERT_EQ(size, result);
}

TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns0) {
    size_t size = 0;
    EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
    size_t result = sThreadedRE->getMaxTextureSize();
    size_t result = mThreadedRE->getMaxTextureSize();
    ASSERT_EQ(size, result);
}

TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns20) {
    size_t dims = 20;
    EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
    size_t result = sThreadedRE->getMaxViewportDims();
    size_t result = mThreadedRE->getMaxViewportDims();
    ASSERT_EQ(dims, result);
}

TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns0) {
    size_t dims = 0;
    EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
    size_t result = sThreadedRE->getMaxViewportDims();
    size_t result = mThreadedRE->getMaxViewportDims();
    ASSERT_EQ(dims, result);
}

TEST_F(RenderEngineThreadedTest, isProtected_returnsFalse) {
    EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
    status_t result = sThreadedRE->isProtected();
    status_t result = mThreadedRE->isProtected();
    ASSERT_EQ(false, result);
}

TEST_F(RenderEngineThreadedTest, isProtected_returnsTrue) {
    EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(true));
    size_t result = sThreadedRE->isProtected();
    size_t result = mThreadedRE->isProtected();
    ASSERT_EQ(true, result);
}

TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsFalse) {
    EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(false));
    status_t result = sThreadedRE->supportsProtectedContent();
    status_t result = mThreadedRE->supportsProtectedContent();
    ASSERT_EQ(false, result);
}

TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) {
    EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
    status_t result = sThreadedRE->supportsProtectedContent();
    status_t result = mThreadedRE->supportsProtectedContent();
    ASSERT_EQ(true, result);
}

TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
    EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
    status_t result = sThreadedRE->useProtectedContext(false);
    status_t result = mThreadedRE->useProtectedContext(false);
    ASSERT_EQ(false, result);
}

TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
    EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
    status_t result = sThreadedRE->useProtectedContext(false);
    status_t result = mThreadedRE->useProtectedContext(false);
    ASSERT_EQ(true, result);
}

TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsFalse) {
    EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(false));
    status_t result = sThreadedRE->cleanupPostRender();
    status_t result = mThreadedRE->cleanupPostRender();
    ASSERT_EQ(false, result);
}

TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsTrue) {
    EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(true));
    status_t result = sThreadedRE->cleanupPostRender();
    status_t result = mThreadedRE->cleanupPostRender();
    ASSERT_EQ(true, result);
}

@@ -214,7 +202,7 @@ TEST_F(RenderEngineThreadedTest, drawLayers) {
                         const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
                         base::unique_fd*) -> status_t { return NO_ERROR; });

    status_t result = sThreadedRE->drawLayers(settings, layers, buffer, false,
    status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
                                              std::move(bufferFence), &drawFence);
    ASSERT_EQ(NO_ERROR, result);
}
+37 −28
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <future>

#include <android-base/stringprintf.h>
#include <private/gui/SyncFeatures.h>
#include <utils/Trace.h>

#include "gl/GLESRenderEngine.h"
@@ -33,36 +34,15 @@ namespace android {
namespace renderengine {
namespace threaded {

std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(
        const RenderEngineCreationArgs& args) {
    return std::make_unique<RenderEngineThreaded>(args);
std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
    return std::make_unique<RenderEngineThreaded>(std::move(factory));
}

void RenderEngineThreaded::setRenderEngine(
        std::unique_ptr<renderengine::RenderEngine> renderEngine) {
    ATRACE_CALL();
    // In order to ensure this is a thread safe call, it also needs to be put on a stack.
    std::promise<void> resultPromise;
    std::future<void> resultFuture = resultPromise.get_future();
    {
        std::lock_guard lock(mThreadMutex);
        mFunctionCalls.push(
                [this, &resultPromise, &renderEngine](renderengine::RenderEngine& /*instance*/) {
                    ATRACE_NAME("REThreaded::setRenderEngine");
                    mRenderEngine = std::move(renderEngine);
                    resultPromise.set_value();
                });
    }
    mCondition.notify_one();
    resultFuture.wait();
}

RenderEngineThreaded::RenderEngineThreaded(const RenderEngineCreationArgs& args)
      : renderengine::impl::RenderEngine(args) {
RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory) {
    ATRACE_CALL();

    std::lock_guard lockThread(mThreadMutex);
    mThread = std::thread(&RenderEngineThreaded::threadMain, this, args);
    mThread = std::thread(&RenderEngineThreaded::threadMain, this, factory);
}

RenderEngineThreaded::~RenderEngineThreaded() {
@@ -78,8 +58,7 @@ RenderEngineThreaded::~RenderEngineThreaded() {
}

// NO_THREAD_SAFETY_ANALYSIS is because std::unique_lock presently lacks thread safety annotations.
void RenderEngineThreaded::threadMain(const RenderEngineCreationArgs& args)
        NO_THREAD_SAFETY_ANALYSIS {
void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_SAFETY_ANALYSIS {
    ATRACE_CALL();

    struct sched_param param = {0};
@@ -88,7 +67,7 @@ void RenderEngineThreaded::threadMain(const RenderEngineCreationArgs& args)
        ALOGE("Couldn't set SCHED_FIFO");
    }

    mRenderEngine = renderengine::gl::GLESRenderEngine::create(args);
    mRenderEngine = factory();

    std::unique_lock<std::mutex> lock(mThreadMutex);
    pthread_setname_np(pthread_self(), mThreadName);
@@ -137,6 +116,36 @@ void RenderEngineThreaded::dump(std::string& result) {
    result.assign(resultFuture.get());
}

bool RenderEngineThreaded::useNativeFenceSync() const {
    std::promise<bool> resultPromise;
    std::future<bool> resultFuture = resultPromise.get_future();
    {
        std::lock_guard lock(mThreadMutex);
        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
            ATRACE_NAME("REThreaded::useNativeFenceSync");
            bool returnValue = SyncFeatures::getInstance().useNativeFenceSync();
            resultPromise.set_value(returnValue);
        });
    }
    mCondition.notify_one();
    return resultFuture.get();
}

bool RenderEngineThreaded::useWaitSync() const {
    std::promise<bool> resultPromise;
    std::future<bool> resultFuture = resultPromise.get_future();
    {
        std::lock_guard lock(mThreadMutex);
        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
            ATRACE_NAME("REThreaded::useWaitSync");
            bool returnValue = SyncFeatures::getInstance().useWaitSync();
            resultPromise.set_value(returnValue);
        });
    }
    mCondition.notify_one();
    return resultFuture.get();
}

void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
    std::promise<void> resultPromise;
    std::future<void> resultFuture = resultPromise.get_future();
+8 −5
Original line number Diff line number Diff line
@@ -28,21 +28,25 @@ namespace android {
namespace renderengine {
namespace threaded {

using CreateInstanceFactory = std::function<std::unique_ptr<renderengine::RenderEngine>()>;

/**
 * This class extends a basic RenderEngine class. It contains a thread. Each time a function of
 * this class is called, we create a lambda function that is put on a queue. The main thread then
 * executes the functions in order.
 */
class RenderEngineThreaded : public impl::RenderEngine {
class RenderEngineThreaded : public RenderEngine {
public:
    static std::unique_ptr<RenderEngineThreaded> create(const RenderEngineCreationArgs& args);
    static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory);

    RenderEngineThreaded(const RenderEngineCreationArgs& args);
    RenderEngineThreaded(CreateInstanceFactory factory);
    ~RenderEngineThreaded() override;
    void primeCache() const override;

    void dump(std::string& result) override;

    bool useNativeFenceSync() const override;
    bool useWaitSync() const override;
    void genTextures(size_t count, uint32_t* names) override;
    void deleteTextures(size_t count, uint32_t const* names) override;
    void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -64,13 +68,12 @@ public:
                        const std::vector<const LayerSettings*>& layers,
                        const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
                        base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
    void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>);

protected:
    Framebuffer* getFramebufferForDrawing() override;

private:
    void threadMain(const RenderEngineCreationArgs& args);
    void threadMain(CreateInstanceFactory factory);

    /* ------------------------------------------------------------------------
     * Threading