summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarissa Wall <marissaw@google.com>2016-09-02 09:51:19 -0700
committerMarissa Wall <marissaw@google.com>2017-03-02 12:35:07 -0800
commit9b0d80b6b4bc520a61af6f0e4cafc206660d9709 (patch)
tree7db9a8c2dd02aae524b039756b10e661868c7fa9
parentdf4e35671b2475b8aa90e1047e48012f76802421 (diff)
downloadflounder-9b0d80b6b4bc520a61af6f0e4cafc206660d9709.tar.gz
hwc2: add hardware window support
Add support for assigning client target/layers to hardware windows. The windows have different features that they can support. Test: Add "TARGET_USES_HWC2 := true" to BoardConfig.mk. Recompile. Run testcases: https://android-review.googlesource.com/#/q/project: platform/frameworks/native+branch:master+topic:test-hwc2 Change-Id: Id578790221c4007e0b0996d605df9de2c06543db
-rw-r--r--hwc2/Android.mk5
-rw-r--r--hwc2/hwc2.h147
-rw-r--r--hwc2/hwc2_buffer.cpp92
-rw-r--r--hwc2/hwc2_display.cpp38
-rw-r--r--hwc2/hwc2_gralloc.cpp93
-rw-r--r--hwc2/hwc2_layer.cpp70
-rw-r--r--hwc2/hwc2_window.cpp160
-rw-r--r--hwc2/include/tegra_adf.h127
-rw-r--r--hwc2/original-kernel-headers/tegra_adf.h125
9 files changed, 855 insertions, 2 deletions
diff --git a/hwc2/Android.mk b/hwc2/Android.mk
index 8697126..b0a33cd 100644
--- a/hwc2/Android.mk
+++ b/hwc2/Android.mk
@@ -46,7 +46,10 @@ LOCAL_SRC_FILES := \
hwc2_callback.cpp \
hwc2_layer.cpp \
hwc2_buffer.cpp \
- hwc2_gralloc.cpp
+ hwc2_gralloc.cpp \
+ hwc2_window.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_MODLE_TAGS := optional
diff --git a/hwc2/hwc2.h b/hwc2/hwc2.h
index 423f589..3ef4cef 100644
--- a/hwc2/hwc2.h
+++ b/hwc2/hwc2.h
@@ -21,18 +21,64 @@
#include <unordered_map>
#include <queue>
+#include <array>
#include <mutex>
#include <string>
#include <adf/adf.h>
#include <adfhwc/adfhwc.h>
+#define HWC2_WINDOW_COUNT 4
+
+#define HWC2_WINDOW_MIN_SOURCE_CROP_WIDTH 1.0
+#define HWC2_WINDOW_MIN_SOURCE_CROP_HEIGHT 1.0
+#define HWC2_WINDOW_MIN_DISPLAY_FRAME_WIDTH 4
+#define HWC2_WINDOW_MIN_DISPLAY_FRAME_HEIGHT 4
+#define HWC2_WINDOW_MIN_DISPLAY_FRAME_SCALE 0.5
+
+#define HWC2_WINDOW_MAX_ROT_SRC_HEIGHT 2560
+#define HWC2_WINDOW_MAX_ROT_SRC_HEIGHT_NO_SCALE 3600
+
+#define HWC2_WINDOW_CAP_YUV 0x001
+#define HWC2_WINDOW_CAP_SCALE 0x002
+#define HWC2_WINDOW_CAP_FLIP 0x004
+#define HWC2_WINDOW_CAP_ROTATE_PACKED 0x008
+#define HWC2_WINDOW_CAP_ROTATE_PLANAR 0x010
+#define HWC2_WINDOW_CAP_PITCH 0x020
+#define HWC2_WINDOW_CAP_TILED 0x040
+#define HWC2_WINDOW_CAP_BLOCK_LINEAR 0x080
+
+#define HWC2_WINDOW_CAP_LAYOUTS (HWC2_WINDOW_CAP_PITCH \
+ | HWC2_WINDOW_CAP_TILED \
+ | HWC2_WINDOW_CAP_BLOCK_LINEAR)
+
+#define HWC2_WINDOW_CAP_COMMON (HWC2_WINDOW_CAP_YUV \
+ | HWC2_WINDOW_CAP_SCALE \
+ | HWC2_WINDOW_CAP_FLIP \
+ | HWC2_WINDOW_CAP_ROTATE_PACKED \
+ | HWC2_WINDOW_CAP_PITCH \
+ | HWC2_WINDOW_CAP_TILED \
+ | HWC2_WINDOW_CAP_BLOCK_LINEAR)
+
+static const std::array<uint32_t, HWC2_WINDOW_COUNT> window_capabilities = {{
+ HWC2_WINDOW_CAP_COMMON | HWC2_WINDOW_CAP_ROTATE_PLANAR,
+ HWC2_WINDOW_CAP_COMMON,
+ HWC2_WINDOW_CAP_COMMON,
+ HWC2_WINDOW_CAP_PITCH
+}};
+
class hwc2_gralloc {
public:
/* hwc2_gralloc follows the singleton design pattern */
static const hwc2_gralloc &get_instance();
- bool is_valid(buffer_handle_t handle) const;
+ bool is_valid(buffer_handle_t handle) const;
+ bool is_stereo(buffer_handle_t handle) const;
+ bool is_yuv(buffer_handle_t handle) const;
+ int get_format(buffer_handle_t handle) const;
+ void get_surfaces(buffer_handle_t handle, const void **surf,
+ size_t *surf_cnt) const;
+ int32_t get_layout(const void *surf, uint32_t surf_idx) const;
private:
hwc2_gralloc();
@@ -42,6 +88,23 @@ private:
* buffer is valid */
bool (*nvgr_is_valid)(buffer_handle_t handle);
+ /* The address of the nvgr_is_stereo symbol. This NVIDIA function checks if
+ * a buffer is stereo */
+ bool (*nvgr_is_stereo)(buffer_handle_t handle);
+
+ /* The address of the nvgr_is_yuv symbol. This NVIDIA function checks if a
+ * buffer is yuv */
+ bool (*nvgr_is_yuv)(buffer_handle_t handle);
+
+ /* The address of the nvgr_get_format symbol. This NVIDIA function returns
+ * the format of a buffer */
+ int (*nvgr_get_format)(buffer_handle_t handle);
+
+ /* The address of the nvgr_get_surfaces symbol. This NVIDIA function returns
+ * the surfaces associated with a buffer handle */
+ void (*nvgr_get_surfaces)(buffer_handle_t handle, const void **surf,
+ size_t *surf_cnt);
+
/* A symbol table handle to the NVIDIA gralloc .so file. */
void *nvgr;
};
@@ -53,6 +116,22 @@ public:
void close_acquire_fence();
+ /* Get properties */
+ buffer_handle_t get_buffer_handle() const { return handle; }
+ hwc_transform_t get_transform() const { return transform; }
+ uint32_t get_adf_buffer_format() const;
+ uint32_t get_layout() const;
+ int get_display_frame_width() const;
+ int get_display_frame_height() const;
+ float get_source_crop_width() const;
+ float get_source_crop_height() const;
+ float get_scale_width() const;
+ float get_scale_height() const;
+ void get_surfaces(const void **surf, size_t *surf_cnt) const;
+ bool is_source_crop_int_aligned() const;
+ bool is_stereo() const;
+ bool is_yuv() const;
+
/* Set properties */
hwc2_error_t set_buffer(buffer_handle_t handle, int32_t acquire_fence);
hwc2_error_t set_dataspace(android_dataspace_t dataspace);
@@ -163,6 +242,20 @@ public:
/* Get properties */
hwc2_layer_t get_id() const { return id; }
hwc2_composition_t get_comp_type() const { return comp_type; }
+ buffer_handle_t get_buffer_handle() const;
+ hwc_transform_t get_transform() const;
+ uint32_t get_adf_buffer_format() const;
+ uint32_t get_layout() const;
+ int get_display_frame_width() const;
+ int get_display_frame_height() const;
+ float get_source_crop_width() const;
+ float get_source_crop_height() const;
+ float get_scale_width() const;
+ float get_scale_height() const;
+ void get_surfaces(const void **surf, size_t *surf_cnt) const;
+ bool is_source_crop_int_aligned() const;
+ bool is_stereo() const;
+ bool is_yuv() const;
/* Set properties */
hwc2_error_t set_comp_type(hwc2_composition_t comp_type);
@@ -194,6 +287,49 @@ private:
static uint64_t layer_cnt;
};
+class hwc2_window {
+public:
+ hwc2_window();
+
+ void clear();
+ hwc2_error_t assign_client_target(uint32_t z_order);
+ hwc2_error_t assign_layer(uint32_t z_order, const hwc2_layer &lyr);
+
+ bool is_empty() const;
+ bool contains_client_target() const;
+ bool contains_layer() const;
+
+ uint32_t get_z_order() const { return z_order; }
+ hwc2_layer_t get_layer() const { return lyr_id; }
+
+ bool has_layer_requirements(const hwc2_layer &lyr) const;
+ bool has_requirements(uint32_t required_capabilities) const;
+ void set_capabilities(uint32_t capabilities);
+
+ static bool is_supported(const hwc2_layer &lyr);
+
+private:
+ /* Each window can contain the client target, a layer or nothing */
+ enum hwc2_window_content_t {
+ HWC2_WINDOW_CONTENT_EMPTY,
+ HWC2_WINDOW_CONTENT_CLIENT_TARGET,
+ HWC2_WINDOW_CONTENT_LAYER
+ } content;
+
+ /* If the content is not HWC2_WINDOW_EMPTY, the z_order corresponds to the
+ * display controller z order. The display controller z order is the reverse
+ * of the SurfaceFlinger z order. In the display controller z order, a
+ * window with lower z order occludes a window with higher z order */
+ uint32_t z_order;
+
+ /* If the content is HWC2_WINDOW_LAYER, lyr_id is the layer it contains */
+ hwc2_layer_t lyr_id;
+
+ /* The capabilities the underlying hardware window can support such as
+ * rotation, scaling, flipping, yuv, and surface layouts */
+ uint32_t capabilities;
+};
+
class hwc2_display {
public:
hwc2_display(hwc2_display_t id, int adf_intf_fd,
@@ -216,6 +352,12 @@ public:
hwc2_error_t set_power_mode(hwc2_power_mode_t mode);
hwc2_error_t get_doze_support(int32_t *out_support) const;
+ /* Window functions */
+ void init_windows();
+ void clear_windows();
+ hwc2_error_t assign_client_target_window(uint32_t z_order);
+ hwc2_error_t assign_layer_window(uint32_t z_order, hwc2_layer_t lyr_id);
+
/* Config functions */
int retrieve_display_configs(struct adf_hwc_helper *adf_helper);
hwc2_error_t get_display_attribute(hwc2_config_t config,
@@ -270,6 +412,9 @@ private:
/* Physical or virtual */
hwc2_display_type_t type;
+ /* The display windows */
+ std::array<hwc2_window, HWC2_WINDOW_COUNT> windows;
+
/* The layers currently in use */
std::unordered_map<hwc2_layer_t, hwc2_layer> layers;
diff --git a/hwc2/hwc2_buffer.cpp b/hwc2/hwc2_buffer.cpp
index 2344eb4..56b8115 100644
--- a/hwc2/hwc2_buffer.cpp
+++ b/hwc2/hwc2_buffer.cpp
@@ -44,6 +44,98 @@ void hwc2_buffer::close_acquire_fence()
}
}
+uint32_t hwc2_buffer::get_adf_buffer_format() const
+{
+ if (!handle)
+ return 0;
+
+ return hwc2_gralloc::get_instance().get_format(handle);
+}
+
+uint32_t hwc2_buffer::get_layout() const
+{
+ const hwc2_gralloc &gralloc = hwc2_gralloc::get_instance();
+ const void *surf;
+ size_t surf_cnt;
+
+ if (!handle)
+ return 0;
+
+ gralloc.get_surfaces(handle, &surf, &surf_cnt);
+
+ return gralloc.get_layout(surf, 0);
+}
+
+int hwc2_buffer::get_display_frame_width() const
+{
+ return display_frame.right - display_frame.left;
+}
+
+int hwc2_buffer::get_display_frame_height() const
+{
+ return display_frame.bottom - display_frame.top;
+}
+
+float hwc2_buffer::get_source_crop_width() const
+{
+ return source_crop.right - source_crop.left;
+}
+
+float hwc2_buffer::get_source_crop_height() const
+{
+ return source_crop.bottom - source_crop.top;
+}
+
+float hwc2_buffer::get_scale_width() const
+{
+ float source_crop_width = get_source_crop_width();
+ if (source_crop_width == 0)
+ return -1.0;
+
+ return get_display_frame_width() / source_crop_width;
+}
+
+float hwc2_buffer::get_scale_height() const
+{
+ float source_crop_height = get_source_crop_height();
+ if (source_crop_height == 0)
+ return -1.0;
+
+ return get_display_frame_height() / source_crop_height;
+}
+
+void hwc2_buffer::get_surfaces(const void **surf, size_t *surf_cnt) const
+{
+ if (!handle)
+ *surf_cnt = 0;
+ else
+ hwc2_gralloc::get_instance().get_surfaces(handle, surf, surf_cnt);
+}
+
+bool hwc2_buffer::is_source_crop_int_aligned() const
+{
+ return (source_crop.left == ceil(source_crop.left)
+ && source_crop.top == ceil(source_crop.top)
+ && source_crop.right == ceil(source_crop.right)
+ && source_crop.bottom == ceil(source_crop.bottom));
+}
+
+bool hwc2_buffer::is_stereo() const
+{
+ if (!handle)
+ return false;
+
+ return hwc2_gralloc::get_instance().is_stereo(handle);
+}
+
+bool hwc2_buffer::is_yuv() const
+{
+ if (!handle)
+ return false;
+
+ return hwc2_gralloc::get_instance().is_yuv(handle);
+}
+
hwc2_error_t hwc2_buffer::set_buffer(buffer_handle_t handle,
int32_t acquire_fence)
{
diff --git a/hwc2/hwc2_display.cpp b/hwc2/hwc2_display.cpp
index 983bba7..a874aba 100644
--- a/hwc2/hwc2_display.cpp
+++ b/hwc2/hwc2_display.cpp
@@ -31,6 +31,7 @@ hwc2_display::hwc2_display(hwc2_display_t id, int adf_intf_fd,
name(),
connection(connection),
type(type),
+ windows(),
layers(),
vsync_enabled(HWC2_VSYNC_DISABLE),
configs(),
@@ -40,6 +41,7 @@ hwc2_display::hwc2_display(hwc2_display_t id, int adf_intf_fd,
adf_dev(adf_dev)
{
init_name();
+ init_windows();
}
hwc2_display::~hwc2_display()
@@ -126,6 +128,42 @@ hwc2_error_t hwc2_display::set_vsync_enabled(hwc2_vsync_t enabled)
return HWC2_ERROR_NONE;
}
+void hwc2_display::init_windows()
+{
+ for (auto it = windows.begin(); it != windows.end(); it++)
+ it->set_capabilities(window_capabilities[it - windows.begin()]);
+}
+
+void hwc2_display::clear_windows()
+{
+ for (auto &window: windows)
+ window.clear();
+}
+
+hwc2_error_t hwc2_display::assign_client_target_window(uint32_t z_order)
+{
+ for (auto &window: windows)
+ if (window.assign_client_target(z_order) == HWC2_ERROR_NONE)
+ return HWC2_ERROR_NONE;
+
+ return HWC2_ERROR_NO_RESOURCES;
+}
+
+hwc2_error_t hwc2_display::assign_layer_window(uint32_t z_order,
+ hwc2_layer_t lyr_id)
+{
+ auto& lyr = layers.find(lyr_id)->second;
+
+ if (!hwc2_window::is_supported(lyr))
+ return HWC2_ERROR_UNSUPPORTED;
+
+ for (auto &window: windows)
+ if (window.assign_layer(z_order, lyr) == HWC2_ERROR_NONE)
+ return HWC2_ERROR_NONE;
+
+ return HWC2_ERROR_NO_RESOURCES;
+}
+
int hwc2_display::retrieve_display_configs(struct adf_hwc_helper *adf_helper)
{
size_t num_configs = 0;
diff --git a/hwc2/hwc2_gralloc.cpp b/hwc2/hwc2_gralloc.cpp
index 9301b3d..0b82b45 100644
--- a/hwc2/hwc2_gralloc.cpp
+++ b/hwc2/hwc2_gralloc.cpp
@@ -16,9 +16,32 @@
#include <cutils/log.h>
#include <dlfcn.h>
+#include <tegra_adf.h>
#include "hwc2.h"
+#define NVGR_PIXEL_FORMAT_YUV420 0x100
+#define NVGR_PIXEL_FORMAT_YUV422 0x101
+#define NVGR_PIXEL_FORMAT_YUV422R 0x102
+#define NVGR_PIXEL_FORMAT_UYVY 0x104
+#define NVGR_PIXEL_FORMAT_NV12 0x106
+
+#define NVGR_SURFACE_LAYOUT_PITCH 1
+#define NVGR_SURFACE_LAYOUT_TILED 2
+#define NVGR_SURFACE_LAYOUT_BLOCK_LINEAR 3
+
+#define NVGR_SURFACE_SIZE 56
+
+#define NVGR_GET_SURFACE(surfaces, idx) \
+ ((void*)((char *) surfaces + (idx * NVGR_SURFACE_SIZE)))
+
+/* The surface struct is defined in an NVIDIA binary. Accesses to the struct
+ * will be done using member offsets */
+#define NVGR_GET_STRUCT_MEMBER(ptr, member_type, member_offset) \
+ (*((member_type *)((char *) ptr + member_offset)))
+
+#define NVGR_SURFACE_OFFSET_LAYOUT 12
+
hwc2_gralloc::hwc2_gralloc()
{
nvgr = dlopen("gralloc.tegra132.so", RTLD_LOCAL | RTLD_LAZY);
@@ -27,6 +50,20 @@ hwc2_gralloc::hwc2_gralloc()
*(void **)(&nvgr_is_valid) = dlsym(nvgr, "nvgr_is_valid");
LOG_ALWAYS_FATAL_IF(!nvgr_is_valid, "failed to find nvgr_is_valid symbol");
+ *(void **)(&nvgr_is_stereo) = dlsym(nvgr, "nvgr_is_stereo");
+ LOG_ALWAYS_FATAL_IF(!nvgr_is_stereo, "failed to find nvgr_is_stereo"
+ " symbol");
+
+ *(void **)(&nvgr_is_yuv) = dlsym(nvgr, "nvgr_is_yuv");
+ LOG_ALWAYS_FATAL_IF(!nvgr_is_stereo, "failed to find nvgr_is_yuv symbol");
+
+ *(void **)(&nvgr_get_format) = dlsym(nvgr, "nvgr_get_format");
+ LOG_ALWAYS_FATAL_IF(!nvgr_get_format, "failed to find nvgr_get_format"
+ " symbol");
+
+ *(void **)(&nvgr_get_surfaces) = dlsym(nvgr, "nvgr_get_surfaces");
+ LOG_ALWAYS_FATAL_IF(!nvgr_get_surfaces, "failed to find nvgr_get_surfaces"
+ " symbol");
}
hwc2_gralloc::~hwc2_gralloc()
@@ -44,3 +81,59 @@ bool hwc2_gralloc::is_valid(buffer_handle_t handle) const
{
return nvgr_is_valid(handle);
}
+
+bool hwc2_gralloc::is_stereo(buffer_handle_t handle) const
+{
+ return nvgr_is_stereo(handle);
+}
+
+bool hwc2_gralloc::is_yuv(buffer_handle_t handle) const
+{
+ return nvgr_is_yuv(handle);
+}
+
+int hwc2_gralloc::get_format(buffer_handle_t handle) const
+{
+ int format = nvgr_get_format(handle);
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_BGR565;
+ case NVGR_PIXEL_FORMAT_YUV420:
+ return DRM_FORMAT_YUV420;
+ case NVGR_PIXEL_FORMAT_YUV422:
+ return DRM_FORMAT_YUV422;
+ case NVGR_PIXEL_FORMAT_YUV422R:
+ return TEGRA_ADF_FORMAT_YCbCr422R;
+ case NVGR_PIXEL_FORMAT_UYVY:
+ return DRM_FORMAT_UYVY;
+ case NVGR_PIXEL_FORMAT_NV12:
+ return DRM_FORMAT_NV12;
+ default:
+ return adf_fourcc_for_hal_pixel_format(format);
+ }
+}
+
+void hwc2_gralloc::get_surfaces(buffer_handle_t handle,
+ const void **surf, size_t *surf_cnt) const
+{
+ nvgr_get_surfaces(handle, surf, surf_cnt);
+}
+
+int32_t hwc2_gralloc::get_layout(const void *surf, uint32_t surf_idx) const
+{
+ uint32_t layout = NVGR_GET_STRUCT_MEMBER(NVGR_GET_SURFACE(surf, surf_idx),
+ uint32_t, NVGR_SURFACE_OFFSET_LAYOUT);
+
+ switch (layout) {
+ case NVGR_SURFACE_LAYOUT_PITCH:
+ return HWC2_WINDOW_CAP_PITCH;
+ case NVGR_SURFACE_LAYOUT_TILED:
+ return HWC2_WINDOW_CAP_TILED;
+ case NVGR_SURFACE_LAYOUT_BLOCK_LINEAR:
+ return HWC2_WINDOW_CAP_BLOCK_LINEAR;
+ default:
+ ALOGE("Unrecognized layout");
+ return -1;
+ }
+}
diff --git a/hwc2/hwc2_layer.cpp b/hwc2/hwc2_layer.cpp
index 125f28f..4da2919 100644
--- a/hwc2/hwc2_layer.cpp
+++ b/hwc2/hwc2_layer.cpp
@@ -26,6 +26,76 @@ hwc2_layer::hwc2_layer(hwc2_layer_t id)
buffer(),
comp_type(HWC2_COMPOSITION_INVALID) { }
+buffer_handle_t hwc2_layer::get_buffer_handle() const
+{
+ return buffer.get_buffer_handle();
+}
+
+hwc_transform_t hwc2_layer::get_transform() const
+{
+ return buffer.get_transform();
+}
+
+uint32_t hwc2_layer::get_adf_buffer_format() const
+{
+ return buffer.get_adf_buffer_format();
+}
+
+uint32_t hwc2_layer::get_layout() const
+{
+ return buffer.get_layout();
+}
+
+int hwc2_layer::get_display_frame_width() const
+{
+ return buffer.get_display_frame_width();
+}
+
+int hwc2_layer::get_display_frame_height() const
+{
+ return buffer.get_display_frame_height();
+}
+
+float hwc2_layer::get_source_crop_width() const
+{
+ return buffer.get_source_crop_width();
+}
+
+float hwc2_layer::get_source_crop_height() const
+{
+ return buffer.get_source_crop_height();
+}
+
+float hwc2_layer::get_scale_width() const
+{
+ return buffer.get_scale_width();
+}
+
+float hwc2_layer::get_scale_height() const
+{
+ return buffer.get_scale_height();
+}
+
+void hwc2_layer::get_surfaces(const void **surf, size_t *surf_cnt) const
+{
+ buffer.get_surfaces(surf, surf_cnt);
+}
+
+bool hwc2_layer::is_source_crop_int_aligned() const
+{
+ return buffer.is_source_crop_int_aligned();
+}
+
+bool hwc2_layer::is_stereo() const
+{
+ return buffer.is_stereo();
+}
+
+bool hwc2_layer::is_yuv() const
+{
+ return buffer.is_yuv();
+}
+
hwc2_error_t hwc2_layer::set_comp_type(hwc2_composition_t comp_type)
{
hwc2_error_t ret = HWC2_ERROR_NONE;
diff --git a/hwc2/hwc2_window.cpp b/hwc2/hwc2_window.cpp
new file mode 100644
index 0000000..ca2f7f6
--- /dev/null
+++ b/hwc2/hwc2_window.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 <cassert>
+
+#include "hwc2.h"
+
+hwc2_window::hwc2_window()
+ : content(HWC2_WINDOW_CONTENT_EMPTY),
+ z_order(0),
+ lyr_id(0) { }
+
+void hwc2_window::clear()
+{
+ content = HWC2_WINDOW_CONTENT_EMPTY;
+}
+
+hwc2_error_t hwc2_window::assign_client_target(uint32_t z_order)
+{
+ /* The client target will never rotate, scale or flip. Its buffer layout
+ * could be changed before present display, so the window must support all
+ * layouts. */
+ if (!is_empty() || !has_requirements(HWC2_WINDOW_CAP_LAYOUTS))
+ return HWC2_ERROR_UNSUPPORTED;
+
+ content = HWC2_WINDOW_CONTENT_CLIENT_TARGET;
+ this->z_order = z_order;
+
+ return HWC2_ERROR_NONE;
+}
+
+hwc2_error_t hwc2_window::assign_layer(uint32_t z_order, const hwc2_layer &lyr)
+{
+ if (!is_empty() || !has_layer_requirements(lyr))
+ return HWC2_ERROR_UNSUPPORTED;
+
+ content = HWC2_WINDOW_CONTENT_LAYER;
+ this->z_order = z_order;
+ this->lyr_id = lyr.get_id();
+
+ return HWC2_ERROR_NONE;
+}
+
+bool hwc2_window::is_empty() const
+{
+ return content == HWC2_WINDOW_CONTENT_EMPTY;
+}
+
+bool hwc2_window::contains_client_target() const
+{
+ return content == HWC2_WINDOW_CONTENT_CLIENT_TARGET;
+}
+
+bool hwc2_window::contains_layer() const
+{
+ return content == HWC2_WINDOW_CONTENT_LAYER;
+}
+
+bool hwc2_window::has_layer_requirements(const hwc2_layer &lyr) const
+{
+ hwc_transform_t transform = lyr.get_transform();
+ uint32_t reqs = 0;
+ int32_t layout;
+
+ layout = lyr.get_layout();
+ if (layout < 0)
+ return false;
+
+ reqs |= layout;
+
+ if (transform & HWC_TRANSFORM_ROT_90) {
+ const void *surf;
+ size_t surf_cnt;
+ lyr.get_surfaces(&surf, &surf_cnt);
+
+ if (surf_cnt > 1)
+ reqs |= HWC2_WINDOW_CAP_ROTATE_PLANAR;
+ else
+ reqs |= HWC2_WINDOW_CAP_ROTATE_PACKED;
+ }
+
+ if (transform & (HWC_TRANSFORM_FLIP_H | HWC_TRANSFORM_FLIP_V))
+ reqs |= HWC2_WINDOW_CAP_FLIP;
+
+ if (lyr.get_scale_width() != 1 || lyr.get_scale_height() != 1)
+ reqs |= HWC2_WINDOW_CAP_SCALE;
+
+ if (lyr.is_yuv())
+ reqs |= HWC2_WINDOW_CAP_YUV;
+
+ return has_requirements(reqs);
+}
+
+bool hwc2_window::has_requirements(uint32_t requirements) const
+{
+ return (requirements & capabilities) == requirements;
+}
+
+void hwc2_window::set_capabilities(uint32_t capabilities)
+{
+ this->capabilities = capabilities;
+}
+
+bool hwc2_window::is_supported(const hwc2_layer &lyr)
+{
+ float source_crop_height = lyr.get_source_crop_height();
+ float scale_width = lyr.get_scale_width();
+ float scale_height = lyr.get_scale_height();
+
+ if (!lyr.get_buffer_handle())
+ return false;
+
+ if (!lyr.get_adf_buffer_format())
+ return false;
+
+ if (lyr.is_stereo())
+ return false;
+
+ if (lyr.get_display_frame_width() < HWC2_WINDOW_MIN_DISPLAY_FRAME_WIDTH
+ || lyr.get_display_frame_height() < HWC2_WINDOW_MIN_DISPLAY_FRAME_HEIGHT)
+ return false;
+
+ if (lyr.get_source_crop_width() < HWC2_WINDOW_MIN_SOURCE_CROP_WIDTH
+ || source_crop_height < HWC2_WINDOW_MIN_SOURCE_CROP_HEIGHT)
+ return false;
+
+ if (scale_width < HWC2_WINDOW_MIN_DISPLAY_FRAME_SCALE
+ || scale_height < HWC2_WINDOW_MIN_DISPLAY_FRAME_SCALE)
+ return false;
+
+ const void *surf;
+ size_t surf_cnt;
+ lyr.get_surfaces(&surf, &surf_cnt);
+
+ if (lyr.get_transform() & HWC_TRANSFORM_ROT_90) {
+ if (surf_cnt == 1 && scale_width == 1 && scale_height == 1
+ && source_crop_height > HWC2_WINDOW_MAX_ROT_SRC_HEIGHT_NO_SCALE)
+ return false;
+ else if (source_crop_height > HWC2_WINDOW_MAX_ROT_SRC_HEIGHT)
+ return false;
+ }
+
+ if (!lyr.is_source_crop_int_aligned())
+ return false;
+
+ return true;
+}
diff --git a/hwc2/include/tegra_adf.h b/hwc2/include/tegra_adf.h
new file mode 100644
index 0000000..52e4d17
--- /dev/null
+++ b/hwc2/include/tegra_adf.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ *** To edit the content of this header, modify the corresponding
+ *** source file (e.g. under external/kernel-headers/original/) then
+ *** run bionic/libc/kernel/tools/update_all.py
+ ***
+ *** Any manual change here will be lost the next time this script will
+ *** be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_VIDEO_TEGRA_ADF_H_
+#define _UAPI_VIDEO_TEGRA_ADF_H_
+#include <linux/types.h>
+#include <video/adf.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#include <drm/drm_fourcc.h>
+#define TEGRA_ADF_FORMAT_P1 fourcc_code('P', '1', ' ', ' ')
+#define TEGRA_ADF_FORMAT_P2 fourcc_code('P', '2', ' ', ' ')
+#define TEGRA_ADF_FORMAT_P4 fourcc_code('P', '4', ' ', ' ')
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_FORMAT_P8 fourcc_code('P', '8', ' ', ' ')
+#define TEGRA_ADF_FORMAT_B6x2G6x2R6x2A8 fourcc_code('B', 'A', '6', '2')
+#define TEGRA_ADF_FORMAT_R6x2G6x2B6x2A8 fourcc_code('R', 'A', '6', '2')
+#define TEGRA_ADF_FORMAT_R6x2G6x2B6x2A8 fourcc_code('R', 'A', '6', '2')
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_FORMAT_YCbCr422R fourcc_code('Y', 'U', '2', 'R')
+enum tegra_adf_interface_type {
+ TEGRA_ADF_INTF_RGB = ADF_INTF_TYPE_DEVICE_CUSTOM,
+ TEGRA_ADF_INTF_LVDS = ADF_INTF_TYPE_DEVICE_CUSTOM + 1,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+#define TEGRA_ADF_EVENT_BANDWIDTH_RENEGOTIATE ADF_EVENT_DEVICE_CUSTOM
+struct tegra_adf_event_bandwidth {
+ struct adf_event base;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 total_bw;
+ __u32 avail_bw;
+ __u32 resvd_bw;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_CAPABILITIES_CURSOR_MODE (1 << 0)
+#define TEGRA_ADF_CAPABILITIES_BLOCKLINEAR (1 << 1)
+struct tegra_adf_capabilities {
+ __u32 caps;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 pad[3];
+};
+#define TEGRA_ADF_BLEND_NONE 0
+#define TEGRA_ADF_BLEND_PREMULT 1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_BLEND_COVERAGE 2
+#define TEGRA_ADF_FLIP_FLAG_INVERT_H (1 << 0)
+#define TEGRA_ADF_FLIP_FLAG_INVERT_V (1 << 1)
+#define TEGRA_ADF_FLIP_FLAG_TILED (1 << 2)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_FLIP_FLAG_CURSOR (1 << 3)
+#define TEGRA_ADF_FLIP_FLAG_GLOBAL_ALPHA (1 << 4)
+#define TEGRA_ADF_FLIP_FLAG_BLOCKLINEAR (1 << 5)
+#define TEGRA_ADF_FLIP_FLAG_SCAN_COLUMN (1 << 6)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TEGRA_ADF_FLIP_FLAG_INTERLACE (1 << 7)
+struct tegra_adf_flip_windowattr {
+ __s32 win_index;
+ __s32 buf_index;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 blend;
+ __u32 x;
+ __u32 y;
+ __u32 out_x;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 out_y;
+ __u32 out_w;
+ __u32 out_h;
+ __u32 z;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 swap_interval;
+ __s64 timestamp_ns;
+ __u32 flags;
+ __u8 global_alpha;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 block_height_log2;
+ __u8 pad1[2];
+ __u32 offset2;
+ __u32 offset_u2;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 offset_v2;
+ __u32 pad2[1];
+};
+struct tegra_adf_flip {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 win_num;
+ __u8 reserved1;
+ __u16 reserved2;
+ __u16 dirty_rect[4];
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ struct tegra_adf_flip_windowattr win[0];
+};
+struct tegra_adf_proposed_bw {
+ __u8 win_num;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ struct {
+ __u32 format;
+ __u32 w;
+ __u32 h;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ struct tegra_adf_flip_windowattr attr;
+ } win[0];
+};
+#define TEGRA_ADF_SET_PROPOSED_BW _IOW(ADF_IOCTL_TYPE, ADF_IOCTL_NR_CUSTOM, struct tegra_adf_proposed_bw)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+enum {
+ TEGRA_DC_Y,
+ TEGRA_DC_U,
+ TEGRA_DC_V,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ TEGRA_DC_NUM_PLANES,
+};
+#endif
+
diff --git a/hwc2/original-kernel-headers/tegra_adf.h b/hwc2/original-kernel-headers/tegra_adf.h
new file mode 100644
index 0000000..7313111
--- /dev/null
+++ b/hwc2/original-kernel-headers/tegra_adf.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ * Copyright (c) 2014, NVIDIA CORPORATION, All rights reserved.
+ *
+ * modified from include/video/tegra_dc_ext.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_VIDEO_TEGRA_ADF_H_
+#define _UAPI_VIDEO_TEGRA_ADF_H_
+
+#include <linux/types.h>
+#include <video/adf.h>
+#include <drm/drm_fourcc.h>
+
+#define TEGRA_ADF_FORMAT_P1 fourcc_code('P', '1', ' ', ' ')
+#define TEGRA_ADF_FORMAT_P2 fourcc_code('P', '2', ' ', ' ')
+#define TEGRA_ADF_FORMAT_P4 fourcc_code('P', '4', ' ', ' ')
+#define TEGRA_ADF_FORMAT_P8 fourcc_code('P', '8', ' ', ' ')
+#define TEGRA_ADF_FORMAT_B6x2G6x2R6x2A8 fourcc_code('B', 'A', '6', '2')
+#define TEGRA_ADF_FORMAT_R6x2G6x2B6x2A8 fourcc_code('R', 'A', '6', '2')
+#define TEGRA_ADF_FORMAT_R6x2G6x2B6x2A8 fourcc_code('R', 'A', '6', '2')
+#define TEGRA_ADF_FORMAT_YCbCr422R fourcc_code('Y', 'U', '2', 'R')
+
+enum tegra_adf_interface_type {
+ TEGRA_ADF_INTF_RGB = ADF_INTF_TYPE_DEVICE_CUSTOM,
+ TEGRA_ADF_INTF_LVDS = ADF_INTF_TYPE_DEVICE_CUSTOM + 1,
+};
+
+#define TEGRA_ADF_EVENT_BANDWIDTH_RENEGOTIATE ADF_EVENT_DEVICE_CUSTOM
+struct tegra_adf_event_bandwidth {
+ struct adf_event base;
+ __u32 total_bw;
+ __u32 avail_bw;
+ __u32 resvd_bw;
+};
+
+#define TEGRA_ADF_CAPABILITIES_CURSOR_MODE (1 << 0)
+#define TEGRA_ADF_CAPABILITIES_BLOCKLINEAR (1 << 1)
+struct tegra_adf_capabilities {
+ __u32 caps;
+ /* Leave some wiggle room for future expansion */
+ __u32 pad[3];
+};
+
+#define TEGRA_ADF_BLEND_NONE 0
+#define TEGRA_ADF_BLEND_PREMULT 1
+#define TEGRA_ADF_BLEND_COVERAGE 2
+
+#define TEGRA_ADF_FLIP_FLAG_INVERT_H (1 << 0)
+#define TEGRA_ADF_FLIP_FLAG_INVERT_V (1 << 1)
+#define TEGRA_ADF_FLIP_FLAG_TILED (1 << 2)
+#define TEGRA_ADF_FLIP_FLAG_CURSOR (1 << 3)
+#define TEGRA_ADF_FLIP_FLAG_GLOBAL_ALPHA (1 << 4)
+#define TEGRA_ADF_FLIP_FLAG_BLOCKLINEAR (1 << 5)
+#define TEGRA_ADF_FLIP_FLAG_SCAN_COLUMN (1 << 6)
+#define TEGRA_ADF_FLIP_FLAG_INTERLACE (1 << 7)
+
+struct tegra_adf_flip_windowattr {
+ __s32 win_index;
+ __s32 buf_index;
+ __u32 blend;
+ /*
+ * x and y are fixed-point: 20 bits of integer (MSB) and 12 bits of
+ * fractional (LSB)
+ */
+ __u32 x;
+ __u32 y;
+ __u32 out_x;
+ __u32 out_y;
+ __u32 out_w;
+ __u32 out_h;
+ __u32 z;
+ __u32 swap_interval;
+ __s64 timestamp_ns;
+ __u32 flags;
+ __u8 global_alpha; /* requires TEGRA_ADF_FLIP_FLAG_GLOBAL_ALPHA */
+ /* log2(blockheight) for blocklinear format */
+ __u8 block_height_log2;
+ __u8 pad1[2];
+ __u32 offset2;
+ __u32 offset_u2;
+ __u32 offset_v2;
+ /* Leave some wiggle room for future expansion */
+ __u32 pad2[1];
+};
+
+struct tegra_adf_flip {
+ __u8 win_num;
+ __u8 reserved1; /* unused - must be 0 */
+ __u16 reserved2; /* unused - must be 0 */
+ __u16 dirty_rect[4]; /* x,y,w,h for partial screen update. 0 ignores */
+ struct tegra_adf_flip_windowattr win[0];
+};
+
+struct tegra_adf_proposed_bw {
+ __u8 win_num;
+ struct {
+ __u32 format;
+ __u32 w;
+ __u32 h;
+ struct tegra_adf_flip_windowattr attr;
+ } win[0];
+};
+
+#define TEGRA_ADF_SET_PROPOSED_BW \
+ _IOW(ADF_IOCTL_TYPE, ADF_IOCTL_NR_CUSTOM, struct tegra_adf_proposed_bw)
+
+enum {
+ TEGRA_DC_Y,
+ TEGRA_DC_U,
+ TEGRA_DC_V,
+ TEGRA_DC_NUM_PLANES,
+};
+
+#endif /* _UAPI_VIDEO_TEGRA_ADF_H_ */