diff --git a/src/newgal/surface-shared.c b/src/newgal/surface-shared.c new file mode 100644 index 00000000..e2f5e3cc --- /dev/null +++ b/src/newgal/surface-shared.c @@ -0,0 +1,421 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT NOTICE +// +// The following open source license statement does not apply to any +// entity in the Exception List published by FMSoft. +// +// For more information, please visit: +// +// https://www.fmsoft.cn/exception-list +// +////////////////////////////////////////////////////////////////////////////// +/* + * This file is part of MiniGUI, a mature cross-platform windowing + * and Graphics User Interface (GUI) support system for embedded systems + * and smart IoT devices. + * + * Copyright (C) 2002~2020, Beijing FMSoft Technologies Co., Ltd. + * Copyright (C) 1998~2002, WEI Yongming + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Or, + * + * As this program is a library, any link to this program must follow + * GNU General Public License version 3 (GPLv3). If you cannot accept + * GPLv3, you need to be licensed from FMSoft. + * + * If you have got a commercial license of this program, please use it + * under the terms and conditions of the commercial license. + * + * For more information about the commercial license, please refer to + * . + */ + +#include +#include +#include + +#include "common.h" +#include "constants.h" + +#if IS_COMPOSITING_SCHEMA + +#include +#include + +#include "misc.h" +#include "newgal.h" +#include "sysvideo.h" +#include "pixels_c.h" +#include "blit.h" + +/* + * Create a shared empty RGB surface of the appropriate depth + */ +GAL_Surface * GAL_CreateSharedRGBSurface (GAL_VideoDevice *video, + Uint32 flags, Uint32 rw_modes, int width, int height, int depth, + Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) +{ + GAL_Surface *screen; + GAL_Surface *surface; + + /* Check to see if we desire the surface in video memory */ + if (video == NULL) { + video = __mg_current_video; + } + + screen = GAL_PublicSurface; + + if (screen && ((screen->flags & GAL_HWSURFACE) == GAL_HWSURFACE)) { + if ((flags & (GAL_SRCCOLORKEY | GAL_SRCALPHA)) != 0) { + flags |= GAL_HWSURFACE; + } + + if ((flags & GAL_SRCCOLORKEY) == GAL_SRCCOLORKEY) { + if (! video->info.blit_hw_CC) { + flags &= ~GAL_HWSURFACE; + } + } + if ((flags & GAL_SRCALPHA) == GAL_SRCALPHA) { + if (! video->info.blit_hw_A) { + flags &= ~GAL_HWSURFACE; + } + } + } + else { + flags &= ~GAL_HWSURFACE; + } + + /* Allocate the surface */ + surface = (GAL_Surface *)malloc (sizeof (*surface)); + if (surface == NULL) { + goto error; + } + + if ((flags & GAL_HWSURFACE) == GAL_HWSURFACE) + surface->video = video; + else + surface->video = NULL; + + surface->flags = GAL_SWSURFACE; + if (Amask) { + surface->flags |= GAL_SRCPIXELALPHA; + } + + surface->format = GAL_AllocFormat (depth, Rmask, Gmask, Bmask, Amask); + if (surface->format == NULL) { + free (surface); + surface = NULL; + goto error; + } + + surface->w = width; + surface->h = height; + surface->pitch = GAL_CalculatePitch (surface); + surface->pixels = NULL; + surface->offset = 0; + // for off-screen surface, DPI always be the default value + surface->dpi = GDCAP_DPI_DEFAULT; + surface->hwdata = NULL; + surface->map = NULL; + surface->format_version = 0; + surface->shared_header = NULL; + GAL_SetClipRect (surface, NULL); + +#ifdef _MGUSE_SYNC_UPDATE + /* Initialize update region */ + InitClipRgn (&surface->update_region, &__mg_free_update_region_list); +#endif + + /* Get the pixels */ + if (surface->w && surface->h) { + int fd = -1; + size_t buf_size; + off_t buf_off; + off_t map_size; + void* data_map; + GAL_SharedSurfaceHeader* hdr; + int byhw = 1; + + if ((flags & GAL_HWSURFACE) == GAL_HWSURFACE && + video->AllocSharedHWSurface) { + fd = video->AllocSharedHWSurface (video, surface, + &buf_size, &buf_off, rw_modes); + } + + if (fd < 0) { // fallback to use software surface + off_t file_size; + + byhw = 0; + buf_size = (surface->h * surface->pitch); + buf_off = sizeof (GAL_SharedSurfaceHeader); + + /* rounde file size to multiple of page size */ + file_size = buf_off + buf_size; + file_size &= ~(getpagesize () - 1); + buf_size = file_size - buf_off; + + fd = __mg_create_anonymous_file (file_size, NULL, rw_modes); + if (fd < 0) { + goto error; + } + } + + map_size = buf_off + buf_size; + data_map = mmap (NULL, map_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (data_map == MAP_FAILED) { + close (fd); + goto error; + } + + surface->shared_header = hdr = (GAL_SharedSurfaceHeader*)data_map; + + /* fill fileds of shared header */ + memset (hdr, 0, sizeof(GAL_SharedSurfaceHeader)); + hdr->semid = -1; + hdr->creator = getpid(); + hdr->fd = fd; + hdr->byhw = byhw; + hdr->width = surface->w; + hdr->height = surface->h; + hdr->pitch = surface->pitch; + hdr->depth = depth; + hdr->Rmask = Rmask; + hdr->Gmask = Gmask; + hdr->Bmask = Bmask; + hdr->Amask = Amask; + hdr->buf_size = buf_size; + hdr->sem_num = __mg_alloc_mutual_sem (&hdr->semid); + if (hdr->sem_num < 0) + goto error; + + surface->pixels = surface->shared_header->buf; + memset (surface->pixels, 0, buf_size); + + if (byhw) + surface->flags |= GAL_HWSURFACE; + else + surface->flags &= ~GAL_HWSURFACE; + } + + /* Allocate an empty mapping */ + surface->map = GAL_AllocBlitMap(); + if (surface->map == NULL) { + goto error; + } + + /* The surface is ready to go */ + surface->refcount = 1; + return(surface); + +error: + if (surface) { + if (surface->shared_header) { + if (surface->shared_header->semid >= 0) { + assert (surface->shared_header->sem_num >= 0); + __mg_free_mutual_sem (surface->shared_header->sem_num); + } + + if (surface->shared_header->byhw) { + assert(video->FreeSharedHWSurface); + video->FreeSharedHWSurface (video, surface); + } + else { + close (surface->shared_header->fd); + munmap (surface->shared_header, + surface->shared_header->buf_size + + sizeof(GAL_SharedSurfaceHeader)); + } + } + + GAL_FreeSurface (surface); + } + + GAL_OutOfMemory (); + return NULL; +} + +/* + * Free data of a shared surface created by the above function. + */ +void GAL_FreeSharedSurfaceData (GAL_Surface *surface) +{ + GAL_VideoDevice *video = surface->video; + + assert (surface->shared_header); + + if (surface->shared_header->semid >= 0) { + assert (surface->shared_header->sem_num >= 0); + __mg_free_mutual_sem (surface->shared_header->sem_num); + } + + if (surface->shared_header->byhw) { + assert (video->FreeSharedHWSurface); + video->FreeSharedHWSurface (video, surface); + } + else { + close (surface->shared_header->fd); + munmap (surface->shared_header, + surface->shared_header->buf_size + + sizeof (GAL_SharedSurfaceHeader)); + } +} + +/* + * Attach to a shared RGB surface + */ +GAL_Surface * GAL_AttachSharedRGBSurface (int fd, size_t map_size, Uint32 flags, BOOL with_wr) +{ + GAL_VideoDevice *video; + GAL_Surface *surface; + int prot = PROT_READ; + void* data_map = MAP_FAILED; + GAL_SharedSurfaceHeader* hdr; + + if (with_wr) { + prot |= PROT_WRITE; + } + + data_map = mmap (NULL, map_size, prot, MAP_SHARED, fd, 0); + if (data_map == MAP_FAILED) { + _ERR_PRINTF("NEWGAL: Failed to map shared RGB surface: %d\n", fd); + return NULL; + } + + /* XXX: We may find the video according to engine name in the future */ + video = __mg_current_video; + + /* Allocate the surface */ + surface = (GAL_Surface *)malloc (sizeof (*surface)); + if (surface == NULL) { + goto error; + } + + hdr = (GAL_SharedSurfaceHeader*) data_map; + surface->shared_header = hdr; + + /* check flags */ + if (hdr->byhw) { + if ((flags & (GAL_SRCCOLORKEY | GAL_SRCALPHA)) != 0) { + flags |= GAL_HWSURFACE; + } + + if ((flags & GAL_SRCCOLORKEY) == GAL_SRCCOLORKEY) { + if (!video->info.blit_hw_CC) { + flags &= ~GAL_HWSURFACE; + } + } + if ((flags & GAL_SRCALPHA) == GAL_SRCALPHA) { + if (!video->info.blit_hw_A) { + flags &= ~GAL_HWSURFACE; + } + } + } + else { + flags &= ~GAL_HWSURFACE; + } + + if ((flags & GAL_HWSURFACE) == GAL_HWSURFACE) { + surface->flags = GAL_HWSURFACE; + surface->video = video; + } + else { + surface->flags = GAL_SWSURFACE; + surface->video = NULL; + video = NULL; + } + + if (hdr->Amask) { + surface->flags |= GAL_SRCPIXELALPHA; + } + + surface->format = GAL_AllocFormat (hdr->depth, + hdr->Rmask, hdr->Gmask, hdr->Bmask, hdr->Amask); + if (surface->format == NULL) { + goto error; + } + + surface->w = hdr->width; + surface->h = hdr->height; + surface->pitch = GAL_CalculatePitch (surface); + surface->pixels = NULL; + surface->offset = 0; + // for off-screen surface, DPI always be the default value + surface->dpi = GDCAP_DPI_DEFAULT; + surface->hwdata = NULL; + surface->map = NULL; + surface->format_version = 0; + GAL_SetClipRect (surface, NULL); + +#ifdef _MGUSE_SYNC_UPDATE + /* Initialize update region */ + InitClipRgn (&surface->update_region, &__mg_free_update_region_list); +#endif + + /* Get the pixels */ + if (surface->w && surface->h) { + if (video && video->AttachSharedHWSurface) { + video->AttachSharedHWSurface (video, surface, fd); + } + + surface->pixels = surface->shared_header->buf; + } + + /* Allocate an empty mapping */ + surface->map = GAL_AllocBlitMap(); + if (surface->map == NULL) { + goto error; + } + + /* The surface is ready to go */ + surface->refcount = 1; + return (surface); + +error: + if (data_map != MAP_FAILED) { + if (video && video->DettachSharedHWSurface) { + video->DettachSharedHWSurface (video, surface); + } + + munmap (data_map, map_size); + GAL_FreeSurface (surface); + } + + GAL_OutOfMemory (); + return NULL; +} + +/* + * Free data of a shared surface created by the above function. + */ +void GAL_DettachSharedSurfaceData (GAL_Surface *surface) +{ + GAL_VideoDevice *video = surface->video; + + assert (surface->shared_header); + + if (video && video->DettachSharedHWSurface) { + video->DettachSharedHWSurface (video, surface); + } + + munmap (surface->shared_header, + surface->shared_header->buf_size + + sizeof (GAL_SharedSurfaceHeader)); +} + +#endif /* IS_COMPOSITING_SCHEMA */ +