Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1466525
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: LINUX

2013-06-13 20:26:17

GDI(Graphics Device Interface)是对绘图接口的描述,是MiniGUI的核心组成部分之一。


GDI虽然是GUI的基础,但是,它实际上不太适合作为GUI的组成部分之一的。因为GUI的核心功能在用户交互上,而不是如何绘制上。对MiniGUI来说,GDI是成也萧何败萧何:MiniGUI内置的GDI使得MiniGUI更紧凑和高效,但是由于其功能受限,使得MiniGUI在绘图精细度上,以及和其他优秀的界面库结合上,存在巨大的缺陷。由此也造成MiniGUI发展受限,无法赶上时代的潮流。


MiniGUI的GDI分成GAL、DC和Surface、位图管理、字体管理以及图元绘制(包括矩形、圆形的绘制和填充),可以用示意图表示:



GDI中涉及很多绘图的算法,这些可以通过查阅计算机图形学相关的书籍就可以了解,这不是我们的重点。我们的重点,在于了解他对显存的管理和操作。

所以,我们从Surface和DC说起。


Surface是管理显存的一个重要对象。它负责管理显存的大小、色深等信息。而且,可以把一块普通的内存看做一个显存,这样,我们就可以在内存中首先构造出该对象。

首先,看它的定义:(src/include/newgal.h)

[cpp]
  1. typedef struct GAL_Surface {  
  2.     Uint32 flags;                       /* Read-only */  
  3.     GAL_PixelFormat *format;            /* Read-only */  
  4.     void *video;                        /* Read-only */  
  5.     int w, h;                           /* Read-only */  
  6.     Uint32 pitch;                       /* Read-only */  
  7.     void *pixels;                       /* Read-write */  
  8.     int offset;                         /* Private */  
  9.   
  10.     /* Hardware-specific surface info */  
  11.     struct private_hwdata *hwdata;  
  12.   
  13.     /* clipping information */  
  14.     GAL_Rect clip_rect;                 /* Read-only */  
  15.   
  16.     /* info for fast blit mapping to other surfaces */  
  17.     struct GAL_BlitMap *map;             /* Private */  
  18.   
  19.     /* format version, bumped at every change to invalidate blit maps */  
  20.     unsigned int format_version;        /* Private */  
  21.   
  22.     /* Reference count -- used when freeing surface */  
  23.     int refcount;                       /* Read-mostly */  
  24. } GAL_Surface  

有几个重要的成员:


format:表示像素的格式,是非常重要的成员

pxiels:是像素的地址指针

map:这是对像素做合并的时候,使用的合并方法。


其中,flags变量来标记surface的一些属性,例如,是硬件surface(surface的pixel指向的内存是显存)或者是软surface(pixel指向普通的内存)等。

由于硬surface和软surface没有太大的区别,所以我们可以先忽略这一部分。


Surface的重要的操作有:创建、删除、Surface的像素合并(BitBlt)。

Surface相关的操作都在src/newgal/surface.c中


首先,看Surface的创建过程。Surface的创建,主要是通过GAL_CreateRGBSurface函数创建的。它初始化一个Surface对象。先看下该函数的实现。

