1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <errno.h>
22
23#include <pthread.h>
24
25#include <hardware/hardware.h>
26#include <hardware/gralloc.h>
27#include <hardware/hwcomposer.h>
28
29#include <system/window.h>
30#include <cutils/native_handle.h>
31
32// normalize and shorten type names
33typedef struct android_native_base_t aBase;
34typedef struct ANativeWindowBuffer aBuffer;
35typedef struct ANativeWindow aWindow;
36
37static int trace_level = 1;
38
39#define _TRACE(n,fmt...) \
40	do { if (trace_level >= n) fprintf(stderr, "CNW: " fmt); } while (0)
41
42#define ERROR(fmt...) _TRACE(0, fmt)
43#define INFO(fmt...) _TRACE(1, fmt)
44#define LOG(fmt...) _TRACE(2, fmt)
45#define TRACE(fmt...) _TRACE(3, fmt)
46
47#define QCT_WORKAROUND 1
48
49typedef struct CNativeBuffer {
50	aBuffer base;
51	struct CNativeBuffer *next;
52	struct CNativeBuffer *prev;
53	int ffd;
54} CNativeBuffer;
55
56typedef struct CNativeWindow {
57	aWindow base;
58
59	hwc_composer_device_1_t *hwc;
60	framebuffer_device_t *fb;
61	alloc_device_t *gr;
62
63	pthread_mutex_t lock;
64	pthread_cond_t cvar;
65
66	aBuffer *front;
67	aBuffer *spare;
68
69	CNativeBuffer free_buffer_queue;
70
71	unsigned width;
72	unsigned height;
73	unsigned xdpi;
74	unsigned ydpi;
75	unsigned format;
76
77	hwc_display_contents_1_t *dclist[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
78
79	hwc_display_contents_1_t dc;
80	hwc_layer_1_t layer[4];
81} CNativeWindow;
82
83static inline CNativeBuffer *from_abuffer(aBuffer *buf) {
84	return (CNativeBuffer*) buf;
85}
86
87static CNativeBuffer *get_front(struct CNativeBuffer *queue) {
88	CNativeBuffer *buf = queue->next;
89	if (buf == queue)
90		return 0;
91	buf->next->prev = queue;
92	queue->next = buf->next;
93	buf->next = buf->prev = 0;
94	return buf;
95}
96
97static void put_front(struct CNativeBuffer *queue, aBuffer *_buf) {
98	struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
99	buf->prev = queue;
100	buf->next = queue->next;
101	queue->next->prev = buf;
102	queue->next = buf;
103}
104
105static void put_back(struct CNativeBuffer *queue, aBuffer *_buf) {
106	struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
107	buf->next = queue;
108	buf->prev = queue->prev;
109	queue->prev->next = buf;
110	queue->prev = buf;
111}
112
113static void cnw_inc_ref(aBase *base) { TRACE("buf %p ref++\n",base); }
114static void cnw_dec_ref(aBase *base) { TRACE("buf %p ref--\n",base); }
115
116static inline CNativeWindow *from_base(aWindow *base) {
117	return (CNativeWindow *) base;
118}
119
120static inline CNativeWindow *from_base_const(const aWindow *base) {
121	return (CNativeWindow *) base;
122}
123
124static int cnw_set_swap_interval(aWindow *base, int interval) {
125	CNativeWindow *win = from_base(base);
126	if (win->fb && win->fb->setSwapInterval)
127		return win->fb->setSwapInterval(win->fb, interval);
128	return 0;
129}
130
131static int cnw_dequeue_buffer1(aWindow *base, aBuffer **buf, int *ffd) {
132	CNativeWindow *win = from_base(base);
133	CNativeBuffer *cnb;
134
135	pthread_mutex_lock(&win->lock);
136
137	while ((cnb = get_front(&win->free_buffer_queue)) == 0) {
138		pthread_cond_wait(&win->cvar, &win->lock);
139	}
140
141	*ffd = cnb->ffd;
142	*buf = &cnb->base;
143	cnb->ffd = -1;
144	LOG("<< dequeue buffer %p %d\n", *buf, *ffd);
145
146	pthread_mutex_unlock(&win->lock);
147	return 0;
148}
149
150static int cnw_lock_buffer0(aWindow *base, aBuffer *buffer) {
151	return 0;
152}
153
154static void set_layer(hwc_layer_1_t *dl, aBuffer *buf, int ffd) {
155	int right = buf->width;
156	int bottom = buf->height;
157
158	dl->compositionType = HWC_FRAMEBUFFER;
159	dl->hints = 0;
160	dl->flags = 0;
161
162	dl->handle = buf->handle;
163	dl->transform = 0;
164	dl->blending = HWC_BLENDING_NONE;
165	dl->sourceCrop.left = 0;
166	dl->sourceCrop.top = 0;
167	dl->sourceCrop.right = right;
168	dl->sourceCrop.bottom = bottom;
169	dl->displayFrame.left = 0;
170	dl->displayFrame.top = 0;
171	dl->displayFrame.right = right;
172	dl->displayFrame.bottom = bottom;
173	dl->visibleRegionScreen.numRects = 1;
174	dl->visibleRegionScreen.rects = &dl->displayFrame;
175
176	dl->acquireFenceFd = ffd;
177	dl->releaseFenceFd = -1;
178}
179
180static void hwc_post(CNativeWindow *win, aBuffer *buf, int ffd) {
181	hwc_composer_device_1_t *hwc = win->hwc;
182	hwc_display_contents_1_t *dc = &(win->dc);
183	hwc_layer_1_t *dl = win->dc.hwLayers;
184	int r, i;
185
186	dc->retireFenceFd = -1;
187	dc->outbufAcquireFenceFd = -1;
188	dc->flags = HWC_GEOMETRY_CHANGED;
189	dc->numHwLayers = 1;
190
191	// some hwcomposers fail if these are NULL
192	dc->dpy = (void*) 0xdeadbeef;
193	dc->sur = (void*) 0xdeadbeef;
194
195	set_layer(&dl[0], buf, ffd);
196
197	if (QCT_WORKAROUND) {
198		set_layer(&dl[1], win->spare, -1);
199		dl[1].compositionType = HWC_FRAMEBUFFER_TARGET;
200		dc->numHwLayers++;
201	}
202
203	r = hwc->prepare(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
204	if (r) {
205		ERROR("hwc->prepare failed r=%d\n",r);
206		return;
207	}
208
209//	for (i = 0; i < dc->numHwLayers; i++)
210//		LOG("dl[%d] ctype=0x%08x hints=0x%08x flags=0x%08x\n", i,
211//			dl[i].compositionType, dl[0].hints, dl[0].flags);
212
213	r = hwc->set(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
214	if (r) {
215		ERROR("hwc->set failed, r=%d\n", r);
216		return;
217	}
218
219	if (dc->retireFenceFd != -1)
220		close(dc->retireFenceFd);
221	if (dl->releaseFenceFd != -1) {
222		CNativeBuffer *cnb = from_abuffer(buf);
223		cnb->ffd = dl->releaseFenceFd;
224	}
225	if (QCT_WORKAROUND)
226		if (dl[1].releaseFenceFd != -1)
227			close(dl[1].releaseFenceFd);
228}
229
230static int cnw_queue_buffer1(aWindow *base, aBuffer *buffer, int ffd) {
231	CNativeWindow *win = from_base(base);
232	int res;
233	LOG(">> queue buffer %p %d\n", buffer, ffd);
234	if (win->fb) {
235		res = win->fb->post(win->fb, buffer->handle);
236		if (ffd != -1)
237			close(ffd);
238	} else {
239		hwc_post(win, buffer, ffd);
240		res = 0;
241	}
242	pthread_mutex_lock(&win->lock);
243	if (win->front)
244		put_back(&win->free_buffer_queue, win->front);
245	win->front = buffer;
246	pthread_cond_signal(&win->cvar);
247	pthread_mutex_unlock(&win->lock);
248
249	return res;
250}
251
252static int cnw_cancel_buffer1(aWindow *base, aBuffer *buf, int ffd) {
253	CNativeWindow *win = from_base(base);
254	CNativeBuffer *cnb = from_abuffer(buf);
255	LOG("<< cancel buffer %p %d\n", buf, ffd);
256	cnb->ffd = ffd;
257	pthread_mutex_lock(&win->lock);
258	put_front(&win->free_buffer_queue, buf);
259	pthread_mutex_unlock(&win->lock);
260	return 0;
261}
262
263static int cnw_dequeue_buffer0(aWindow *base, aBuffer **buf) {
264	int ffd = -1;
265	int r;
266	r = cnw_dequeue_buffer1(base, buf, &ffd);
267	if (ffd != -1)
268		close(ffd);
269	return r;
270}
271
272static int cnw_queue_buffer0(aWindow *base, aBuffer *buf) {
273	return cnw_queue_buffer1(base, buf, -1);
274}
275
276static int cnw_cancel_buffer0(aWindow *base, aBuffer *buf) {
277	return cnw_cancel_buffer1(base, buf, -1);
278}
279
280static int cnw_query(const aWindow *base, int what, int *value) {
281	CNativeWindow *win = from_base_const(base);
282
283	switch (what) {
284	case NATIVE_WINDOW_WIDTH:
285	case NATIVE_WINDOW_DEFAULT_WIDTH:
286		*value = win->width;
287		TRACE("query window width: %d\n", *value);
288		return 0;
289	case NATIVE_WINDOW_HEIGHT:
290	case NATIVE_WINDOW_DEFAULT_HEIGHT:
291		*value = win->height;
292		TRACE("query window height: %d\n", *value);
293		return 0;
294	case NATIVE_WINDOW_FORMAT:
295		*value = win->format;
296		TRACE("query window format: %d\n", *value);
297		return 0;
298	case NATIVE_WINDOW_TRANSFORM_HINT:
299		TRACE("query transform hint: 0\n");
300		*value = 0;
301		return 0;
302	case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
303		TRACE("query min undequeued buffers: 1\n");
304		*value = 1;
305		return 0;
306	default:
307		*value = 0;
308		ERROR("query %d unknown!\n", what);
309		return -EINVAL;
310	}
311}
312
313static int cnw_perform(aWindow *base, int op, ...) {
314	CNativeWindow *win = from_base(base);
315	va_list ap;
316	va_start(ap, op);
317
318	switch (op) {
319	case NATIVE_WINDOW_SET_USAGE:
320		TRACE("set usage %d\n", va_arg(ap,int));
321		return 0;
322	case NATIVE_WINDOW_CONNECT:
323	case NATIVE_WINDOW_DISCONNECT:
324	case NATIVE_WINDOW_API_CONNECT:
325	case NATIVE_WINDOW_API_DISCONNECT:
326		return 0;
327	case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
328		TRACE("set buffers format %d\n", va_arg(ap,int));
329		return 0;
330	case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
331		TRACE("set buffers transform %d\n", va_arg(ap,int));
332		return 0;
333	case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
334		TRACE("set buffers timestamp %lld\n", va_arg(ap,long long));
335		return 0;
336	case NATIVE_WINDOW_SET_SCALING_MODE:
337		TRACE("set scaling mode %d\n", va_arg(ap,int));
338		return 0;
339	case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
340		int w = va_arg(ap,int);
341		int h = va_arg(ap,int);
342		if ((w == win->width) && (h == win->height)) {
343			TRACE("set buffers dimensions %d x %d\n", w, h);
344			return 0;
345		}
346		ERROR("cannot resize buffers to %d x %d\n", w, h);
347		return -1;
348	}
349	default:
350		ERROR("perform %d unknown!\n", op);
351		return -ENODEV;
352	}
353}
354
355static void hwc_invalidate(const struct hwc_procs *procs) {}
356static void hwc_vsync(const struct hwc_procs *procs, int disp, int64_t ts) {}
357static void hwc_hotplug(const struct hwc_procs *procs, int disp, int conn) {}
358
359struct hwc_procs hprocs = {
360	.invalidate = hwc_invalidate,
361	.vsync = hwc_vsync,
362	.hotplug = hwc_hotplug,
363};
364
365uint32_t attrs[] = {
366	HWC_DISPLAY_WIDTH,
367	HWC_DISPLAY_HEIGHT,
368	HWC_DISPLAY_VSYNC_PERIOD,
369	HWC_DISPLAY_DPI_X,
370	HWC_DISPLAY_DPI_Y,
371	HWC_DISPLAY_NO_ATTRIBUTE,
372};
373
374static int hwc_init(CNativeWindow *win) {
375	hw_module_t const* module;
376	hwc_composer_device_1_t *hwc;
377	unsigned i;
378	int r;
379	uint32_t configs[32];
380	uint32_t numconfigs = 32;
381	int32_t values[8];
382
383	if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
384		ERROR("cannot open hw composer module\n");
385		return -ENODEV;
386	}
387
388	if (hwc_open_1(module, &hwc)) {
389		ERROR("cannot open hwc device\n");
390		return -ENODEV;
391	}
392	win->hwc = hwc;
393
394	LOG("hwc version 0x%08x\n", hwc->common.version);
395
396	if ((hwc->common.version & 0xFFFF0000) < 0x01010000) {
397		ERROR("hwc version less than 1.1\n");
398		hwc_close_1(hwc);
399		return -ENODEV;
400	}
401
402	hwc->registerProcs(hwc, &hprocs);
403
404	if (hwc->getDisplayConfigs(hwc, 0, configs, &numconfigs)) {
405		ERROR("cannot get configs\n");
406		return -ENODEV;
407	}
408	for (i = 0; i < numconfigs; i++)
409		LOG("cfg[%d] = 0x%08x\n", i, configs[i]);
410
411	if ((r = hwc->getDisplayAttributes(hwc, 0, configs[0], attrs, values))) {
412		ERROR("cannot get attributes %d\n", r);
413		return -ENODEV;
414	}
415
416	win->width = values[0];
417	win->height = values[1];
418	win->xdpi = values[3];
419	win->ydpi = values[4];
420	win->format = HAL_PIXEL_FORMAT_RGBA_8888;
421
422	hwc->blank(hwc, 0, 0);
423
424	win->dclist[0] = &(win->dc);
425	return 0;
426}
427
428static aBuffer *cnw_alloc(CNativeWindow *win, unsigned format, unsigned usage) {
429	CNativeBuffer *cnb;
430	aBuffer *buf;
431	int err;
432
433	if (!(cnb = malloc(sizeof(CNativeBuffer))))
434		return 0;
435
436	buf = &cnb->base;
437	cnb->ffd = -1;
438
439	buf->common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
440	buf->common.version = sizeof(aBuffer);
441	buf->common.incRef = cnw_inc_ref;
442	buf->common.decRef = cnw_dec_ref;
443
444	buf->width = win->width;
445	buf->height = win->height;
446	buf->format = format;
447	buf->usage = usage;
448
449	err = win->gr->alloc(win->gr, win->width, win->height,
450		format, usage, &buf->handle, &buf->stride);
451	if (err) {
452		ERROR("gralloc of %d x %d failed: err=%d\n",
453			win->width, win->height, err);
454		free(buf);
455		return 0;
456	}
457	INFO("alloc buffer %p %d x %d\n", buf, win->width, win->height);
458	return buf;
459}
460
461static int cnw_init(CNativeWindow *win) {
462	hw_module_t const* module;
463	framebuffer_device_t *fb = NULL;
464	alloc_device_t *gr;
465	int err, i, n;
466	unsigned usage, format;
467
468	memset(win, 0, sizeof(CNativeWindow));
469
470	win->free_buffer_queue.next = &(win->free_buffer_queue);
471	win->free_buffer_queue.prev = &(win->free_buffer_queue);
472
473	if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
474		ERROR("cannot open gralloc module\n");
475		return -ENODEV;
476	}
477
478	if (hwc_init(win)) {
479		ERROR("cannot open hwcomposer, trying legacy fb HAL\n");
480		err = framebuffer_open(module, &fb);
481		if (err) {
482			ERROR("cannot open fb HAL (%s)", strerror(-err));
483			return -ENODEV;
484		}
485		win->width = fb->width;
486		win->height = fb->height;
487		win->format = fb->format;
488		win->xdpi = fb->xdpi;
489		win->ydpi = fb->ydpi;
490		win->fb = fb;
491	}
492
493	INFO("display %d x %d fmt=%d\n",
494		win->width, win->height, win->format);
495
496	err = gralloc_open(module, &gr);
497	if (err) {
498		ERROR("couldn't open gralloc HAL (%s)", strerror(-err));
499		return -ENODEV;
500	}
501	win->gr = gr;
502
503	usage = GRALLOC_USAGE_HW_FB |
504		GRALLOC_USAGE_HW_COMPOSER |
505		GRALLOC_USAGE_HW_RENDER;
506
507	for (i = 0; i < 2; i++) {
508		aBuffer *buf = cnw_alloc(win, win->format, usage);
509		if (!buf)
510			return -ENOMEM;
511		put_back(&win->free_buffer_queue, buf);
512	}
513
514	if (!win->fb && QCT_WORKAROUND) {
515		win->spare = cnw_alloc(win, win->format, usage);
516		if (!win->spare)
517			return -ENOMEM;
518	}
519
520	// Disgusting, but we need to init these "const" fields
521	// and unlike C++ we can't use const_cast<>
522	*((float*) &win->base.xdpi) = win->xdpi;
523	*((float*) &win->base.ydpi) = win->ydpi;
524	*((int*) &win->base.minSwapInterval) = 1;
525	*((int*) &win->base.maxSwapInterval) = 1;
526
527	win->base.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
528	win->base.common.version = sizeof(aWindow);
529	win->base.common.incRef = cnw_inc_ref;
530	win->base.common.decRef = cnw_dec_ref;
531
532	win->base.setSwapInterval = cnw_set_swap_interval;
533	win->base.dequeueBuffer_DEPRECATED = cnw_dequeue_buffer0;
534	win->base.lockBuffer_DEPRECATED = cnw_lock_buffer0;
535	win->base.queueBuffer_DEPRECATED = cnw_queue_buffer0;
536	win->base.query = cnw_query;
537	win->base.perform = cnw_perform;
538	win->base.cancelBuffer_DEPRECATED = cnw_cancel_buffer0;
539	win->base.dequeueBuffer = cnw_dequeue_buffer1;
540	win->base.queueBuffer = cnw_queue_buffer1;
541	win->base.cancelBuffer = cnw_cancel_buffer1;
542
543	pthread_mutex_init(&win->lock, NULL);
544	pthread_cond_init(&win->cvar, NULL);
545
546	return 0;
547}
548
549void cnw_destroy(CNativeWindow *win) {
550	if (win->fb)
551		framebuffer_close(win->fb);
552	if (win->hwc)
553		hwc_close_1(win->hwc);
554	if (win->gr)
555		gralloc_close(win->gr);
556	free(win);
557}
558
559CNativeWindow *cnw_create(void) {
560	CNativeWindow *win;
561	char *x;
562	if ((x = getenv("CNWDEBUG")))
563		trace_level = atoi(x);
564	if (!(win = malloc(sizeof(CNativeWindow))))
565		return NULL;
566	if (cnw_init(win)) {
567		cnw_destroy(win);
568		return NULL;
569	}
570	return win;
571}
572
573void cnw_info(CNativeWindow *win, unsigned *w, unsigned *h, unsigned *fmt) {
574	*w = win->width;
575	*h = win->height;
576	*fmt = win->format;
577}
578
579