#include <tdm_helper.h>
#include <linux/fb.h>
+#include <drm.h>
#include <video/sprdfb.h>
#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
#include "tdm_sprd.h"
#define MIN_WIDTH 32
#define FB_DEV_LCD "/dev/fb0"
+#define HW_LAYER_NUM 2
+
+#define LIST_INSERT_AFTER(__after, __item) \
+ (__item)->prev = (__after); \
+ (__item)->next = (__after)->next; \
+ (__after)->next->prev = (__item); \
+ (__after)->next = (__item);
+
typedef struct _tdm_sprd_output_data tdm_sprd_output_data;
typedef struct _tdm_sprd_layer_data tdm_sprd_layer_data;
+typedef struct _tdm_sprd_hwc_window_data tdm_sprd_hwc_window_data;
typedef struct _tdm_sprd_vblank_data_s tdm_sprd_vblank_data;
typedef enum {
tdm_output_dpms dpms_value;
+ tdm_sprd_hwc_window_data *target_hwc_window;
+
+ int need_validate;
+ int need_target_buffer;
+
struct list_head capture_list;
+ struct list_head hwc_window_list;
};
struct _tdm_sprd_layer_data {
tdm_sprd_display_buffer *display_buffer;
int display_buffer_changed;
- // current hw overlay setting
+ /* current hw overlay setting */
overlay_info ovi;
int enabled_flag;
};
+struct _tdm_sprd_hwc_window_data {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_sprd_data *sprd_data;
+ tdm_sprd_output_data *output_data;
+
+ /* not fixed data below */
+ int zpos;
+
+ tdm_hwc_window_info info;
+ int info_changed;
+
+ tdm_sprd_display_buffer *display_buffer;
+ int display_buffer_changed;
+ int enabled_flag;
+
+ /* client_type stores the initial type given to us by client(compositor) */
+ tdm_hwc_window_composition client_type;
+ /* validated_type stores the type after running Validate */
+ tdm_hwc_window_composition validated_type;
+
+ tdm_hwc_window_flag flags;
+};
+
typedef struct _Drm_Event_Context {
void (*vblank_handler)(int fd, unsigned int sequence, unsigned int tv_sec,
unsigned int tv_usec, void *user_data);
TBM_FORMAT_ARGB8888
};
+tbm_format hwc_window_video_formats[] = {
+ TBM_FORMAT_RGB565,
+ TBM_FORMAT_XRGB8888,
+ TBM_FORMAT_ARGB8888,
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420
+};
+
+tdm_hwc_window * _sprd_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error);
+
+
#if 0
static tdm_error
check_hw_restriction(unsigned int output_w, unsigned int buf_w,
}
static tdm_error
+_sprd_layer_attach_window(tdm_sprd_layer_data *layer_data, tdm_sprd_hwc_window_data *hwc_window_data)
+{
+ tdm_error ret = TDM_ERROR_NONE;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
+ RETURN_VAL_IF_FAIL(hwc_window_data, TDM_ERROR_OPERATION_FAILED);
+
+ if (hwc_window_data == NULL || hwc_window_data->display_buffer == NULL) {
+ ret = sprd_layer_unset_buffer(layer_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ } else {
+ ret = sprd_layer_set_info((tdm_layer *)layer_data, (tdm_info_layer *)&(hwc_window_data->info));
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ RETURN_VAL_IF_FAIL(hwc_window_data->display_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
+ ret = sprd_layer_set_buffer(layer_data, hwc_window_data->display_buffer->buffer);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ }
+ return ret;
+}
+
+static tdm_error
_tdm_sprd_display_do_commit(tdm_sprd_output_data *output_data)
{
tdm_error res = TDM_ERROR_NONE;
return NULL;
}
LIST_INITHEAD(&output_data->capture_list);
+ if (sprd_data->hwc_mode)
+ LIST_INITHEAD(&output_data->hwc_window_list);
return output_data;
}
return tdm_sprd_pp_create(sprd_data, error);
}
+tdm_sprd_layer_data *
+_sprd_output_get_layer(tdm_sprd_output_data *output_data, int index)
+{
+ RETURN_VAL_IF_FAIL(output_data, NULL);
+
+ tdm_sprd_layer_data *l = NULL;
+ LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link)
+ if (l->zpos == index)
+ return l;
+ return NULL;
+}
+
+
tdm_error
sprd_output_get_capability(tdm_output *output, tdm_caps_output *caps)
{
RETURN_VAL_IF_FAIL(output_data, NULL);
RETURN_VAL_IF_FAIL(count, NULL);
+ if (output_data->sprd_data->hwc_mode) {
+ TDM_INFO("layers aren't supported in HWC mode");
+ *count = 0;
+ ret = TDM_ERROR_NONE;
+ goto failed_get;
+ }
+
*count = 0;
LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
(*count)++;
return TDM_ERROR_NONE;
}
+static tdm_error
+_tdm_sprd_display_prepare_commit(tdm_sprd_output_data *output_data) {
+
+ tdm_sprd_layer_data * layer = NULL;
+ int i = HW_LAYER_NUM-1;
+ tdm_sprd_hwc_window_data *hw = NULL;
+
+ RETURN_VAL_IF_FAIL(output_data->need_validate == 0, TDM_ERROR_OPERATION_FAILED);
+
+ /* set target hwc window */
+ if (output_data->need_target_buffer) {
+ layer = _sprd_output_get_layer(output_data, i--);
+ _sprd_layer_attach_window(layer, output_data->target_hwc_window);
+ }
+
+ /* set hwc windows */
+ LIST_FOR_EACH_ENTRY_REV(hw, &output_data->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+ if (hw->client_type != TDM_COMPOSITION_DEVICE && hw->client_type != TDM_COMPOSITION_VIDEO)
+ continue;
+ if (i < 0)
+ return TDM_ERROR_OPERATION_FAILED;
+ layer = _sprd_output_get_layer(output_data, i--);
+ _sprd_layer_attach_window(layer, hw);
+ }
+
+ /* disable unused layer */
+ while (i >= 0) {
+ layer = _sprd_output_get_layer(output_data, i--);
+ _sprd_layer_attach_window(layer, NULL);
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+
tdm_error
sprd_output_commit(tdm_output *output, int sync, void *user_data)
{
sprd_data = output_data->sprd_data;
+ if (sprd_data->hwc_mode) {
+ ret = _tdm_sprd_display_prepare_commit(output_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ }
+
_tdm_sprd_display_do_commit(output_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
tdm_sprd_vblank_data *vblank_data = calloc(1, sizeof(tdm_sprd_vblank_data));
uint target_msc;
RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(output_data->sprd_data, TDM_ERROR_INVALID_PARAMETER);
+
+ if (output_data->sprd_data->hwc_mode) {
+
+ tdm_hwc_window_info info = {0};
+ tdm_error ret = TDM_ERROR_NONE;
+ tdm_sprd_hwc_window_data * target_hwc_window;
+
+ info.src_config.pos.h = mode->vdisplay;
+ info.src_config.pos.w = mode->hdisplay;
+ info.src_config.size.h = mode->hdisplay;
+ info.src_config.size.v = mode->vdisplay;
+ info.src_config.format = TBM_FORMAT_ARGB8888;
+
+ target_hwc_window = _sprd_output_hwc_window_create(output_data, &info, &ret);
+ if (ret != TDM_ERROR_NONE) {
+ TDM_ERR("create target hwc window failed (%d)", ret);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ if (output_data->target_hwc_window)
+ sprd_output_hwc_window_destroy(output, output_data->target_hwc_window);
+
+ output_data->target_hwc_window = target_hwc_window;
+ }
output_data->current_mode = mode;
output_data->mode_changed = 1;
return TDM_ERROR_NONE;
}
+tdm_sprd_display_buffer *
+_tdm_sprd_display_creat_buffer(tdm_sprd_data *sprd_data, tbm_surface_h surface, tdm_error * err)
+{
+ int i, count;
+ int bw, bh;
+ tdm_sprd_display_buffer * display_buffer = NULL;
+ tdm_error res = TDM_ERROR_NONE;
+
+ RETURN_VAL_IF_FAIL(sprd_data, NULL);
+ RETURN_VAL_IF_FAIL(surface, NULL);
+
+ display_buffer = calloc(1, sizeof(tdm_sprd_display_buffer));
+ if (!display_buffer) {
+ if (err)
+ *err = TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ display_buffer->buffer = surface;
+
+ res = tdm_buffer_add_destroy_handler(surface, _tdm_sprd_display_cb_destroy_buffer, sprd_data);
+ if (res != TDM_ERROR_NONE) {
+ if (err)
+ *err = res;
+ TDM_ERR("add destroy handler fail");
+ free(display_buffer);
+ return NULL;
+ }
+
+ tdm_helper_get_buffer_full_size(surface, &bw, &bh);
+
+ display_buffer->width = bw;
+ display_buffer->height = bh;
+ display_buffer->format = tbm_surface_get_format(surface);
+ display_buffer->count = tbm_surface_internal_get_num_bos(surface);
+ count = tbm_surface_internal_get_num_planes(display_buffer->format);
+ TDM_DBG("create buffer: %dx%d %c%c%c%c bo_num:%d plane_num:%d",
+ display_buffer->width, display_buffer->height, FOURCC_STR(display_buffer->format),
+ display_buffer->count, count);
+
+ for (i = 0; i < display_buffer->count; i++) {
+ tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
+ display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+ display_buffer->name[i] = tbm_bo_export(bo);
+ TDM_DBG(" create buffer: bo%d(name:%d handle:%d)", i, display_buffer->name[i],
+ display_buffer->handles[i]);
+ }
+ for (i = 0; i < count; i++) {
+ tbm_surface_internal_get_plane_data(surface, i, &display_buffer->size, &display_buffer->offsets[i],
+ &display_buffer->pitches[i]);
+ TDM_DBG(" create buffer: plane%d(size:%d offset:%d pitch:%d)", i, display_buffer->size,
+ display_buffer->offsets[i], display_buffer->pitches[i]);
+ }
+
+ if (IS_RGB(display_buffer->format))
+ display_buffer->width = display_buffer->pitches[0] >> 2;
+ else
+ display_buffer->width = display_buffer->pitches[0];
+
+ if (err)
+ *err = TDM_ERROR_NONE;
+
+ return display_buffer;
+}
+
tdm_error
sprd_layer_set_buffer(tdm_layer *layer, tbm_surface_h surface)
{
tdm_sprd_data *sprd_data;
tdm_sprd_display_buffer *display_buffer;
tdm_error err = TDM_ERROR_NONE;
- int i, count;
RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
RETURN_VAL_IF_FAIL(surface, TDM_ERROR_INVALID_PARAMETER);
sprd_data = layer_data->sprd_data;
display_buffer = _tdm_sprd_display_find_buffer(sprd_data, surface);
if (!display_buffer) {
- int bw, bh;
-
- display_buffer = calloc(1, sizeof(tdm_sprd_display_buffer));
- if (!display_buffer) {
- TDM_ERR("alloc failed");
- return TDM_ERROR_OUT_OF_MEMORY;
- }
- display_buffer->buffer = surface;
-
- err = tdm_buffer_add_destroy_handler(surface, _tdm_sprd_display_cb_destroy_buffer, sprd_data);
- if (err != TDM_ERROR_NONE) {
- TDM_ERR("add destroy handler fail");
- free(display_buffer);
- return TDM_ERROR_OPERATION_FAILED;
- }
+ display_buffer = _tdm_sprd_display_creat_buffer(sprd_data, surface, &err);
+ RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
LIST_ADDTAIL(&display_buffer->link, &sprd_data->buffer_list);
-
- tdm_helper_get_buffer_full_size(surface, &bw, &bh);
-
- display_buffer->width = bw;
- display_buffer->height = bh;
- display_buffer->format = tbm_surface_get_format(surface);
- display_buffer->count = tbm_surface_internal_get_num_bos(surface);
- count = tbm_surface_internal_get_num_planes(display_buffer->format);
- TDM_DBG("set buffer layer(0x%x): %dx%d %c%c%c%c bo_num:%d plane_num:%d", layer_data->capabilities,
- display_buffer->width, display_buffer->height, FOURCC_STR(display_buffer->format),
- display_buffer->count, count);
-
- for (i = 0; i < display_buffer->count; i++) {
- tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
- display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
- display_buffer->name[i] = tbm_bo_export(bo);
- TDM_DBG(" set buffer layer(0x%x): bo%d(name:%d handle:%d)", layer_data->capabilities, i,
- display_buffer->name[i], display_buffer->handles[i]);
- }
- for (i = 0; i < count; i++) {
- tbm_surface_internal_get_plane_data(surface, i, &display_buffer->size, &display_buffer->offsets[i],
- &display_buffer->pitches[i]);
- TDM_DBG(" set buffer layer(0x%x): plane%d(size:%d offset:%d pitch:%d)", layer_data->capabilities, i,
- display_buffer->size, display_buffer->offsets[i], display_buffer->pitches[i]);
-
- }
-
- if (IS_RGB(display_buffer->format))
- display_buffer->width = display_buffer->pitches[0] >> 2;
- else
- display_buffer->width = display_buffer->pitches[0];
}
layer_data->display_buffer = display_buffer;
sprd_output_attach_capture(tdm_output *output, tdm_capture *capture)
{
RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(capture, TDM_ERROR_INVALID_PARAMETER);
+
tdm_sprd_output_capture_data *output_capture_data_p =
calloc(1, sizeof(tdm_sprd_output_capture_data));
RETURN_VAL_IF_FAIL(output_capture_data_p, TDM_ERROR_OUT_OF_MEMORY);
sprd_output_dettach_capture(tdm_output *output, tdm_capture *capture)
{
RETURN_VOID_IF_FAIL(output);
+ RETURN_VOID_IF_FAIL(capture);
+
tdm_sprd_output_data *output_data = output;
if (!LIST_IS_EMPTY(&output_data->capture_list)) {
tdm_sprd_output_capture_data *l = NULL, *ll = NULL;
}
return TDM_ERROR_NONE;
}
+
+static int
+_sprd_layer_is_supported_format(tdm_sprd_layer_data *layer_data, tbm_format format)
+{
+ RETURN_VAL_IF_FAIL(layer_data, 0);
+ return IS_RGB(format);
+}
+
+static int
+_sprd_hwc_window_is_reserved_buffer(tdm_sprd_hwc_window_data *hwc_window) {
+ tbm_bo bo = NULL;
+ int falgs = 0;
+
+ RETURN_VAL_IF_FAIL(hwc_window != NULL, 0);
+ RETURN_VAL_IF_FAIL(hwc_window->display_buffer != NULL, 0);
+
+ bo = tbm_surface_internal_get_bo(hwc_window->display_buffer->buffer, 0);
+ RETURN_VAL_IF_FAIL(bo != NULL, 0);
+
+ falgs = tbm_bo_get_flags(bo);
+
+ return falgs & TBM_BO_SCANOUT;
+}
+
+tdm_error
+_sprd_output_insert_hwc_window(tdm_sprd_output_data *output, tdm_sprd_hwc_window_data *hwc_window)
+{
+
+ RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(hwc_window, TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_hwc_window_data *item = NULL;
+ LIST_FOR_EACH_ENTRY_REV(item, &output->hwc_window_list, link) {
+
+ if (item == hwc_window)
+ return TDM_ERROR_OPERATION_FAILED;
+
+ if (item->zpos <= hwc_window->zpos)
+ break;
+ }
+
+ LIST_INSERT_AFTER(&item->link, &hwc_window->link);
+
+ return TDM_ERROR_NONE;
+}
+
+int
+_sprd_output_get_changed_number(tdm_sprd_output_data *sprd_output)
+{
+ int num = 0;
+ tdm_sprd_hwc_window_data *hw = NULL;
+
+ RETURN_VAL_IF_FAIL(sprd_output, TDM_ERROR_INVALID_PARAMETER);
+
+ LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ if (hw->client_type != hw->validated_type)
+ num++;
+ }
+ return num;
+}
+
+tdm_hwc_window *
+_sprd_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+ tdm_sprd_output_data *sprd_output = output;
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ if (!sprd_output) {
+ TDM_ERR("invalid params");
+ if (error)
+ *error = TDM_ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ sprd_hwc_window = calloc(1, sizeof(tdm_sprd_hwc_window_data));
+ if (!sprd_hwc_window) {
+ TDM_ERR("alloc failed");
+ if (error)
+ *error = TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ if ((sprd_hwc_window->sprd_data = sprd_output_get_sprd_data(output)) == NULL) {
+ TDM_ERR("invalid params");
+ if (error)
+ *error = TDM_ERROR_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ sprd_hwc_window->output_data = output;
+ sprd_hwc_window->zpos = 0;
+
+ if (info)
+ memcpy(&sprd_hwc_window->info, info, sizeof(tdm_hwc_window_info));
+
+ LIST_INITHEAD(&sprd_hwc_window->link);
+
+ return sprd_hwc_window;
+fail:
+ if (sprd_hwc_window)
+ free(sprd_hwc_window);
+ return NULL;
+}
+
+tdm_hwc_window *
+sprd_output_hwc_window_create(tdm_output *output, tdm_error *error)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+ tdm_sprd_output_data *sprd_output = output;
+
+ RETURN_VAL_IF_FAIL(sprd_output, NULL);
+
+ sprd_hwc_window = _sprd_output_hwc_window_create(sprd_output, NULL, error);
+ RETURN_VAL_IF_FAIL(sprd_hwc_window, NULL);
+
+ _sprd_output_insert_hwc_window(sprd_output, sprd_hwc_window);
+
+ TDM_DBG("hwc_window(%p) create", sprd_hwc_window);
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ return sprd_hwc_window;
+}
+
+tdm_error
+sprd_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window)
+{
+ RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(hwc_window, TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+ LIST_DEL(&sprd_hwc_window->link);
+
+ free(sprd_hwc_window);
+
+ return TDM_ERROR_NONE;
+}
+
+static const char *
+_comp_to_str(tdm_hwc_window_composition composition_type)
+{
+ if (composition_type == TDM_COMPOSITION_CLIENT)
+ return "CLIENT";
+ else if (composition_type == TDM_COMPOSITION_DEVICE_CANDIDATE)
+ return "DEVICE_CANDIDATE";
+ else if (composition_type == TDM_COMPOSITION_DEVICE)
+ return "DEVICE";
+ else if (composition_type == TDM_COMPOSITION_CURSOR)
+ return "CURSOR";
+ else if (composition_type == TDM_COMPOSITION_VIDEO)
+ return "VIDEO";
+
+ return "unknown";
+}
+
+static int
+_get_number_of_visible_windows(tdm_sprd_output_data *sprd_output)
+{
+ int number = 0;
+ tdm_sprd_hwc_window_data *window = NULL;
+
+ RETURN_VAL_IF_FAIL(sprd_output, 0);
+
+ LIST_FOR_EACH_ENTRY(window, &sprd_output->hwc_window_list, link) {
+ if (window->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ number++;
+ }
+
+ return number;
+}
+
+tdm_error
+sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types)
+{
+ tdm_sprd_output_data *sprd_output = output;
+ tdm_sprd_data *sprd_data = NULL;
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
+ tdm_sprd_hwc_window_data *hw = NULL;
+ int hw_layer_count = 0;
+ int need_target_buffer = 0;
+ int is_client_detected = 0;
+ int max_hw_layer = HW_LAYER_NUM;
+ int i = 0;
+
+ sprd_data = sprd_output->sprd_data;
+ RETURN_VAL_IF_FAIL(sprd_data != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_layer_data * layer = NULL;
+
+ if (_get_number_of_visible_windows(sprd_output) > max_hw_layer)
+ need_target_buffer = 1;
+
+ is_client_detected = 0;
+ /* check client_type */
+ LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ if ((hw->client_type == TDM_COMPOSITION_DEVICE || hw->client_type == TDM_COMPOSITION_VIDEO)
+ && !is_client_detected) {
+ hw->validated_type = TDM_COMPOSITION_DEVICE_CANDIDATE;
+ } else {
+ hw->validated_type = TDM_COMPOSITION_CLIENT;
+ need_target_buffer = 1;
+ is_client_detected = 1;
+ }
+ }
+
+ if (need_target_buffer)
+ max_hw_layer--;
+
+ is_client_detected = 0;
+ /* check format and flags for DEVICE_CANDIDATE */
+ LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ if (hw->validated_type == TDM_COMPOSITION_DEVICE_CANDIDATE) {
+ if (is_client_detected || hw_layer_count >= max_hw_layer) {
+ is_client_detected = 1;
+ hw->validated_type = TDM_COMPOSITION_CLIENT;
+ } else {
+ if (hw->client_type == TDM_COMPOSITION_VIDEO && hw_layer_count == 0 &&
+ _sprd_hwc_window_is_reserved_buffer(hw)) {
+ hw_layer_count++;
+ hw->validated_type = TDM_COMPOSITION_VIDEO;
+ continue;
+
+ }
+ layer = _sprd_output_get_layer(sprd_output, hw_layer_count);
+ /* check format */
+ if (!_sprd_layer_is_supported_format(layer, hw->info.src_config.format))
+ hw->validated_type = TDM_COMPOSITION_CLIENT;
+ else if (!hw->display_buffer || !hw->display_buffer->buffer)
+ hw->validated_type = TDM_COMPOSITION_CLIENT;
+ /* check buffer flags */
+ else if (_sprd_hwc_window_is_reserved_buffer(hw)) {
+ hw_layer_count++;
+ hw->validated_type = TDM_COMPOSITION_DEVICE;
+ continue;
+
+ }
+ is_client_detected = 1;
+ }
+ }
+ }
+
+ if (is_client_detected)
+ need_target_buffer = 1;
+
+ LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ if (need_target_buffer && hw_layer_count == i++)
+ TDM_DBG(" window(%p) target", sprd_output->target_hwc_window);
+ else
+ TDM_DBG(" window(%p) type: %s -> %s", hw,
+ _comp_to_str(hw->client_type), _comp_to_str(hw->validated_type));
+ }
+
+ sprd_output->need_target_buffer = need_target_buffer;
+
+ *num_types = _sprd_output_get_changed_number(sprd_output);
+
+ if (*num_types == 0)
+ sprd_output->need_validate = 0;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_output_hwc_get_changed_composition_types(tdm_output *output,
+ uint32_t *num_elements,
+ tdm_hwc_window **hwc_window,
+ tdm_hwc_window_composition *composition_types)
+{
+ tdm_sprd_output_data *sprd_output = output;
+ int num = 0;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ if ((hwc_window == NULL) || (composition_types == NULL)) {
+ *num_elements = _sprd_output_get_changed_number(sprd_output);
+ return TDM_ERROR_NONE;
+ }
+
+ tdm_sprd_hwc_window_data *hw = NULL;
+ LIST_FOR_EACH_ENTRY_REV(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ if (num >= *num_elements)
+ break;
+
+ if (hw->client_type != hw->validated_type) {
+ composition_types[num] = hw->validated_type;
+ hwc_window[num] = hw;
+ num++;
+ }
+ }
+
+ /* set real num of changed composition types */
+ *num_elements = num;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_output_hwc_accept_changes(tdm_output *output)
+{
+ tdm_sprd_output_data *sprd_output = output;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ tdm_sprd_hwc_window_data *hw = NULL;
+ LIST_FOR_EACH_ENTRY_REV(hw, &sprd_output->hwc_window_list, link) {
+ if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+ continue;
+
+ hw->client_type = hw->validated_type;
+ }
+
+ sprd_output->need_validate = 0;
+
+ return TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+sprd_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error)
+{
+ tdm_sprd_output_data *sprd_output = output;
+ tbm_surface_queue_h tqueue = NULL;
+
+ if (error)
+ *error = TDM_ERROR_INVALID_PARAMETER;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, NULL);
+
+ if (sprd_output->target_hwc_window == NULL) {
+ if (error)
+ *error = TDM_ERROR_OPERATION_FAILED;
+ return NULL;
+ }
+
+ tqueue = sprd_hwc_window_get_tbm_buffer_queue(sprd_output->target_hwc_window, error);
+ RETURN_VAL_IF_FAIL(tqueue, NULL);
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+ return tqueue;
+}
+
+tdm_error
+sprd_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
+ tdm_hwc_region damage)
+{
+ tdm_sprd_output_data *sprd_output = output;
+ tdm_error err;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_output->target_hwc_window != NULL, TDM_ERROR_OPERATION_FAILED);
+
+ err = sprd_hwc_window_set_buffer(sprd_output->target_hwc_window, buffer);
+ RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
+
+ err = sprd_hwc_window_set_buffer_damage(sprd_output->target_hwc_window, damage);
+ RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
+
+ return TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+sprd_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+ tdm_sprd_output_data *sprd_output = NULL;
+ tbm_surface_queue_h tqueue = NULL;
+
+ if (error)
+ *error = TDM_ERROR_INVALID_PARAMETER;
+
+ RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
+ sprd_hwc_window = hwc_window;
+ sprd_output = sprd_hwc_window->output_data;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, NULL);
+
+ int wight = sprd_hwc_window->info.src_config.size.h;
+ int hight = sprd_hwc_window->info.src_config.size.v;
+ tbm_format format = sprd_hwc_window->info.src_config.format;
+
+ tqueue = tbm_surface_queue_create(3, wight, hight, format, TBM_BO_SCANOUT);
+ if (error)
+ *error = TDM_ERROR_OPERATION_FAILED;
+ RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+ return tqueue;
+
+}
+
+tdm_error
+sprd_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+ tdm_sprd_output_data *sprd_output;
+
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(zpos < 256, TDM_ERROR_INVALID_PARAMETER);
+
+ sprd_output = sprd_hwc_window->output_data;
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ if (sprd_hwc_window->zpos == zpos)
+ return TDM_ERROR_NONE;
+
+ LIST_DEL(&sprd_hwc_window->link);
+
+ sprd_hwc_window->zpos = zpos;
+
+ _sprd_output_insert_hwc_window(sprd_output, sprd_hwc_window);
+
+ sprd_output->need_validate = 1;
+
+ return TDM_ERROR_NONE;
+
+}
+
+tdm_error
+sprd_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_composition comp_type)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+ tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ if (sprd_hwc_window->client_type == comp_type)
+ return TDM_ERROR_NONE;
+
+ sprd_hwc_window->client_type = comp_type;
+ sprd_output->need_validate = 1;
+
+ return TDM_ERROR_NONE;
+
+}
+
+tdm_error
+sprd_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+ tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ //TODO::
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+ tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ if (memcmp(&sprd_hwc_window->info, info, sizeof(tdm_hwc_window_info)) == 0)
+ return TDM_ERROR_NONE;
+
+ sprd_hwc_window->info = *info;
+ sprd_output->need_validate = 1;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+ tdm_sprd_output_data *sprd_output;
+ tdm_sprd_data *sprd_data;
+ tdm_error err = TDM_ERROR_OPERATION_FAILED;
+
+ tdm_sprd_display_buffer *display_buffer = NULL;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, err);
+
+ sprd_output = sprd_hwc_window->output_data;
+ sprd_data = sprd_hwc_window->sprd_data;
+
+ RETURN_VAL_IF_FAIL(sprd_output != NULL, err);
+ RETURN_VAL_IF_FAIL(sprd_data != NULL, err);
+
+ if (!surface) {
+ sprd_hwc_window->display_buffer = NULL;
+ return TDM_ERROR_NONE;
+ }
+
+ display_buffer = _tdm_sprd_display_find_buffer(sprd_data, surface);
+ if (!display_buffer) {
+ display_buffer = _tdm_sprd_display_creat_buffer(sprd_data, surface, &err);
+ RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
+ LIST_ADDTAIL(&display_buffer->link, &sprd_data->buffer_list);
+ }
+
+ if (sprd_hwc_window->display_buffer == display_buffer)
+ return TDM_ERROR_NONE;
+
+ sprd_hwc_window->display_buffer = display_buffer;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ sprd_hwc_window->flags |= flags;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+ RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+ sprd_hwc_window->flags &= ~flags;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_video_get_capability(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_video_capability *video_capability)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+ RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(video_capability != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_hwc_window->validated_type == TDM_COMPOSITION_VIDEO, TDM_ERROR_INVALID_PARAMETER);
+
+ *video_capability = TDM_HWC_WINDOW_VIDEO_CAPABILITY_SCANOUT;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_video_get_supported_format(tdm_hwc_window *hwc_window,
+ const tbm_format **formats,
+ int *count)
+{
+ tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+ RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(sprd_hwc_window->validated_type == TDM_COMPOSITION_VIDEO, TDM_ERROR_INVALID_PARAMETER);
+
+ *formats = hwc_window_video_formats;
+ *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format);
+
+ return TDM_ERROR_NONE;
+}