~thopiekar/arm-mali/libvdpau-sunxi

64.1.1 by Icenowy
add support of a33
1
/*
74 by Jens Kuske
Add OSD support for A33/A80
2
 * Copyright (c) 2015-2016 Jens Kuske <jenskuske@gmail.com>
64.1.1 by Icenowy
add support of a33
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17
 *
18
 */
19
20
#include <errno.h>
21
#include <fcntl.h>
22
#include <stdlib.h>
23
#include <stdint.h>
24
#include <unistd.h>
25
#include <sys/ioctl.h>
26
#include "kernel-headers/drv_display.h"
27
#include "vdpau_private.h"
28
#include "sunxi_disp.h"
29
30
struct sunxi_disp1_5_private
31
{
32
	struct sunxi_disp pub;
33
34
	int fd;
35
	disp_layer_info video_info;
74 by Jens Kuske
Add OSD support for A33/A80
36
	int video_layer;
37
	disp_layer_info osd_info;
38
	int osd_layer;
69 by Jens Kuske
Work around disp bugs when video layer is outside of screen
39
	unsigned int screen_width;
64.1.1 by Icenowy
add support of a33
40
};
41
42
static void sunxi_disp1_5_close(struct sunxi_disp *sunxi_disp);
43
static int sunxi_disp1_5_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface);
44
static void sunxi_disp1_5_close_video_layer(struct sunxi_disp *sunxi_disp);
45
static int sunxi_disp1_5_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface);
46
static void sunxi_disp1_5_close_osd_layer(struct sunxi_disp *sunxi_disp);
47
48
struct sunxi_disp *sunxi_disp1_5_open(int osd_enabled)
49
{
50
	struct sunxi_disp1_5_private *disp = calloc(1, sizeof(*disp));
51
52
	disp->fd = open("/dev/disp", O_RDWR);
53
	if (disp->fd == -1)
54
		goto err_open;
55
74 by Jens Kuske
Add OSD support for A33/A80
56
	unsigned long args[4] = { 0, 0, (unsigned long) &disp->video_info };
64.1.1 by Icenowy
add support of a33
57
74 by Jens Kuske
Add OSD support for A33/A80
58
	disp->video_layer = 1;
59
	args[1] = disp->video_layer;
64.1.1 by Icenowy
add support of a33
60
64.1.2 by Jens Kuske
Use tiled yuv on A33 to save some memory space and bandwidth
61
	disp->video_info.mode = DISP_LAYER_WORK_MODE_SCALER;
64.1.1 by Icenowy
add support of a33
62
	disp->video_info.alpha_mode = 1;
63
	disp->video_info.alpha_value = 255;
64
	disp->video_info.pipe = 1;
65
	disp->video_info.ck_enable = 0;
66
	disp->video_info.b_trd_out = 0;
67
	disp->video_info.zorder = 1;
68
69
	if (ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args))
70
		goto err_video_layer;
71
72
	if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args))
73
		goto err_video_layer;
74
74 by Jens Kuske
Add OSD support for A33/A80
75
	if (osd_enabled)
76
	{
77
		disp->osd_layer = 2;
78
		args[1] = disp->osd_layer;
79
		args[2] = (unsigned long)&disp->osd_info;
80
81
		disp->osd_info.mode = DISP_LAYER_WORK_MODE_NORMAL;
82
		disp->osd_info.alpha_mode = 0;
83
		disp->osd_info.alpha_value = 255;
84
		disp->osd_info.pipe = 0;
85
		disp->osd_info.ck_enable = 0;
86
		disp->osd_info.b_trd_out = 0;
87
		disp->osd_info.zorder = 2;
88
89
		if (ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args))
90
			goto err_video_layer;
91
92
		if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args))
93
			goto err_video_layer;
94
	}
95
69 by Jens Kuske
Work around disp bugs when video layer is outside of screen
96
	disp->screen_width = ioctl(disp->fd, DISP_CMD_GET_SCN_WIDTH, args);
