| /* Copyright (C) 2015 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| |
| #include <QtCore> |
| #include <QColor> |
| #include <QImage> |
| #include <QObject> |
| #include <QPainter> |
| #include <QRect> |
| #include <QWidget> |
| |
| #include "android/skin/argb.h" |
| #include "android/skin/rect.h" |
| #include "android/skin/surface.h" |
| #include "android/skin/winsys.h" |
| #include "android/skin/qt/emulator-qt-window.h" |
| #include "android/utils/setenv.h" |
| |
| #define DEBUG 1 |
| |
| #if DEBUG |
| #include "android/utils/debug.h" |
| |
| #define D(...) VERBOSE_PRINT(surface,__VA_ARGS__) |
| #else |
| #define D(...) ((void)0) |
| #endif |
| |
| static int next_id = 0; |
| |
| extern SkinSurface *skin_surface_create(int w, int h, int original_w, int original_h) |
| { |
| auto s = new SkinSurface(); |
| auto window = EmulatorQtWindow::getInstancePtr(); |
| if (window == NULL) return NULL; |
| if (s != NULL) { |
| QSemaphore semaphore; |
| window->createBitmap(s, original_w, original_h, &semaphore); |
| semaphore.acquire(); |
| s->refcount = 1; |
| s->w = w; |
| s->h = h; |
| s->original_w = original_w; |
| s->original_h = original_h; |
| s->id = next_id++; |
| s->window = window; |
| D("Created surface %d %d w,%d h, original %d, %d", s->id, w, h, original_w, original_h); |
| } |
| else { |
| D( "not enough memory to allocate new skin surface !" ); |
| } |
| return s; |
| } |
| |
| extern SkinSurface *skin_surface_create(int w, int h) |
| { |
| D("skin_surface_create %d, %d", w, h); |
| return skin_surface_create(w, h, w, h); |
| } |
| |
| static void skin_surface_free(SkinSurface *s) |
| { |
| D("skin_surface_free %d", s->id); |
| QSemaphore semaphore; |
| s->window->releaseBitmap(s, &semaphore); |
| semaphore.acquire(); |
| delete s; |
| } |
| |
| extern int skin_surface_height(SkinSurface *s) |
| { |
| D("skin_surface_height %d", s->id); |
| return s->h; |
| } |
| |
| extern void skin_surface_unrefp(SkinSurface* *psurface) |
| { |
| SkinSurface *surf = *psurface; |
| if (surf) { |
| D("skin_surface_unref %d", surf->id); |
| if (--surf->refcount <= 0) |
| skin_surface_free(surf); |
| *psurface = NULL; |
| } |
| } |
| |
| extern int skin_surface_width(SkinSurface *s) |
| { |
| D("skin_surface_width %d", s->id); |
| return s->w; |
| } |
| |
| extern SkinSurface* skin_surface_create_argb32_from(int w, int h, int pitch, uint32_t *pixels) |
| { |
| D("skin_surface_create_argb32_from %d, %d, pitch %d", w, h, pitch); |
| SkinSurface* s = skin_surface_create(w, h, w, h); |
| SkinRect rect; |
| rect.size.h = h; |
| rect.size.w = w; |
| rect.pos.x = 0; |
| rect.pos.y = 0; |
| skin_surface_upload(s, &rect, pixels, pitch); |
| return s; |
| } |
| |
| extern SkinSurface* skin_surface_resize(SkinSurface *surface, int w, int h, int original_w, int original_h) |
| { |
| if ( surface == NULL ) { |
| return skin_surface_create(w, h, original_w, original_h); |
| } else if ( surface->original_w == original_w && surface->original_h == original_h ) { |
| surface->w = w; |
| surface->h = h; |
| return surface; |
| } else { |
| skin_surface_unrefp(&surface); |
| return skin_surface_create(w, h, original_w, original_h); |
| } |
| } |
| |
| extern void skin_surface_create_window(SkinSurface* surface, |
| int x, |
| int y, |
| int w, |
| int h) { |
| D("skin_surface_create_window %d, %d, %d, %d", x, y, w, h); |
| QSemaphore semaphore; |
| EmulatorQtWindow *window = EmulatorQtWindow::getInstance(); |
| if (window == NULL) return; |
| QRect rect(x, y, w, h); |
| window->showWindow(surface, &rect, &semaphore); |
| semaphore.acquire(); |
| D("ID of backing bitmap surface is %d", surface->id); |
| } |
| |
| extern void skin_surface_update(SkinSurface *surface, SkinRect *rect) |
| { |
| #if 0 |
| D("skin_surface_update %d: %d,%d,%d,%d", surface->id, rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| #endif |
| QRect qrect(rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| QSemaphore semaphore; |
| surface->window->requestUpdate(&qrect, &semaphore); |
| semaphore.acquire(); |
| } |
| |
| extern void skin_surface_blit(SkinSurface *dst, SkinPos *pos, SkinSurface *src, SkinRect *rect, SkinBlitOp op) |
| { |
| #if 0 |
| D("skin_surface_blit from %d (%d, %d) to %d: %d,%d,%d,%d", src->id, rect->pos.x, rect->pos.y, dst->id, rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| #endif |
| QRect qrect(rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| QPoint qpos(pos->x, pos->y); |
| QPainter::CompositionMode qop; |
| switch(op) { |
| default: |
| case SKIN_BLIT_COPY: |
| qop = QPainter::CompositionMode_Source; |
| break; |
| case SKIN_BLIT_SRCOVER: |
| qop = QPainter::CompositionMode_SourceOver; |
| break; |
| } |
| QSemaphore semaphore; |
| dst->window->blit(src->bitmap, &qrect, dst->bitmap, &qpos, &qop, &semaphore); |
| semaphore.acquire(); |
| } |
| |
| extern void skin_surface_fill(SkinSurface *dst, SkinRect *rect, uint32_t argb_premul) |
| { |
| D("skin_surface_fill %d: %d, %d, %d, %d: %x", dst->id, rect->pos.x, rect->pos.y, rect->size.w, rect->size.h, argb_premul); |
| QRect qrect(rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| QColor color(argb_premul); |
| QSemaphore semaphore; |
| dst->window->fill(dst, &qrect, &color, &semaphore); |
| semaphore.acquire(); |
| } |
| |
| extern void skin_surface_upload(SkinSurface *surface, SkinRect *rect, const void *pixels, int pitch) |
| { |
| #if 0 |
| D("skin_surface_upload %d: %d,%d,%d,%d", surface->id, rect->pos.x, rect->pos.y, rect->size.w, rect->size.h); |
| #endif |
| uint32_t *src = ((uint32_t*)pixels); |
| uint32_t *dst = ((uint32_t*)surface->bitmap->bits()) + surface->w * rect->pos.y; |
| int num = 0; |
| for (int y = rect->pos.y; y < rect->pos.y + rect->size.h; y++) { |
| for (int x = rect->pos.x; x < rect->pos.x + rect->size.w; x++) { |
| *(dst + x) = *(src + x -rect->pos.x); |
| num++; |
| } |
| src += pitch / sizeof(uint32_t); |
| dst += surface->w; |
| } |
| } |
| |
| extern void skin_surface_get_scaled_rect(SkinSurface *surface, const SkinRect *from, SkinRect *to) |
| { |
| int fromx = from->pos.x; |
| int fromy = from->pos.y; |
| int fromw = from->size.w; |
| int fromh = from->size.h; |
| int w = surface->w; |
| int h = surface->h; |
| int original_w = surface->original_w; |
| int original_h = surface->original_h; |
| to->pos.x = from->pos.x * w / original_w; |
| to->pos.y = from->pos.y * h / original_h; |
| to->size.w = from->size.w * w / original_w; |
| to->size.h = from->size.h * h / original_h; |
| D("skin_surface_get_scaled_rect %d: %d, %d, %d, %d => %d, %d, %d, %d", surface->id, fromx, fromy, fromw, fromh, to->pos.x, to->pos.y, to->size.w, to->size.h); |
| } |
| |
| extern void skin_surface_reverse_map(SkinSurface *surface, int *x, int *y) |
| { |
| int new_x = *x * surface->original_w / surface->w; |
| int new_y = *y * surface->original_h / surface->h; |
| #if 0 |
| D("skin_surface_reverse_map %d: %d,%d to %d,%d", surface->id, *x, *y, new_x, new_y); |
| #endif |
| *x = new_x; |
| *y = new_y; |
| } |