| /**************************************************************************** |
| * graphics/nxbe/nxbe_setsize.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you 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. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <assert.h> |
| #include <debug.h> |
| #include <sys/param.h> |
| |
| #ifdef CONFIG_NX_RAMBACKED |
| # include <string.h> |
| #ifdef CONFIG_BUILD_KERNEL |
| # include <nuttx/pgalloc.h> |
| #else |
| # include <nuttx/kmalloc.h> |
| #endif |
| #endif |
| |
| #include <nuttx/nx/nxglib.h> |
| |
| #include "nxbe.h" |
| #include "nxmu.h" |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: nxbe_realloc |
| * |
| * Description: |
| * After the display size has changed, reallocate the pre-window frame |
| * buffer for the new framebuffer size. |
| * |
| * REVISIT: This currently takes a brute force force approach, allocating |
| * the new framebuffer while the old framebuffer is still in place. There |
| * may be some clever way to do this reallocation in place. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_NX_RAMBACKED |
| static void nxbe_realloc(FAR struct nxbe_window_s *wnd, |
| FAR struct nxgl_rect_s *oldbounds) |
| { |
| FAR nxgl_mxpixel_t *newfb; |
| FAR uint8_t *src; |
| FAR uint8_t *dest; |
| struct nxgl_rect_s bounds; |
| nxgl_coord_t minheight; |
| nxgl_coord_t newwidth; |
| nxgl_coord_t newheight; |
| nxgl_coord_t oldwidth; |
| nxgl_coord_t oldheight; |
| nxgl_coord_t row; |
| size_t newfbsize; |
| unsigned int minstride; |
| unsigned int newstride; |
| unsigned int bpp; |
| #ifdef CONFIG_BUILD_KERNEL |
| unsigned int newnpages; |
| #endif |
| |
| /* Allocate framebuffer memory if the per-window framebuffer feature has |
| * been selected. |
| * |
| * REVISIT: This initial state of the framebuffer is uninitialized and |
| * not synchronized with the graphic device content. It will take a full |
| * screen update from the application to force the framebuffer and device |
| * to be consistent. |
| */ |
| |
| if (NXBE_ISRAMBACKED(wnd)) |
| { |
| oldwidth = oldbounds->pt2.x - oldbounds->pt1.x + 1; |
| oldheight = oldbounds->pt2.y - oldbounds->pt1.y + 1; |
| |
| newwidth = wnd->bounds.pt2.x - wnd->bounds.pt1.x + 1; |
| newheight = wnd->bounds.pt2.y - wnd->bounds.pt1.y + 1; |
| |
| bpp = wnd->be->plane[0].pinfo.bpp; |
| newstride = (bpp * newwidth + 7) >> 3; |
| newfbsize = newstride * newheight; |
| |
| #ifdef CONFIG_BUILD_KERNEL |
| /* Re-allocate memory from the page pool. */ |
| |
| /* Determine the number of pages to be allocated. */ |
| |
| newnpages = (uint16_t)MM_NPAGES(newfbsize); |
| |
| /* Allocate the pages */ |
| |
| newfb = (FAR nxgl_mxpixel_t *)mm_pgalloc(newnpages); |
| if (newfb == NULL) |
| { |
| /* Fall back to no RAM back up */ |
| |
| gerr("ERROR: mm_pgalloc() failed for fbsize=%lu, npages=%u\n", |
| (unsigned long)newfbsize, npages); |
| |
| mm_pgfree(wnd->fbmem, wnd->npages); |
| wnd->stride = 0; |
| wnd->npages = 0; |
| wnd->fbmem = NULL; |
| NXBE_CLRRAMBACKED(wnd); |
| return; |
| } |
| #else |
| /* Re-allocate memory from the user space heap. */ |
| |
| newfb = kumm_malloc(newfbsize); |
| if (newfb == NULL) |
| { |
| /* Fall back to no RAM back up */ |
| |
| gerr("ERROR: kumm_malloc() failed for fbsize=%lu\n", |
| (unsigned long)newfbsize); |
| |
| kumm_free(wnd->fbmem); |
| wnd->stride = 0; |
| wnd->fbmem = NULL; |
| NXBE_CLRRAMBACKED(wnd); |
| return; |
| } |
| #endif |
| |
| /* Copy the content of the old framebuffer to the new frame buffer */ |
| |
| minheight = MIN(oldheight, newheight); |
| minstride = MIN(wnd->stride, newstride); |
| |
| /* Process each line one at a time */ |
| |
| for (src = (FAR uint8_t *)wnd->fbmem, dest = (FAR uint8_t *)newfb, |
| row = 0; |
| row < minheight; |
| src += wnd->stride, dest += newstride, row++) |
| { |
| /* Copy valid row data */ |
| |
| memcpy(dest, src, minstride); |
| |
| /* Pad any extra pixel data on the right (with zeroes?) */ |
| |
| if (minstride < newstride) |
| { |
| memset(dest + minstride, 0, newstride - minstride); |
| } |
| } |
| |
| /* Pad any extra lines at the bottom (with zeroes?) */ |
| |
| if (row < newheight) |
| { |
| size_t nbytes = newstride * (newheight - row); |
| memset(dest, 0, nbytes); |
| } |
| |
| /* Free the old framebuffer and configure for the new framebuffer */ |
| |
| #ifdef CONFIG_BUILD_KERNEL |
| mm_pgfree(wnd->fbmem, wnd->npages); |
| wnd->npages = newnpages; |
| #else |
| kumm_free(wnd->fbmem); |
| #endif |
| wnd->stride = newstride; |
| wnd->fbmem = newfb; |
| |
| /* If the window became wider, then send a message requesting an update |
| * of the new territory on the right. |
| */ |
| |
| if (oldwidth < newwidth) |
| { |
| /* Get a bounding box in device coordinates */ |
| |
| bounds.pt1.x = wnd->bounds.pt1.x + oldwidth; |
| bounds.pt1.y = wnd->bounds.pt1.y; |
| bounds.pt2.x = wnd->bounds.pt2.x; |
| bounds.pt2.y = wnd->bounds.pt2.y + MIN(oldheight, newheight) - 1; |
| |
| /* Send the redraw request */ |
| |
| nxmu_redrawreq(wnd, &bounds); |
| } |
| |
| /* If the window became taller, then send a message requesting an |
| * update of the new territory at the bottom. |
| */ |
| |
| if (oldheight < newheight) |
| { |
| /* Get a bounding box in device coordinates */ |
| |
| bounds.pt1.x = wnd->bounds.pt1.x; |
| bounds.pt1.y = wnd->bounds.pt1.y + oldheight; |
| bounds.pt2.x = wnd->bounds.pt2.x; |
| bounds.pt2.y = wnd->bounds.pt2.y; |
| |
| /* Send the redraw request */ |
| |
| nxmu_redrawreq(wnd, &bounds); |
| } |
| } |
| } |
| #else |
| # define nxbe_realloc(w,b) |
| #endif |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: nxbe_setsize |
| * |
| * Description: |
| * This function checks for intersections and redraws the display after |
| * a change in the size of a window. |
| * |
| ****************************************************************************/ |
| |
| void nxbe_setsize(FAR struct nxbe_window_s *wnd, |
| FAR const struct nxgl_size_s *size) |
| { |
| struct nxgl_rect_s bounds; |
| |
| DEBUGASSERT(wnd != NULL && size != NULL); |
| |
| /* Save the 'before' size of the window's bounding box */ |
| |
| nxgl_rectcopy(&bounds, &wnd->bounds); |
| |
| /* Add the window origin to the supplied size get the new window bounding |
| * box |
| */ |
| |
| wnd->bounds.pt2.x = wnd->bounds.pt1.x + size->w - 1; |
| wnd->bounds.pt2.y = wnd->bounds.pt1.y + size->h - 1; |
| |
| /* Clip the new bounding box so that lies within the background screen */ |
| |
| nxgl_rectintersect(&wnd->bounds, &wnd->bounds, &wnd->be->bkgd.bounds); |
| |
| /* Report the new size/position. The application needs to know the new |
| * size before getting redraw requests. |
| */ |
| |
| nxmu_reportposition(wnd); |
| |
| /* Re-allocate the per-window framebuffer memory for the new window size. */ |
| |
| nxbe_realloc(wnd, &bounds); |
| |
| /* We need to update the larger of the two regions described by the |
| * original bounding box and the new bounding box. That will be the |
| * union of the two bounding boxes. |
| */ |
| |
| nxgl_rectunion(&bounds, &bounds, &wnd->bounds); |
| |
| /* Then redraw this window AND all windows below it. Having resized the |
| * window, we may have exposed previoulsy obscured portions of windows |
| * below this one. |
| */ |
| |
| nxbe_redrawbelow(wnd->be, wnd, &bounds); |
| } |