07.显示系统:第003课_最简单的Surface测试程序:第01节_最简单的Surface测试程序

在前面的章节中,简单的分析了android显示系统的框架,我们知道一个应用程序之中,存在一个或者多个buffer用来存放界面的数据,单应用程序构造好这些buffer之后,他会把这些buffer发送给surfaceFlinger,由surfaceFlinger决定在合适的时候把buffer中的数据拷贝到framebuffer,这样才能在屏幕上显示界面。应用程序的buffer需要向surfaceFlinger进行申请。

surfaceFlinger管理着两个驱动程序,一个为ashmem(匿名共享内存),其中应用程序的buffer来自ashmem(匿名共享内存)。同时还管理者多个应用程序发送过来的buffer,由他决定如何把这多个应用程序的数据叠加起来,最终发送给framebuffer。下面我们编写一个Surface测试程序。

Surface测试程序流程

编写改程序,最核心的东西就是如何得到buffer,写buffer,最后再提交buffer。
在这里插入图片描述
上图的APP是我们的引用程序,存在一个或者多个buf(用来存放界面数据),多个buf合成一个surface(APP的界面)。这些buf是想surfaceFlinger申请的。

编写Surface测试程序流程如下:
1.获得surfacelinger服务
2.创建surface。
3.得到buffer
4.写buffer
5.提交buffer
其中3,4,5是一个循环的过程,如上图中的3个buffer,提交完第一个buf的时候,APP可以构建第二个buf,当第二个构建成功然后提交,紧接着构造第三个buffer,这样进行循环。

Surface测试程序编写

从头到尾写一个测试程序是十分困难的,在安卓5.0的源码中android-5.0.2\frameworks\native\services\surfaceflinger\tests\resize目录下存在文件Android.mk,与resize.cpp。我们把其拷贝到RK3399安卓源码7.1,frameworks\native\services\surfaceflinger\tests\APP_0010_Surfacetest(自己创建),并且修改resize.cpp为SurfaceTest.cpp。可惜的是,该测试程序并不能直接使用 mmm命令编译通过。还要做一些修改,修改之后代码如下:
SurfaceTest.cpp:

#include <cutils/memory.h>

#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <android/native_window.h>

#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>

using namespace android;


