4224d9ea16
* Remove unused local variables. * Suppress warning of unused template functions. * Fix error of unused expression value. Bug: 66996870 Test: build with WITH_TIDY=1 Change-Id: I5a37c24f3be0f61b0ae4552e34b7311f561d499e
578 lines
14 KiB
C
578 lines
14 KiB
C
/*
|
|
* Copyright (C) 2013 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <hardware/hardware.h>
|
|
#include <hardware/gralloc.h>
|
|
#include <hardware/hwcomposer.h>
|
|
|
|
#include <system/window.h>
|
|
#include <cutils/native_handle.h>
|
|
|
|
// normalize and shorten type names
|
|
typedef struct android_native_base_t aBase;
|
|
typedef struct ANativeWindowBuffer aBuffer;
|
|
typedef struct ANativeWindow aWindow;
|
|
|
|
static int trace_level = 1;
|
|
|
|
#define _TRACE(n,fmt...) \
|
|
do { if (trace_level >= (n)) fprintf(stderr, "CNW: " fmt); } while (0)
|
|
|
|
#define ERROR(fmt...) _TRACE(0, fmt)
|
|
#define INFO(fmt...) _TRACE(1, fmt)
|
|
#define LOG(fmt...) _TRACE(2, fmt)
|
|
#define TRACE(fmt...) _TRACE(3, fmt)
|
|
|
|
#define QCT_WORKAROUND 1
|
|
|
|
typedef struct CNativeBuffer {
|
|
aBuffer base;
|
|
struct CNativeBuffer *next;
|
|
struct CNativeBuffer *prev;
|
|
int ffd;
|
|
} CNativeBuffer;
|
|
|
|
typedef struct CNativeWindow {
|
|
aWindow base;
|
|
|
|
hwc_composer_device_1_t *hwc;
|
|
framebuffer_device_t *fb;
|
|
alloc_device_t *gr;
|
|
|
|
pthread_mutex_t lock;
|
|
pthread_cond_t cvar;
|
|
|
|
aBuffer *front;
|
|
aBuffer *spare;
|
|
|
|
CNativeBuffer free_buffer_queue;
|
|
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned xdpi;
|
|
unsigned ydpi;
|
|
unsigned format;
|
|
|
|
hwc_display_contents_1_t *dclist[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
|
|
|
|
hwc_display_contents_1_t dc;
|
|
hwc_layer_1_t layer[4];
|
|
} CNativeWindow;
|
|
|
|
static inline CNativeBuffer *from_abuffer(aBuffer *buf) {
|
|
return (CNativeBuffer*) buf;
|
|
}
|
|
|
|
static CNativeBuffer *get_front(struct CNativeBuffer *queue) {
|
|
CNativeBuffer *buf = queue->next;
|
|
if (buf == queue)
|
|
return 0;
|
|
buf->next->prev = queue;
|
|
queue->next = buf->next;
|
|
buf->next = buf->prev = 0;
|
|
return buf;
|
|
}
|
|
|
|
static void put_front(struct CNativeBuffer *queue, aBuffer *_buf) {
|
|
struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
|
|
buf->prev = queue;
|
|
buf->next = queue->next;
|
|
queue->next->prev = buf;
|
|
queue->next = buf;
|
|
}
|
|
|
|
static void put_back(struct CNativeBuffer *queue, aBuffer *_buf) {
|
|
struct CNativeBuffer *buf = (struct CNativeBuffer *) _buf;
|
|
buf->next = queue;
|
|
buf->prev = queue->prev;
|
|
queue->prev->next = buf;
|
|
queue->prev = buf;
|
|
}
|
|
|
|
static void cnw_inc_ref(aBase *base) { TRACE("buf %p ref++\n",base); }
|
|
static void cnw_dec_ref(aBase *base) { TRACE("buf %p ref--\n",base); }
|
|
|
|
static inline CNativeWindow *from_base(aWindow *base) {
|
|
return (CNativeWindow *) base;
|
|
}
|
|
|
|
static inline CNativeWindow *from_base_const(const aWindow *base) {
|
|
return (CNativeWindow *) base;
|
|
}
|
|
|
|
static int cnw_set_swap_interval(aWindow *base, int interval) {
|
|
CNativeWindow *win = from_base(base);
|
|
if (win->fb && win->fb->setSwapInterval)
|
|
return win->fb->setSwapInterval(win->fb, interval);
|
|
return 0;
|
|
}
|
|
|
|
static int cnw_dequeue_buffer1(aWindow *base, aBuffer **buf, int *ffd) {
|
|
CNativeWindow *win = from_base(base);
|
|
CNativeBuffer *cnb;
|
|
|
|
pthread_mutex_lock(&win->lock);
|
|
|
|
while ((cnb = get_front(&win->free_buffer_queue)) == 0) {
|
|
pthread_cond_wait(&win->cvar, &win->lock);
|
|
}
|
|
|
|
*ffd = cnb->ffd;
|
|
*buf = &cnb->base;
|
|
cnb->ffd = -1;
|
|
LOG("<< dequeue buffer %p %d\n", *buf, *ffd);
|
|
|
|
pthread_mutex_unlock(&win->lock);
|
|
return 0;
|
|
}
|
|
|
|
static int cnw_lock_buffer0(aWindow *base, aBuffer *buffer) {
|
|
return 0;
|
|
}
|
|
|
|
static void set_layer(hwc_layer_1_t *dl, aBuffer *buf, int ffd) {
|
|
int right = buf->width;
|
|
int bottom = buf->height;
|
|
|
|
dl->compositionType = HWC_FRAMEBUFFER;
|
|
dl->hints = 0;
|
|
dl->flags = 0;
|
|
|
|
dl->handle = buf->handle;
|
|
dl->transform = 0;
|
|
dl->blending = HWC_BLENDING_NONE;
|
|
dl->sourceCrop.left = 0;
|
|
dl->sourceCrop.top = 0;
|
|
dl->sourceCrop.right = right;
|
|
dl->sourceCrop.bottom = bottom;
|
|
dl->displayFrame.left = 0;
|
|
dl->displayFrame.top = 0;
|
|
dl->displayFrame.right = right;
|
|
dl->displayFrame.bottom = bottom;
|
|
dl->visibleRegionScreen.numRects = 1;
|
|
dl->visibleRegionScreen.rects = &dl->displayFrame;
|
|
|
|
dl->acquireFenceFd = ffd;
|
|
dl->releaseFenceFd = -1;
|
|
}
|
|
|
|
static void hwc_post(CNativeWindow *win, aBuffer *buf, int ffd) {
|
|
hwc_composer_device_1_t *hwc = win->hwc;
|
|
hwc_display_contents_1_t *dc = &(win->dc);
|
|
hwc_layer_1_t *dl = win->dc.hwLayers;
|
|
int r;
|
|
|
|
dc->retireFenceFd = -1;
|
|
dc->outbufAcquireFenceFd = -1;
|
|
dc->flags = HWC_GEOMETRY_CHANGED;
|
|
dc->numHwLayers = 1;
|
|
|
|
// some hwcomposers fail if these are NULL
|
|
dc->dpy = (void*) 0xdeadbeef;
|
|
dc->sur = (void*) 0xdeadbeef;
|
|
|
|
set_layer(&dl[0], buf, ffd);
|
|
|
|
if (QCT_WORKAROUND) {
|
|
set_layer(&dl[1], win->spare, -1);
|
|
dl[1].compositionType = HWC_FRAMEBUFFER_TARGET;
|
|
dc->numHwLayers++;
|
|
}
|
|
|
|
r = hwc->prepare(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
|
|
if (r) {
|
|
ERROR("hwc->prepare failed r=%d\n",r);
|
|
return;
|
|
}
|
|
|
|
// for (i = 0; i < dc->numHwLayers; i++)
|
|
// LOG("dl[%d] ctype=0x%08x hints=0x%08x flags=0x%08x\n", i,
|
|
// dl[i].compositionType, dl[0].hints, dl[0].flags);
|
|
|
|
r = hwc->set(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist);
|
|
if (r) {
|
|
ERROR("hwc->set failed, r=%d\n", r);
|
|
return;
|
|
}
|
|
|
|
if (dc->retireFenceFd != -1)
|
|
close(dc->retireFenceFd);
|
|
if (dl->releaseFenceFd != -1) {
|
|
CNativeBuffer *cnb = from_abuffer(buf);
|
|
cnb->ffd = dl->releaseFenceFd;
|
|
}
|
|
if (QCT_WORKAROUND)
|
|
if (dl[1].releaseFenceFd != -1)
|
|
close(dl[1].releaseFenceFd);
|
|
}
|
|
|
|
static int cnw_queue_buffer1(aWindow *base, aBuffer *buffer, int ffd) {
|
|
CNativeWindow *win = from_base(base);
|
|
int res;
|
|
LOG(">> queue buffer %p %d\n", buffer, ffd);
|
|
if (win->fb) {
|
|
res = win->fb->post(win->fb, buffer->handle);
|
|
if (ffd != -1)
|
|
close(ffd);
|
|
} else {
|
|
hwc_post(win, buffer, ffd);
|
|
res = 0;
|
|
}
|
|
pthread_mutex_lock(&win->lock);
|
|
if (win->front)
|
|
put_back(&win->free_buffer_queue, win->front);
|
|
win->front = buffer;
|
|
pthread_cond_signal(&win->cvar);
|
|
pthread_mutex_unlock(&win->lock);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int cnw_cancel_buffer1(aWindow *base, aBuffer *buf, int ffd) {
|
|
CNativeWindow *win = from_base(base);
|
|
CNativeBuffer *cnb = from_abuffer(buf);
|
|
LOG("<< cancel buffer %p %d\n", buf, ffd);
|
|
cnb->ffd = ffd;
|
|
pthread_mutex_lock(&win->lock);
|
|
put_front(&win->free_buffer_queue, buf);
|
|
pthread_mutex_unlock(&win->lock);
|
|
return 0;
|
|
}
|
|
|
|
static int cnw_dequeue_buffer0(aWindow *base, aBuffer **buf) {
|
|
int ffd = -1;
|
|
int r;
|
|
r = cnw_dequeue_buffer1(base, buf, &ffd);
|
|
if (ffd != -1)
|
|
close(ffd);
|
|
return r;
|
|
}
|
|
|
|
static int cnw_queue_buffer0(aWindow *base, aBuffer *buf) {
|
|
return cnw_queue_buffer1(base, buf, -1);
|
|
}
|
|
|
|
static int cnw_cancel_buffer0(aWindow *base, aBuffer *buf) {
|
|
return cnw_cancel_buffer1(base, buf, -1);
|
|
}
|
|
|
|
static int cnw_query(const aWindow *base, int what, int *value) {
|
|
CNativeWindow *win = from_base_const(base);
|
|
|
|
switch (what) {
|
|
case NATIVE_WINDOW_WIDTH:
|
|
case NATIVE_WINDOW_DEFAULT_WIDTH:
|
|
*value = win->width;
|
|
TRACE("query window width: %d\n", *value);
|
|
return 0;
|
|
case NATIVE_WINDOW_HEIGHT:
|
|
case NATIVE_WINDOW_DEFAULT_HEIGHT:
|
|
*value = win->height;
|
|
TRACE("query window height: %d\n", *value);
|
|
return 0;
|
|
case NATIVE_WINDOW_FORMAT:
|
|
*value = win->format;
|
|
TRACE("query window format: %d\n", *value);
|
|
return 0;
|
|
case NATIVE_WINDOW_TRANSFORM_HINT:
|
|
TRACE("query transform hint: 0\n");
|
|
*value = 0;
|
|
return 0;
|
|
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
|
|
TRACE("query min undequeued buffers: 1\n");
|
|
*value = 1;
|
|
return 0;
|
|
default:
|
|
*value = 0;
|
|
ERROR("query %d unknown!\n", what);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static int cnw_perform(aWindow *base, int op, ...) {
|
|
CNativeWindow *win = from_base(base);
|
|
va_list ap;
|
|
va_start(ap, op);
|
|
|
|
switch (op) {
|
|
case NATIVE_WINDOW_SET_USAGE:
|
|
TRACE("set usage %d\n", va_arg(ap,int));
|
|
return 0;
|
|
case NATIVE_WINDOW_CONNECT:
|
|
case NATIVE_WINDOW_DISCONNECT:
|
|
case NATIVE_WINDOW_API_CONNECT:
|
|
case NATIVE_WINDOW_API_DISCONNECT:
|
|
return 0;
|
|
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
|
|
TRACE("set buffers format %d\n", va_arg(ap,int));
|
|
return 0;
|
|
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
|
|
TRACE("set buffers transform %d\n", va_arg(ap,int));
|
|
return 0;
|
|
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
|
|
TRACE("set buffers timestamp %lld\n", va_arg(ap,long long));
|
|
return 0;
|
|
case NATIVE_WINDOW_SET_SCALING_MODE:
|
|
TRACE("set scaling mode %d\n", va_arg(ap,int));
|
|
return 0;
|
|
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
|
|
unsigned int w = va_arg(ap,unsigned int);
|
|
unsigned int h = va_arg(ap,unsigned int);
|
|
if ((w == win->width) && (h == win->height)) {
|
|
TRACE("set buffers dimensions %d x %d\n", w, h);
|
|
return 0;
|
|
}
|
|
ERROR("cannot resize buffers to %d x %d\n", w, h);
|
|
return -1;
|
|
}
|
|
default:
|
|
ERROR("perform %d unknown!\n", op);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
static void hwc_invalidate(const struct hwc_procs *procs) {}
|
|
static void hwc_vsync(const struct hwc_procs *procs, int disp, int64_t ts) {}
|
|
static void hwc_hotplug(const struct hwc_procs *procs, int disp, int conn) {}
|
|
|
|
struct hwc_procs hprocs = {
|
|
.invalidate = hwc_invalidate,
|
|
.vsync = hwc_vsync,
|
|
.hotplug = hwc_hotplug,
|
|
};
|
|
|
|
uint32_t attrs[] = {
|
|
HWC_DISPLAY_WIDTH,
|
|
HWC_DISPLAY_HEIGHT,
|
|
HWC_DISPLAY_VSYNC_PERIOD,
|
|
HWC_DISPLAY_DPI_X,
|
|
HWC_DISPLAY_DPI_Y,
|
|
HWC_DISPLAY_NO_ATTRIBUTE,
|
|
};
|
|
|
|
static int hwc_init(CNativeWindow *win) {
|
|
hw_module_t const* module;
|
|
hwc_composer_device_1_t *hwc;
|
|
unsigned i;
|
|
int r;
|
|
uint32_t configs[32];
|
|
size_t numconfigs = 32;
|
|
int32_t values[8];
|
|
|
|
if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
|
|
ERROR("cannot open hw composer module\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (hwc_open_1(module, &hwc)) {
|
|
ERROR("cannot open hwc device\n");
|
|
return -ENODEV;
|
|
}
|
|
win->hwc = hwc;
|
|
|
|
LOG("hwc version 0x%08x\n", hwc->common.version);
|
|
|
|
if ((hwc->common.version & 0xFFFF0000) < 0x01010000) {
|
|
ERROR("hwc version less than 1.1\n");
|
|
hwc_close_1(hwc);
|
|
return -ENODEV;
|
|
}
|
|
|
|
hwc->registerProcs(hwc, &hprocs);
|
|
|
|
if (hwc->getDisplayConfigs(hwc, 0, configs, &numconfigs)) {
|
|
ERROR("cannot get configs\n");
|
|
return -ENODEV;
|
|
}
|
|
for (i = 0; i < numconfigs; i++)
|
|
LOG("cfg[%d] = 0x%08x\n", i, configs[i]);
|
|
|
|
if ((r = hwc->getDisplayAttributes(hwc, 0, configs[0], attrs, values))) {
|
|
ERROR("cannot get attributes %d\n", r);
|
|
return -ENODEV;
|
|
}
|
|
|
|
win->width = values[0];
|
|
win->height = values[1];
|
|
win->xdpi = values[3];
|
|
win->ydpi = values[4];
|
|
win->format = HAL_PIXEL_FORMAT_RGBA_8888;
|
|
|
|
hwc->blank(hwc, 0, 0);
|
|
|
|
win->dclist[0] = &(win->dc);
|
|
return 0;
|
|
}
|
|
|
|
static aBuffer *cnw_alloc(CNativeWindow *win, unsigned format, unsigned usage) {
|
|
CNativeBuffer *cnb;
|
|
aBuffer *buf;
|
|
int err;
|
|
|
|
if (!(cnb = malloc(sizeof(CNativeBuffer))))
|
|
return 0;
|
|
|
|
buf = &cnb->base;
|
|
cnb->ffd = -1;
|
|
|
|
buf->common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
|
|
buf->common.version = sizeof(aBuffer);
|
|
buf->common.incRef = cnw_inc_ref;
|
|
buf->common.decRef = cnw_dec_ref;
|
|
|
|
buf->width = win->width;
|
|
buf->height = win->height;
|
|
buf->format = format;
|
|
buf->usage = usage;
|
|
|
|
err = win->gr->alloc(win->gr, win->width, win->height,
|
|
format, usage, &buf->handle, &buf->stride);
|
|
if (err) {
|
|
ERROR("gralloc of %d x %d failed: err=%d\n",
|
|
win->width, win->height, err);
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
INFO("alloc buffer %p %d x %d\n", buf, win->width, win->height);
|
|
return buf;
|
|
}
|
|
|
|
static int cnw_init(CNativeWindow *win) {
|
|
hw_module_t const* module;
|
|
framebuffer_device_t *fb = NULL;
|
|
alloc_device_t *gr;
|
|
int err, i;
|
|
unsigned usage;
|
|
|
|
memset(win, 0, sizeof(CNativeWindow));
|
|
|
|
win->free_buffer_queue.next = &(win->free_buffer_queue);
|
|
win->free_buffer_queue.prev = &(win->free_buffer_queue);
|
|
|
|
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
|
|
ERROR("cannot open gralloc module\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (hwc_init(win)) {
|
|
ERROR("cannot open hwcomposer, trying legacy fb HAL\n");
|
|
err = framebuffer_open(module, &fb);
|
|
if (err) {
|
|
ERROR("cannot open fb HAL (%s)", strerror(-err));
|
|
return -ENODEV;
|
|
}
|
|
win->width = fb->width;
|
|
win->height = fb->height;
|
|
win->format = fb->format;
|
|
win->xdpi = fb->xdpi;
|
|
win->ydpi = fb->ydpi;
|
|
win->fb = fb;
|
|
}
|
|
|
|
INFO("display %d x %d fmt=%d\n",
|
|
win->width, win->height, win->format);
|
|
|
|
err = gralloc_open(module, &gr);
|
|
if (err) {
|
|
ERROR("couldn't open gralloc HAL (%s)", strerror(-err));
|
|
return -ENODEV;
|
|
}
|
|
win->gr = gr;
|
|
|
|
usage = GRALLOC_USAGE_HW_FB |
|
|
GRALLOC_USAGE_HW_COMPOSER |
|
|
GRALLOC_USAGE_HW_RENDER;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
aBuffer *buf = cnw_alloc(win, win->format, usage);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
put_back(&win->free_buffer_queue, buf);
|
|
}
|
|
|
|
if (!win->fb && QCT_WORKAROUND) {
|
|
win->spare = cnw_alloc(win, win->format, usage);
|
|
if (!win->spare)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
// Disgusting, but we need to init these "const" fields
|
|
// and unlike C++ we can't use const_cast<>
|
|
*((float*) &win->base.xdpi) = win->xdpi;
|
|
*((float*) &win->base.ydpi) = win->ydpi;
|
|
*((int*) &win->base.minSwapInterval) = 1;
|
|
*((int*) &win->base.maxSwapInterval) = 1;
|
|
|
|
win->base.common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
|
|
win->base.common.version = sizeof(aWindow);
|
|
win->base.common.incRef = cnw_inc_ref;
|
|
win->base.common.decRef = cnw_dec_ref;
|
|
|
|
win->base.setSwapInterval = cnw_set_swap_interval;
|
|
win->base.dequeueBuffer_DEPRECATED = cnw_dequeue_buffer0;
|
|
win->base.lockBuffer_DEPRECATED = cnw_lock_buffer0;
|
|
win->base.queueBuffer_DEPRECATED = cnw_queue_buffer0;
|
|
win->base.query = cnw_query;
|
|
win->base.perform = cnw_perform;
|
|
win->base.cancelBuffer_DEPRECATED = cnw_cancel_buffer0;
|
|
win->base.dequeueBuffer = cnw_dequeue_buffer1;
|
|
win->base.queueBuffer = cnw_queue_buffer1;
|
|
win->base.cancelBuffer = cnw_cancel_buffer1;
|
|
|
|
pthread_mutex_init(&win->lock, NULL);
|
|
pthread_cond_init(&win->cvar, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cnw_destroy(CNativeWindow *win) {
|
|
if (win->fb)
|
|
framebuffer_close(win->fb);
|
|
if (win->hwc)
|
|
hwc_close_1(win->hwc);
|
|
if (win->gr)
|
|
gralloc_close(win->gr);
|
|
free(win);
|
|
}
|
|
|
|
CNativeWindow *cnw_create(void) {
|
|
CNativeWindow *win;
|
|
char *x;
|
|
if ((x = getenv("CNWDEBUG")))
|
|
trace_level = atoi(x);
|
|
if (!(win = malloc(sizeof(CNativeWindow))))
|
|
return NULL;
|
|
if (cnw_init(win)) {
|
|
cnw_destroy(win);
|
|
return NULL;
|
|
}
|
|
return win;
|
|
}
|
|
|
|
void cnw_info(CNativeWindow *win, unsigned *w, unsigned *h, unsigned *fmt) {
|
|
*w = win->width;
|
|
*h = win->height;
|
|
*fmt = win->format;
|
|
}
|
|
|