From: Harish Krupo Date: Fri, 17 Nov 2017 20:47:05 +0000 (+0530) Subject: Linux Backend Support X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=059fcc31f8f634020fcb82b61e41d606ce659070;p=android-x86%2Fexternal-IA-Hardware-Composer.git Linux Backend Support Jira: None. Test: Build passes on Linux. Signed-off-by: Harish Krupo --- diff --git a/Makefile.am b/Makefile.am index f6e0bb1..48d9315 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/autogen.sh b/autogen.sh index 5df14b7..39f752c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -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 $? diff --git a/configure.ac b/configure.ac index f8854b9..4ce5e4d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 +]) diff --git a/iahwc.pc.in b/iahwc.pc.in index 2ff3f41..72a1b73 100644 --- a/iahwc.pc.in +++ b/iahwc.pc.in @@ -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 index 0000000..ef27463 --- /dev/null +++ b/os/linux/iahwc.h @@ -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 +#include + +#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 index 0000000..d6b7e77 --- /dev/null +++ b/os/linux/linux_frontend.cpp @@ -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 +#include + +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(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 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( + DeviceHook); + case IAHWC_FUNC_REGISTER_CALLBACK: + return ToHook( + DeviceHook); + case IAHWC_FUNC_DISPLAY_GET_INFO: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_GET_NAME: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_GET_CONFIGS: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_SET_GAMMA: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_SET_CONFIG: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_GET_CONFIG: + return ToHook( + DisplayHook); + case IAHWC_FUNC_DISPLAY_CLEAR_ALL_LAYERS: + return ToHook( + DisplayHook); + case IAHWC_FUNC_PRESENT_DISPLAY: + return ToHook( + DisplayHook); + case IAHWC_FUNC_CREATE_LAYER: + return ToHook( + DisplayHook); + case IAHWC_FUNC_LAYER_SET_BO: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_ACQUIRE_FENCE: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_USAGE: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_TRANSFORM: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_SOURCE_CROP: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_DISPLAY_FRAME: + return ToHook( + LayerHook); + case IAHWC_FUNC_LAYER_SET_SURFACE_DAMAGE: + return ToHook( + LayerHook); + 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(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 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(data, hook); + native_display_->VSyncControl(true); + int ret = native_display_->RegisterVsyncCallback(std::move(callback), + static_cast(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(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(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 index 0000000..2cfb145 --- /dev/null +++ b/os/linux/linux_frontend.h @@ -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 +#include +#include +#include +#include +#include +#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 layers_; + }; + + static IAHWC* toIAHWC(iahwc_device_t* dev) { + return static_cast(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 + static iahwc_function_ptr_t ToHook(T function) { + static_assert(std::is_same::value, "Incompatible fn pointer"); + return reinterpret_cast(function); + } + + template + static T DeviceHook(iahwc_device_t* dev, Args... args) { + IAHWC* hwc = toIAHWC(dev); + return static_cast(((*hwc).*func)(std::forward(args)...)); + } + + template + 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((display->*func)(std::forward(args)...)); + } + + template + 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((layer.*func)(std::forward(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 displays_; +}; + +} // namespace hwcomposer +#endif diff --git a/os/linux/platformdefines.h b/os/linux/platformdefines.h index e17c009..fd6d28d 100644 --- a/os/linux/platformdefines.h +++ b/os/linux/platformdefines.h @@ -17,9 +17,10 @@ #ifndef OS_LINUX_PLATFORMDEFINES_H_ #define OS_LINUX_PLATFORMDEFINES_H_ -#include -#include #include +#include +#include +#include #include diff --git a/tests/Makefile.am b/tests/Makefile.am index 1c69abc..c28db3a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 0000000..616811d --- /dev/null +++ b/tests/apps/linux_frontend_test.cpp @@ -0,0 +1,806 @@ +/* + * Copyright (c) 2012 Arvin Schnell + * Copyright (c) 2012 Rob Clark + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// clang-format off +#include "esUtil.h" +#include +#include +// clang-format on + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "glcubelayerrenderer.h" +#include "videolayerrenderer.h" +#include "imagelayerrenderer.h" +#include "cclayerrenderer.h" +#include "jsonhandlers.h" + +#include +#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 layers; + std::vector layer_bos; + std::vector> layer_renderers; + std::vector> layers_fences; + std::vector 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(0); + layer_parameter.format = static_cast(25); + layer_parameter.transform = static_cast(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(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 ] [-j|--json " + "] [-p|--powermode ][--displaymode " + "= 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 \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; +}