DSDisplayDevice: implement HWC functions. 73/241573/1
authorSooChan Lim <sc1.lim@samsung.com>
Fri, 3 Jul 2020 06:13:25 +0000 (15:13 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Thu, 20 Aug 2020 09:45:52 +0000 (18:45 +0900)
Change-Id: I664b763358926f1575f42c122072035e7ca8c366

src/DSDisplayDevice/DSDisplayDeviceHWCTDMImpl.cpp
src/DSDisplayDevice/DSDisplayDeviceHWCTDMImpl.h
src/DSDisplayDevice/DSDisplayDeviceHWCWindowTDMImpl.cpp
src/DSDisplayDevice/DSDisplayDeviceHWCWindowTDMImpl.h
src/DSDisplayDevice/DSDisplayDeviceOutputTDMImpl.cpp
src/DSDisplayDevice/DSDisplayDeviceTDMImpl.cpp
src/DSDisplayDevice/IDSDisplayDeviceHWC.h
tests/DSDisplayDeviceTDMImpl-test.cpp

index d8b17c7..f7b1cce 100644 (file)
 #include "DSDisplayDeviceHWCTDMImpl.h"
 #include "DSDisplayDeviceHWCWindowTDMImpl.h"
 #include "DSDebugLog.h"
+#include <cstring>
 
 namespace display_server
 {
+
 DSDisplayDeviceHWCTDMImpl::DSDisplayDeviceHWCTDMImpl(tdm_hwc *thwc)
-       : __thwc(thwc)
+       : __thwc(thwc),
+         __bufferQueue(nullptr)
+{}
+
+DSDisplayDeviceHWCTDMImpl::~DSDisplayDeviceHWCTDMImpl()
+{
+       clearVisibleHWCWindows();
+}
+
+std::shared_ptr<IDSBufferQueue> DSDisplayDeviceHWCTDMImpl::getTargetBufferQueue()
 {
+       tdm_error terror;
+       tbm_surface_queue_h tqueue;
+
+       if (__bufferQueue) {
+               DSLOG_INF("TDM_HWC", "return the existed IDSBufferQueue.");
+               return __bufferQueue;
+       }
+
+       tqueue = tdm_hwc_get_client_target_buffer_queue(__thwc, &terror);
+       if (terror != TDM_ERROR_NONE) {
+               DSLOG_ERR("HWCTDM", "tdm_hwc_get_client_target_buffer_queue fails.\n");
+       }
 
+       __bufferQueue = std::make_shared<DSBufferQueueTBMImpl>(tqueue);
+
+       return __bufferQueue;
 }
-DSDisplayDeviceHWCTDMImpl::~DSDisplayDeviceHWCTDMImpl()
+
+bool DSDisplayDeviceHWCTDMImpl::setTargetBuffer(std::shared_ptr<IDSBuffer> buffer)
 {
+       tdm_error terror;
+       tdm_region fb_damage;
+       std::memset(&fb_damage, 0, sizeof (tdm_region));
+
+       terror = tdm_hwc_set_client_target_buffer(__thwc, (tbm_surface_h)buffer->getNativeBuffer(), fb_damage);
+       if (terror != TDM_ERROR_NONE) {
+               DSLOG_ERR("TDM_HWC", "tdm_hwc_set_client_target_buffer fails.");
+               return false;
+       }
 
+       return true;
 }
 
-IDSDisplayDeviceHWCWindow *DSDisplayDeviceHWCTDMImpl::createHWCWindow()
+std::shared_ptr<IDSDisplayDeviceHWCWindow> DSDisplayDeviceHWCTDMImpl::makeHWCWindow()
 {
+       std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow;
        tdm_error terror;
        tdm_hwc_window *twindow;
-       IDSDisplayDeviceHWCWindow *deviceHWCWindow;
 
        twindow = tdm_hwc_create_window(__thwc, &terror);
        if (!twindow) {
-               DSLOG_ERR("TDM HWCWindow", "tdm_hwc_create_window fails.\n");
+               DSLOG_ERR("HWCTDM", "tdm_hwc_create_window fails.\n");
                return nullptr;
        }
 
-       deviceHWCWindow = new DSDisplayDeviceHWCWindowTDMImpl(twindow);
+       deviceHWCWindow = std::make_shared<DSDisplayDeviceHWCWindowTDMImpl>(twindow);
        if (!deviceHWCWindow) {
-               DSLOG_ERR("TDM HWCWindow", "new DSDisplayDeviceHWCWindowTDMImpl fails.\n");
+               DSLOG_ERR("HWCTDM", "new DSDisplayDeviceHWCWindowTDMImpl fails.\n");
                return nullptr;
        }
 
-       __deviceHWCWindowList.push_back(deviceHWCWindow);
-
        return deviceHWCWindow;
 }
 
-void DSDisplayDeviceHWCTDMImpl::destroyHWCWindow(IDSDisplayDeviceHWCWindow *deviceHWCWindow)
+bool DSDisplayDeviceHWCTDMImpl::addVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow)
+{
+       __visibleDeviceHWCWindowList.push_back(deviceHWCWindow);
+
+       return true;
+}
+
+bool DSDisplayDeviceHWCTDMImpl::removeVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow)
+{
+       __visibleDeviceHWCWindowList.remove(deviceHWCWindow);
+
+       return true;
+}
+
+void DSDisplayDeviceHWCTDMImpl::clearVisibleHWCWindows()
 {
-       delete deviceHWCWindow;
-       __deviceHWCWindowList.remove(deviceHWCWindow);
+       __visibleDeviceHWCWindowList.clear();
 }
 
 bool DSDisplayDeviceHWCTDMImpl::commit()
 {
        tdm_error terror;
-       int numVisibleHWCWins = __deviceHWCWindowList.size(); //TODO: need to fix. change it to visible windows list. __deviceHWCWindowList is not the visible window list.
-       DSDisplayDeviceHWCWindowTDMImpl *hwcWinsImpl;
-       uint32_t numTypes;
+       uint32_t numChanges;
 
-       // get the thwc_windows to request validate.
+       if (!__validate(numChanges)) {
+               DSLOG_ERR("HWCTDM", "__validate fails.\n");
+               return false;
+       }
+
+       if (numChanges > 0) {
+               if (!__updateChanges(numChanges)) {
+                       DSLOG_ERR("HWCTDM", "__updateChanges fails.\n");
+                       return false;
+               }
+       }
+
+       if (!__acceptValidation()) {
+               DSLOG_ERR("HWCTDM", "__acceptValidation fails.\n");
+               return false;
+       }
+
+       //TODO: tdm_hwc_commit
+       terror = tdm_hwc_commit(__thwc, 0, NULL, NULL);
+       if (terror != TDM_ERROR_NONE) {
+               DSLOG_ERR("HWCTDM", "tdm_hwc_commit fails.");
+               return false;
+       }
+
+       return true;
+}
+
+bool DSDisplayDeviceHWCTDMImpl::__validate(uint32_t &numChanges)
+{
+       int numVisibleHWCWins = __visibleDeviceHWCWindowList.size();
+       tdm_error terror;
        tdm_hwc_window **thwc_windows;
+       int i = 0;
+
+       // get the thwc_windows to request validate.
        thwc_windows = (tdm_hwc_window **)calloc(numVisibleHWCWins, sizeof(tdm_hwc_window *));
        if (thwc_windows == nullptr) {
                DSLOG_ERR("TDM_HWC", "calloc thwc_windows fails.");
                return false;
        }
 
-       int i = 0;
-       for (auto *hwcwins : __deviceHWCWindowList) {
-               hwcWinsImpl =  (DSDisplayDeviceHWCWindowTDMImpl *)hwcwins;
-               thwc_windows[i++] = hwcWinsImpl->getTDMHWCWindow();
+       for (auto &&deviceHWCWindow : __visibleDeviceHWCWindowList) {
+               auto deviceHWCWindowTDM = std::dynamic_pointer_cast<DSDisplayDeviceHWCWindowTDMImpl>(deviceHWCWindow);
+               thwc_windows[i++] = deviceHWCWindowTDM->getNativeHWCWindow();
        }
 
        // validate thwc_windows
-       terror = tdm_hwc_validate(__thwc, thwc_windows, numVisibleHWCWins, &numTypes);
+       terror = tdm_hwc_validate(__thwc, thwc_windows, numVisibleHWCWins, &numChanges);
        if (terror != TDM_ERROR_NONE) {
                DSLOG_ERR("TDM_HWC", "tdm_hwc_validate fails.");
                free(thwc_windows);
@@ -75,56 +153,60 @@ bool DSDisplayDeviceHWCTDMImpl::commit()
 
        free(thwc_windows);
 
-       // get changed_types
+       return true;
+}
+
+bool DSDisplayDeviceHWCTDMImpl::__updateChanges(uint32_t numChanges)
+{
+       tdm_error terror;
        tdm_hwc_window **changed_thwc_window = NULL;
        tdm_hwc_window_composition *tcomposition_types = NULL;
-       uint32_t numChanges = 0;
-       if (numTypes > 0) {
-               changed_thwc_window = (tdm_hwc_window **)calloc(numTypes, sizeof(tdm_hwc_window *));
-               if (changed_thwc_window == nullptr) {
-                       DSLOG_ERR("TDM_HWC", "calloc changed_thwc_window fails.");
-                       return false;
-               }
-
-               tcomposition_types = (tdm_hwc_window_composition *)calloc(numTypes, sizeof(tdm_hwc_window_composition));
-               if (tcomposition_types == nullptr) {
-                       DSLOG_ERR("TDM_HWC", "calloc changed_thwc_window fails.");
-                       free(changed_thwc_window);
-                       return false;
-               }
-
-               terror = tdm_hwc_get_changed_composition_types(__thwc, &numChanges, changed_thwc_window, tcomposition_types);
-               if (terror != TDM_ERROR_NONE) {
-                       DSLOG_ERR("TDM_HWC", "tdm_hwc_get_changed_composition_types fails.");
-                       free(tcomposition_types);
-                       free(changed_thwc_window);
-                       return false;
-               }
+       int i;
 
-               for (i = 0; i < (int)numChanges; ++i) {
-                       //TODO: change the TYPES of HWCWindows
-               }
+       changed_thwc_window = (tdm_hwc_window **)calloc(numChanges, sizeof(tdm_hwc_window *));
+       if (changed_thwc_window == nullptr) {
+               DSLOG_ERR("TDM_HWC", "calloc changed_thwc_window fails.");
+               return false;
+       }
 
-               // TODO: accept_validation is depending on the transitions.
-               terror =  tdm_hwc_accept_validation(__thwc);
-               if (terror != TDM_ERROR_NONE) {
-                       DSLOG_ERR("TDM_HWC", "tdm_hwc_accept_validation fails.");
-                       free(tcomposition_types);
-                       free(changed_thwc_window);
-                       return false;
-               }
+       // get changed_types
+       tcomposition_types = (tdm_hwc_window_composition *)calloc(numChanges, sizeof(tdm_hwc_window_composition));
+       if (tcomposition_types == nullptr) {
+               DSLOG_ERR("TDM_HWC", "calloc changed_thwc_window fails.");
+               free(changed_thwc_window);
+               return false;
+       }
 
+       terror = tdm_hwc_get_changed_composition_types(__thwc, &numChanges, changed_thwc_window, tcomposition_types);
+       if (terror != TDM_ERROR_NONE) {
+               DSLOG_ERR("TDM_HWC", "tdm_hwc_get_changed_composition_types fails.");
                free(tcomposition_types);
                free(changed_thwc_window);
+               return false;
        }
 
-       //TODO: tdm_hwc_commit
-       terror = tdm_hwc_commit(__thwc, 0, NULL, NULL);
+       for (i = 0; i < (int)numChanges; ++i) {
+               //TODO: change the TYPES of HWCWindows
+       }
+
+       free(tcomposition_types);
+       free(changed_thwc_window);
+
+       return true;
+}
+
+bool DSDisplayDeviceHWCTDMImpl::__acceptValidation()
+{
+       tdm_error terror;
+
+       // TODO: accept_validation is depending on the transitions.
+       terror =  tdm_hwc_accept_validation(__thwc);
        if (terror != TDM_ERROR_NONE) {
-               DSLOG_ERR("TDM_HWC", "tdm_hwc_commit fails.");
+               DSLOG_ERR("TDM_HWC", "tdm_hwc_accept_validation fails.\n");
                return false;
        }
 
        return true;
 }
-}
\ No newline at end of file
+
+}
index cd266e7..ba1daaf 100644 (file)
@@ -2,6 +2,7 @@
 #define _DS_DISPLAY_DEVICE_HWC_TDM_IMPL_H_
 
 #include "IDSDisplayDeviceHWC.h"
+#include "DSBufferQueueTBMImpl.h"
 #include <tdm.h>
 #include <list>
 
@@ -13,13 +14,22 @@ public:
        DSDisplayDeviceHWCTDMImpl(tdm_hwc *thwc);
        ~DSDisplayDeviceHWCTDMImpl();
 
-       IDSDisplayDeviceHWCWindow *createHWCWindow() override;
-       void destroyHWCWindow(IDSDisplayDeviceHWCWindow *deviceHWCWindow) override;
-       bool commit() override;
+       std::shared_ptr<IDSBufferQueue>            getTargetBufferQueue() override;
+       bool                                       setTargetBuffer(std::shared_ptr<IDSBuffer> buffer) override;
+       std::shared_ptr<IDSDisplayDeviceHWCWindow> makeHWCWindow() override;
+       bool                                       addVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow) override;
+       bool                                       removeVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow) override;
+       void                                       clearVisibleHWCWindows() override;
+       bool                                       commit() override;
 
 private:
        tdm_hwc *__thwc;