[cpp]
  1. GAL_Surface * GAL_CreateRGBSurface (Uint32 flags,  
  2.             int width, int height, int depth,  
  3.             Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)  
  4. {  
  5.     GAL_VideoDevice *video = current_video;  
  6.     GAL_VideoDevice *this  = current_video;  
  7.     GAL_Surface *screen;  
  8.     GAL_Surface *surface;  
  9.   
  10.     /* Check to see if we desire the surface in video memory */  
  11.     if ( video ) {  
  12.         screen = GAL_PublicSurface;  
  13.     } else {  
  14.         screen = NULL;  
  15.     }  
  16.     if ( screen && ((screen->flags&GAL_HWSURFACE) == GAL_HWSURFACE) ) {  
  17.         if ( (flags&(GAL_SRCCOLORKEY|GAL_SRCALPHA)) != 0 ) {  
  18.             flags |= GAL_HWSURFACE;  
  19.         }  
  20.         if ( (flags & GAL_SRCCOLORKEY) == GAL_SRCCOLORKEY ) {  
  21.             if ( ! current_video->info.blit_hw_CC ) {  
  22.                 flags &= ~GAL_HWSURFACE;  
  23.             }  
  24.         }  
  25.         if ( (flags & GAL_SRCALPHA) == GAL_SRCALPHA ) {  
  26.             if ( ! current_video->info.blit_hw_A ) {  
  27.                 flags &= ~GAL_HWSURFACE;  
  28.             }  
  29.         }  
  30.     } else {  
  31.         flags &= ~GAL_HWSURFACE;  
  32.     }  
  33.   
  34.     /* Allocate the surface */  
  35.     surface = (GAL_Surface *)malloc(sizeof(*surface));  
  36.     if ( surface == NULL ) {  
  37.         GAL_OutOfMemory();  
  38.         return(NULL);  
  39.     }  
  40.     if ((flags & GAL_HWSURFACE) == GAL_HWSURFACE)  
  41.         surface->video = current_video;  
  42.     else  
  43.         surface->video = NULL;  
  44.   
  45.     surface->flags = GAL_SWSURFACE;  
  46.   
  47.     if ( (flags & GAL_HWSURFACE) == GAL_HWSURFACE ) {  
  48.         depth = screen->format->BitsPerPixel;  
  49.         Rmask = screen->format->Rmask;  
  50.         Gmask = screen->format->Gmask;  
  51.         Bmask = screen->format->Bmask;  
  52.         Amask = screen->format->Amask;  
  53.     }  
  54.     surface->format = GAL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);  
  55.     if ( surface->format == NULL ) {  
  56.         free(surface);  
  57.         return(NULL);  
  58.     }  
  59.     if ( Amask ) {  
  60.         surface->flags |= GAL_SRCALPHA;  
  61.     }  
  62.     surface->w = width;  
  63.     surface->h = height;  
  64.     surface->pitch = GAL_CalculatePitch(surface);  
  65.     surface->pixels = NULL;  
  66.     surface->offset = 0;  
  67.     surface->hwdata = NULL;  
  68.     surface->map = NULL;  
  69.     surface->format_version = 0;  
  70.     GAL_SetClipRect(surface, NULL);  
  71.   
  72.     /* Get the pixels */  
  73.     if ( ((flags&GAL_HWSURFACE) == GAL_SWSURFACE) ||   
  74.                 (video->AllocHWSurface(this, surface) < 0) ) {  
  75.         if ( surface->w && surface->h ) {  
  76.             surface->pixels = malloc(surface->h*surface->pitch);  
  77.             if ( surface->pixels == NULL ) {  
  78.                 GAL_FreeSurface(surface);  
  79.                 GAL_OutOfMemory();  
  80.                 return(NULL);  
  81.             }  
  82.             /* This is important for bitmaps */  
  83.             memset(surface->pixels, 0, surface->h*surface->pitch);  
  84.             surface->flags &= ~GAL_HWSURFACE;  
  85.         }  
  86.     }  
  87.   
  88.     /* Allocate an empty mapping */  
  89.     surface->map = GAL_AllocBlitMap();  
  90.     if ( surface->map == NULL ) {  
  91.         GAL_FreeSurface(surface);  
  92.         return(NULL);  
  93.     }  
  94.   
  95.     /* The surface is ready to go */  
  96.     surface->refcount = 1;  
  97. #ifdef CHECK_LEAKS   
  98.     ++surfaces_allocated;  
  99. #endif   
  100.     return(surface);  
  101. }  
该函数创建一个GAL_Surface结构体对象,并初始化了其成员。这其中,我们需要重点注意对format成员和map成员的初始化。


