Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 |
| 33 | typedef struct android_native_base_t aBase; |
| 34 | typedef struct ANativeWindowBuffer aBuffer; |
| 35 | typedef struct ANativeWindow aWindow; |
| 36 | |
| 37 | static int trace_level = 1; |
| 38 | |
| 39 | #define _TRACE(n,fmt...) \ |
Chih-Hung Hsieh | 4d52b43 | 2016-05-12 10:07:30 -0700 | [diff] [blame] | 40 | do { if (trace_level >= (n)) fprintf(stderr, "CNW: " fmt); } while (0) |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
| 49 | typedef struct CNativeBuffer { |
| 50 | aBuffer base; |
| 51 | struct CNativeBuffer *next; |
| 52 | struct CNativeBuffer *prev; |
| 53 | int ffd; |
| 54 | } CNativeBuffer; |
| 55 | |
| 56 | typedef 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 | |
Jesse Hall | fc0ff2a | 2013-08-16 11:13:36 -0700 | [diff] [blame] | 77 | hwc_display_contents_1_t *dclist[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 78 | |
| 79 | hwc_display_contents_1_t dc; |
| 80 | hwc_layer_1_t layer[4]; |
| 81 | } CNativeWindow; |
| 82 | |
| 83 | static inline CNativeBuffer *from_abuffer(aBuffer *buf) { |
| 84 | return (CNativeBuffer*) buf; |
| 85 | } |
| 86 | |
| 87 | static 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 | |
| 97 | static 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 | |
| 105 | static 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 | |
| 113 | static void cnw_inc_ref(aBase *base) { TRACE("buf %p ref++\n",base); } |
| 114 | static void cnw_dec_ref(aBase *base) { TRACE("buf %p ref--\n",base); } |
| 115 | |
| 116 | static inline CNativeWindow *from_base(aWindow *base) { |
| 117 | return (CNativeWindow *) base; |
| 118 | } |
| 119 | |
| 120 | static inline CNativeWindow *from_base_const(const aWindow *base) { |
| 121 | return (CNativeWindow *) base; |
| 122 | } |
| 123 | |
| 124 | static 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 | |
| 131 | static 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 | |
| 150 | static int cnw_lock_buffer0(aWindow *base, aBuffer *buffer) { |
| 151 | return 0; |
| 152 | } |
| 153 | |
| 154 | static 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 | |
| 180 | static 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; |
Chih-Hung Hsieh | 4224d9e | 2017-12-01 11:28:37 -0800 | [diff] [blame] | 184 | int r; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
Jesse Hall | fc0ff2a | 2013-08-16 11:13:36 -0700 | [diff] [blame] | 203 | r = hwc->prepare(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist); |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
Jesse Hall | fc0ff2a | 2013-08-16 11:13:36 -0700 | [diff] [blame] | 213 | r = hwc->set(hwc, HWC_NUM_PHYSICAL_DISPLAY_TYPES, win->dclist); |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
| 230 | static 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 | |
| 252 | static 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 | |
| 263 | static 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 | |
| 272 | static int cnw_queue_buffer0(aWindow *base, aBuffer *buf) { |
| 273 | return cnw_queue_buffer1(base, buf, -1); |
| 274 | } |
| 275 | |
| 276 | static int cnw_cancel_buffer0(aWindow *base, aBuffer *buf) { |
| 277 | return cnw_cancel_buffer1(base, buf, -1); |
| 278 | } |
| 279 | |
| 280 | static 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 | |
| 313 | static 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: { |
Andreas Gampe | 1aa58f9 | 2015-12-16 14:17:44 -0800 | [diff] [blame] | 340 | unsigned int w = va_arg(ap,unsigned int); |
| 341 | unsigned int h = va_arg(ap,unsigned int); |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
| 355 | static void hwc_invalidate(const struct hwc_procs *procs) {} |
| 356 | static void hwc_vsync(const struct hwc_procs *procs, int disp, int64_t ts) {} |
| 357 | static void hwc_hotplug(const struct hwc_procs *procs, int disp, int conn) {} |
| 358 | |
| 359 | struct hwc_procs hprocs = { |
| 360 | .invalidate = hwc_invalidate, |
| 361 | .vsync = hwc_vsync, |
| 362 | .hotplug = hwc_hotplug, |
| 363 | }; |
| 364 | |
| 365 | uint32_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 | |
| 374 | static 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]; |
Andreas Gampe | 1aa58f9 | 2015-12-16 14:17:44 -0800 | [diff] [blame] | 380 | size_t numconfigs = 32; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
| 428 | static 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 | |
| 461 | static int cnw_init(CNativeWindow *win) { |
| 462 | hw_module_t const* module; |
| 463 | framebuffer_device_t *fb = NULL; |
| 464 | alloc_device_t *gr; |
Chih-Hung Hsieh | 4224d9e | 2017-12-01 11:28:37 -0800 | [diff] [blame] | 465 | int err, i; |
| 466 | unsigned usage; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 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 | |
| 549 | void 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 | |
| 559 | CNativeWindow *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 | |
| 573 | void cnw_info(CNativeWindow *win, unsigned *w, unsigned *h, unsigned *fmt) { |
| 574 | *w = win->width; |
| 575 | *h = win->height; |
| 576 | *fmt = win->format; |
| 577 | } |
| 578 | |