97
64.1.1 by Icenowy
add support of a33
98
	disp->pub.close = sunxi_disp1_5_close;
99
	disp->pub.set_video_layer = sunxi_disp1_5_set_video_layer;
100
	disp->pub.close_video_layer = sunxi_disp1_5_close_video_layer;
101
	disp->pub.set_osd_layer = sunxi_disp1_5_set_osd_layer;
102
	disp->pub.close_osd_layer = sunxi_disp1_5_close_osd_layer;
103
104
	return (struct sunxi_disp *)disp;
105
106
err_video_layer:
107
	close(disp->fd);
108
err_open:
109
	free(disp);
110
	return NULL;
111
}
112
113
static void sunxi_disp1_5_close(struct sunxi_disp *sunxi_disp)
114
{
115
	struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp;
116
74 by Jens Kuske
Add OSD support for A33/A80
117
	unsigned long args[4] = { 0, disp->video_layer };
64.1.1 by Icenowy
add support of a33
118
119
	ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args);
120
74 by Jens Kuske
Add OSD support for A33/A80
121
	if (disp->osd_layer)
122
	{
123
		args[1] = disp->osd_layer;
124
		ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args);
125
	}
126
64.1.1 by Icenowy
add support of a33
127
	close(disp->fd);
128
	free(sunxi_disp);
129
}
130
131
static int sunxi_disp1_5_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface)
132
{
133
	struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp;
134
69 by Jens Kuske
Work around disp bugs when video layer is outside of screen
135
	disp_window src = { .x = surface->video_src_rect.x0, .y = surface->video_src_rect.y0,
136
			    .width = surface->video_src_rect.x1 - surface->video_src_rect.x0,
137
			    .height = surface->video_src_rect.y1 - surface->video_src_rect.y0 };
138
	disp_window scn = { .x = x + surface->video_dst_rect.x0, .y = y + surface->video_dst_rect.y0,
139
			    .width = surface->video_dst_rect.x1 - surface->video_dst_rect.x0,
140
			    .height = surface->video_dst_rect.y1 - surface->video_dst_rect.y0 };
141
142
	if (scn.y < 0)
143
	{
144
		int scn_clip = -scn.y;
145
		int src_clip = scn_clip * src.height / scn.height;
146
		scn.y = 0;
147
		scn.height -= scn_clip;
148
		src.y += src_clip;
149
		src.height -= src_clip;
150
	}
151
	if (scn.x < 0)
152
	{
153
		int scn_clip = -scn.x;
154
		int src_clip = scn_clip * src.width / scn.width;
155
		scn.x = 0;
156
		scn.width -= scn_clip;
157
		src.x += src_clip;
158
		src.width -= src_clip;
159
	}
160
	if (scn.x + scn.width > disp->screen_width)
161
	{
162
		int scn_clip = scn.x + scn.width - disp->screen_width;
163
		int src_clip = scn_clip * src.width / scn.width;
164
		scn.width -= scn_clip;
165
		src.width -= src_clip;
166
	}
167
74 by Jens Kuske
Add OSD support for A33/A80
168
	unsigned long args[4] = { 0, disp->video_layer, (unsigned long)(&disp->video_info) };
64.1.1 by Icenowy
add support of a33
169
	switch (surface->vs->source_format)
170
	{
171
	case VDP_YCBCR_FORMAT_YUYV:
172
		disp->video_info.fb.format = DISP_FORMAT_YUV422_I_YUYV;
173
		break;
174
	case VDP_YCBCR_FORMAT_UYVY:
175
		disp->video_info.fb.format = DISP_FORMAT_YUV422_I_UYVY;
176
		break;
177
	case VDP_YCBCR_FORMAT_NV12:
178
		disp->video_info.fb.format = DISP_FORMAT_YUV420_SP_UVUV;
179
		break;
64.1.2 by Jens Kuske
Use tiled yuv on A33 to save some memory space and bandwidth
180
	case INTERNAL_YCBCR_FORMAT:
181
		disp->video_info.fb.format = DISP_FORMAT_YUV420_SP_TILE_UVUV;
182
		break;
64.1.1 by Icenowy
add support of a33
183
	case VDP_YCBCR_FORMAT_YV12:
184
	default:
185
		disp->video_info.fb.format = DISP_FORMAT_YUV420_P;
186
		break;
187
	}
188
71 by Jens Kuske
Use libcedrus
189
	disp->video_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->yuv->data);