-       std::list<IDSDisplayDeviceHWCWindow *> __deviceHWCWindowList;
+       std::shared_ptr<DSBufferQueueTBMImpl> __bufferQueue;
+       std::list<std::shared_ptr<IDSDisplayDeviceHWCWindow>> __visibleDeviceHWCWindowList;
+
+       bool __validate(uint32_t &numChanges);
+       bool __updateChanges(uint32_t numChanges);
+       bool __acceptValidation();
 };
 }
 
index 7fcf260..3fde0ef 100644 (file)
@@ -8,8 +8,10 @@ DSDisplayDeviceHWCWindowTDMImpl::DSDisplayDeviceHWCWindowTDMImpl(tdm_hwc_window
        : __twindow(twindow)
 {}
 DSDisplayDeviceHWCWindowTDMImpl::~DSDisplayDeviceHWCWindowTDMImpl()
-{}
-tdm_hwc_window *DSDisplayDeviceHWCWindowTDMImpl::getTDMHWCWindow()
+{
+       tdm_hwc_window_destroy(__twindow);
+}
+tdm_hwc_window *DSDisplayDeviceHWCWindowTDMImpl::getNativeHWCWindow()
 {
        return __twindow;
 }
index 43facd9..d4d9bbf 100644 (file)
@@ -11,10 +11,11 @@ class DSDisplayDeviceHWCWindowTDMImpl : public IDSDisplayDeviceHWCWindow
 public:
        DSDisplayDeviceHWCWindowTDMImpl(tdm_hwc_window *twindow);
        ~DSDisplayDeviceHWCWindowTDMImpl();
-       tdm_hwc_window *getTDMHWCWindow();
+       tdm_hwc_window *getNativeHWCWindow();
 private:
        tdm_hwc_window* __twindow;
 };