对format成员,它调用了GAL_AllocFormat函数。首先,看下GAL_PixelFormat的定义:

[cpp]
  1. typedef struct GAL_PixelFormat {  
  2.     GAL_Palette *palette;  
  3.     BOOL   DitheredPalette;  
  4.     Uint8  BitsPerPixel;  
  5.     Uint8  BytesPerPixel;  
  6.     Uint8  Rloss;  
  7.     Uint8  Gloss;  
  8.     Uint8  Bloss;  
  9.     Uint8  Aloss;  
  10.     Uint8  Rshift;  
  11.     Uint8  Gshift;  
  12.     Uint8  Bshift;  
  13.     Uint8  Ashift;  
  14.     Uint32 Rmask;  
  15.     Uint32 Gmask;  
  16.     Uint32 Bmask;  
  17.     Uint32 Amask;  
  18.   
  19.     /* RGB color key information */  
  20.     gal_pixel colorkey;  
  21.     /* Alpha value information (per-surface alpha) */  
  22.     gal_uint8 alpha;  
  23. } GAL_PixelFormat;  
palette成员主要用在8位及以下的像素中,不是考虑的重点。


BitsPerPixel是一个像素占用的位数,可以选择的是1,2,4,8,16,24,32

BytesPerPixel是一个像素占用的字节数,可以是,1,2,4等

下面的成员,按照R、G、B、A分成loss, shift, mask三组,它是相对于一个分量8位来说的,分别表示RGBA分量所丢失的位数、在像素中的偏移位数和掩码值

例如,对于16位以565格式保存的RGB像素格式来说,其高6位被R分量占用,Rloss为3,Rshift为11,Rmask则为0xF800; 中间6位被G分量占用,Gloss为2,GShift为5,Gmask为0x07E0;B分量占用剩余的5位,其中Bloss为3,Bshift为0,Bmask为0x001F,表示如下:

RRRR RGGG GGGB BBBB

用这些信息,就可以通过RGB分量计算出一个像素的值,如:

[cpp]
  1.     Uint32 pixv = (r >> format->Rloss) << format->Rshift  
  2. | (g >> format->Gloss) << format->Gshift  
  3. | (b >> format->Bloss) << format->Bshift  
  4. | ((a >> format->Aloss) << format->Ashift & format->Amask);  

然后我们看下GAL_AllocFormat函数的实现:


