OSDN Git Service

Linux Backend Support
authorHarish Krupo <harish.krupo.kps@intel.com>
Fri, 17 Nov 2017 20:47:05 +0000 (02:17 +0530)
committerKalyan Kondapally <kalyan.kondapally@intel.com>
Fri, 2 Feb 2018 09:37:25 +0000 (01:37 -0800)
Jira: None.
Test: Build passes on Linux.

Signed-off-by: Harish Krupo <harish.krupo.kps@intel.com>
Makefile.am
autogen.sh
configure.ac
iahwc.pc.in
os/linux/iahwc.h [new file with mode: 0644]
os/linux/linux_frontend.cpp [new file with mode: 0644]
os/linux/linux_frontend.h [new file with mode: 0644]
os/linux/platformdefines.h
tests/Makefile.am
tests/apps/linux_frontend_test.cpp [new file with mode: 0644]

index f6e0bb1..48d9315 100644 (file)
@@ -58,9 +58,15 @@ AM_CPPFLAGS += -DUSE_GL
 libhwcomposer_la_LIBADD += $(GLES2_LIBS)
 endif
 
+if ENABLE_LINUX_FRONTEND
+libhwcomposer_la_SOURCES += \
+       os/linux/iahwc.h \
+       os/linux/linux_frontend.h \
+       os/linux/linux_frontend.cpp
+endif
 
-libhwcincdir = $(includedir)/libhwc
-libhwcinc_HEADERS =    \
+libiahwcincdir = $(includedir)/libiahwc
+libiahwcinc_HEADERS =  \
        $(top_srcdir)/public/gpudevice.h        \
        $(top_srcdir)/public/hwcbuffer.h        \
        $(top_srcdir)/public/hwcdefs.h  \
@@ -68,7 +74,8 @@ libhwcinc_HEADERS =   \
        $(top_srcdir)/public/hwcrect.h  \
        $(top_srcdir)/public/nativebufferhandler.h      \
        $(top_srcdir)/public/nativedisplay.h    \
-       $(top_srcdir)/public/spinlock.h
+       $(top_srcdir)/public/spinlock.h \
+       $(top_srcdir)/os/linux/iahwc.h
 
 
 pkgconfigdir = $(libdir)/pkgconfig
index 5df14b7..39f752c 100755 (executable)
@@ -8,13 +8,6 @@ cd $srcdir
 
 mkdir -p m4
 
-if ! type gtkdocize > /dev/null 2>&1; then
-        echo "EXTRA_DIST =" > gtk-doc.make
-        echo "CLEANFILES =" >> gtk-doc.make
-else
-        gtkdocize || exit $?
-fi
-
 autoreconf -v --install -Itests/third_party/json-c/autoconf-archive/m4 || exit 1
 cd $ORIGDIR || exit $?
 
index f8854b9..4ce5e4d 100644 (file)
@@ -53,6 +53,15 @@ fi])
 
 AM_CONDITIONAL([ENABLE_VULKAN], [test "x$enable_vulkan" = "xyes"])
 