+
 }
 
 #endif
index bfdb287..ed1e9c9 100644 (file)
@@ -45,7 +45,7 @@ DSDisplayDeviceOutputTDMImpl::DSDisplayDeviceOutputTDMImpl(tdm_output *toutput)
                __displayDeviceHWC = std::make_shared<DSDisplayDeviceHWCTDMImpl>(thwc);
        } else {
                //TODO: need fallback for HWC
-               DSLOG_WRN("TDM OUTPUT", "tdm_output_get_hwc fails.\n");
+               DSLOG_WRN("TDM OUTPUT", "tdm_output_get_hwc fails.");
        }
 }
 
index 7dccce7..c950704 100644 (file)
@@ -1,5 +1,6 @@
 #include "DSDisplayDeviceTDMImpl.h"
 #include "DSDisplayDeviceOutputTDMImpl.h"
+#include "DSDisplayDeviceHWCTDMImpl.h"
 #include "DSDebugLog.h"
 
 namespace display_server
@@ -35,6 +36,17 @@ DSDisplayDeviceTDMImpl::DSDisplayDeviceTDMImpl()
 
 DSDisplayDeviceTDMImpl::~DSDisplayDeviceTDMImpl()
 {
+       // Clear the visible hwc windows before tdm_display_deinit.
+       // Otherwise, the process will block inside libtdm
+       // when it calls tdm_hwc_window_destroy() function at ~DSDisplayDeviceHWCWindowTDMImpl()
+       // because the mutex_lock(private_display->lock) is destroyed at tdm_display_deinit().
+       for (auto displayDeviceOutput: __outputList) {
+               std::shared_ptr<IDSDisplayDeviceHWC> displayDeviceHWC = displayDeviceOutput->getHWC();
+               if (displayDeviceHWC) {
+                       displayDeviceHWC->clearVisibleHWCWindows();
+               }
+       }
+
        tdm_display_deinit(__tdisplay);
 }
 
