Broadcom Nexus学习 (一) Graphics,Display

0. Broadcom Nexus介绍:

Nexus是Broadcom提供的一套开发中间件,以标准API形式为Digital TV 和Set-Top boxes上层程序提供标准接口,它将不同的底层与上层开发隔绝开来,以达到上层开发与底层无关的目的。所有Interface的用法和思路基本上是一致的。Sam最先接触到的Nexus模块就是 Graphics.

 

1. Nexus Platform 接口和初始化:

Nexus有个API初始化各个模块以及硬件(NEXUS_Platform_Init())。应用程序也可以利用其参数定制初始化哪些模块以及动作。通常使用NEXUS_Platform_GetDefaultSettings()得到缺省的setting.修改想要修改的内容,之后再调用NEXUS_Platform_Init()初始化Platform.

 

 

NEXUS_PlatformSettings platformSettings;
NEXUS_Platform_GetDefaultSettings(&platformSettings);

//.... 修改必要的设置
NEXUS_Platform_Init(&platformSettings);

 

NEXUS_PlatformSettings结构体中可选择的选项通常有:I2C channel是否打开,是否FPGA channel打开,是否打开output等。

 

NEXUS_Platform_Init()会自动地打开和配置Interface.(如各种output等)。应用程序不应该再次去打开它,而是使用NEXUS_Platform_GetConfiguration()重新得到Handle.

 

NEXUS_PlatformConfiguration platformConfiguration;
NEXUS_Platform_GetConfiguration(&platformConfiguration);

 

NEXUS_PlatformConfiguration结构体包含如下内容:

NEXUS_I2cHandle i2c[NEXUS_NUM_I2C_CHANNELS];  //I2C channel.

我们通常最关心的是output Handle,

 struct {
        NEXUS_ComponentOutputHandle component[NEXUS_NUM_COMPONENT_OUTPUTS];
        NEXUS_CompositeOutputHandle composite[NEXUS_NUM_COMPOSITE_OUTPUTS];
        NEXUS_RfmHandle rfm[NEXUS_NUM_RFM_OUTPUTS];
        NEXUS_SvideoOutputHandle svideo[NEXUS_NUM_SVIDEO_OUTPUTS];
        NEXUS_AudioDacHandle audioDacs[NEXUS_NUM_AUDIO_DACS];
        NEXUS_SpdifOutputHandle spdif[NEXUS_NUM_SPDIF_OUTPUTS];
        NEXUS_I2sOutputHandle i2s[NEXUS_NUM_I2S_OUTPUTS];
        NEXUS_HdmiOutputHandle hdmi[NEXUS_NUM_HDMI_OUTPUTS];
        NEXUS_Ccir656OutputHandle ccir656[NEXUS_NUM_656_OUTPUTS];
    } outputs;

分量,混合和Svideo output handle就在其中。

 

 

2. Graphics 具体讲解:

Nexus graphics 包含几个Interface. 各个Interface各自提供一些能力,应用程序可以将它们组合起来使用。

Interface包含如下:

Display: 是Graphics模块的核心,它指定哪个surface为framebuffer(当前显示的)。指定哪几个output会输出(composite,svideo等),以及如何将framebuffer合成到video上。

 

Surface: 其实就是一块内存。创建Surface时用参数指定:width, height, pitch, pixel format。长度x宽度x每个象素的长度就决定了Surface大小。可创建surface的个数限制与分配给Nexus的堆大小。

 

Graphics2D: 提供从一块surface blit(整块copy)到另一块surface的能力。提供填充一块surface 使用某种颜色和Alpha的能力。

 

Graphics3D: 提供适配一个3D graphics到Surface的能力。

VideoImageInput:Route graphics through the video feeder hardware (MFD)

 

2.1. Surface的创建(NEXUS_Surface_Create):

Surface创建使用NEXUS_Surface_Create创建。Surface的长度,宽度,深度,pixel format则可以由参数决定。

具体过程如下:

NEXUS_SurfaceHandle surface;
NEXUS_SurfaceCreateSettings createSettings;

 

NEXUS_Surface_GetDefaultCreateSettings(&createSettings);
createSettings.pixelFormat = NEXUS_PixelFormat_eA8_R8_G8_B8;
createSettings.width = 720;
createSettings.height = 480;
surface = NEXUS_Surface_Create(&createSettings);

 

NEXUS_SurfaceCreateSettings:结构体中包含了Surface的一些关键点:象素格式,调色板格式,surface长度,宽度。倾斜度(缺省为:象素长度x宽度,也就是每行的字节数)

 