+# For linux
+AC_ARG_ENABLE(linux-frontend,
+AS_HELP_STRING([--enable-linux-frontend],
+[Compile linux frontend (EXPERIMENTAL) @<:@default=no@:>@]),
+[enable_linux_frontend="$enableval"],
+[enable_linux_frontend=no])
+
+AM_CONDITIONAL([ENABLE_LINUX_FRONTEND], [test "x$enable_linux_frontend" = "xyes"])
+
 # For hotplug
 AC_ARG_ENABLE(hotplug-support,
   AS_HELP_STRING([--disable-hotplug-support],
@@ -203,3 +212,12 @@ AC_CONFIG_FILES([
                iahwc.pc
                ])
 AC_OUTPUT
+
+echo -e """\nEnabled options """
+
+AC_MSG_RESULT([
+     Vulkan                   $enable_vulkan
+     Linux frontend           $enable_linux_frontend
+     GBM                      $enable_gbm
+     Hotplug Support          $disable_hotplug_support
+])
index 2ff3f41..72a1b73 100644 (file)
@@ -8,4 +8,4 @@ includedir=@includedir@
 Name: IA Hardware Composer
 Description: Hardware composer for Intel Architecture
 Version: 0.1.1
-Cflags: -I${includedir}
+Cflags: -I${includedir}/libiahwc
diff --git a/os/linux/iahwc.h b/os/linux/iahwc.h
new file mode 100644 (file)
index 0000000..ef27463
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ */
+
+#ifndef OS_LINUX_IAHWC_H_
+#define OS_LINUX_IAHWC_H_
+
+#include <gbm.h>
+#include <stdint.h>
+
+#define IAHWC_MODULE IAHWC_MODULE_INFO
+#define IAHWC_MODULE_STR "IAHWC_MODULE_INFO"
+
+typedef void (*iahwc_function_ptr_t)();
+typedef uint32_t iahwc_display_t;
+typedef uint32_t iahwc_layer_t;
+typedef void* iahwc_callback_data_t;
+
+struct iahwc_device;
+
+typedef struct iahwc_module {
+  const char* name;
+  int (*open)(const struct iahwc_module* module, struct iahwc_device** device);
+} iahwc_module_t;
+
+typedef struct iahwc_device {
+  struct iahwc_module module;
+  int (*close)(struct iahwc_device* device);
+  iahwc_function_ptr_t (*getFunctionPtr)(struct iahwc_device* device,
+                                         int descriptor);
+} iahwc_device_t;
+
+typedef enum {
+  IAHWC_ERROR_NONE = 0,
+  IAHWC_ERROR_BAD_CONFIG,
+  IAHWC_ERROR_BAD_DISPLAY,
+  IAHWC_ERROR_BAD_LAYER,
+  IAHWC_ERROR_BAD_PARAMETER,
+  IAHWC_ERROR_HAS_CHANGES,
+  IAHWC_ERROR_NO_RESOURCES,
+  IAHWC_ERROR_NOT_VALIDATED,
+  IAHWC_ERROR_UNSUPPORTED,
+} iahwc_error_t;
+
+enum iahwc_display_configs {
+  IAHWC_CONFIG_WIDTH = 1,
+  IAHWC_CONFIG_HEIGHT = 2,
+  IAHWC_CONFIG_REFRESHRATE = 3,
+  IAHWC_CONFIG_DPIX = 4,
+  IAHWC_CONFIG_DPIY = 5
+};
+
+enum iahwc_function_descriptors {
+  IAHWC_FUNC_INVALID = 0,
+  IAHWC_FUNC_GET_NUM_DISPLAYS,
+  IAHWC_FUNC_REGISTER_CALLBACK,
+  IAHWC_FUNC_DISPLAY_GET_INFO,
+  IAHWC_FUNC_DISPLAY_GET_NAME,
+  IAHWC_FUNC_DISPLAY_GET_CONFIGS,
+  IAHWC_FUNC_DISPLAY_SET_GAMMA,
+  IAHWC_FUNC_DISPLAY_SET_CONFIG,
+  IAHWC_FUNC_DISPLAY_GET_CONFIG,
+  IAHWC_FUNC_DISPLAY_CLEAR_ALL_LAYERS,
+  IAHWC_FUNC_PRESENT_DISPLAY,
+  IAHWC_FUNC_CREATE_LAYER,
+  IAHWC_FUNC_LAYER_SET_BO,
+  IAHWC_FUNC_LAYER_SET_ACQUIRE_FENCE,
+  IAHWC_FUNC_LAYER_SET_USAGE,
+  IAHWC_FUNC_LAYER_SET_TRANSFORM,
+  IAHWC_FUNC_LAYER_SET_SOURCE_CROP,
+  IAHWC_FUNC_LAYER_SET_DISPLAY_FRAME,
+  IAHWC_FUNC_LAYER_SET_SURFACE_DAMAGE,
+};
+
+enum iahwc_callback_descriptor { IAHWC_CALLBACK_VSYNC };
+
+enum iahwc_layer_usage {
+  IAHWC_LAYER_USAGE_CURSOR,
+  IAHWC_LAYER_USAGE_OVERLAY,
+  IAHWC_LAYER_USAGE_NORMAL,
+};
+
+enum iahwc_layer_transform {
+  IAHWC_TRANSFORM_FLIP_H,
+  IAHWC_TRANSFORM_FLIP_V,
+  IAHWC_TRANSFORM_ROT_90,
+  IAHWC_TRANSFORM_ROT_180,
+  IAHWC_TRANSFORM_ROT_270,
+  IAHWC_TRANSFORM_FLIP_H_ROT_90,
+  IAHWC_TRANSFORM_FLIP_V_ROT_90
+};
+
+typedef struct iahwc_rect {
+  int left;
+  int top;
+  int right;
+  int bottom;
+} iahwc_rect_t;
+
+typedef struct iahwc_region {
+  size_t numRects;
+  iahwc_rect_t const* rects;
+} iahwc_region_t;
+
+typedef int (*IAHWC_PFN_GET_NUM_DISPLAYS)(iahwc_device_t*, int* num_displays);
+typedef int (*IAHWC_PFN_REGISTER_CALLBACK)(iahwc_device_t*, int descriptor,
+                                           iahwc_display_t display_handle,
+                                           iahwc_callback_data_t data,
+                                           iahwc_function_ptr_t hook);
+typedef int (*IAHWC_PFN_DISPLAY_GET_INFO)(iahwc_device_t*,
+                                          iahwc_display_t display_handle,
+                                          uint32_t config, int attribute,
+                                          int32_t* value);
+typedef int (*IAHWC_PFN_DISPLAY_GET_NAME)(iahwc_device_t*,
+                                          iahwc_display_t display_handle,
+                                          uint32_t* size, char* name);
+typedef int (*IAHWC_PFN_DISPLAY_GET_CONFIGS)(iahwc_device_t*,
+                                             iahwc_display_t display_handle,
+                                             uint32_t* num_configs,
+                                             uint32_t* configs);
+typedef int (*IAHWC_PFN_DISPLAY_SET_GAMMA)(iahwc_device_t*,
+                                           iahwc_display_t display_handle,
+                                           float r, float g, float b);
+typedef int (*IAHWC_PFN_DISPLAY_SET_CONFIG)(iahwc_device_t*,
+                                            iahwc_display_t display_handle,
+                                            uint32_t config);
+typedef int (*IAHWC_PFN_DISPLAY_GET_CONFIG)(iahwc_device_t*,
+                                            iahwc_display_t display_handle,
+                                            uint32_t* config);
+typedef int (*IAHWC_PFN_DISPLAY_CLEAR_ALL_LAYERS)(
+    iahwc_device_t*, iahwc_display_t display_handle);
+typedef int (*IAHWC_PFN_PRESENT_DISPLAY)(iahwc_device_t*,
+                                         iahwc_display_t display_handle,
+                                         int32_t* release_fd);
+typedef int (*IAHWC_PFN_CREATE_LAYER)(iahwc_device_t*,
+                                      iahwc_display_t display_handle,
+                                      iahwc_layer_t* layer_handle);
+typedef int (*IAHWC_PFN_LAYER_SET_BO)(iahwc_device_t*,
+                                      iahwc_display_t display_handle,
+                                      iahwc_layer_t layer_handle,
+                                      struct gbm_bo*);
+typedef int (*IAHWC_PFN_LAYER_SET_ACQUIRE_FENCE)(iahwc_device_t*,
+                                                 iahwc_display_t display_handle,
+                                                 iahwc_layer_t layer_handle,
+                                                 int32_t acquire_fence);
+typedef int (*IAHWC_PFN_LAYER_SET_USAGE)(iahwc_device_t*,
+                                         iahwc_display_t display_handle,
+                                         iahwc_layer_t layer_handle,
+                                         int32_t layer_usage);
+typedef int (*IAHWC_PFN_LAYER_SET_TRANSFORM)(iahwc_device_t*,
+                                             iahwc_display_t display_handle,
+                                             iahwc_layer_t layer_handle,
+                                             int32_t layer_transform);
+typedef int (*IAHWC_PFN_LAYER_SET_SOURCE_CROP)(iahwc_device_t*,
+                                               iahwc_display_t display_handle,
+                                               iahwc_layer_t layer_handle,
+                                               iahwc_rect_t rect);
+typedef int (*IAHWC_PFN_LAYER_SET_DISPLAY_FRAME)(iahwc_device_t*,
+                                                 iahwc_display_t display_handle,
+                                                 iahwc_layer_t layer_handle,
+                                                 iahwc_rect_t rect);
+typedef int (*IAHWC_PFN_LAYER_SET_SURFACE_DAMAGE)(
+    iahwc_device_t*, iahwc_display_t display_handle, iahwc_layer_t layer_handle,
+    iahwc_region_t region);
+typedef int (*IAHWC_PFN_VSYNC)(iahwc_callback_data_t data,
+                               iahwc_display_t display, int64_t timestamp);
+#endif // OS_LINUX_IAHWC_H_
diff --git a/os/linux/linux_frontend.cpp b/os/linux/linux_frontend.cpp
new file mode 100644 (file)
index 0000000..d6b7e77
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linux_frontend.h"
+#include <commondrmutils.h>
+#include <hwcrect.h>
+
+namespace hwcomposer {
+
+class IAHWCVsyncCallback : public hwcomposer::VsyncCallback {
+ public:
+  IAHWCVsyncCallback(iahwc_callback_data_t data, iahwc_function_ptr_t hook)
+      : data_(data), hook_(hook) {
+  }
+
+  void Callback(uint32_t display, int64_t timestamp) {
+    if (hook_ != NULL) {
+      auto hook = reinterpret_cast<IAHWC_PFN_VSYNC>(hook_);
+      hook(data_, display, timestamp);
+    }
+  }
+
+ private:
+  iahwc_callback_data_t data_;
+  iahwc_function_ptr_t hook_;
+};
+
+IAHWC::IAHWC() {
+  getFunctionPtr = HookGetFunctionPtr;
+  close = HookClose;
+}
+
+int32_t IAHWC::Init() {
+  if (!device_.Initialize()) {
+    fprintf(stderr, "Unable to initialize GPU DEVICE");
+    return IAHWC_ERROR_NO_RESOURCES;
+  }
+
+  std::vector<hwcomposer::NativeDisplay*> displays = device_.GetAllDisplays();
+
+  for (hwcomposer::NativeDisplay* display : displays) {
+    displays_.emplace_back(new IAHWCDisplay());
+    IAHWCDisplay* iahwc_display = displays_.back();
+    iahwc_display->Init(display);
+  }
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::HookOpen(const iahwc_module_t* module, iahwc_device_t** device) {
+  IAHWC* iahwc = new IAHWC();
+  iahwc->Init();
+  *device = iahwc;
+
+  return IAHWC_ERROR_NONE;
+}
+
+iahwc_function_ptr_t IAHWC::HookGetFunctionPtr(iahwc_device_t* /* device */,
+                                               int func_descriptor) {
+  switch (func_descriptor) {
+    case IAHWC_FUNC_GET_NUM_DISPLAYS:
+      return ToHook<IAHWC_PFN_GET_NUM_DISPLAYS>(
+          DeviceHook<int32_t, decltype(&IAHWC::GetNumDisplays),
+                     &IAHWC::GetNumDisplays, int*>);
+    case IAHWC_FUNC_REGISTER_CALLBACK:
+      return ToHook<IAHWC_PFN_REGISTER_CALLBACK>(
+          DeviceHook<int32_t, decltype(&IAHWC::RegisterCallback),
+                     &IAHWC::RegisterCallback, int, uint32_t,
+                     iahwc_callback_data_t, iahwc_function_ptr_t>);
+    case IAHWC_FUNC_DISPLAY_GET_INFO:
+      return ToHook<IAHWC_PFN_DISPLAY_GET_INFO>(
+          DisplayHook<decltype(&IAHWCDisplay::GetDisplayInfo),
+                      &IAHWCDisplay::GetDisplayInfo, uint32_t, int, int32_t*>);
+    case IAHWC_FUNC_DISPLAY_GET_NAME:
+      return ToHook<IAHWC_PFN_DISPLAY_GET_NAME>(
+          DisplayHook<decltype(&IAHWCDisplay::GetDisplayName),
+                      &IAHWCDisplay::GetDisplayName, uint32_t*, char*>);
+    case IAHWC_FUNC_DISPLAY_GET_CONFIGS:
+      return ToHook<IAHWC_PFN_DISPLAY_GET_CONFIGS>(
+          DisplayHook<decltype(&IAHWCDisplay::GetDisplayConfigs),
+                      &IAHWCDisplay::GetDisplayConfigs, uint32_t*, uint32_t*>);
+    case IAHWC_FUNC_DISPLAY_SET_GAMMA:
+      return ToHook<IAHWC_PFN_DISPLAY_SET_GAMMA>(
+          DisplayHook<decltype(&IAHWCDisplay::SetDisplayGamma),
+                      &IAHWCDisplay::SetDisplayGamma, float, float, float>);
+    case IAHWC_FUNC_DISPLAY_SET_CONFIG:
+      return ToHook<IAHWC_PFN_DISPLAY_SET_CONFIG>(
+          DisplayHook<decltype(&IAHWCDisplay::SetDisplayConfig),
+                      &IAHWCDisplay::SetDisplayConfig, uint32_t>);
+    case IAHWC_FUNC_DISPLAY_GET_CONFIG:
+      return ToHook<IAHWC_PFN_DISPLAY_GET_CONFIG>(
+          DisplayHook<decltype(&IAHWCDisplay::GetDisplayConfig),
+                      &IAHWCDisplay::GetDisplayConfig, uint32_t*>);
+    case IAHWC_FUNC_DISPLAY_CLEAR_ALL_LAYERS:
+      return ToHook<IAHWC_PFN_DISPLAY_CLEAR_ALL_LAYERS>(
+          DisplayHook<decltype(&IAHWCDisplay::ClearAllLayers),
+                      &IAHWCDisplay::ClearAllLayers>);
+    case IAHWC_FUNC_PRESENT_DISPLAY:
+      return ToHook<IAHWC_PFN_PRESENT_DISPLAY>(
+          DisplayHook<decltype(&IAHWCDisplay::PresentDisplay),
+                      &IAHWCDisplay::PresentDisplay, int32_t*>);
+    case IAHWC_FUNC_CREATE_LAYER:
+      return ToHook<IAHWC_PFN_CREATE_LAYER>(
+          DisplayHook<decltype(&IAHWCDisplay::CreateLayer),
+                      &IAHWCDisplay::CreateLayer, uint32_t*>);
+    case IAHWC_FUNC_LAYER_SET_BO:
+      return ToHook<IAHWC_PFN_LAYER_SET_BO>(
+          LayerHook<decltype(&IAHWCLayer::SetBo), &IAHWCLayer::SetBo, gbm_bo*>);
+    case IAHWC_FUNC_LAYER_SET_ACQUIRE_FENCE:
+      return ToHook<IAHWC_PFN_LAYER_SET_ACQUIRE_FENCE>(
+          LayerHook<decltype(&IAHWCLayer::SetAcquireFence),
+                    &IAHWCLayer::SetAcquireFence, int32_t>);
+    case IAHWC_FUNC_LAYER_SET_USAGE:
+      return ToHook<IAHWC_PFN_LAYER_SET_USAGE>(
+          LayerHook<decltype(&IAHWCLayer::SetLayerUsage),
+                    &IAHWCLayer::SetLayerUsage, int32_t>);
+    case IAHWC_FUNC_LAYER_SET_TRANSFORM:
+      return ToHook<IAHWC_PFN_LAYER_SET_TRANSFORM>(
+          LayerHook<decltype(&IAHWCLayer::SetLayerTransform),
+                    &IAHWCLayer::SetLayerTransform, int32_t>);
+    case IAHWC_FUNC_LAYER_SET_SOURCE_CROP:
+      return ToHook<IAHWC_PFN_LAYER_SET_SOURCE_CROP>(
+          LayerHook<decltype(&IAHWCLayer::SetLayerSourceCrop),
+                    &IAHWCLayer::SetLayerSourceCrop, iahwc_rect_t>);
+    case IAHWC_FUNC_LAYER_SET_DISPLAY_FRAME:
+      return ToHook<IAHWC_PFN_LAYER_SET_DISPLAY_FRAME>(
+          LayerHook<decltype(&IAHWCLayer::SetLayerDisplayFrame),
+                    &IAHWCLayer::SetLayerDisplayFrame, iahwc_rect_t>);
+    case IAHWC_FUNC_LAYER_SET_SURFACE_DAMAGE:
+      return ToHook<IAHWC_PFN_LAYER_SET_SURFACE_DAMAGE>(
+          LayerHook<decltype(&IAHWCLayer::SetLayerSurfaceDamage),
+                    &IAHWCLayer::SetLayerSurfaceDamage, iahwc_region_t>);
+    case IAHWC_FUNC_INVALID:
+    default:
+      return NULL;
+  }
+}
+
+int IAHWC::HookClose(iahwc_device_t* dev) {
+  delete dev;
+  return 0;
+}
+
+// private function implementations
+
+int IAHWC::GetNumDisplays(int* num_displays) {
+  *num_displays = 0;
+  for (IAHWCDisplay* display : displays_) {
+    if (display->IsConnected())
+      *num_displays += 1;
+  }
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::RegisterCallback(int32_t description, uint32_t display_id,
+                            iahwc_callback_data_t data,
+                            iahwc_function_ptr_t hook) {
+  switch (description) {
+    case IAHWC_CALLBACK_VSYNC: {
+      if (display_id >= displays_.size())
+        return IAHWC_ERROR_BAD_DISPLAY;
+      IAHWCDisplay* display = displays_.at(display_id);
+      return display->RegisterVsyncCallback(data, hook);
+    }
+    default:
+      return IAHWC_ERROR_BAD_PARAMETER;
+  }
+}
+
+IAHWC::IAHWCDisplay::IAHWCDisplay() : native_display_(NULL) {
+}
+
+int IAHWC::IAHWCDisplay::Init(hwcomposer::NativeDisplay* display) {
+  native_display_ = display;
+  native_display_->InitializeLayerHashGenerator(4);
+}
+
+int IAHWC::IAHWCDisplay::GetDisplayInfo(uint32_t config, int attribute,
+                                        int32_t* value) {
+  hwcomposer::HWCDisplayAttribute attrib =
+      static_cast<hwcomposer::HWCDisplayAttribute>(attribute);
+
+  bool ret = native_display_->GetDisplayAttribute(config, attrib, value);
+
+  if (!ret)
+    return IAHWC_ERROR_NO_RESOURCES;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::GetDisplayName(uint32_t* size, char* name) {
+  bool ret = native_display_->GetDisplayName(size, name);
+
+  if (!ret)
+    return IAHWC_ERROR_NO_RESOURCES;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::GetDisplayConfigs(uint32_t* num_configs,
+                                           uint32_t* configs) {
+  bool ret = native_display_->GetDisplayConfigs(num_configs, configs);
+
+  if (!ret)
+    return IAHWC_ERROR_NO_RESOURCES;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::SetDisplayGamma(float r, float b, float g) {
+  native_display_->SetGamma(r, g, b);
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::SetDisplayConfig(uint32_t config) {
+  bool ret = native_display_->SetActiveConfig(config);
+
+  if (!ret)
+    return IAHWC_ERROR_NO_RESOURCES;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::GetDisplayConfig(uint32_t* config) {
+  bool ret = native_display_->GetActiveConfig(config);
+
+  if (!ret)
+    return IAHWC_ERROR_NO_RESOURCES;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::ClearAllLayers() {
+  layers_.clear();
+  native_display_->ResetLayerHashGenerator();
+
+  return IAHWC_ERROR_NONE;
+}
+int IAHWC::IAHWCDisplay::PresentDisplay(int32_t* release_fd) {
+  std::vector<hwcomposer::HwcLayer*> layers;
+  hwcomposer::HwcLayer* cursor_layer = NULL;
+
+  for (auto & [ first, second ] : layers_) {
+    if (second.GetLayerUsage() == IAHWC_LAYER_USAGE_CURSOR)
+      cursor_layer = second.GetLayer();
+    else
+      layers.emplace_back(second.GetLayer());
+  }
+
+  if (cursor_layer)
+    layers.insert(layers.begin(), cursor_layer);
+
+  native_display_->Present(layers, release_fd);
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::CreateLayer(uint32_t* layer_handle) {
+  *layer_handle = native_display_->AcquireId();
+  layers_.emplace(*layer_handle, IAHWCLayer());
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCDisplay::RegisterVsyncCallback(iahwc_callback_data_t data,
+                                               iahwc_function_ptr_t hook) {
+  auto callback = std::make_shared<IAHWCVsyncCallback>(data, hook);
+  native_display_->VSyncControl(true);
+  int ret = native_display_->RegisterVsyncCallback(std::move(callback),
+                                                   static_cast<int>(0));
+  if (ret) {
+    return IAHWC_ERROR_BAD_DISPLAY;
+  }
+  return IAHWC_ERROR_NONE;
+}
+
+bool IAHWC::IAHWCDisplay::IsConnected() {
+  return native_display_->IsConnected();
+}
+
+IAHWC::IAHWCLayer::IAHWCLayer() {
+  layer_usage_ = IAHWC_LAYER_USAGE_NORMAL;
+}
+
+IAHWC::IAHWCLayer::~IAHWCLayer() {
+  ::close(hwc_handle_.import_data.fd);
+}
+
+int IAHWC::IAHWCLayer::SetBo(gbm_bo* bo) {
+  int32_t width, height;
+
+  ::close(hwc_handle_.import_data.fd);
+
+  width = gbm_bo_get_width(bo);
+  height = gbm_bo_get_height(bo);
+
+  hwc_handle_.import_data.width = width;
+  hwc_handle_.import_data.height = height;
+  hwc_handle_.import_data.format = gbm_bo_get_format(bo);
+  hwc_handle_.import_data.fd = gbm_bo_get_fd(bo);
+  hwc_handle_.import_data.stride = gbm_bo_get_stride(bo);
+  hwc_handle_.total_planes =
+      drm_bo_get_num_planes(hwc_handle_.import_data.format);
+  hwc_handle_.bo = bo;
+  hwc_handle_.hwc_buffer_ = true;
+  hwc_handle_.gbm_flags = 0;
+
+  iahwc_layer_.SetNativeHandle(&hwc_handle_);
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetAcquireFence(int32_t acquire_fence) {
+  iahwc_layer_.SetAcquireFence(acquire_fence);
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetLayerUsage(int32_t layer_usage) {
+  layer_usage_ = layer_usage;
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetLayerTransform(int32_t layer_transform) {
+  // 270* and 180* cannot be combined with flips. More specifically, they
+  // already contain both horizontal and vertical flips, so those fields are
+  // redundant in this case. 90* rotation can be combined with either horizontal
+  // flip or vertical flip, so treat it differently
+  int32_t temp = 0;
+  if (layer_transform == IAHWC_TRANSFORM_ROT_270) {
+    temp = hwcomposer::HWCTransform::kTransform270;
+  } else if (layer_transform == IAHWC_TRANSFORM_ROT_180) {
+    temp = hwcomposer::HWCTransform::kTransform180;
+  } else {
+    if (layer_transform & IAHWC_TRANSFORM_FLIP_H)
+      temp |= hwcomposer::HWCTransform::kReflectX;
+    if (layer_transform & IAHWC_TRANSFORM_FLIP_V)
+      temp |= hwcomposer::HWCTransform::kReflectY;
+    if (layer_transform & IAHWC_TRANSFORM_ROT_90)
+      temp |= hwcomposer::HWCTransform::kTransform90;
+  }
+  iahwc_layer_.SetTransform(temp);
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetLayerSourceCrop(iahwc_rect_t rect) {
+  iahwc_layer_.SetSourceCrop(
+      hwcomposer::HwcRect<float>(rect.left, rect.top, rect.right, rect.bottom));
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetLayerDisplayFrame(iahwc_rect_t rect) {
+  iahwc_layer_.SetDisplayFrame(
+      hwcomposer::HwcRect<float>(rect.left, rect.top, rect.right, rect.bottom),
+      0);
+
+  return IAHWC_ERROR_NONE;
+}
+
+int IAHWC::IAHWCLayer::SetLayerSurfaceDamage(iahwc_region_t region) {
+  uint32_t num_rects = region.numRects;
+  hwcomposer::HwcRegion hwc_region;
+
+  for (size_t rect = 0; rect < num_rects; ++rect) {
+    hwc_region.emplace_back(region.rects[rect].left, region.rects[rect].top,
+                            region.rects[rect].right,
+                            region.rects[rect].bottom);
+  }
+
+  iahwc_layer_.SetSurfaceDamage(hwc_region);
+
+  return IAHWC_ERROR_NONE;
+}
+
+hwcomposer::HwcLayer* IAHWC::IAHWCLayer::GetLayer() {
+  return &iahwc_layer_;
+}
+
+} // namespace hwcomposer
+
+iahwc_module_t IAHWC_MODULE_INFO = {
+  .name = "IA Hardware Composer",
+  .open = hwcomposer::IAHWC::HookOpen,
+};
diff --git a/os/linux/linux_frontend.h b/os/linux/linux_frontend.h
new file mode 100644 (file)
index 0000000..2cfb145
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ */
+
+#ifndef LINUX_FRONTEND_H_
+#define LINUX_FRONTEND_H_
+
+#include <gpudevice.h>
+#include <hwcdefs.h>
+#include <hwclayer.h>
+#include <map>
+#include <type_traits>
+#include <vector>
+#include "iahwc.h"
+
+namespace hwcomposer {
+
+class IAHWC : public iahwc_device {
+ public:
+  IAHWC();
+  int32_t Init();
+
+  class IAHWCLayer {
+   public:
+    IAHWCLayer();
+    ~IAHWCLayer();
+    int SetBo(gbm_bo* bo);
+    int SetAcquireFence(int32_t acquire_fence);
+    int SetLayerUsage(int32_t layer_usage);
+    int32_t GetLayerUsage() {
+      return layer_usage_;
+    }
+    int SetLayerTransform(int32_t layer_transform);
+    int SetLayerSourceCrop(iahwc_rect_t rect);
+    int SetLayerDisplayFrame(iahwc_rect_t rect);
+    int SetLayerSurfaceDamage(iahwc_region_t region);
+    hwcomposer::HwcLayer* GetLayer();
+
+   private:
+    hwcomposer::HwcLayer iahwc_layer_;
+    struct gbm_handle hwc_handle_;
+    int32_t layer_usage_;
+  };
+
+  class IAHWCDisplay {
+   public:
+    IAHWCDisplay();
+    int Init(hwcomposer::NativeDisplay* display);
+    int GetDisplayInfo(uint32_t config, int attribute, int32_t* value);
+    int GetDisplayName(uint32_t* size, char* name);
+    int GetDisplayConfigs(uint32_t* num_configs, uint32_t* configs);
+    int SetDisplayGamma(float r, float b, float g);
+    int SetDisplayConfig(uint32_t config);
+    int GetDisplayConfig(uint32_t* config);
+    int ClearAllLayers();
+    int PresentDisplay(int32_t* release_fd);
+    int RegisterVsyncCallback(iahwc_callback_data_t data,
+                              iahwc_function_ptr_t hook);
+    int CreateLayer(uint32_t* layer_handle);
+    bool IsConnected();
+    IAHWCLayer& get_layer(iahwc_layer_t layer) {
+      return layers_.at(layer);
+    }
+
+   private:
+    hwcomposer::NativeDisplay* native_display_;
+    std::map<iahwc_layer_t, IAHWCLayer> layers_;
+  };
+
+  static IAHWC* toIAHWC(iahwc_device_t* dev) {
+    return static_cast<IAHWC*>(dev);
+  }
+
+  static int HookOpen(const iahwc_module_t*, iahwc_device_t**);
+  static int HookClose(iahwc_device_t*);
+  static iahwc_function_ptr_t HookGetFunctionPtr(iahwc_device_t*, int);
+
+  template <typename PFN, typename T>
+  static iahwc_function_ptr_t ToHook(T function) {
+    static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer");
+    return reinterpret_cast<iahwc_function_ptr_t>(function);
+  }
+
+  template <typename T, typename HookType, HookType func, typename... Args>
+  static T DeviceHook(iahwc_device_t* dev, Args... args) {
+    IAHWC* hwc = toIAHWC(dev);
+    return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
+  }
+
+  template <typename HookType, HookType func, typename... Args>
+  static int32_t DisplayHook(iahwc_device_t* dev,
+                             iahwc_display_t display_handle, Args... args) {
+    IAHWC* hwc = toIAHWC(dev);
+    IAHWCDisplay* display = hwc->displays_.at(display_handle);
+    return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...));
+  }
+
+  template <typename HookType, HookType func, typename... Args>
+  static int32_t LayerHook(iahwc_device_t* dev, iahwc_display_t display_handle,
+                           iahwc_layer_t layer_handle, Args... args) {
+    IAHWC* hwc = toIAHWC(dev);
+    IAHWCDisplay* display = hwc->displays_.at(display_handle);
+    IAHWCLayer& layer = display->get_layer(layer_handle);
+
+    return static_cast<int32_t>((layer.*func)(std::forward<Args>(args)...));
+  }
+
+ private:
+  int GetNumDisplays(int* num_displays);
+  int RegisterCallback(int32_t description, uint32_t display_handle,
+                       iahwc_callback_data_t data, iahwc_function_ptr_t hook);
+  hwcomposer::GpuDevice device_;
+  std::vector<IAHWCDisplay*> displays_;
+};
+
+} // namespace hwcomposer
+#endif
index e17c009..fd6d28d 100644 (file)
 #ifndef OS_LINUX_PLATFORMDEFINES_H_
 #define OS_LINUX_PLATFORMDEFINES_H_
 
-#include <stdio.h>
-#include <stddef.h>
 #include <gbm.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <cmath>
 
 #include <va/va_drm.h>
 
index 1c69abc..c28db3a 100644 (file)
@@ -21,7 +21,8 @@
 #  SOFTWARE.
 #
 
-bin_PROGRAMS = testlayers
+bin_PROGRAMS = testlayers \
+              linux_test
 
 testlayers_LDFLAGS = \
        -no-undefined
@@ -65,3 +66,31 @@ testlayers_SOURCES +=   \
     ./common/cclayerrenderer.cpp
 
 endif
+
+linux_test_LDFLAGS = \
+       -no-undefined
+
+linux_test_LDADD = \
+       $(DRM_LIBS) \
+       $(GBM_LIBS) \
+       $(EGL_LIBS) \
+       $(GLES2_LIBS) \
+       -ldl    \
+       $(top_builddir)/tests/third_party/json-c/libjson-c.la \
+       $(top_builddir)/libhwcomposer.la
+
+linux_test_CFLAGS = \
+       -O0 -g -lm \
+       $(DRM_CFLAGS) \
+       $(GBM_CFLAGS) \
+       $(EGL_CFLAGS) \
+       $(GLES2_CFLAGS) \
+        $(AM_CPPFLAGS)
+
+linux_test_SOURCES = \
+    ./common/layerrenderer.cpp \
+    ./common/gllayerrenderer.cpp \
+    ./common/glcubelayerrenderer.cpp \
+    ./common/esTransform.cpp \
+    ./common/jsonhandlers.cpp \
+    ./apps/linux_frontend_test.cpp
diff --git a/tests/apps/linux_frontend_test.cpp b/tests/apps/linux_frontend_test.cpp
new file mode 100644 (file)
index 0000000..616811d
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * Copyright (c) 2012 Arvin Schnell <arvin.schnell@gmail.com>
+ * Copyright (c) 2012 Rob Clark <rob@ti.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* Based on a egl cube test app originally written by Arvin Schnell */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <linux/kd.h>
+#include <linux/major.h>
+#include <linux/vt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+
+#include <drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+// clang-format off
+#include "esUtil.h"
+#include <EGL/eglext.h>
+#include <GLES2/gl2ext.h>
+// clang-format on
+
+#include <libsync.h>
+
+#include <gpudevice.h>
+#include <hwclayer.h>
+#include <hwcdefs.h>
+#include <nativedisplay.h>
+#include <platformdefines.h>
+#include <spinlock.h>
+
+#include <iahwc.h>
+
+#include "glcubelayerrenderer.h"
+#include "videolayerrenderer.h"
+#include "imagelayerrenderer.h"
+#include "cclayerrenderer.h"
+#include "jsonhandlers.h"
+
+#include <nativebufferhandler.h>
+#include "platformcommondefines.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+int tty;
+
+static void reset_vt() {
+  struct vt_mode mode = {0};
+
+  if (ioctl(tty, KDSETMODE, KD_TEXT))
+    fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
+
+  mode.mode = VT_AUTO;
+  if (ioctl(tty, VT_SETMODE, &mode) < 0)
+    fprintf(stderr, "could not reset vt handling\n");
+
+  exit(0);
+}
+
+static void handle_signal(int sig) {
+  if (sig == 11)
+    printf("received SIGSEGV\n");
+  fflush(stdout);
+  reset_vt();
+}
+
+static int setup_tty() {
+  struct vt_mode mode = {0};
+  struct stat buf;
+  int ret, kd_mode;
+
+  tty = dup(STDIN_FILENO);
+
+  if (fstat(tty, &buf) == -1 || major(buf.st_rdev) != TTY_MAJOR) {
+    fprintf(stderr, "Please run the program in a vt \n");
+    goto err_close;
+  }
+
+  ret = ioctl(tty, KDGETMODE, &kd_mode);
+  if (ret) {
+    fprintf(stderr, "failed to get VT mode: %m\n");
+    return -1;
+  }
+
+  if (kd_mode != KD_TEXT) {
+    fprintf(stderr,
+            "Already in graphics mode, "
+            "is a display server running?\n");
+    goto err_close;
+  }
+
+  ioctl(tty, VT_ACTIVATE, minor(buf.st_rdev));
+  ioctl(tty, VT_WAITACTIVE, minor(buf.st_rdev));
+
+  ret = ioctl(tty, KDSETMODE, KD_GRAPHICS);
+  if (ret) {
+    fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n");
+    goto err_close;
+  }
+
+  mode.mode = VT_PROCESS;
+  mode.relsig = 0;
+  mode.acqsig = 0;
+  if (ioctl(tty, VT_SETMODE, &mode) < 0) {
+    fprintf(stderr, "failed to take control of vt handling\n");
+    goto err_close;
+  }
+
+  struct sigaction act;
+  act.sa_handler = handle_signal;
+  act.sa_flags = SA_RESETHAND;
+  sigaction(SIGINT, &act, NULL);
+  sigaction(SIGSEGV, &act, NULL);
+  sigaction(SIGABRT, &act, NULL);
+
+  atexit(reset_vt);
+
+  return 0;
+
+err_close:
+  close(tty);
+  exit(0);
+}
+
+/* Exit after rendering the given number of frames. If 0, then continue
+ * rendering forever.
+ */
+static uint64_t arg_frames = 0;
+
+/*flag set to test displaymode*/
+static int display_mode;
+int force_mode = 0, config_index = 0, print_display_config = 0;
+LAYER_PARAMETER layer_parameter;
+
+glContext gl;
+
+struct iahwc_backend {
+  iahwc_module_t *iahwc_module;
+  iahwc_device_t *iahwc_device;
+  IAHWC_PFN_GET_NUM_DISPLAYS iahwc_get_num_displays;
+  IAHWC_PFN_REGISTER_CALLBACK iahwc_register_callback;
+  IAHWC_PFN_DISPLAY_GET_INFO iahwc_get_display_info;
+  IAHWC_PFN_DISPLAY_GET_NAME iahwc_get_display_name;
+  IAHWC_PFN_DISPLAY_GET_CONFIGS iahwc_get_display_configs;
+  IAHWC_PFN_DISPLAY_SET_GAMMA iahwc_set_display_gamma;
+  IAHWC_PFN_DISPLAY_SET_CONFIG iahwc_set_display_config;
+  IAHWC_PFN_DISPLAY_GET_CONFIG iahwc_get_display_config;
+  IAHWC_PFN_PRESENT_DISPLAY iahwc_present_display;
+  IAHWC_PFN_CREATE_LAYER iahwc_create_layer;
+  IAHWC_PFN_LAYER_SET_BO iahwc_layer_set_bo;
+  IAHWC_PFN_LAYER_SET_ACQUIRE_FENCE iahwc_layer_set_acquire_fence;
+  IAHWC_PFN_LAYER_SET_USAGE iahwc_layer_set_usage;
+  IAHWC_PFN_LAYER_SET_TRANSFORM iahwc_layer_set_transform;
+  IAHWC_PFN_LAYER_SET_SOURCE_CROP iahwc_layer_set_source_crop;
+  IAHWC_PFN_LAYER_SET_DISPLAY_FRAME iahwc_layer_set_display_frame;
+  IAHWC_PFN_LAYER_SET_SURFACE_DAMAGE iahwc_layer_set_surface_damage;
+  IAHWC_PFN_VSYNC iahwc_vsync;
+
+} * backend;
+
+struct frame {
+  std::vector<iahwc_layer_t> layers;
+  std::vector<gbm_bo *> layer_bos;
+  std::vector<std::unique_ptr<LayerRenderer>> layer_renderers;
+  std::vector<std::vector<uint32_t>> layers_fences;
+  std::vector<int32_t> fences;
+};
+
+bool init_gl() {
+  EGLint major, minor, n;
+  static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
+                                           EGL_NONE};
+
+  static const EGLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_DONT_CARE,
+                                          EGL_NONE};
+
+  gl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+  if (!eglInitialize(gl.display, &major, &minor)) {
+    printf("failed to initialize EGL\n");
+    return false;
+  }
+
+#define get_proc(name, proc)                  \
+  do {                                        \
+    gl.name = (proc)eglGetProcAddress(#name); \
+    assert(gl.name);                          \
+  } while (0)
+  get_proc(glEGLImageTargetRenderbufferStorageOES,
+           PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC);
+  get_proc(eglCreateImageKHR, PFNEGLCREATEIMAGEKHRPROC);
+  get_proc(eglCreateSyncKHR, PFNEGLCREATESYNCKHRPROC);
+  get_proc(eglDestroySyncKHR, PFNEGLDESTROYSYNCKHRPROC);
+  get_proc(eglWaitSyncKHR, PFNEGLWAITSYNCKHRPROC);
+  get_proc(eglClientWaitSyncKHR, PFNEGLCLIENTWAITSYNCKHRPROC);
+  get_proc(eglDupNativeFenceFDANDROID, PFNEGLDUPNATIVEFENCEFDANDROIDPROC);
+  get_proc(glEGLImageTargetTexture2DOES, PFNGLEGLIMAGETARGETTEXTURE2DOESPROC);
+  get_proc(eglDestroyImageKHR, PFNEGLDESTROYIMAGEKHRPROC);
+
+  printf("Using display %p with EGL version %d.%d\n", gl.display, major, minor);
+
+  printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
+  printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
+  printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
+
+  if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+    printf("failed to bind api EGL_OPENGL_ES_API\n");
+    return false;
+  }
+  if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) ||
+      n != 1) {
+    printf("failed to choose config: %d\n", n);
+    return false;
+  }
+  gl.context =
+      eglCreateContext(gl.display, gl.config, EGL_NO_CONTEXT, context_attribs);
+  if (gl.context == NULL) {
+    printf("failed to create context\n");
+    return false;
+  }
+  return true;
+}
+
+static struct frame frames[2];
+
+char json_path[1024];
+char log_path[1024];
+TEST_PARAMETERS test_parameters;
+hwcomposer::NativeBufferHandler *buffer_handler;
+
+static uint32_t layerformat2gbmformat(LAYER_FORMAT format,
+                                      uint32_t *usage_format, uint32_t *usage) {
+  *usage = 0;
+
+  switch (format) {
+    case LAYER_FORMAT_C8:
+      return DRM_FORMAT_C8;
+    case LAYER_FORMAT_R8:
+      return DRM_FORMAT_R8;
+    case LAYER_FORMAT_GR88:
+      return DRM_FORMAT_GR88;
+    case LAYER_FORMAT_RGB332:
+      return DRM_FORMAT_RGB332;
+    case LAYER_FORMAT_BGR233:
+      return DRM_FORMAT_BGR233;
+    case LAYER_FORMAT_XRGB4444:
+      return DRM_FORMAT_XRGB4444;
+    case LAYER_FORMAT_XBGR4444:
+      return DRM_FORMAT_XBGR4444;
+    case LAYER_FORMAT_RGBX4444:
+      return DRM_FORMAT_RGBX4444;
+    case LAYER_FORMAT_BGRX4444:
+      return DRM_FORMAT_BGRX4444;
+    case LAYER_FORMAT_ARGB4444:
+      return DRM_FORMAT_ARGB4444;
+    case LAYER_FORMAT_ABGR4444:
+      return DRM_FORMAT_ABGR4444;
+    case LAYER_FORMAT_RGBA4444:
+      return DRM_FORMAT_RGBA4444;
+    case LAYER_FORMAT_BGRA4444:
+      return DRM_FORMAT_BGRA4444;
+    case LAYER_FORMAT_XRGB1555:
+      return DRM_FORMAT_XRGB1555;
+    case LAYER_FORMAT_XBGR1555:
+      return DRM_FORMAT_XBGR1555;
+    case LAYER_FORMAT_RGBX5551:
+      return DRM_FORMAT_RGBX5551;
+    case LAYER_FORMAT_BGRX5551:
+      return DRM_FORMAT_BGRX5551;
+    case LAYER_FORMAT_ARGB1555:
+      return DRM_FORMAT_ARGB1555;
+    case LAYER_FORMAT_ABGR1555:
+      return DRM_FORMAT_ABGR1555;
+    case LAYER_FORMAT_RGBA5551:
+      return DRM_FORMAT_RGBA5551;
+    case LAYER_FORMAT_BGRA5551:
+      return DRM_FORMAT_BGRA5551;
+    case LAYER_FORMAT_RGB565:
+      return DRM_FORMAT_RGB565;
+    case LAYER_FORMAT_BGR565:
+      return DRM_FORMAT_BGR565;
+    case LAYER_FORMAT_RGB888:
+      return DRM_FORMAT_RGB888;
+    case LAYER_FORMAT_BGR888:
+      return DRM_FORMAT_BGR888;
+    case LAYER_FORMAT_XRGB8888:
+      return DRM_FORMAT_XRGB8888;
+    case LAYER_FORMAT_XBGR8888:
+      return DRM_FORMAT_XBGR8888;
+    case LAYER_FORMAT_RGBX8888:
+      return DRM_FORMAT_RGBX8888;
+    case LAYER_FORMAT_BGRX8888:
+      return DRM_FORMAT_BGRX8888;
+    case LAYER_FORMAT_ARGB8888:
+      return DRM_FORMAT_ARGB8888;
+    case LAYER_FORMAT_ABGR8888:
+      return DRM_FORMAT_ABGR8888;
+    case LAYER_FORMAT_RGBA8888:
+      return DRM_FORMAT_RGBA8888;
+    case LAYER_FORMAT_BGRA8888:
+      return DRM_FORMAT_BGRA8888;
+    case LAYER_FORMAT_XRGB2101010:
+      return DRM_FORMAT_XRGB2101010;
+    case LAYER_FORMAT_XBGR2101010:
+      return DRM_FORMAT_XBGR2101010;
+    case LAYER_FORMAT_RGBX1010102:
+      return DRM_FORMAT_RGBX1010102;
+    case LAYER_FORMAT_BGRX1010102:
+      return DRM_FORMAT_BGRX1010102;
+    case LAYER_FORMAT_ARGB2101010:
+      return DRM_FORMAT_ARGB2101010;
+    case LAYER_FORMAT_ABGR2101010:
+      return DRM_FORMAT_ABGR2101010;
+    case LAYER_FORMAT_RGBA1010102:
+      return DRM_FORMAT_RGBA1010102;
+    case LAYER_FORMAT_BGRA1010102:
+      return DRM_FORMAT_BGRA1010102;
+    case LAYER_FORMAT_YUYV:
+      return DRM_FORMAT_YUYV;
+    case LAYER_FORMAT_YVYU:
+      return DRM_FORMAT_YVYU;
+    case LAYER_FORMAT_UYVY:
+      return DRM_FORMAT_UYVY;
+    case LAYER_FORMAT_VYUY:
+      return DRM_FORMAT_VYUY;
+    case LAYER_FORMAT_AYUV:
+      return DRM_FORMAT_AYUV;
+    case LAYER_FORMAT_NV12:
+      return DRM_FORMAT_NV12;
+    case LAYER_FORMAT_NV21:
+      return DRM_FORMAT_NV21;
+    case LAYER_FORMAT_NV16:
+      return DRM_FORMAT_NV16;
+    case LAYER_FORMAT_NV61:
+      return DRM_FORMAT_NV61;
+    case LAYER_FORMAT_YUV410:
+      return DRM_FORMAT_YUV410;
+    case LAYER_FORMAT_YVU410:
+      return DRM_FORMAT_YVU410;
+    case LAYER_FORMAT_YUV411:
+      return DRM_FORMAT_YUV411;
+    case LAYER_FORMAT_YVU411:
+      return DRM_FORMAT_YVU411;
+    case LAYER_FORMAT_YUV420:
+      return DRM_FORMAT_YUV420;
+    case LAYER_FORMAT_YVU420:
+      return DRM_FORMAT_YVU420;
+    case LAYER_FORMAT_YUV422:
+      return DRM_FORMAT_YUV422;
+    case LAYER_FORMAT_YVU422:
+      return DRM_FORMAT_YVU422;
+    case LAYER_FORMAT_YUV444:
+      return DRM_FORMAT_YUV444;
+    case LAYER_FORMAT_YVU444:
+      return DRM_FORMAT_YVU444;
+    case LAYER_HAL_PIXEL_FORMAT_YV12:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YV12;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_YVU420_ANDROID;
+    case LAYER_HAL_PIXEL_FORMAT_Y8:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_Y8;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R8;
+    case LAYER_HAL_PIXEL_FORMAT_Y16:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_Y16;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R16;
+    case LAYER_HAL_PIXEL_FORMAT_YCbCr_444_888:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCbCr_444_888;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_YUV444;
+    case LAYER_HAL_PIXEL_FORMAT_YCbCr_422_I:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCbCr_422_I;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_YUYV;
+    case LAYER_HAL_PIXEL_FORMAT_YCbCr_422_SP:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCbCr_422_SP;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_NV16;
+    case LAYER_HAL_PIXEL_FORMAT_YCbCr_422_888:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCbCr_422_888;
+      *usage |= hwcomposer::kLayerVideo;
+      return DRM_FORMAT_YUV422;
+    case LAYER_HAL_PIXEL_FORMAT_YCbCr_420_888:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCbCr_420_888;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_NV12;
+    case LAYER_HAL_PIXEL_FORMAT_YCrCb_420_SP:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_YCrCb_420_SP;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_NV21;
+    case LAYER_HAL_PIXEL_FORMAT_RAW16:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_RAW16;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R16;
+    case LAYER_HAL_PIXEL_FORMAT_RAW_OPAQUE:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_RAW_OPAQUE;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R16;
+    case LAYER_HAL_PIXEL_FORMAT_BLOB:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_BLOB;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R8;
+    case LAYER_ANDROID_SCALER_AVAILABLE_FORMATS_RAW16:
+      *usage_format = LAYER_ANDROID_SCALER_AVAILABLE_FORMATS_RAW16;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_R16;
+    case LAYER_HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
+      *usage_format = LAYER_HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL;
+      *usage = hwcomposer::kLayerVideo;
+      return DRM_FORMAT_NV12_Y_TILED_INTEL;
+    case LAYER_FORMAT_UNDEFINED:
+      return (uint32_t)-1;
+  }
+
+  return (uint32_t)-1;
+}
+
+static void fill_hwclayer(iahwc_layer_t layer_handle_,
+                          LAYER_PARAMETER *pParameter,
+                          LayerRenderer *pRenderer) {
+  backend->iahwc_layer_set_transform(backend->iahwc_device, 0, layer_handle_,
+                                     pParameter->transform);
+  backend->iahwc_layer_set_source_crop(
+      backend->iahwc_device, 0, layer_handle_,
+      {pParameter->source_crop_x, pParameter->source_crop_y,
+       pParameter->source_crop_width, pParameter->source_crop_height});
+  backend->iahwc_layer_set_display_frame(
+      backend->iahwc_device, 0, layer_handle_,
+      {pParameter->frame_x, pParameter->frame_y, pParameter->frame_width,
+       pParameter->frame_height});
+}
+
+static void init_frames(int32_t width, int32_t height) {
+  size_t LAYER_PARAM_SIZE;
+  if (display_mode) {
+    layer_parameter.type = static_cast<LAYER_TYPE>(0);
+    layer_parameter.format = static_cast<LAYER_FORMAT>(25);
+    layer_parameter.transform = static_cast<LAYER_TRANSFORM>(0);
+    layer_parameter.resource_path = "";
+    layer_parameter.source_width = width;
+    layer_parameter.source_height = height;
+    layer_parameter.source_crop_x = 0;
+    layer_parameter.source_crop_y = 0;
+    layer_parameter.source_crop_width = width;
+    layer_parameter.source_crop_height = height;
+    layer_parameter.frame_x = 0;
+    layer_parameter.frame_y = 0;
+    layer_parameter.frame_width = width;
+    layer_parameter.frame_height = height;
+    LAYER_PARAM_SIZE = 1;
+  } else {
+    parseParametersJson(json_path, &test_parameters);
+    LAYER_PARAM_SIZE = test_parameters.layers_parameters.size();
+  }
+  for (size_t j = 0; j < LAYER_PARAM_SIZE; ++j) {
+    if (!display_mode) {
+      layer_parameter = test_parameters.layers_parameters[j];
+      if (layer_parameter.source_width > width)
+        layer_parameter.source_width = width;
+
+      if (layer_parameter.source_height > height)
+        layer_parameter.source_height = height;
+
+      if (layer_parameter.source_crop_width > width)
+        layer_parameter.source_crop_width = width;
+
+      if (layer_parameter.source_crop_height > height)
+        layer_parameter.source_crop_height = height;
+
+      if (layer_parameter.frame_width > width)
+        layer_parameter.frame_width = width;
+
+      if (layer_parameter.frame_height > height)
+        layer_parameter.frame_height = height;
+    }
+
+    LayerRenderer *renderer = NULL;
+    // hwcomposer::HwcLayer *hwc_layer = NULL;
+    iahwc_layer_t layer_handle_;
+    backend->iahwc_create_layer(backend->iahwc_device, 0, &layer_handle_);
+    uint32_t usage_format, usage;
+    uint64_t modificators[4];
+    uint32_t gbm_format =
+        layerformat2gbmformat(layer_parameter.format, &usage_format, &usage);
+
+    switch (layer_parameter.type) {
+      case LAYER_TYPE_GL:
+        renderer = new GLCubeLayerRenderer(buffer_handler, false);
+        break;
+      default:
+        printf("un-recognized layer type!\n");
+        exit(-1);
+    }
+
+    if (!renderer->Init(layer_parameter.source_width,
+                        layer_parameter.source_height, gbm_format, usage_format,
+                        usage, &gl, layer_parameter.resource_path.c_str())) {
+      printf("\nrender init not successful\n");
+      exit(-1);
+    }
+
+    fill_hwclayer(layer_handle_, &layer_parameter, renderer);
+    for (size_t i = 0; i < ARRAY_SIZE(frames); ++i) {
+      struct frame *frame = &frames[i];
+      frame->layers_fences.resize(LAYER_PARAM_SIZE);
+      frame->layers.push_back(layer_handle_);
+      frame->layer_renderers.push_back(
+          std::unique_ptr<LayerRenderer>(renderer));
+      gbm_handle *buffer_handle_ = renderer->GetNativeBoHandle();
+      frame->layer_bos.push_back(buffer_handle_->bo);
+    }
+  }
+}
+
+static void print_help(void) {
+  printf(
+      "usage: testjsonlayers [-h|--help] [-f|--frames <frames>] [-j|--json "
+      "<jsonfile>] [-p|--powermode <on/off/doze/dozesuspend>][--displaymode "
+      "<print/forcemode displayconfigindex]\n");
+}
+
+static void parse_args(int argc, char *argv[]) {
+  static const struct option longopts[] = {
+      {"help", no_argument, NULL, 'h'},
+      {"frames", required_argument, NULL, 'f'},
+      {"json", required_argument, NULL, 'j'},
+      {"log", required_argument, NULL, 'l'},
+      {"displaymode", required_argument, &display_mode, 1},
+      {0},
+  };
+
+  char *endptr;
+  int opt;
+  int longindex = 0;
+  FILE *fp;
+
+  /* Suppress getopt's poor error messages */
+  opterr = 0;
+
+  while ((opt = getopt_long(argc, argv, "+:hf:j:l:", longopts,
+                            /*longindex*/ &longindex)) != -1) {
+    switch (opt) {
+      case 0:
+        if (!strcmp(optarg, "forcemode")) {
+          force_mode = 1;
+          config_index = atoi(argv[optind++]);
+        }
+        if (!strcmp(optarg, "print")) {
+          print_display_config = 1;
+        }
+        break;
+      case 'h':
+        print_help();
+        exit(0);
+        break;
+      case 'j':
+        if (strlen(optarg) >= 1024) {
+          printf("too long json file path, litmited less than 1024!\n");
+          exit(0);
+        }
+        printf("optarg:%s\n", optarg);
+        strcpy(json_path, optarg);
+        break;
+      case 'f':
+        errno = 0;
+        arg_frames = strtoul(optarg, &endptr, 0);
+        if (errno || *endptr != '\0') {
+          fprintf(stderr, "usage error: invalid value for <frames>\n");
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case 'l':
+        if (strlen(optarg) >= 1024) {
+          printf(
+              "too long log file path, please provide less than 1024 "
+              "characters!\n");
+          exit(0);
+        }
+        printf("optarg:%s\n", optarg);
+        strcpy(log_path, optarg);
+        fp = freopen(log_path, "w", stdout);
+        fp = freopen(log_path, "a", stderr);
+        if (!fp) {
+          printf("unable to open log file\n");
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case ':':
+        fprintf(stderr, "usage error: %s requires an argument\n",
+                argv[optind - 1]);
+        exit(EXIT_FAILURE);
+        break;
+      case '?':
+      default:
+        assert(opt == '?');
+        fprintf(stderr, "usage error: unknown option '%s'\n", argv[optind - 1]);
+        exit(EXIT_FAILURE);
+        break;
+    }
+  }
+
+  if (optind < argc) {
+    fprintf(stderr, "usage error: trailing args\n");
+    exit(EXIT_FAILURE);
+  }
+}
+
+int main(int argc, char *argv[]) {
+  int ret, fd, primary_width, primary_height;
+  void *iahwc_dl_handle;
+  iahwc_module_t *iahwc_module;
+  iahwc_device_t *iahwc_device;
+  int num_displays, i;
+  uint num_configs;
+  uint32_t *configs, preferred_config;
+  int32_t kms_fence = -1;
+
+  setup_tty();
+
+  backend = new iahwc_backend;
+
+  iahwc_dl_handle = dlopen("libhwcomposer.so", RTLD_NOW);
+  if (!iahwc_dl_handle) {
+    printf("Unable to open libhwcomposer.so: %s\n", dlerror());
+    printf("aborting...\n");
+    abort();
+  }
+
+  iahwc_module = (iahwc_module_t *)dlsym(iahwc_dl_handle, IAHWC_MODULE_STR);
+  iahwc_module->open(iahwc_module, &iahwc_device);
+
+  backend->iahwc_module = iahwc_module;
+  backend->iahwc_device = iahwc_device;
+
+  backend->iahwc_get_num_displays =
+      (IAHWC_PFN_GET_NUM_DISPLAYS)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_GET_NUM_DISPLAYS);
+  backend->iahwc_create_layer =
+      (IAHWC_PFN_CREATE_LAYER)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_CREATE_LAYER);
+  backend->iahwc_get_display_info =
+      (IAHWC_PFN_DISPLAY_GET_INFO)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_GET_INFO);
+  backend->iahwc_get_display_configs =
+      (IAHWC_PFN_DISPLAY_GET_CONFIGS)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_GET_CONFIGS);
+  backend->iahwc_get_display_name =
+      (IAHWC_PFN_DISPLAY_GET_NAME)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_GET_NAME);
+  backend->iahwc_set_display_gamma =
+      (IAHWC_PFN_DISPLAY_SET_GAMMA)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_SET_GAMMA);
+  backend->iahwc_set_display_config =
+      (IAHWC_PFN_DISPLAY_SET_CONFIG)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_SET_CONFIG);
+  backend->iahwc_get_display_config =
+      (IAHWC_PFN_DISPLAY_GET_CONFIG)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_DISPLAY_GET_CONFIG);
+  backend->iahwc_present_display =
+      (IAHWC_PFN_PRESENT_DISPLAY)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_PRESENT_DISPLAY);
+  backend->iahwc_layer_set_bo =
+      (IAHWC_PFN_LAYER_SET_BO)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_BO);
+  backend->iahwc_layer_set_acquire_fence =
+      (IAHWC_PFN_LAYER_SET_ACQUIRE_FENCE)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_ACQUIRE_FENCE);
+  backend->iahwc_layer_set_transform =
+      (IAHWC_PFN_LAYER_SET_TRANSFORM)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_TRANSFORM);
+  backend->iahwc_layer_set_source_crop =
+      (IAHWC_PFN_LAYER_SET_SOURCE_CROP)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_SOURCE_CROP);
+  backend->iahwc_layer_set_display_frame =
+      (IAHWC_PFN_LAYER_SET_DISPLAY_FRAME)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_DISPLAY_FRAME);
+  backend->iahwc_layer_set_surface_damage =
+      (IAHWC_PFN_LAYER_SET_SURFACE_DAMAGE)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_LAYER_SET_SURFACE_DAMAGE);
+  backend->iahwc_register_callback =
+      (IAHWC_PFN_REGISTER_CALLBACK)iahwc_device->getFunctionPtr(
+          iahwc_device, IAHWC_FUNC_REGISTER_CALLBACK);
+
+  parse_args(argc, argv);
+
+  fd = open("/dev/dri/renderD128", O_RDWR);
+  if (fd == -1) {
+    ETRACE("Can't open GPU file");
+    exit(-1);
+  }
+
+  buffer_handler = hwcomposer::NativeBufferHandler::CreateInstance(fd);
+
+  if (!buffer_handler)
+    exit(-1);
+
+  if (!init_gl()) {
+    delete buffer_handler;
+    exit(-1);
+  }
+
+  backend->iahwc_get_num_displays(iahwc_device, &num_displays);
+  printf("Number of displays available is %d\n", num_displays);
+
+  backend->iahwc_get_display_configs(iahwc_device, 0, &num_configs, NULL);
+  printf("Number of configs %d\n", num_configs);
+  configs = new uint32_t[num_configs];
+  backend->iahwc_get_display_configs(iahwc_device, 0, &num_configs, configs);
+  backend->iahwc_get_display_config(iahwc_device, 0, &preferred_config);
+
+  printf("Preferred config is %d\n", preferred_config);
+
+  for (i = 0; i < num_configs; i++) {
+    int width, height, refresh_rate, dpix, dpiy;
+    backend->iahwc_get_display_info(iahwc_device, 0, configs[i],
+                                    IAHWC_CONFIG_WIDTH, &width);
+    backend->iahwc_get_display_info(iahwc_device, 0, configs[i],
+                                    IAHWC_CONFIG_HEIGHT, &height);
+    backend->iahwc_get_display_info(iahwc_device, 0, configs[i],
+                                    IAHWC_CONFIG_REFRESHRATE, &refresh_rate);
+    backend->iahwc_get_display_info(iahwc_device, 0, configs[i],
+                                    IAHWC_CONFIG_DPIX, &dpix);
+    backend->iahwc_get_display_info(iahwc_device, 0, configs[i],
+                                    IAHWC_CONFIG_DPIY, &dpiy);
+
+    printf(
+        "Config %d: width %d, height %d, refresh rate %d, dpix %d, dpiy %d\n",
+        configs[i], width, height, refresh_rate, dpix, dpiy);
+
+    if (configs[i] == preferred_config) {
+      primary_width = width;
+      primary_height = height;
+    }
+  }
+
+  printf("Width of primary display is %d height of the primary display is %d\n",
+         primary_width, primary_height);
+
+  init_frames(primary_width, primary_height);
+
+  int64_t gpu_fence_fd = -1; /* out-fence from gpu, in-fence to kms */
+  uint32_t frame_total = 0;
+
+  for (uint64_t i = 0; arg_frames == 0 || i < arg_frames; ++i) {
+    struct frame *frame = &frames[i % ARRAY_SIZE(frames)];
+    if (kms_fence != -1) {
+      sync_wait(kms_fence, -1);
+      close(kms_fence);
+      kms_fence = -1;
+    }
+
+    for (uint32_t j = 0; j < frame->layers.size(); j++) {
+      frame->layers_fences[j].clear();
+      frame->layer_renderers[j]->Draw(&gpu_fence_fd);
+      backend->iahwc_layer_set_acquire_fence(iahwc_device, 0, frame->layers[j],
+                                             gpu_fence_fd);
+      iahwc_region_t damage_region;
+      damage_region.numRects = 1;
+      iahwc_rect_t *rect = new iahwc_rect_t[1];
+      rect[0] = {layer_parameter.frame_x, layer_parameter.frame_y,
+                 layer_parameter.frame_width, layer_parameter.frame_height};
+      damage_region.rects = rect;
+      backend->iahwc_layer_set_surface_damage(iahwc_device, 0, frame->layers[j],
+                                              damage_region);
+      backend->iahwc_layer_set_bo(iahwc_device, 0, frame->layers[j],
+                                  frame->layer_bos[j]);
+    }
+
+    backend->iahwc_present_display(iahwc_device, 0, &kms_fence);
+    frame_total++;
+  }
+
+  reset_vt();
+  return 0;
+}