2470 lines
68 KiB
C
2470 lines
68 KiB
C
/****************************************************************************
|
|
* examples/ltdc/dma2d.c
|
|
*
|
|
* Copyright (C) 2008, 2011-2012, 2015 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
* Marco Krahl <ocram.lhark@gmail.com>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include "ltdc.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Function
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_remove_dma2d_surface
|
|
*
|
|
* Description:
|
|
* Remove the surface of the dma2dlayer
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_remove_dma2d_surface(FAR struct dma2d_surface *sur)
|
|
{
|
|
if (sur)
|
|
{
|
|
up_dma2dremovelayer(sur->dma2d);
|
|
free(sur);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_create_dma2d_surface
|
|
*
|
|
* Description:
|
|
* Create a surface for the dma2dlayer
|
|
*
|
|
****************************************************************************/
|
|
|
|
static FAR struct dma2d_surface *ltdc_create_dma2d_surface(uint16_t xres,
|
|
uint16_t yres,
|
|
uint8_t fmt)
|
|
{
|
|
int ret;
|
|
FAR struct dma2d_surface *sur = (FAR struct dma2d_surface *)
|
|
malloc(sizeof(struct dma2d_surface));
|
|
|
|
if (sur)
|
|
{
|
|
sur->dma2d = up_dma2dcreatelayer(xres, yres, fmt);
|
|
|
|
if (!sur->dma2d)
|
|
{
|
|
_err("ERROR: up_dma2dcreatelayer failed\n");
|
|
free(sur);
|
|
sur = NULL;
|
|
}
|
|
else
|
|
{
|
|
ret = sur->dma2d->getvideoinfo(sur->dma2d, &sur->vinfo);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: getvideoinfo() failed\n");
|
|
}
|
|
else
|
|
{
|
|
ret = sur->dma2d->getplaneinfo(sur->dma2d, 0, &sur->pinfo);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: getplaneinfo() failed\n");
|
|
}
|
|
}
|
|
|
|
if(ret != OK)
|
|
{
|
|
ltdc_remove_dma2d_surface(sur);
|
|
sur = NULL;
|
|
}
|
|
else
|
|
{
|
|
int lid;
|
|
sur->dma2d->getlid(sur->dma2d, &lid);
|
|
_info("dma2d layer %d is created with: "
|
|
"layer = %p, xres = %d, yres = %d, fb start address = %p, "
|
|
"fb size = %d, fmt = %d, bpp = %d\n",
|
|
lid, sur->dma2d, sur->vinfo.xres, sur->vinfo.yres,
|
|
sur->pinfo.fbmem, sur->pinfo.fblen, sur->vinfo.fmt,
|
|
sur->pinfo.bpp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return sur;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_clearlayer
|
|
*
|
|
* Description:
|
|
* Clear the whole ltdc layer with a specific color
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_clearlayer(FAR struct surface *sur, uint8_t color)
|
|
{
|
|
uint32_t argb;
|
|
struct ltdc_area_s area;
|
|
|
|
argb = ltdc_color(&sur->vinfo, color);
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = sur->vinfo.xres;
|
|
area.yres = sur->vinfo.yres;
|
|
|
|
sur->layer->fillarea(sur->layer, &area, argb);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: dma2d_clearlayer
|
|
*
|
|
* Description:
|
|
* Clear the whole dma2d layer with a specific color
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void dma2d_clearlayer(FAR struct dma2d_surface *sur, uint8_t color)
|
|
{
|
|
uint32_t argb;
|
|
struct ltdc_area_s area;
|
|
|
|
argb = ltdc_color(&sur->vinfo, color);
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = sur->vinfo.xres;
|
|
area.yres = sur->vinfo.yres;
|
|
|
|
sur->dma2d->fillarea(sur->dma2d, &area, argb);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_blendshadow
|
|
*
|
|
* Description:
|
|
* Helper: Blend a rectangle with an existing layer.
|
|
* This also blends a subjacent mirror image of the rectangle position
|
|
* dependent.
|
|
*
|
|
* Note! layer back and fore must have the same size.
|
|
* layer dest must be larger or equal to the size of the layer back and
|
|
* fore.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_blendshadow(FAR struct surface *dest,
|
|
FAR struct dma2d_surface *fore,
|
|
FAR struct dma2d_surface *back,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
fb_coord_t shadowlen,
|
|
uint8_t alpha)
|
|
{
|
|
FAR struct ltdc_area_s area;
|
|
int32_t shadowx;
|
|
int32_t shadowy;
|
|
|
|
area.xpos = xpos;
|
|
area.ypos = ypos;
|
|
area.xres = back->vinfo.xres;
|
|
area.yres = back->vinfo.yres;
|
|
|
|
/* Calculate the position of the mirror image */
|
|
|
|
shadowx = ((xpos - (dest->vinfo.xres - back->vinfo.xres) / 2) * shadowlen * 2) /
|
|
((dest->vinfo.xres - back->vinfo.xres) / 2);
|
|
if (xpos + shadowx < 0)
|
|
{
|
|
shadowx = -xpos;
|
|
}
|
|
else if (xpos + back->vinfo.xres + shadowx > dest->vinfo.xres)
|
|
{
|
|
shadowx = dest->vinfo.xres - (xpos + back->vinfo.xres);
|
|
}
|
|
|
|
shadowy = ((ypos - (dest->vinfo.yres - back->vinfo.yres) / 2) * shadowlen * 2) /
|
|
((dest->vinfo.yres - back->vinfo.yres) / 2);
|
|
|
|
if (ypos + shadowy < 0)
|
|
{
|
|
shadowy = -ypos;
|
|
}
|
|
else if (ypos + back->vinfo.yres + shadowy > dest->vinfo.yres)
|
|
{
|
|
shadowy = dest->vinfo.yres - (ypos + back->vinfo.yres);
|
|
}
|
|
|
|
/* We do not really need the scratch layer, but we want to test blit and blend
|
|
* operation with 3 dma2d layer
|
|
*/
|
|
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, dest->dma2d, &area);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
|
|
/* Blend the shadow surface semitransparency */
|
|
|
|
back->dma2d->setalpha(back->dma2d, 86 * alpha / 255);
|
|
fore->dma2d->setalpha(fore->dma2d, 169 * alpha / 255);
|
|
dest->layer->blend(dest->layer, xpos + shadowx, ypos + shadowy, fore->dma2d,
|
|
0, 0, back->dma2d, &area);
|
|
|
|
/* Blit to the origin surface */
|
|
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
dest->layer->blend(dest->layer, xpos, ypos, fore->dma2d,
|
|
0, 0, back->dma2d, &area);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_blendrect
|
|
*
|
|
* Description:
|
|
* Helper: Blend a rectangle to the a specific pixel position.
|
|
* Note! This is only useful for the blitflipositioning test.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_blendrect(FAR struct dma2d_surface *fore,
|
|
FAR struct dma2d_surface *back,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
fb_coord_t shadowlen)
|
|
{
|
|
FAR struct surface *sur = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
/* Clear the invisible flip layer */
|
|
|
|
ltdc_clearlayer(sur, LTDC_BLACK);
|
|
|
|
/* Blend the rectangle */
|
|
|
|
ltdc_blendshadow(sur, fore, back, xpos, ypos, 16, 255);
|
|
|
|
/* Flip the layer to make the changes visible */
|
|
|
|
sur->layer->update(sur->layer, LTDC_UPDATE_FLIP|
|
|
LTDC_SYNC_VBLANK|
|
|
LTDC_SYNC_WAIT);
|
|
|
|
usleep(10);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_blendoutline
|
|
*
|
|
* Description:
|
|
* Draw the outline of a rectangle.
|
|
* Note! This is done by performing sequential blend operations.
|
|
* It does not claim to have a good speed performance.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_blendoutline(FAR struct dma2d_surface *fore,
|
|
FAR struct dma2d_surface *back)
|
|
{
|
|
int n;
|
|
struct ltdc_area_s area;
|
|
|
|
/* Use the inactive layer as second scratch layer */
|
|
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
/* Draw the outline */
|
|
|
|
for (n = 0; n < 5 ; n++)
|
|
{
|
|
area.xpos = n;
|
|
area.ypos = n;
|
|
area.yres = fore->vinfo.yres - n * 2;
|
|
area.xres = fore->vinfo.xres - n * 2;
|
|
|
|
if (n == 0 || n == 2)
|
|
{
|
|
dma2d_clearlayer(fore, LTDC_BLACK);
|
|
back->dma2d->setalpha(back->dma2d, 1);
|
|
back->dma2d->setalpha(fore->dma2d, 2);
|
|
}
|
|
else if (n == 1)
|
|
{
|
|
dma2d_clearlayer(fore, LTDC_WHITE);
|
|
back->dma2d->setalpha(back->dma2d, 2);
|
|
back->dma2d->setalpha(fore->dma2d, 1);
|
|
}
|
|
else if (n == 3)
|
|
{
|
|
dma2d_clearlayer(fore, LTDC_BLACK);
|
|
back->dma2d->setalpha(back->dma2d, 3);
|
|
back->dma2d->setalpha(fore->dma2d, 1);
|
|
}
|
|
else
|
|
{
|
|
dma2d_clearlayer(fore, LTDC_BLACK);
|
|
back->dma2d->setalpha(back->dma2d, 3);
|
|
back->dma2d->setalpha(fore->dma2d, 0);
|
|
}
|
|
|
|
inactive->dma2d->blend(inactive->dma2d, n, n, back->dma2d,
|
|
n, n, fore->dma2d, &area);
|
|
}
|
|
|
|
/* Copy the result back to the background layer */
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.yres = back->vinfo.yres;
|
|
area.xres = back->vinfo.xres;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, inactive->dma2d, &area);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_calcpixel
|
|
*
|
|
* Description:
|
|
* Calculates the next pixel position.
|
|
* This is based on the Breseham algorithmus.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_calcpos(int32_t *x0, int32_t *y0, int32_t x1, int32_t y1)
|
|
{
|
|
if (*x0 != x1 && *y0 != y1)
|
|
{
|
|
int32_t sx = *x0<x1 ? 1 : -1;
|
|
int32_t sy = *y0<y1 ? 1 : -1;
|
|
int32_t dx = x1 - *x0 < 0 ? *x0 - x1 : x1 - *x0;
|
|
int32_t dy = y1 - *y0 < 0 ? y1 - *y0 : *y0 - y1;
|
|
int32_t e = 2 * (dx + dy);
|
|
|
|
if (e > dy)
|
|
{
|
|
*x0 += sx;
|
|
}
|
|
if (e < dx)
|
|
{
|
|
*y0 += sy;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_interface
|
|
*
|
|
* Description:
|
|
* Test: Error handling of dma2d interface
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_interface(void)
|
|
{
|
|
int ret;
|
|
uint8_t alpha = 0;
|
|
uint32_t blendmode = 0;
|
|
#ifdef CONFIG_STM32_LTDC_L2
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
#else
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
#endif
|
|
FAR struct dma2d_layer_s *dma2d = active->dma2d;
|
|
|
|
_info("Perform simple dma2d interface test\n");
|
|
|
|
/* test setalpha */
|
|
|
|
ret = dma2d->setalpha(dma2d, 127);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: setalpha() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* test getalpha */
|
|
|
|
ret = dma2d->getalpha(dma2d, &alpha);
|
|
|
|
if (ret != OK || alpha != 127)
|
|
{
|
|
_err("ERROR: getalpha() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* test setblendmode */
|
|
|
|
ret = dma2d->setblendmode(dma2d, DMA2D_BLEND_ALPHA);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: setblendmode() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* test getblendmode */
|
|
|
|
ret = dma2d->getblendmode(dma2d, &blendmode);
|
|
|
|
if (ret != OK || blendmode != DMA2D_BLEND_ALPHA)
|
|
{
|
|
_err("ERROR: getblendmode() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
/* test setclut */
|
|
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
int i;
|
|
FAR struct fb_cmap_s *cmapltdc = ltdc_createcmap(LTDC_EXAMPLE_NCOLORS);
|
|
FAR struct fb_cmap_s *cmap = ltdc_createcmap(256);
|
|
|
|
if (!cmap || !cmapltdc)
|
|
{
|
|
ltdc_deletecmap(cmap);
|
|
ltdc_deletecmap(cmapltdc);
|
|
_exit(1);
|
|
}
|
|
|
|
/* store the clut table of the ltdc layer */
|
|
|
|
ret = active->layer->getclut(active->layer, cmapltdc);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: ltdc getclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
for (i = 0; i < LTDC_EXAMPLE_NCOLORS; i++)
|
|
{
|
|
#ifdef CONFIG_FB_TRANSPARENCY
|
|
_info("ltdc color %d, %02x:%02x:%02x:%02x\n", i,
|
|
cmapltdc->transp[i],
|
|
cmapltdc->red[i],
|
|
cmapltdc->green[i],
|
|
cmapltdc->blue[i]);
|
|
#else
|
|
_info("ltdc color %d, %02x:%02x:%02x\n", i,
|
|
cmapltdc->red[i],
|
|
cmapltdc->green[i],
|
|
cmapltdc->blue[i]);
|
|
#endif
|
|
}
|
|
|
|
ret = dma2d->getclut(dma2d, cmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: getclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
memset(cmap->red, 0, 256);
|
|
memset(cmap->green, 0, 256);
|
|
memset(cmap->blue, 0, 256);
|
|
#ifdef CONFIG_FB_TRANSPARENCY
|
|
memset(cmap->transp, 0, 256);
|
|
#endif
|
|
_info("set color lookup table to black\n");
|
|
|
|
ret = dma2d->setclut(dma2d, cmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: setclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
ret = dma2d->getclut(dma2d, cmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: getclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* Check if the clut is black */
|
|
|
|
#ifdef CONFIG_FB_TRANSPARENCY
|
|
if(memcmp(cmap->red, cmap->blue, 256) ||
|
|
memcmp(cmap->red, cmap->green, 256) ||
|
|
memcmp(cmap->transp, cmap->blue, 256))
|
|
#else
|
|
if(memcmp(cmap->red, cmap->blue, 256) ||
|
|
memcmp(cmap->red, cmap->green, 256))
|
|
#endif
|
|
{
|
|
_err("ERROR: unexpected clut content\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* Check if the ltdc clut is set by the dma2d interface */
|
|
|
|
ret = active->layer->getclut(active->layer, cmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: ltdc getclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* Check if the ltdc clut is black */
|
|
|
|
#ifdef CONFIG_FB_TRANSPARENCY
|
|
if(memcmp(cmap->red, cmap->blue, 256) ||
|
|
memcmp(cmap->red, cmap->green, 256) ||
|
|
memcmp(cmap->transp, cmap->blue, 256))
|
|
#else
|
|
if(memcmp(cmap->red, cmap->blue, 256) ||
|
|
memcmp(cmap->red, cmap->green, 256))
|
|
#endif
|
|
{
|
|
_err("ERROR: unexpected clut content\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* Check if the clut is set by the ltdc interface */
|
|
|
|
/* Restore the clut table of the ltdc layer */
|
|
|
|
ret = active->layer->setclut(active->layer, cmapltdc);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: ltdc setclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
/* Compare with the related clut table of the dma2d layer */
|
|
|
|
ret = dma2d->getclut(dma2d, cmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: getclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
#ifdef CONFIG_FB_TRANSPARENCY
|
|
if(memcmp(cmap->transp, cmapltdc->transp, LTDC_EXAMPLE_NCOLORS) ||
|
|
memcmp(cmap->red, cmapltdc->red, LTDC_EXAMPLE_NCOLORS) ||
|
|
memcmp(cmap->green, cmapltdc->green, LTDC_EXAMPLE_NCOLORS) ||
|
|
memcmp(cmap->blue, cmapltdc->blue, LTDC_EXAMPLE_NCOLORS))
|
|
#else
|
|
if(memcmp(cmap->red, cmapltdc->red, LTDC_EXAMPLE_NCOLORS) ||
|
|
memcmp(cmap->green, cmapltdc->green, LTDC_EXAMPLE_NCOLORS) ||
|
|
memcmp(cmap->blue, cmapltdc->blue, LTDC_EXAMPLE_NCOLORS))
|
|
#endif
|
|
{
|
|
_err("ERROR: clut of ltdc layer and related dma2d layer are different\n");
|
|
_exit(1);
|
|
}
|
|
else
|
|
{
|
|
_info("ok, changing the clut by the ltdc layer also changed the clut of "
|
|
"the dma2d layer as expected.\n");
|
|
}
|
|
|
|
/* Check expected setclut error */
|
|
|
|
cmap->first = 256;
|
|
|
|
ret = dma2d->setclut(dma2d, cmap);
|
|
|
|
if (ret == OK)
|
|
{
|
|
_err("ERROR: setclut() failed, expected error if first color exceeds 256\n");
|
|
}
|
|
else
|
|
{
|
|
_info("setclut() Ok, unsupported cmap detected\n");
|
|
}
|
|
|
|
/* Check expected getclut error */
|
|
|
|
ret = dma2d->getclut(dma2d, cmap);
|
|
|
|
if (ret == OK)
|
|
{
|
|
_err("ERROR: getclut() failed, expected error if first color exceeds 256\n");
|
|
}
|
|
else
|
|
{
|
|
_info("getclut() Ok, unsupported cmap detected\n");
|
|
}
|
|
|
|
cmap->first = 0;
|
|
|
|
/* Restore the clut table of the ltdc layer if something goes wrong */
|
|
|
|
ret = active->layer->setclut(active->layer, cmapltdc);
|
|
|
|
if (ret != OK)
|
|
{
|
|
_err("ERROR: ltdc setclut() failed\n");
|
|
_exit(1);
|
|
}
|
|
|
|
ltdc_deletecmap(cmap);
|
|
ltdc_deletecmap(cmapltdc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_fillarea
|
|
*
|
|
* Description:
|
|
* Test: Drawing color to specific area.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_fillarea(void)
|
|
{
|
|
int ret = !OK;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Wrong positioning detection */
|
|
|
|
area.xpos = 1;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres;
|
|
area.yres = active->vinfo.yres;
|
|
|
|
_info("check if the ltdc driver recognized when positioning overflows the whole"
|
|
" layer buffer\n");
|
|
|
|
if (active->layer->fillarea(active->layer, &area, 0) != OK)
|
|
{
|
|
ret = OK;
|
|
}
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 1;
|
|
|
|
if (active->layer->fillarea(active->layer, &area, 0) != OK)
|
|
{
|
|
ret = OK == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
_info("check if the dma2d driver recognized when positioning overflows the"
|
|
" whole layer buffer\n");
|
|
|
|
if (active->dma2d->fillarea(active->dma2d, &area, 0) != OK)
|
|
{
|
|
ret = OK == OK ? OK : ret;
|
|
}
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 1;
|
|
|
|
if (active->dma2d->fillarea(active->dma2d, &area, 0) != OK)
|
|
{
|
|
ret = OK == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
/* Flip with non blend */
|
|
|
|
_info("Perform fillarea test\n");
|
|
|
|
_info("Ensure that the active layer is opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
_info("Disable blend mode for the active layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_drawcolor(&active->vinfo, active->pinfo.fbmem,
|
|
active->vinfo.xres, active->vinfo.yres,
|
|
ltdc_color(&active->vinfo, LTDC_BLACK));
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
active->layer->update(active->layer, LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
_info("Draw a red rectangle in top left quarter of the screen\n");
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
active->layer->fillarea(active->layer, &area,
|
|
ltdc_color(&active->vinfo, LTDC_RED));
|
|
|
|
usleep(1000000);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_drawcolor(&active->vinfo, active->pinfo.fbmem,
|
|
active->vinfo.xres, active->vinfo.yres,
|
|
ltdc_color(&active->vinfo, LTDC_BLACK));
|
|
|
|
_info("Draw a green rectangle in top right quarter of the screen\n");
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = 0;
|
|
|
|
active->layer->fillarea(active->layer, &area,
|
|
ltdc_color(&active->vinfo, LTDC_GREEN));
|
|
|
|
usleep(1000000);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_drawcolor(&active->vinfo, active->pinfo.fbmem,
|
|
active->vinfo.xres, active->vinfo.yres,
|
|
ltdc_color(&active->vinfo, LTDC_BLACK));
|
|
|
|
_info("Draw a white rectangle in bottom left quarter of the screen\n");
|
|
|
|
area.xpos = 0;
|
|
area.ypos = active->vinfo.yres/2;
|
|
|
|
active->layer->fillarea(active->layer, &area,
|
|
ltdc_color(&active->vinfo, LTDC_WHITE));
|
|
|
|
_info("Draw a blue rectangle in bottom right quarter of the screen\n");
|
|
|
|
usleep(1000000);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_drawcolor(&active->vinfo, active->pinfo.fbmem,
|
|
active->vinfo.xres, active->vinfo.yres,
|
|
ltdc_color(&active->vinfo, LTDC_BLACK));
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = active->vinfo.yres/2;
|
|
|
|
active->layer->fillarea(active->layer, &area,
|
|
ltdc_color(&active->vinfo, LTDC_BLUE));
|
|
|
|
usleep(1000000);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_drawcolor(&active->vinfo, active->pinfo.fbmem,
|
|
active->vinfo.xres, active->vinfo.yres,
|
|
ltdc_color(&active->vinfo, LTDC_BLACK));
|
|
}
|
|
|
|
#ifdef CONFIG_STM32_LTDC_L2
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blitsimple
|
|
*
|
|
* Description:
|
|
* Test: Perform simple blit operation to check source area positioning
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blitsimple(void)
|
|
{
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Flip with non blend */
|
|
|
|
_info("Perform simple blit operation\n");
|
|
|
|
_info("active->pinfo.fbmem = %p\n", active->pinfo.fbmem);
|
|
_info("inactive->pinfo.fbmem = %p\n", inactive->pinfo.fbmem);
|
|
|
|
_info("Ensure that both ltdc layer are opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
inactive->layer->setalpha(inactive->layer, 0xff);
|
|
_info("Disable blend mode for ltdc both layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
inactive->layer->setblendmode(inactive->layer, LTDC_BLEND_NONE);
|
|
|
|
/* Fullscreen blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
inactive->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
ltdc_simple_draw(&inactive->vinfo, &inactive->pinfo);
|
|
|
|
_info("Blit the whole bottom layer to the top layer\n");
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres;
|
|
area.yres = inactive->vinfo.yres;
|
|
active->layer->blit(active->layer, 0, 0, inactive->dma2d, &area);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Top left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the top left red rectangle from the bottom layer with the"
|
|
" top layer\n");
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Top right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = inactive->vinfo.xres/2;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the top right green rectangle from the bottom layer with the"
|
|
" top layer\n");
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = inactive->vinfo.yres/2;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom left white rectangle from the bottom layer with the"
|
|
" top layer\n");
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = inactive->vinfo.xres/2;
|
|
area.ypos = inactive->vinfo.yres/2;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom right blue rectangle from the bottom layer with the"
|
|
" top layer\n");
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
|
|
usleep(1000000);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blitpositioning
|
|
*
|
|
* Description:
|
|
* Test: Perform simple blit operation to check source and destination
|
|
* positioning
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blitpositioning(void)
|
|
{
|
|
uint32_t x, y;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Set layer in the middle of the screen */
|
|
|
|
_info("active->pinfo.fbmem = %p\n", active->pinfo.fbmem);
|
|
_info("inactive->pinfo.fbmem = %p\n", inactive->pinfo.fbmem);
|
|
|
|
_info("Ensure that both ltdc layer opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
inactive->layer->setalpha(inactive->layer, 0xff);
|
|
_info("Disable blend mode for both ltdc layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
inactive->layer->setblendmode(inactive->layer, LTDC_BLEND_NONE);
|
|
|
|
/* Fullscreen blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
inactive->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
/* Create colored background buffer */
|
|
ltdc_simple_draw(&inactive->vinfo, &inactive->pinfo);
|
|
|
|
|
|
_info("Perform positioning test\n");
|
|
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
|
|
x = active->vinfo.xres/4;
|
|
y = active->vinfo.yres/4;
|
|
|
|
/* Move right */
|
|
|
|
for (; x < active->vinfo.xres/4 + active->vinfo.xres/8; x++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = x;
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (; y < active->vinfo.yres/4 + active->vinfo.yres/8; y++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.ypos = y;
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; x >= active->vinfo.xres/4 - active->vinfo.xres/8; x--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = x;
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; y >= active->vinfo.yres/4; y--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.ypos = y;
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; x <= active->vinfo.xres/4; x++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = x;
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
|
|
usleep(5);
|
|
}
|
|
|
|
_info("Perform move test\n");
|
|
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
/* Move right */
|
|
|
|
for (x = area.xpos; x < area.xpos + area.xres/8; x++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, x, area.ypos, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (y = area.ypos; y < area.ypos + area.yres/8; y++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; x >= area.xpos - area.xres/8; x--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; y >= area.ypos; y--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; x <= area.xpos; x++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, x, y, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
_info("Perform reference positioning test\n");
|
|
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
/* Move right */
|
|
|
|
for (; area.xpos >= active->vinfo.xres/4 - active->vinfo.xres/8; area.xpos--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (; area.ypos >= active->vinfo.yres/4 - active->vinfo.yres/8; area.ypos--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; area.xpos < active->vinfo.xres/4 + active->vinfo.xres/8; area.xpos++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; area.ypos < active->vinfo.yres/4; area.ypos++)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; area.xpos >= active->vinfo.xres/4; area.xpos--)
|
|
{
|
|
/* Cleanup current screen */
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blendsimple
|
|
*
|
|
* Description:
|
|
* Test: Perform simple blend operation to check source area positioning
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blendsimple(void)
|
|
{
|
|
uint8_t alpha;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
_info("Perform simple blend operation\n");
|
|
|
|
_info("active->pinfo.fbmem = %p\n", active->pinfo.fbmem);
|
|
_info("inactive->pinfo.fbmem = %p\n", inactive->pinfo.fbmem);
|
|
|
|
_info("Ensure that both ltdc layer are opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
inactive->layer->setalpha(inactive->layer, 0xff);
|
|
_info("Enable alpha blend mode for both dma2d layer\n");
|
|
active->dma2d->setblendmode(active->dma2d, DMA2D_BLEND_ALPHA);
|
|
inactive->dma2d->setblendmode(inactive->dma2d, DMA2D_BLEND_ALPHA);
|
|
|
|
/* Fullscreen blend */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
active->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_UPDATE_SIM|LTDC_SYNC_VBLANK);
|
|
|
|
ltdc_simple_draw(&inactive->vinfo, &inactive->pinfo);
|
|
|
|
_info("Blend the whole bottom layer to the top layer\n");
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres;
|
|
area.yres = inactive->vinfo.yres;
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
active->dma2d->setalpha(active->dma2d, 255 - alpha/4);
|
|
inactive->dma2d->setalpha(inactive->dma2d, alpha);
|
|
active->layer->blend(active->layer, area.xpos, area.ypos,
|
|
active->dma2d, area.xpos, area.ypos,
|
|
inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Blend top left to the middle */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blend the top left red rectangle from the bottom layer with the middle"
|
|
" of the top layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
active->dma2d->setalpha(active->dma2d, 255 - alpha/4);
|
|
inactive->dma2d->setalpha(inactive->dma2d, alpha);
|
|
active->layer->blend(active->layer, area.xpos, area.ypos,
|
|
active->dma2d, area.xpos, area.ypos,
|
|
inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Top right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = inactive->vinfo.xres/2;
|
|
area.ypos = 0;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blend the top right green rectangle from the bottom layer with the"
|
|
" middle of the top layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
active->dma2d->setalpha(active->dma2d, 255 - alpha/4);
|
|
inactive->dma2d->setalpha(inactive->dma2d, alpha);
|
|
active->layer->blend(active->layer, area.xpos, area.ypos,
|
|
active->dma2d, area.xpos, area.ypos,
|
|
inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Bottom left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = inactive->vinfo.yres/2;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom left white rectangle from the bottom layer with the"
|
|
" middle of the top layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
active->dma2d->setalpha(active->dma2d, 255 - alpha/4);
|
|
inactive->dma2d->setalpha(inactive->dma2d, alpha);
|
|
active->layer->blend(active->layer, area.xpos, area.ypos,
|
|
active->dma2d, area.xpos, area.ypos,
|
|
inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
/* Bottom right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = inactive->vinfo.xres/2;
|
|
area.ypos = inactive->vinfo.yres/2;
|
|
area.xres = inactive->vinfo.xres/2;
|
|
area.yres = inactive->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom right blue rectangle from the bottom layer with the"
|
|
" middle of the top layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
active->dma2d->setalpha(active->dma2d, 255 - alpha/4);
|
|
inactive->dma2d->setalpha(inactive->dma2d, alpha);
|
|
active->layer->blend(active->layer, area.xpos, area.ypos,
|
|
active->dma2d, area.xpos, area.ypos,
|
|
inactive->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
}
|
|
#endif /* CONFIG_STM32_LTDC_L2 */
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blitdynamiclayer
|
|
*
|
|
* Description:
|
|
* Test: Perform simple blit operation with allocated dma2d layer using the
|
|
* dma2d interface.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blitdynamiclayer(void)
|
|
{
|
|
int ret = !OK;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct ltdc_area_s forearea;
|
|
FAR struct dma2d_surface *fore;
|
|
FAR struct dma2d_surface *back;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
/* Create two new dma2d layer */
|
|
|
|
back = ltdc_create_dma2d_surface(active->vinfo.xres, active->vinfo.yres,
|
|
active->vinfo.fmt);
|
|
|
|
if (!back)
|
|
{
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create background dma2d surface: %p\n", back);
|
|
|
|
fore = ltdc_create_dma2d_surface(active->vinfo.xres/2, active->vinfo.yres/2,
|
|
active->vinfo.fmt);
|
|
|
|
if (!fore)
|
|
{
|
|
ltdc_remove_dma2d_surface(back);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create foreground dma2d surface: %p\n", fore);
|
|
|
|
/* Wrong positioning detection */
|
|
|
|
forearea.xpos = 0;
|
|
forearea.ypos = 0;
|
|
forearea.xres = fore->vinfo.xres;
|
|
forearea.yres = fore->vinfo.yres;
|
|
|
|
_info("check if the ltdc driver recognized when positioning overflows the whole"
|
|
" layer buffer\n");
|
|
|
|
if (active->layer->blit(active->layer,
|
|
active->vinfo.xres - forearea.xres + 1,
|
|
active->vinfo.yres - forearea.yres, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = OK;
|
|
}
|
|
|
|
if (active->layer->blit(active->layer,
|
|
active->vinfo.xres - forearea.xres,
|
|
active->vinfo.yres - forearea.yres + 1, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
forearea.xpos = 1;
|
|
|
|
if (active->layer->blit(active->layer, 0, 0, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
forearea.xpos = 0;
|
|
forearea.ypos = 1;
|
|
|
|
if (active->layer->blit(active->layer, 0, 0, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
_info("check if the dma2d driver recognized when positioning overflows the"
|
|
" whole layer buffer\n");
|
|
|
|
forearea.xpos = 0;
|
|
forearea.ypos = 0;
|
|
|
|
if (active->dma2d->blit(active->dma2d,
|
|
active->vinfo.xres - forearea.xres + 1,
|
|
active->vinfo.yres - forearea.yres, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = OK;
|
|
}
|
|
|
|
if (active->dma2d->blit(active->dma2d,
|
|
active->vinfo.xres - forearea.xres,
|
|
active->vinfo.yres - forearea.yres + 1, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
forearea.xpos = 1;
|
|
|
|
if (active->dma2d->blit(active->dma2d, 0, 0, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
forearea.xpos = 0;
|
|
forearea.ypos = 1;
|
|
|
|
if (active->dma2d->blit(active->dma2d, 0, 0, fore->dma2d, &forearea) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
/* Initialize the dma2d fullscreen background layer */
|
|
|
|
ltdc_simple_draw(&back->vinfo, &back->pinfo);
|
|
|
|
/* Initialize foreground area for blitting to the screen */
|
|
|
|
forearea.xpos = 0;
|
|
forearea.ypos = 0;
|
|
forearea.xres = fore->vinfo.xres;
|
|
forearea.yres = fore->vinfo.yres;
|
|
|
|
/* Blit test */
|
|
|
|
_info("Perform simple dma2d blit operation\n");
|
|
|
|
_info("Ensure that the ltdc layer is opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
_info("Disable blend mode for the ltdc layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
active->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
/* Top left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blit the top left red rectangle from the background layer to the"
|
|
" foreground layer\n");
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, back->dma2d, &area);
|
|
|
|
_info("Blit the resulting dma2d layer to the middle of the screen\n");
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, back->dma2d, &forearea);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Top right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blit the top right green rectangle from the background layer to the"
|
|
" foreground layer\n");
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, back->dma2d, &area);
|
|
|
|
_info("Blit the resulting dma2d layer to the middle of the screen\n");
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, &forearea);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = active->vinfo.yres/2;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom left white rectangle from the background layer to the"
|
|
" foreground layer\n");
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, back->dma2d, &area);
|
|
|
|
_info("Blit the resulting dma2d layer to the middle of the screen\n");
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, &forearea);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = active->vinfo.yres/2;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom right blue rectangle from the background layer to the"
|
|
" foreground layer\n");
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, back->dma2d, &area);
|
|
|
|
_info("Blit the resulting dma2d layer to the middle of the screen\n");
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, &forearea);
|
|
|
|
usleep(1000000);
|
|
|
|
/* Middle to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/4;
|
|
area.ypos = active->vinfo.yres/4;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blit the bottom half rectangle from the background layers to the middle"
|
|
" of the foreground layer\n");
|
|
fore->dma2d->blit(fore->dma2d, 0, 0, back->dma2d, &area);
|
|
|
|
_info("Blit the resulting dma2d layer to the middle of the screen\n");
|
|
active->layer->blit(active->layer, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, &forearea);
|
|
|
|
usleep(1000000);
|
|
|
|
ltdc_remove_dma2d_surface(fore);
|
|
ltdc_remove_dma2d_surface(back);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blenddynamiclayer
|
|
*
|
|
* Description:
|
|
* Test: Perform simple blend operation with allocated dma2d layer using the
|
|
* dma2d interface.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blenddynamiclayer(void)
|
|
{
|
|
int ret = !OK;
|
|
uint8_t alpha;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct dma2d_surface *fore;
|
|
FAR struct dma2d_surface *back;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
/* Create two new dma2d layer */
|
|
|
|
back = ltdc_create_dma2d_surface(active->vinfo.xres, active->vinfo.yres,
|
|
active->vinfo.fmt);
|
|
|
|
if (!back)
|
|
{
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create background dma2d surface: %p\n", back);
|
|
|
|
fore = ltdc_create_dma2d_surface(active->vinfo.xres/2, active->vinfo.yres/2,
|
|
active->vinfo.fmt);
|
|
|
|
if (!fore)
|
|
{
|
|
ltdc_remove_dma2d_surface(back);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create foreground dma2d surface: %p\n", fore);
|
|
|
|
/* Wrong positioning detection */
|
|
|
|
_info("check if the ltdc driver recognized when positioning overflows the whole"
|
|
" layer buffer\n");
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = back->vinfo.xres;
|
|
area.xres = back->vinfo.yres;
|
|
|
|
if (active->layer->blend(active->layer,
|
|
active->vinfo.xres - area.xres + 1,
|
|
active->vinfo.yres - area.yres, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = OK;
|
|
}
|
|
|
|
if (active->layer->blend(active->layer,
|
|
active->vinfo.xres - area.xres + 1,
|
|
active->vinfo.yres - area.yres, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (active->layer->blend(active->layer, 0, 0, fore->dma2d,
|
|
fore->vinfo.xres - area.xres + 1,
|
|
fore->vinfo.yres - area.yres, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (active->layer->blend(active->layer, 0, 0, fore->dma2d,
|
|
fore->vinfo.xres - area.xres,
|
|
fore->vinfo.yres - area.yres + 1, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
area.xpos = 1;
|
|
if (active->layer->blend(active->layer, 0, 0, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 1;
|
|
if (active->layer->blend(active->layer, 0, 0, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
_info("check if the dma2d driver recognized when positioning overflows the"
|
|
" whole layer buffer\n");
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
|
|
if (active->dma2d->blend(active->dma2d,
|
|
active->vinfo.xres - area.xres + 1,
|
|
active->vinfo.yres - area.yres, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = OK;
|
|
}
|
|
|
|
if (active->dma2d->blend(active->dma2d,
|
|
active->vinfo.xres - area.xres + 1,
|
|
active->vinfo.yres - area.yres, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (active->dma2d->blend(active->dma2d, 0, 0, fore->dma2d,
|
|
fore->vinfo.xres - area.xres + 1,
|
|
fore->vinfo.yres - area.yres, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (active->dma2d->blend(active->dma2d, 0, 0, fore->dma2d,
|
|
fore->vinfo.xres - area.xres,
|
|
fore->vinfo.yres - area.yres + 1, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
area.xpos = 1;
|
|
if (active->dma2d->blend(active->dma2d, 0, 0, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 1;
|
|
if (active->dma2d->blend(active->dma2d, 0, 0, fore->dma2d,
|
|
0, 0, back->dma2d, &area) != OK)
|
|
{
|
|
ret = ret == OK ? OK : ret;
|
|
}
|
|
|
|
if (ret == OK)
|
|
{
|
|
_info("ok, driver detects wrong positioning\n");
|
|
}
|
|
else
|
|
{
|
|
_err("ERROR: fail, wrong positioning can overflow layer buffer\n");
|
|
}
|
|
|
|
/* Initialize the dma2d fullscreen background layer */
|
|
|
|
ltdc_simple_draw(&back->vinfo, &back->pinfo);
|
|
|
|
/* Blit test */
|
|
|
|
_info("Perform simple dma2d blend operation\n");
|
|
|
|
_info("Ensure that the ltdc layer is opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
_info("Disable blend mode for the ltdc layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
_info("Enable alpha blend mode for both dma2d layer\n");
|
|
fore->dma2d->setblendmode(fore->dma2d, DMA2D_BLEND_ALPHA);
|
|
back->dma2d->setblendmode(back->dma2d, DMA2D_BLEND_ALPHA);
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
active->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
/* Top left to the middle */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blend the top left red rectangle from the background layer with the"
|
|
" middle of the foreground layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
active->dma2d->blend(active->dma2d, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, 0, 0,
|
|
back->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
/* Top right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = 0;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blend the top right green rectangle from the background layer with the"
|
|
" middle of the foreground layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
active->dma2d->blend(active->dma2d, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, 0, 0,
|
|
back->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom left to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = 0;
|
|
area.ypos = active->vinfo.yres/2;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blend the bottom left white rectangle from the background layer with the"
|
|
" middle of foreground layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
active->dma2d->blend(active->dma2d, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, 0, 0,
|
|
back->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
/* Bottom right to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/2;
|
|
area.ypos = active->vinfo.yres/2;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blend the bottom right blue rectangle from the background layer with the"
|
|
" middle of the foreground layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
active->dma2d->blend(active->dma2d, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, 0, 0,
|
|
back->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
/* Middle to the middle blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
area.xpos = active->vinfo.xres/4;
|
|
area.ypos = active->vinfo.yres/4;
|
|
area.xres = active->vinfo.xres/2;
|
|
area.yres = active->vinfo.yres/2;
|
|
|
|
_info("Blend the bottom half screen rectangle from the background layers middle"
|
|
" with the middle of the foreground layer\n");
|
|
|
|
for (alpha = 0; alpha < 255 ; alpha++)
|
|
{
|
|
fore->dma2d->setalpha(fore->dma2d, 255 - alpha);
|
|
back->dma2d->setalpha(back->dma2d, alpha);
|
|
active->dma2d->blend(active->dma2d, active->vinfo.xres/4,
|
|
active->vinfo.yres/4, fore->dma2d, 0, 0,
|
|
back->dma2d, &area);
|
|
usleep(5);
|
|
}
|
|
|
|
usleep(1000000);
|
|
|
|
ltdc_remove_dma2d_surface(fore);
|
|
ltdc_remove_dma2d_surface(back);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blitflippositioning
|
|
*
|
|
* Description:
|
|
* Perform simple blit and flip operation with both interfaces
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_dma2d_blitflippositioning(void)
|
|
{
|
|
uint32_t x, y;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct dma2d_surface *fore;
|
|
FAR struct dma2d_surface *back;
|
|
FAR struct dma2d_surface *image;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8 || inactive->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_warn("WARNING: skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Create three new dma2d layer */
|
|
|
|
fore = ltdc_create_dma2d_surface(active->vinfo.xres/2, active->vinfo.yres/2,
|
|
active->vinfo.fmt);
|
|
|
|
if (!fore)
|
|
{
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create foreground dma2d surface: %p\n", fore);
|
|
|
|
back = ltdc_create_dma2d_surface(active->vinfo.xres/2, active->vinfo.yres/2,
|
|
active->vinfo.fmt);
|
|
|
|
if (!back)
|
|
{
|
|
ltdc_remove_dma2d_surface(fore);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create background dma2d surface: %p\n", back);
|
|
|
|
image = ltdc_create_dma2d_surface(active->vinfo.xres, active->vinfo.yres,
|
|
active->vinfo.fmt);
|
|
|
|
if (!image)
|
|
{
|
|
ltdc_remove_dma2d_surface(fore);
|
|
ltdc_remove_dma2d_surface(back);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create the dma2d surface to store the image: %p\n", image);
|
|
|
|
_info("Enable alpha blending for both dma2d layer\n");
|
|
fore->dma2d->setblendmode(fore->dma2d, DMA2D_BLEND_ALPHA);
|
|
back->dma2d->setblendmode(back->dma2d, DMA2D_BLEND_ALPHA);
|
|
|
|
|
|
_info("Ensure that both ltdc layer opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
inactive->layer->setalpha(inactive->layer, 0xff);
|
|
_info("Disable blend mode for both ltdc layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
inactive->layer->setblendmode(inactive->layer, LTDC_BLEND_NONE);
|
|
|
|
/* Fullscreen blit */
|
|
|
|
_info("Set the active layer to fullscreen black\n");
|
|
ltdc_clearlayer(active, LTDC_BLACK);
|
|
|
|
_info("Flip the top layer to the active visible layer\n");
|
|
inactive->layer->update(active->layer,
|
|
LTDC_UPDATE_ACTIVATE|LTDC_SYNC_VBLANK);
|
|
|
|
/* Draw the four colored rectangles for blend operations */
|
|
|
|
ltdc_simple_draw(&image->vinfo, &image->pinfo);
|
|
|
|
_info("Perform positioning test\n");
|
|
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
area.yres = back->vinfo.yres;
|
|
area.xres = back->vinfo.xres;
|
|
|
|
/* Move right */
|
|
|
|
y = active->vinfo.yres/4;
|
|
|
|
for (x = active->vinfo.xres/4; x < active->vinfo.xres/4 + active->vinfo.xres/8; x++)
|
|
{
|
|
area.xpos = x;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (; y < active->vinfo.yres/4 + active->vinfo.yres/8; y++)
|
|
{
|
|
area.ypos = y;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; x >= active->vinfo.xres/4 - active->vinfo.xres/8; x--)
|
|
{
|
|
area.xpos = x;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; y >= active->vinfo.yres/4; y--)
|
|
{
|
|
area.ypos = y;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; x <= active->vinfo.xres/4; x++)
|
|
{
|
|
area.xpos = x;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
|
|
ltdc_simple_draw(&back->vinfo, &back->pinfo);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
_info("Perform move test\n");
|
|
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
area.yres = back->vinfo.yres;
|
|
area.xres = back->vinfo.xres;
|
|
|
|
back->dma2d->blit(back->dma2d, 0, 0, inactive->dma2d, &area);
|
|
|
|
/* Move right */
|
|
|
|
y = area.ypos;
|
|
|
|
for (x = area.xpos; x < area.xpos + active->vinfo.xres/8; x++)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (; y < area.ypos + active->vinfo.yres/8; y++)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; x >= area.xpos - active->vinfo.xres/8; x--)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; y >= area.ypos; y--)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; x <= area.xpos; x++)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, x, y, 16);
|
|
}
|
|
|
|
|
|
_info("Perform reference positioning test\n");
|
|
|
|
area.xpos = inactive->vinfo.xres/4;
|
|
area.ypos = inactive->vinfo.yres/4;
|
|
area.yres = back->vinfo.yres;
|
|
area.xres = back->vinfo.xres;
|
|
|
|
|
|
/* Move right */
|
|
|
|
for (; area.xpos >= active->vinfo.xres/4 - active->vinfo.xres/8; area.xpos--)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, active->vinfo.xres/4, active->vinfo.yres/4, 16);
|
|
}
|
|
|
|
/* Move down */
|
|
|
|
for (; area.ypos >= active->vinfo.yres/4 - active->vinfo.yres/8; area.ypos--)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, active->vinfo.xres/4, active->vinfo.yres/4, 16);
|
|
}
|
|
|
|
/* Move left */
|
|
|
|
for (; area.xpos < active->vinfo.xres/4 + active->vinfo.xres/8; area.xpos++)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, active->vinfo.xres/4, active->vinfo.yres/4, 16);
|
|
}
|
|
|
|
/* Move up */
|
|
|
|
for (; area.ypos < active->vinfo.yres/4; area.ypos++)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, active->vinfo.xres/4, active->vinfo.yres/4, 16);
|
|
}
|
|
|
|
/* Move right to the start position */
|
|
|
|
for (; area.xpos >= active->vinfo.xres/4; area.xpos--)
|
|
{
|
|
back->dma2d->blit(back->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(fore, back);
|
|
|
|
ltdc_blendrect(fore, back, active->vinfo.xres/4, active->vinfo.yres/4, 16);
|
|
}
|
|
|
|
ltdc_remove_dma2d_surface(fore);
|
|
ltdc_remove_dma2d_surface(back);
|
|
ltdc_remove_dma2d_surface(image);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_screensaver
|
|
*
|
|
* Description:
|
|
* Perform the screensaver test.
|
|
* Note! This test runs in an endless loop.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void ltdc_screensaver(void)
|
|
{
|
|
int32_t x1, y1, x2, y2;
|
|
FAR struct ltdc_area_s area;
|
|
FAR struct dma2d_surface *scratch;
|
|
FAR struct dma2d_surface *rect1;
|
|
FAR struct dma2d_surface *rect2;
|
|
FAR struct dma2d_surface *image;
|
|
FAR struct surface *active = ltdc_get_surface(LTDC_LAYER_ACTIVE);
|
|
FAR struct surface *inactive = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (active->vinfo.fmt == FB_FMT_RGB8 || inactive->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
_info("skipped, output to layer with CLUT pixel format not supported\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Create three new dma2d layer */
|
|
|
|
scratch = ltdc_create_dma2d_surface(active->vinfo.xres/4,
|
|
active->vinfo.yres/4,
|
|
active->vinfo.fmt);
|
|
|
|
if (!scratch)
|
|
{
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create a scratch dma2d layer: %p\n", scratch);
|
|
|
|
rect1 = ltdc_create_dma2d_surface(active->vinfo.xres/4,
|
|
active->vinfo.yres/4,
|
|
active->vinfo.fmt);
|
|
|
|
if (!rect1)
|
|
{
|
|
ltdc_remove_dma2d_surface(scratch);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create a dma2d layer for the rectangle 1: %p\n", rect1);
|
|
|
|
rect2 = ltdc_create_dma2d_surface(active->vinfo.xres/4,
|
|
active->vinfo.yres/4,
|
|
active->vinfo.fmt);
|
|
|
|
if (!rect2)
|
|
{
|
|
ltdc_remove_dma2d_surface(scratch);
|
|
ltdc_remove_dma2d_surface(rect1);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create a dma2d layer for rectangle 2: %p\n", rect2);
|
|
|
|
image = ltdc_create_dma2d_surface(active->vinfo.xres,
|
|
active->vinfo.yres,
|
|
active->vinfo.fmt);
|
|
|
|
if (!image)
|
|
{
|
|
ltdc_remove_dma2d_surface(scratch);
|
|
ltdc_remove_dma2d_surface(rect1);
|
|
ltdc_remove_dma2d_surface(rect2);
|
|
_exit(1);
|
|
}
|
|
|
|
_info("create a dma2d layer to store the background image: %p\n", image);
|
|
|
|
_info("Enable alpha blending for the dma2d layer\n");
|
|
scratch->dma2d->setblendmode(scratch->dma2d, DMA2D_BLEND_ALPHA);
|
|
rect1->dma2d->setblendmode(rect1->dma2d, DMA2D_BLEND_ALPHA);
|
|
rect2->dma2d->setblendmode(rect2->dma2d, DMA2D_BLEND_ALPHA);
|
|
|
|
/* ltdc layer settings */
|
|
|
|
_info("Ensure that both ltdc layer opaque\n");
|
|
active->layer->setalpha(active->layer, 0xff);
|
|
inactive->layer->setalpha(inactive->layer, 0xff);
|
|
_info("Disable blend mode for both ltdc layer\n");
|
|
active->layer->setblendmode(active->layer, LTDC_BLEND_NONE);
|
|
inactive->layer->setblendmode(inactive->layer, LTDC_BLEND_NONE);
|
|
|
|
/* Draw the four colored rectangles for blend operations */
|
|
|
|
ltdc_simple_draw(&image->vinfo, &image->pinfo);
|
|
|
|
_info("Perform screensaver\n");
|
|
|
|
area.xpos = image->vinfo.xres/4 + image->vinfo.xres / 8;
|
|
area.ypos = image->vinfo.yres/4 + image->vinfo.yres / 8;
|
|
area.xres = rect1->vinfo.xres;
|
|
area.yres = rect1->vinfo.yres;
|
|
|
|
/* Create a rectangle with fix content */
|
|
|
|
rect1->dma2d->blit(rect1->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(scratch, rect1);
|
|
|
|
/* Randomize the start position */
|
|
|
|
x1 = rand() % (inactive->vinfo.xres - rect1->vinfo.xres);
|
|
y1 = rand() % (inactive->vinfo.yres - rect1->vinfo.yres);
|
|
x2 = rand() % (inactive->vinfo.xres - rect2->vinfo.xres);
|
|
y2 = rand() % (inactive->vinfo.yres - rect2->vinfo.yres);
|
|
|
|
/* Change the blend area to the rect2 resolution */
|
|
|
|
area.yres = rect2->vinfo.yres;
|
|
area.xres = rect2->vinfo.xres;
|
|
|
|
for(;;)
|
|
{
|
|
int32_t xend1;
|
|
int32_t yend1;
|
|
int32_t xend2;
|
|
int32_t yend2;
|
|
|
|
/* Randomize next end position */
|
|
|
|
xend1 = rand() % (inactive->vinfo.xres - rect1->vinfo.xres);
|
|
yend1 = rand() % (inactive->vinfo.yres - rect1->vinfo.yres);
|
|
xend2 = rand() % (inactive->vinfo.xres - rect2->vinfo.xres);
|
|
yend2 = rand() % (inactive->vinfo.yres - rect2->vinfo.yres);
|
|
|
|
while (x1 != xend1 && y1 != yend1 && x2 != xend2 && y2 != yend2)
|
|
{
|
|
FAR struct surface *sur = ltdc_get_surface(LTDC_LAYER_INACTIVE);
|
|
|
|
/* Calculate the next pixel start positions */
|
|
|
|
ltdc_calcpos(&x1, &y1, xend1, yend1);
|
|
ltdc_calcpos(&x2, &y2, xend2, yend2);
|
|
|
|
area.xpos = x2;
|
|
area.ypos = y2;
|
|
|
|
/* Create the rectangle with the dynamic content */
|
|
|
|
rect2->dma2d->blit(rect2->dma2d, 0, 0, image->dma2d, &area);
|
|
|
|
ltdc_blendoutline(scratch, rect2);
|
|
|
|
ltdc_clearlayer(sur, LTDC_BLACK);
|
|
|
|
/* Blend rect2 as underlying rectangle */
|
|
|
|
ltdc_blendshadow(sur, scratch, rect2, x2, y2, 10, 255);
|
|
|
|
/* Blend rect1 as overlying rectangle ans semitransparency */
|
|
|
|
ltdc_blendshadow(sur, scratch, rect1, x1, y1, 10, 127);
|
|
|
|
/* Flip the layer to make the changes visible */
|
|
|
|
sur->layer->update(sur->layer, LTDC_UPDATE_FLIP|
|
|
LTDC_SYNC_VBLANK|
|
|
LTDC_SYNC_WAIT);
|
|
|
|
usleep(500);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ltdc_dma2d_blitmain
|
|
*
|
|
* Description:
|
|
* Triggers the dma2d tests
|
|
*
|
|
****************************************************************************/
|
|
|
|
void ltdc_dma2d_main(void)
|
|
{
|
|
|
|
ltdc_dma2d_interface();
|
|
ltdc_dma2d_fillarea();
|
|
#ifdef CONFIG_STM32_LTDC_L2
|
|
ltdc_dma2d_blitsimple();
|
|
ltdc_dma2d_blitpositioning();
|
|
ltdc_dma2d_blendsimple();
|
|
#endif
|
|
ltdc_dma2d_blitdynamiclayer();
|
|
ltdc_dma2d_blenddynamiclayer();
|
|
#ifdef CONFIG_STM32_LTDC_L2
|
|
ltdc_dma2d_blitflippositioning();
|
|
ltdc_screensaver();
|
|
#endif
|
|
}
|