2.2:Display的建立和配置:

 

2.2.1: Display的创建:

与Surface创建相同,Display创建时,也需要参数来指定Display的创建模式。

 

NEXUS_DisplaySettings displaySettings;

NEXUS_DisplayHandle display;

 

NEXUS_Display_GetDefaultSettings(&displaySettings);
displaySettings.format = NEXUS_VideoFormat_eNtsc;
display = NEXUS_Display_Open(0, &displaySettings);

 

NEXUS_DisplaySettings 结构体中包含Display的一些选项。其中format表明此Display将要输出的制式。它决定了TV中显示的宽,高。

 

2.2.2:Display显示输出channel的配置:

如前所述,在Platform初始化时,Output Interface已经被打开。此时需要得到它们的Handle. 给Display添加Output .

 

NEXUS_PlatformConfiguration platformConfig;

 

NEXUS_Platform_GetConfiguration(&platformConfig);

 

NEXUS_Display_AddOutput(display, NEXUS_ComponentOutput_GetConnector(platformConfig.outputs.component[0]));

NEXUS_Display_AddOutput(display, NEXUS_CompositeOutput_GetConnector(platformConfig.outputs.composite[0]));

此处Display添加了分量和混合2种输出。

 

2.2.3:Display Frame buffer的指定:

只有将某个Surface指定为Frame buffer, Surface中的内容才会按格式和设置显示到TV上。所以应用程序可以创建2-3个surface,轮流指定为Frame Buffer来加快速度。

 

NEXUS_Display_SetGraphicsFramebuffer(display, surface);

 

3. Graphics2D的建立和使用:

3.1:Graphics2D的建立:

Graphics2D的建立与其它Interface相同,需要参数指定Graphics2D的特征。

NEXUS_Graphics2DHandle gfx;

NEXUS_Graphics2DOpenSettings openSettings;

 

openSettings.preAllocPacketMemory = true; //if maxOperations is non-zero, this must be true.
openSettings.maxOperations = 100;  //同步,异步blit的最大次数。如果是异步blit,则需要在blit次数超此次数之前使用NEXUS_Graphics2D_Checkpoint()。

 

gfx = NEXUS_Graphics2D_Open(0, &openSettings);

 

3.3: Graphics2D Setting:

NEXUS_Graphics2DSettings gfxSettings;

 

NEXUS_Graphics2D_GetSettings(gfx, &gfxSettings);
gfxSettings.checkpointCallback.callback = complete;
gfxSettings.checkpointCallback.context = event;
NEXUS_Graphics2D_SetSettings(gfx, &gfxSettings);

 

NEXUS_Graphics2DSettings比较重要的参数有:

bool blockedSync; //如果为true,则所有fill,blit会阻塞直到动作完成。(只有简单的程序会这么用)

此时,不需要NEXUS_Graphics2D_Checkpoint。

如果为false,则fill,blit不会被阻塞。所以需要NEXUS_Graphics2D_Checkpoint()来检测fill或blit动作是否已经完成。

 

NEXUS_CallbackDesc checkpointCallback;  在异步时使用,NEXUS_Graphics2D_Checkpoint()会调用它的callback。第一个参数为context.

 

callback function通常的处理是:BKNI_SetEvent(),发送一个event.

 

 

3.4:Graphics2D Fill:

在使用Fill功能时,需要先指定Surface. fill的颜色,Fill Surface的区域,color和alpha方式等。

NEXUS_Graphics2D_GetDefaultFillSettings(&fillSettings);
fillSettings.surface = framebuffer; //指定surface.
fillSettings.rect.width = createSettings.width;   //如果要fill整个surface. x,y=0. width,height与surface宽高相同。
fillSettings.rect.height = createSettings.height;
fillSettings.color = 0; //色彩方式
NEXUS_Graphics2D_Fill(gfx, &fillSettings);

 

如果为异步方式(3.3中讲过),Fill后,必须加上NEXUS_Graphics2D_Checkpoint(gfx, NULL); 以确认Fill动作已真的完成。

注意:此处NEXUS_Graphics2D_Checkpoint(gfx, NULL); 只是察看Graphics Hardware是否正在Blit或Fill. 如果返回值为Success.表明当前硬件没有Blit或Fill. 如果返NEXUS_GRAPHICS2D_QUEUED,泽表明此时有Fill或Blit在排队。此时,则当Blit或Fill完成时NEXUS_Graphics2DSettings::checkpointCallback 会被调用。

 