int main()
{
    // set up the thread-pool
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);

    sp<Surface> surface = surfaceControl->getSurface();

    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();

    ANativeWindow_Buffer outBuffer;
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
    surface->unlockAndPost();

    surface->lock(&outBuffer,NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
    surface->unlockAndPost();

    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setSize(320, 240);
    SurfaceComposerClient::closeGlobalTransaction();

    
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	SurfaceTest.cpp

LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libutils \
    libui \
    libgui \
	libbinder

LOCAL_MODULE:= SurfaceTest

LOCAL_MODULE_TAGS := tests

include $(BUILD_EXECUTABLE)

编写完成上面两个文件之后,使用mmm命令编译,然后重新生生system.img烧写到开发板。

启动开发板之后,执行命令SurfaceTest,可以看到屏幕的做上角出现一块绿色的区域。我们把这个版本的代码保存下来为APP_0010_Surfacetest-v1,

下面是我们APP_0010_Surfacetest-v2版本

#include <cutils/memory.h>

#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <android/native_window.h>

#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>

using namespace android;


int main()
{
    // set up the thread-pool
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger
	/*获得SurfaceComposerClient服务*/
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
	/*创建Surface*/
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);

    sp<Surface> surface = surfaceControl->getSurface();

    SurfaceComposerClient::openGlobalTransaction();
	/*设置Z轴高度*/
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();


    ANativeWindow_Buffer outBuffer;
	/*获得这个surface的一个buf*/
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
	/*填充buf*/
    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
	/*提交buf给surfaceflinger,让其显示*/
    surface->unlockAndPost();
	/*增加一个休眠时间*/
	sleep(3);
	
    surface->lock(&outBuffer,NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
    surface->unlockAndPost();
	sleep(3);

    surface->lock(&outBuffer,NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
    surface->unlockAndPost();
	sleep(3);

    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setSize(320, 240);
    SurfaceComposerClient::closeGlobalTransaction();

    
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}

编译之后可以看三种颜色以一定时间间隔不停的交换。

最后是编写我们的APP_0010_Surfacetest-v3版本:

#include <cutils/memory.h>

#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <android/native_window.h>

#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>

using namespace android;


int main()
{
    // set up the thread-pool
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger
	/*获得SurfaceComposerClient服务*/
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
	/*创建Surface*/
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);

    sp<Surface> surface = surfaceControl->getSurface();

    SurfaceComposerClient::openGlobalTransaction();
	/*设置Z轴高度*/
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();


    ANativeWindow_Buffer outBuffer;
	/*获得这个surface的一个buf*/
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
	/*填充buf*/
    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
	/*提交buf给surfaceflinger,让其显示*/
    surface->unlockAndPost();
	/*增加一个休眠时间*/
	sleep(3);
	
    surface->lock(&outBuffer,NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
    surface->unlockAndPost();
	sleep(3);

    surface->lock(&outBuffer,NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
    surface->unlockAndPost();
	sleep(3);

	for(int i = 0; i <100; i++){
		surface->lock(&outBuffer,NULL);
		printf("%03d buff addr = 0x%x\n",i,(unsigned long)outBuffer.bits);
		surface->unlockAndPost();
	}

    
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}

在这个版本中,我们打印了outBuffer.bits的地址,在开发板运行之后,打印信息如下:

000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000

000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000

000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000

000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000
......
......

我们可以发现,其使用了四个buf,后面都是重复使用。这样我们知道对于同一个应用程序。他分配了3个buf。

如果我们在上面的程序添加代码 surfaceControl->setLayer(100000),改变其z轴高度,我们可以实现对显示的隐藏或者遮挡。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以帮你设计一款基于Pygame的射击游戏。 首先,你需要安装Pygame库,可以使用以下命令在终端中安装: ```python pip install pygame ``` 接下来,我们需要创建一个Pygame窗口,在窗口中绘制一些图形。我们可以使用Pygame中的Surface类来创建一个窗口,并使用draw模块中的函数来绘制图形。 ```python import pygame # 初始化Pygame pygame.init() # 创建窗口 WINDOW_WIDTH = 640 WINDOW_HEIGHT = 480 window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) # 设置窗口标题 pygame.display.set_caption('射击游戏') # 绘制背景 background_color = (0, 0, 0) window.fill(background_color) # 绘制一个圆 circle_color = (255, 255, 255) circle_radius = 20 circle_position = (WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2) pygame.draw.circle(window, circle_color, circle_position, circle_radius) # 更新窗口 pygame.display.update() # 游戏循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() ``` 上面的代码创建了一个窗口,并在窗口中绘制了一个白色圆形。我们还添加了一个游戏循环,以便可以处理事件并在窗口中更新图形。 接下来,我们需要添加一些游戏元素,如玩家、敌人和子弹。我们可以使用Pygame中的Sprite类来创建这些游戏元素,并使用Group类来管理它们。 ```python import pygame # 初始化Pygame pygame.init() # 创建窗口 WINDOW_WIDTH = 640 WINDOW_HEIGHT = 480 window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) # 设置窗口标题 pygame.display.set_caption('射击游戏') # 绘制背景 background_color = (0, 0, 0) window.fill(background_color) # 创建玩家 class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.Surface((50, 50)) self.image.fill((255, 0, 0)) self.rect = self.image.get_rect() self.rect.center = (WINDOW_WIDTH // 2, WINDOW_HEIGHT - 50) # 创建敌人 class Enemy(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.Surface((50, 50)) self.image.fill((0, 255, 0)) self.rect = self.image.get_rect() self.rect.center = (WINDOW_WIDTH // 2, 50) # 创建子弹 class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.Surface((10, 20)) self.image.fill((0, 0, 255)) self.rect = self.image.get_rect() self.rect.center = (x, y) # 创建游戏元素组 all_sprites = pygame.sprite.Group() enemies = pygame.sprite.Group() bullets = pygame.sprite.Group() # 添加游戏元素到组中 player = Player() all_sprites.add(player) enemy = Enemy() all_sprites.add(enemy) enemies.add(enemy) # 更新窗口 all_sprites.draw(window) pygame.display.update() # 游戏循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: # 创建子弹 bullet = Bullet(player.rect.centerx, player.rect.top) all_sprites.add(bullet) bullets.add(bullet) # 移动子弹 for bullet in bullets: bullet.rect.y -= 5 if bullet.rect.bottom < 0: bullets.remove(bullet) all_sprites.remove(bullet) # 更新窗口 all_sprites.update() window.fill(background_color) all_sprites.draw(window) pygame.display.update() ``` 上面的代码添加了玩家、敌人和子弹,以及将它们添加到了游戏元素组中。我们还添加了一些游戏逻辑,例如让子弹向上移动,并在子弹超出窗口范围时将其从组中删除。 最后,我们可以添加更多游戏逻辑,例如让敌人向下移动、玩家与敌人碰撞时游戏结束等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南才尽,年少无知!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值