使用帧缓冲区时出现闪烁区域

问题描述

大家好!最近在研究一些PSP编程,尝试用pspdisplay.h库做一个小游戏。游戏非常基础,目前只有一个红色方块四处移动,屏幕上会出现一些十字形的东西。一切都很顺利,直到我注意到根据我更新和交换帧缓冲区的频率,屏幕上的某个地方会出现一个区域?其中所有输出的对象都倾向于闪烁。该区域的宽度均为 480 像素,高度为 10-20 像素。该区域在 Y 轴上的位置取决于帧缓冲区更新的频率。如何解决?是什么原因造成的?为什么区域位置取决于帧缓冲区的更新频率? P.S 如果你想看它的视频,这里是我的 reddit 问题的链接,关于固定到它的视频的相同问题:https://www.reddit.com/r/PSP/comments/mccjp4/been_studying_some_psp_programming_recently_and/?utm_source=share&utm_medium=web2x&context=3

要重现此问题,您需要 PSP 3000、psptoolchain 和 pspsdk。

我有一个小的 Cell 结构,它保存了 8x8 正方形左上角的坐标、颜色和方向,即上、下、左、右或无:

struct Cell{

    uint32_t color;

    int x;
    int y;

    directions direction;

    bool occupied;

    inline Cell();

    inline Cell(uint32_t,int,bool,directions);

    ~Cell();
}; 

之后我初始化 PSP 屏幕并控制并启动一个循环,该循环一直运行直到用户按下 START 按钮。在控制检查之后是时间检查,如果所需的毫秒数已经过去,则将正方形沿其方向移动一个像素。

while(running){

        running = is_running();

        sceCtrlPeekBufferPositive(&button_input,1);
        if(button_input.Buttons != 0){
            if(button_input.Buttons & PSP_CTRL_UP){
                cl.direction = directions::up;
            }
            if(button_input.Buttons & PSP_CTRL_DOWN){
                cl.direction = directions::down;
            }
            if(button_input.Buttons & PSP_CTRL_LEFT){
                cl.direction = directions::left;
            }
            if(button_input.Buttons & PSP_CTRL_RIGHT){
                cl.direction = directions::right;
            }
            if(button_input.Buttons & PSP_CTRL_START){
                running = 0;

            }
        }

        if(current_timestamp() - lmt >= 40){
              clear(0xff000);
              switch(cl.direction){
                  case directions::up: 
                      cl.y--;
                      break;
                  case directions::down:
                      cl.y++;
                      break;
                  case directions::left:
                      cl.x--;
                      break;
                  case directions::none:
                      break;
                  case directions::right:
                      cl.x++;
               }

        }
        draw_cell(cl);
        swap_buffers();
        scedisplayWaitVblank();
        lmt = current_timestamp();
}       

draw_cell(Cell cl) 函数只是将一个单元格写入绘制缓冲区。 swap_buffers() 函数通过将我的方块输出到屏幕来交换绘制缓冲区和显示缓冲区。 clear 函数只是用一种颜色填充绘制缓冲区,作为它的参数。

void draw_cell(Cell cl){
    for(int y = cl.y; y < cl.y+8; y++){
        for(int x = cl.x; x < cl.x+8; x++){
            draw_buffer[x + y * 512] = cl.color;
        }
    }

}

void clear(uint32_t color){
    for(int i = 0; i < 512 * 272; i++){
        draw_buffer[i] = color;
    }   
}

void swap_buffers(){
        uint32_t* temp = disp_buffer;
        disp_buffer = draw_buffer;
        draw_buffer = temp;

        sceKernelDcacheWritebackInvalidateall();
        scedisplaySetFrameBuf(disp_buffer,512,PSP_disPLAY_PIXEL_FORMAT_8888,PSP_disPLAY_SETBUF_IMMEDIATE);
    }

使用此代码,您将能够重现我的问题(您还需要初始化显示和控件,并设置退出回调以使程序工作,当然,还需要创建一个 Cell 类型的对象,称为 cl)。要在程序运行时注意问题,请在屏幕上移动方块并观察它。最终你会在屏幕上偶然发现一个区域,你的方块会在那里闪烁。离开该区域将停止闪烁,再次进入将再次开始闪烁。如果您使用时间检查调整 if() 并更改屏幕更新之间的时间,您会注意到闪烁区域将更改其在 Y 轴上的位置。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)