[cpp]
  1. GAL_PixelFormat *GAL_AllocFormat(int bpp,  
  2.             Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)  
  3. {  
  4.     GAL_PixelFormat *format;  
  5.     Uint32 mask;  
  6.   
  7.     /* Allocate an empty pixel format structure */  
  8.     format = malloc(sizeof(*format));  
  9.     if ( format == NULL ) {  
  10.         GAL_OutOfMemory();  
  11.         return(NULL);  
  12.     }  
  13.     memset(format, 0, sizeof(*format));  
  14.     format->alpha = GAL_ALPHA_OPAQUE;  
  15.   
  16.     /* Set up the format */  
  17.     format->BitsPerPixel = bpp;  
  18.     format->BytesPerPixel = (bpp+7)/8;  
  19.     format->DitheredPalette = FALSE;  
  20.     switch (bpp) {  
  21.         case 1:  
  22.             /* Create the 2 color black-white palette */  
  23.             format->palette = (GAL_Palette *)malloc(  
  24.                             sizeof(GAL_Palette));  
  25.             if ( format->palette == NULL ) {  
  26.                 GAL_FreeFormat(format);  
  27.                 GAL_OutOfMemory();  
  28.                 return(NULL);  
  29.             }  
  30.             (format->palette)->ncolors = 2;  
  31.             (format->palette)->colors = (GAL_Color *)malloc(  
  32.                 (format->palette)->ncolors*sizeof(GAL_Color));  
  33.             if ( (format->palette)->colors == NULL ) {  
  34.                 GAL_FreeFormat(format);  
  35.                 GAL_OutOfMemory();  
  36.                 return(NULL);  
  37.             }  
  38.             format->palette->colors[0].r = 0xFF;  
  39.             format->palette->colors[0].g = 0xFF;  
  40.             format->palette->colors[0].b = 0xFF;  
  41.             format->palette->colors[1].r = 0x00;  
  42.             format->palette->colors[1].g = 0x00;  
  43.             format->palette->colors[1].b = 0x00;  
  44.             format->Rloss = 8;  
  45.             format->Gloss = 8;  
  46.             format->Bloss = 8;  
  47.             format->Aloss = 8;  
  48.             format->Rshift = 0;  
  49.             format->Gshift = 0;  
  50.             format->Bshift = 0;  
  51.             format->Ashift = 0;  
  52.             format->Rmask = 0;  
  53.             format->Gmask = 0;  
  54.             format->Bmask = 0;  
  55.             format->Amask = 0;  
  56.             break;  
  57.   
  58.         case 4:  
  59.             /* Create the 16 color VGA palette */  
  60.             format->palette = (GAL_Palette *)malloc(  
  61.                             sizeof(GAL_Palette));  
  62.             if ( format->palette == NULL ) {  
  63.                 GAL_FreeFormat(format);  
  64.                 GAL_OutOfMemory();  
  65.                 return(NULL);  
  66.             }  
  67.             (format->palette)->ncolors = 16;  
  68.             (format->palette)->colors = (GAL_Color *)malloc(  
  69.                 (format->palette)->ncolors*sizeof(GAL_Color));  
  70.             if ( (format->palette)->colors == NULL ) {  
  71.                 GAL_FreeFormat(format);  
  72.                 GAL_OutOfMemory();  
  73.                 return(NULL);  
  74.             }  
  75.             /* Punt for now, will this ever be used? */  
  76.             memset((format->palette)->colors, 0,  
  77.                 (format->palette)->ncolors*sizeof(GAL_Color));  
  78.   
  79.             /* Palettized formats have no mask info */  
  80.             format->Rloss = 8;  
  81.             format->Gloss = 8;  
  82.             format->Bloss = 8;  
  83.             format->Aloss = 8;  
  84.             format->Rshift = 0;  
  85.             format->Gshift = 0;  
  86.             format->Bshift = 0;  
  87.             format->Ashift = 0;  
  88.             format->Rmask = 0;  
  89.             format->Gmask = 0;  
  90.             format->Bmask = 0;  
  91.             format->Amask = 0;  
  92.             break;  
  93.   
  94.         case 8:  
  95.             /* Create an empty 256 color palette */  
  96.             format->palette = (GAL_Palette *)malloc(  
  97.                             sizeof(GAL_Palette));  
  98.             if ( format->palette == NULL ) {  
  99.                 GAL_FreeFormat(format);  
  100.                 GAL_OutOfMemory();  
  101.                 return(NULL);  
  102.             }  
  103.             (format->palette)->ncolors = 256;  
  104.             (format->palette)->colors = (GAL_Color *)malloc(  
  105.                 (format->palette)->ncolors*sizeof(GAL_Color));  
  106.             if ( (format->palette)->colors == NULL ) {  
  107.                 GAL_FreeFormat(format);  
  108.                 GAL_OutOfMemory();  
  109.                 return(NULL);  
  110.             }  
  111.             memset((format->palette)->colors, 0,  
  112.                 (format->palette)->ncolors*sizeof(GAL_Color));  
  113.   
  114.             /* Palettized formats have no mask info */  
  115.             format->Rloss = 8;  
  116.             format->Gloss = 8;  
  117.             format->Bloss = 8;  
  118.             format->Aloss = 8;  
  119.             format->Rshift = 0;  
  120.             format->Gshift = 0;  
  121.             format->Bshift = 0;  
  122.             format->Ashift = 0;  
  123.             format->Rmask = 0;  
  124.             format->Gmask = 0;  
  125.             format->Bmask = 0;  
  126.             format->Amask = 0;  
  127.             break;  
  128.   
  129.         default:  
  130.             /* No palette, just packed pixel info */  
  131.             format->palette = NULL;  
  132.             format->Rshift = 0;  
  133.             format->Rloss = 8;  
  134.             if ( Rmask ) {  
  135.                 for ( mask = Rmask; !(mask&0x01); mask >>= 1 )  
  136.                     ++format->Rshift;  
  137.                 for ( ; (mask&0x01); mask >>= 1 )  
  138.                     --format->Rloss;  
  139.             }  
  140.             format->Gshift = 0;  
  141.             format->Gloss = 8;  
  142.             if ( Gmask ) {  
  143.                 for ( mask = Gmask; !(mask&0x01); mask >>= 1 )  
  144.                     ++format->Gshift;  
  145.                 for ( ; (mask&0x01); mask >>= 1 )  
  146.                     --format->Gloss;  
  147.             }  
  148.             format->Bshift = 0;  
  149.             format->Bloss = 8;  
  150.             if ( Bmask ) {  
  151.                 for ( mask = Bmask; !(mask&0x01); mask >>= 1 )  
  152.                     ++format->Bshift;  
  153.                 for ( ; (mask&0x01); mask >>= 1 )  
  154.                     --format->Bloss;  
  155.             }  
  156.             format->Ashift = 0;  
  157.             format->Aloss = 8;  
  158.             if ( Amask ) {  
  159.                 for ( mask = Amask; !(mask&0x01); mask >>= 1 )  
  160.                     ++format->Ashift;  
  161.                 for ( ; (mask&0x01); mask >>= 1 )  
  162.                     --format->Aloss;  
  163.             }  
  164.             format->Rmask = Rmask;  
  165.             format->Gmask = Gmask;  
  166.             format->Bmask = Bmask;  
  167.             format->Amask = Amask;  
  168.             break;  
  169.     }  
  170.     /* Calculate some standard bitmasks, if necessary  
  171.      * Note:  This could conflict with an alpha mask, if given. 
  172.      */  
  173.     if ( (bpp > 8) && !format->Rmask && !format->Gmask && !format->Bmask ) {  
  174.         /* R-G-B */  
  175.         if ( bpp > 24 )  
  176.             bpp = 24;  
  177.         format->Rloss = 8-(bpp/3);  
  178.         format->Gloss = 8-(bpp/3)-(bpp%3);  
  179.         format->Bloss = 8-(bpp/3);  
  180.         format->Rshift = ((bpp/3)+(bpp%3))+(bpp/3);  
  181.         format->Gshift = (bpp/3);  
  182.         format->Bshift = 0;  
  183.         format->Rmask = ((0xFF>>format->Rloss)<Rshift);  
  184.         format->Gmask = ((0xFF>>format->Gloss)<Gshift);  
  185.         format->Bmask = ((0xFF>>format->Bloss)<Bshift);  
  186.     }  
  187.     return(format);  
  188. }  