如3.3所讲,NEXUS_Graphics2D_Checkpoint()如果返回Success,则表明Fill完成,如果返回NEXUS_GRAPHICS2D_QUEUED,则在Fill动作完成后,自动调用callback function. Callback function又发送了一个event. 所以可以在NEXUS_Graphics2D_Checkpoint(gfx, NULL); 后添加:

BKNI_WaitForEvent();来确认Fill动作的完成。

 

3.5: Graphics2D Blit:

与其它动作类似,Blit也需要得到setting. 并设置想要blit的源sruface和目标surface. 以及各自的区域。

NEXUS_Graphics2DBlitSettings blitSettings;

 

NEXUS_Graphics2D_GetDefaultBlitSettings(&blitSettings);

blitSettings.source.surface = surface;
blitSettings.source.rect.x = 0;
blitSettings.source.rect.y = 0;
blitSettings.source.rect.width = 100;
blitSettings.source.rect.height = 140;

blitSettings.output.surface = surface;
blitSettings.output.rect.x = (rand() % (createSettings.width-120)) + 100;
blitSettings.output.rect.y = (rand() % (createSettings.height-20));
blitSettings.output.rect.width = 20;
blitSettings.output.rect.height = 20;

blitSettings.colorOp = NEXUS_BlitColorOp_eCopySource;
blitSettings.alphaOp = NEXUS_BlitAlphaOp_eCopySource;

rc = NEXUS_Graphics2D_Blit(gfx, &blitSettings);

 

 

4. Surface的长度,宽度的决定:

看到这个条目,可能会觉得有些奇怪,Surface的长宽,不是由自己指定的吗。呵呵,其实Sam的意思是决定Surface长宽的因素总结。

 

Surface如果想全屏显示于Display当前的video format下。则需要与video format长宽相同。

NEXUS_VideoFormat_GetInfo(displaySettings.format, &videoFormatInfo); //从display video 取出信息

createSettings.pixelFormat = NEXUS_PixelFormat_eA8_R8_G8_B8;
createSettings.width = videoFormatInfo.width;  //讲长度宽度设置为与video format相同
createSettings.height = videoFormatInfo.height;
surface = NEXUS_Surface_Create(&createSettings);

 

还有一种情况比较特殊,下一节统一讲。

 

 

5.Display 如何放置Graphics Frame buffer于Video Window相关知识:

Display可以指定某个Surface为Graphics Frame buffer.但是Surface是否要全部显示,以及显示在TV屏幕的哪个位置,这是可设定的。下面就详细分析这个议题。

首先,有4个宽高值需要注意:

1. VideoWindow的宽高。

2. GraphicsFramebuffer的宽高。

3. Surface的宽高。

4. Display video format的宽高。

 

Display的video format决定了TV屏幕的大小,也就是VideoWindow的大小。所以Sam认为Dispaly Video format的宽高等同于VideoWindow的宽高。

GraphicsFramebuffer的大小应该是个虚值,可能与它指定的Surface相同。

Surface的大小可以自己定义,但哪一部份显示则由Display指定。

 

 

结构体NEXUS_GraphicsSettings中的值决定了Display如何将Graphics Frame buffer匹配于VideoWindow.也就是说将Graphics Frame Buffer如何放置于TV 屏幕。放置在什么位置,显示哪一部份Frame buffer内容等等。(所以前面说surface指定为framebuffer并不意味着它能全部显示)

 

NEXUS_Rect position;

NEXUS_Rect clip;

 

NEXUS_Rect结构体是个矩形,x,y表示左上角位置:

typedef struct NEXUS_Rect
{
    int16_t x;
    int16_t y;
    uint16_t width;
    uint16_t height;
} NEXUS_Rect;

position: 顾名思义,是说Display中Surface显示的部分。换句话说,Video Window(TV屏幕)的这一部分用来显示Framebuffer(Surface).

clip: Surface 中想要显示的部分。

 

当Display想要将surface显示于一个Video Window时,其实是将Surface中clip部分显示于Video window的Position部分。

 

我们会很快想到,如果position与clip大小不同怎么办?

当clip的宽度小于position的宽度时(高度相同),会将其水平拉伸。

当clip的高度小于position时(宽度相同),则无法显示。

 

当clip的宽度大于position的宽度时,则只显示一部分。

当clip的高度大于position的高度时,则只显示position部分。

你可能感兴趣的:(display,video,nexus,Broadcom)