index 995ee57..154b4d7 100644 (file)
@@ -2,18 +2,26 @@
 #define _I_DS_DISPLAY_DEVICE_HWC_H_
 
 #include "IDSDisplayDeviceHWCWindow.h"
+#include "IDSBufferQueue.h"
+#include <memory>
 
 namespace display_server
 {
+
 class IDSDisplayDeviceHWC
 {
 public:
        virtual ~IDSDisplayDeviceHWC() = default;
 
-       virtual IDSDisplayDeviceHWCWindow  *createHWCWindow() = 0;
-       virtual void                       destroyHWCWindow(IDSDisplayDeviceHWCWindow *deviceHWCWindow) = 0;
-       virtual bool                       commit() = 0;
+       virtual std::shared_ptr<IDSBufferQueue>            getTargetBufferQueue() = 0;
+       virtual bool                                       setTargetBuffer(std::shared_ptr<IDSBuffer> buffer) = 0;
+       virtual std::shared_ptr<IDSDisplayDeviceHWCWindow> makeHWCWindow() = 0;
+       virtual bool                                       addVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow) = 0;
+       virtual bool                                       removeVisibleHWCWindow(std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow) = 0;
+       virtual void                                       clearVisibleHWCWindows() = 0;
+       virtual bool                                       commit() = 0;
 };