190
	disp->video_info.fb.addr[1] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size;
191
	disp->video_info.fb.addr[2] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size + surface->vs->chroma_size / 2;
64.1.1 by Icenowy
add support of a33
192
193
	disp->video_info.fb.size.width = surface->vs->width;
194
	disp->video_info.fb.size.height = surface->vs->height;
69 by Jens Kuske
Work around disp bugs when video layer is outside of screen
195
	disp->video_info.fb.src_win = src;
196
	disp->video_info.screen_win = scn;
64.1.1 by Icenowy
add support of a33
197
	disp->video_info.fb.pre_multiply = 1;
198
199
	if (ioctl(disp->fd, DISP_CMD_LAYER_ENABLE, args))
200
		return -EINVAL;
201
202
	if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args))
203
		return -EINVAL;
204
205
	return 0;
206
}
207
208
static void sunxi_disp1_5_close_video_layer(struct sunxi_disp *sunxi_disp)
209
{
210
	struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp;
211
74 by Jens Kuske
Add OSD support for A33/A80
212
	unsigned long args[4] = { 0, disp->video_layer };
64.1.1 by Icenowy
add support of a33
213
214
	ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args);
215
}
216
217
static int sunxi_disp1_5_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface)
218
{
74 by Jens Kuske
Add OSD support for A33/A80
219
	struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp;
220
221
	unsigned long args[4] = { 0, disp->osd_layer, (unsigned long)(&disp->osd_info) };
222
223
	disp_window src = { .x = surface->rgba.dirty.x0, .y = surface->rgba.dirty.y0,
224
			  .width = surface->rgba.dirty.x1 - surface->rgba.dirty.x0,
225
			  .height = surface->rgba.dirty.y1 - surface->rgba.dirty.y0 };
226
	disp_window scn = { .x = x + surface->rgba.dirty.x0, .y = y + surface->rgba.dirty.y0,
227
			  .width = min_nz(width, surface->rgba.dirty.x1) - surface->rgba.dirty.x0,
228
			  .height = min_nz(height, surface->rgba.dirty.y1) - surface->rgba.dirty.y0 };
229
230
	switch (surface->rgba.format)
231
	{
232
	case VDP_RGBA_FORMAT_R8G8B8A8:
233
		disp->osd_info.fb.format = DISP_FORMAT_ABGR_8888;
234
		break;
235
	case VDP_RGBA_FORMAT_B8G8R8A8:
236
	default:
237
		disp->osd_info.fb.format = DISP_FORMAT_ARGB_8888;
238
		break;
239
	}
240
241
	disp->osd_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->rgba.data);
242
	disp->osd_info.fb.size.width = surface->rgba.width;
243
	disp->osd_info.fb.size.height = surface->rgba.height;
244
	disp->osd_info.fb.src_win = src;
245
	disp->osd_info.screen_win = scn;
246
247
	if (ioctl(disp->fd, DISP_CMD_LAYER_ENABLE, args))
248
		return -EINVAL;
249
250
	if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args))
251
		return -EINVAL;
252
253
	return 0;
64.1.1 by Icenowy
add support of a33
254
}
255
256
static void sunxi_disp1_5_close_osd_layer(struct sunxi_disp *sunxi_disp)
257
{
74 by Jens Kuske
Add OSD support for A33/A80
258
	struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp;
259
260
	unsigned long args[4] = { 0, disp->osd_layer };
261
262
	ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args);
64.1.1 by Icenowy
add support of a33
263
}