代码很长,但是并不复杂。switch部分重点看default分支的代码。其余部分的代码,是当像素占用的字节数在一个字节以内的情况。这种情况下注意是通过调色板实现的,现在不常用了,不重点考虑。


default分支的代码,注意通过Rmask、Gmask、Bmask和Amask的值,计算得到loss和shift的,算法很简单。不再赘述。


另外一部分重要的代码是map成员变量的初始化。因为它关系到两个surface的混合。首先看下GAL_BitMap结构的定义

[cpp]
  1. /* Blit mapping definition */  
  2. typedef struct GAL_BlitMap {  
  3.     GAL_Surface *dst;  
  4.     int identity;  
  5.     Uint8 *table;  
  6.     GAL_blit hw_blit;  
  7.     GAL_blit sw_blit;  
  8.     struct private_hwaccel *hw_data;  
  9.     struct private_swaccel *sw_data;  
  10.   
  11.     /* the version count matches the destination; mismatch indicates 
  12.        an invalid mapping */  
  13.         unsigned int format_version;  
  14. } GAL_BlitMap;  

这里需要关注的重点是hw_blit和sw_blit变量,它们是主要指向blit的操作的回调。GAL_blit的定义是:


[cpp]
  1. typedef int (*GAL_blit)(struct GAL_Surface *src, GAL_Rect *srcrect,  
  2.                         struct GAL_Surface *dst, GAL_Rect *dstrect);  