+
 }
 
 #endif
index eb6875c..b8cf18e 100644 (file)
@@ -223,7 +223,7 @@ TEST_F(DSDisplayDeviceTDMImplTest, DeviceOutput_registerCallbackOutputResolution
 
 // DSDisplayDeviceTDMHWC
 
-TEST_F(DSDisplayDeviceTDMImplTest, DeviceOutput_createHWCWindow)
+TEST_F(DSDisplayDeviceTDMImplTest, DeviceOutput_makeHWCWindow)
 {
        std::unique_ptr<IDSDisplayDevice> displayDevice = std::make_unique<DSDisplayDeviceTDMImpl>();
        std::list<std::shared_ptr<IDSDisplayDeviceOutput>> outputList = displayDevice->getOutputList();
@@ -232,7 +232,7 @@ TEST_F(DSDisplayDeviceTDMImplTest, DeviceOutput_createHWCWindow)
        IDSDisplayDeviceOutput::ConnectorType connType;
        IDSDisplayDeviceOutput::ConnectState connState;
        std::shared_ptr<IDSDisplayDeviceHWC> deviceHWC;
-       IDSDisplayDeviceHWCWindow *deviceHWCWindow;
+       std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow;
 
        for (std::shared_ptr<IDSDisplayDeviceOutput> output : outputList) {
                connType = output->getConnectType();
@@ -244,10 +244,8 @@ TEST_F(DSDisplayDeviceTDMImplTest, DeviceOutput_createHWCWindow)
                deviceHWC = output->getHWC();
                EXPECT_TRUE(deviceHWC != nullptr);
 
-               deviceHWCWindow = deviceHWC->createHWCWindow();
+               deviceHWCWindow = deviceHWC->makeHWCWindow();
                EXPECT_TRUE(deviceHWC != nullptr);
-
-               deviceHWC->destroyHWCWindow(deviceHWCWindow);
        }
 }
 
@@ -260,7 +258,7 @@ TEST_F(DSDisplayDeviceTDMImplTest, DeviceHWC_commit)
        IDSDisplayDeviceOutput::ConnectorType connType;
        IDSDisplayDeviceOutput::ConnectState connState;
        std::shared_ptr<IDSDisplayDeviceHWC> deviceHWC;
-       IDSDisplayDeviceHWCWindow *deviceHWCWindow;
+       std::shared_ptr<IDSDisplayDeviceHWCWindow> deviceHWCWindow;
 
        for (std::shared_ptr<IDSDisplayDeviceOutput> output : outputList) {
                connType = output->getConnectType();
@@ -269,15 +267,38 @@ TEST_F(DSDisplayDeviceTDMImplTest, DeviceHWC_commit)
                EXPECT_TRUE(connState <= IDSDisplayDeviceOutput::STATE_MODESET);
                if (connState == IDSDisplayDeviceOutput::STATE_DISCONNECTED) continue;
 
+               DSDisplayDeviceOutputMode *bestMode = nullptr;
+               for (DSDisplayDeviceOutputMode *mode : output->getAvailableModes()) {
+                       if (bestMode == nullptr) {
+                               bestMode = mode;
+                               continue;
+                       }
+
+                       int resSize = mode->hdisplay * mode->vdisplay;
+                       int resSizeBest = bestMode->hdisplay *bestMode->vdisplay;
+                       if  (resSize > resSizeBest) {
+                               bestMode = mode;
+                       }
+               }
+               EXPECT_TRUE(output->setMode(bestMode) == true);
+               EXPECT_TRUE(output->getMode() == bestMode);
+
                deviceHWC = output->getHWC();
                EXPECT_TRUE(deviceHWC != nullptr);
 
-               deviceHWCWindow = deviceHWC->createHWCWindow();
+               auto bufferQueue = deviceHWC->getTargetBufferQueue();
                EXPECT_TRUE(deviceHWC != nullptr);
 
-               // commit
-               deviceHWC->commit();
+               deviceHWCWindow = deviceHWC->makeHWCWindow();
+               EXPECT_TRUE(deviceHWC != nullptr);
+               EXPECT_TRUE(deviceHWC->addVisibleHWCWindow(deviceHWCWindow));
+
+               auto buffer = bufferQueue->dequeueBuffer();
+               EXPECT_TRUE(buffer != nullptr);
 
-               deviceHWC->destroyHWCWindow(deviceHWCWindow);
+               EXPECT_TRUE(deviceHWC->setTargetBuffer(buffer));
+
+               // commit
+               EXPECT_TRUE(deviceHWC->commit());
        }
 }
\ No newline at end of file