关于它的用法,后面会详细介绍。下面看下GAL_AllocBlitMap的实现


[cpp]
  1. GAL_BlitMap *GAL_AllocBlitMap(void)  
  2. {  
  3.     GAL_BlitMap *map;  
  4.   
  5.     /* Allocate the empty map */  
  6.     map = (GAL_BlitMap *)malloc(sizeof(*map));  
  7.     if ( map == NULL ) {  
  8.         GAL_OutOfMemory();  
  9.         return(NULL);  
  10.     }  
  11.     memset(map, 0, sizeof(*map));  
  12.   
  13.     /* Allocate the software blit data */  
  14.     map->sw_data = (struct private_swaccel *)malloc(sizeof(*map->sw_data));  
  15.     if ( map->sw_data == NULL ) {  
  16.         GAL_FreeBlitMap(map);  
  17.         GAL_OutOfMemory();  
  18.         return(NULL);  
  19.     }  
  20.     memset(map->sw_data, 0, sizeof(*map->sw_data));  
  21.   
  22.     /* It's ready to go */  
  23.     return(map);  
  24. }  
该函数只是做了分配空间的操作。



Surface的另外一个重要操作,就是做层之间的混合。它是通过GAL_LowerBlit来实现的(lower表示更接近于设备底层的实现),其代码如下:

[cpp]
  1. int GAL_LowerBlit (GAL_Surface *src, GAL_Rect *srcrect,  
  2.                 GAL_Surface *dst, GAL_Rect *dstrect)  
  3. {  
  4.     GAL_blit do_blit;  
  5.   
  6.     /* Check to make sure the blit mapping is valid */  
  7.     if ( (src->map->dst != dst) ||  
  8.              (src->map->dst->format_version != src->map->format_version) ) {  
  9.         if ( GAL_MapSurface(src, dst) < 0 ) {  
  10.             return(-1);  
  11.         }  
  12.     }  
  13.   
  14.     /* Figure out which blitter to use */  
  15.     if ( (src->flags & GAL_HWACCEL) == GAL_HWACCEL ) {  
  16.         do_blit = src->map->hw_blit;  
  17.     } else {  
  18.         do_blit = src->map->sw_blit;  
  19.     }  
  20.     return(do_blit(src, srcrect, dst, dstrect));  
  21. }  



可以看到,它通过map的hw_blit或者sw_blit调用来实现的。

hw_blit是用硬件加速实现的函数,所以,它是由GAL层实现和设置的。每种不同的开发板有字节的实现方法,所以,这不是我们讨论的重点。

sw_blit只软件实现的混合函数,由MiniGUI自己提供,它的确定,是在GAL_MapSurface函数中确定。

当第一次调用GAL_LowerBlit的时候,src->map->dst必定为NULL所以,就会调用到该函数。

GAL_MapSurface会调用到GAL_CalculateBlit函数,还选择一个正确的sw_blit,该函数会计算并填充hw_blit和sw_blit函数。这是一个比较复杂的过程。不过最终,sw_blit大部分情况下,会得到GAL_SoftBlit函数的指针。


关于这部分的详细情况,可以查看相关代码。

阅读(3459) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~