The problem is that I get BAD flicker, but only sometimes. In fact, I can get to a situation where I'll link, get no flicker, then I'll add a couple of C++ instructions, compile, link, and get flicker.
Here's the relevant code. I'm posting everything related to graphics since I'm really getting desperate with this bug.
Code: Select all
#define PIXEL_SIZE (4)
#define BUF_WIDTH (512)
#define PSP_SCREEN_WIDTH 480
#define PSP_SCREEN_HEIGHT 272
#define PSP_FRAME_SIZE (BUF_WIDTH * PSP_SCREEN_HEIGHT * PIXEL_SIZE)
#define MOUSE_SIZE 128
#define KBD_DATA_SIZE 130560
#define MAX_FPS 30
unsigned int __attribute__((aligned(16))) displayList[2048];
unsigned short __attribute__((aligned(16))) clut256[256];
unsigned short __attribute__((aligned(16))) mouseClut[256];
unsigned short __attribute__((aligned(16))) cursorPalette[256];
unsigned int __attribute__((aligned(16))) mouseBuf256[MOUSE_SIZE*MOUSE_SIZE];
unsigned long RGBToColour(unsigned long r, unsigned long g, unsigned long b) {
return (((b >> 3) << 10) | ((g >> 3) << 5) | ((r >> 3) << 0)) | 0x8000;
}
const OSystem::GraphicsMode OSystem_PSP::s_supportedGraphicsModes[] = {
{ "320x200 (centered)", "320x200 16-bit centered", CENTERED_320X200 },
{ "435x272 (best-fit, centered)", "435x272 16-bit centered", CENTERED_435X272 },
{ "480x272 (full screen)", "480x272 16-bit stretched", STRETCHED_480X272 },
{ "362x272 (4:3, centered)", "362x272 16-bit centered", CENTERED_362X272 },
{0, 0, 0}
};
OSystem_PSP::OSystem_PSP() : _screenWidth(0), _screenHeight(0), _overlayWidth(0), _overlayHeight(0),
_offscreen(0), _overlayBuffer(0), _overlayVisible(false), _shakePos(0), _lastScreenUpdate(0),
_mouseBuf(0), _prevButtons(0), _lastPadCheck(0), _padAccel(0), _mixer(0) {
memset(_palette, 0, sizeof(_palette));
_cursorPaletteDisabled = true;
_samplesPerSec = 0;
//init SDL
uint32 sdlFlags = SDL_INIT_AUDIO | SDL_INIT_TIMER;
SDL_Init(sdlFlags);
_keyboardVisible = false;
_clut = clut256;
_mouseBuf = (byte *)mouseBuf256;
_graphicMode = STRETCHED_480X272;
_keySelected = 1;
_mouseX = PSP_SCREEN_WIDTH >> 1; // Mouse in the middle of the screen
_mouseY = PSP_SCREEN_HEIGHT >> 1;
// Init GU
sceGuInit();
sceGuStart(0, displayList);
sceGuDrawBuffer(GU_PSM_8888, (void *)0, BUF_WIDTH);
sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, (void*)PSP_FRAME_SIZE, BUF_WIDTH);
sceGuDepthBuffer((void*)(PSP_FRAME_SIZE * 2), BUF_WIDTH);
sceGuOffset(2048 - (PSP_SCREEN_WIDTH/2), 2048 - (PSP_SCREEN_HEIGHT/2));
sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
sceGuDepthRange(0xC350, 0x2710);
sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuFrontFace(GU_CW);
sceGuEnable(GU_TEXTURE_2D);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuDisplay(1);
}
OSystem_PSP::~OSystem_PSP() {
free(_offscreen);
free(_overlayBuffer);
free(_mouseBuf);
delete _keyboard;
_offscreen = 0;
_overlayBuffer = 0;
_mouseBuf = 0;
sceGuTerm();
}
void OSystem_PSP::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
PSPDebugTrace("initSize\n");
_screenWidth = width;
_screenHeight = height;
const int scrBufSize = _screenWidth * _screenHeight * (format ? format->bytesPerPixel : 4);
_overlayWidth = PSP_SCREEN_WIDTH; //width;
_overlayHeight = PSP_SCREEN_HEIGHT; //height;
free(_overlayBuffer);
_overlayBuffer = (OverlayColor *)memalign(64, _overlayWidth * _overlayHeight * sizeof(OverlayColor));
fprintf(stderr, "_overlaybuffer is from %p, size = %x\n", _overlayBuffer, _overlayWidth * _overlayHeight * sizeof(OverlayColor));
free(_offscreen);
_offscreen = (byte *)memalign(64, scrBufSize);
fprintf(stderr, "_offscreen is at %p, size = %x\n", _offscreen, scrBufSize);
bzero(_offscreen, scrBufSize);
clearOverlay();
memset(_palette, 0xFFFF, 256 * sizeof(unsigned short));
_mouseVisible = false;
sceKernelDcacheWritebackAll();
}
int16 OSystem_PSP::getWidth() {
return _screenWidth;
}
int16 OSystem_PSP::getHeight() {
return _screenHeight;
}
void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) {
const byte *b = colors;
for (uint i = 0; i < num; ++i) {
_palette[start + i] = RGBToColour(b[0], b[1], b[2]);
b += 4;
}
//copy to CLUT
memcpy(_clut, _palette, 256 * sizeof(unsigned short));
//force update of mouse CLUT as well, as it may have been set up before this palette was set
memcpy(mouseClut, _palette, 256 * sizeof(unsigned short));
mouseClut[_mouseKeyColour] = 0;
sceKernelDcacheWritebackAll();
}
void OSystem_PSP::setCursorPalette(const byte *colors, uint start, uint num) {
const byte *b = colors;
for (uint i = 0; i < num; ++i) {
cursorPalette[start + i] = RGBToColour(b[0], b[1], b[2]);
b += 4;
}
cursorPalette[0] = 0;
_cursorPaletteDisabled = false;
sceKernelDcacheWritebackAll();
}
void OSystem_PSP::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
//Clip the coordinates
if (x < 0) {
w += x;
buf -= x;
x = 0;
}
if (y < 0) {
h += y;
buf -= y * pitch;
y = 0;
}
if (w > _screenWidth - x) {
w = _screenWidth - x;
}
if (h > _screenHeight - y) {
h = _screenHeight - y;
}
if (w <= 0 || h <= 0)
return;
byte *dst = _offscreen + y * _screenWidth + x;
if (_screenWidth == pitch && pitch == w) {
memcpy(dst, buf, h * w);
} else {
do {
memcpy(dst, buf, w);
buf += pitch;
dst += _screenWidth;
} while (--h);
}
sceKernelDcacheWritebackAll();
}
Graphics::Surface *OSystem_PSP::lockScreen() {
_framebuffer.pixels = _offscreen;
_framebuffer.w = _screenWidth;
_framebuffer.h = _screenHeight;
_framebuffer.pitch = _screenWidth;
_framebuffer.bytesPerPixel = 1;
return &_framebuffer;
}
void OSystem_PSP::unlockScreen() {
// The screen is always completely update anyway, so we don't have to force a full update here.
sceKernelDcacheWritebackAll();
}
void OSystem_PSP::updateScreen() {
u32 now = getMillis();
if (now - _lastScreenUpdate < 1000 / MAX_FPS)
return;
_lastScreenUpdate = now;
sceGuStart(0, displayList);
sceGuClearColor(0xFF000000);
sceGuClear(GU_COLOR_BUFFER_BIT);
sceGuClutMode(GU_PSM_5551, 0, 0xFF, 0);
sceGuClutLoad(32, clut256); // upload 32*8 entries (256)
sceGuTexMode(GU_PSM_T8, 0, 0, 0); // 8-bit image
if (_screenWidth == 320)
sceGuTexImage(0, 512, 256, _screenWidth, _offscreen);
else
sceGuTexImage(0, 512, 512, _screenWidth, _offscreen);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
sceGuTexOffset(0,0);
sceGuAmbientColor(0xFFFFFFFF);
sceGuColor(0xFFFFFFFF);
Vertex *vertices = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
vertices[0].u = 0.5f;
vertices[0].v = 0.5f;
vertices[1].u = _screenWidth - 0.5f;
vertices[1].v = _screenHeight - 0.5f;
switch (_graphicMode) {
case CENTERED_320X200:
vertices[0].x = (PSP_SCREEN_WIDTH - 320) / 2;
vertices[0].y = (PSP_SCREEN_HEIGHT - 200) / 2;
vertices[0].z = 0;
vertices[1].x = PSP_SCREEN_WIDTH - (PSP_SCREEN_WIDTH - 320) / 2;
vertices[1].y = PSP_SCREEN_HEIGHT - (PSP_SCREEN_HEIGHT - 200) / 2;
vertices[1].z = 0;
break;
case CENTERED_435X272:
vertices[0].x = (PSP_SCREEN_WIDTH - 435) / 2;
vertices[0].y = 0; vertices[0].z = 0;
vertices[1].x = PSP_SCREEN_WIDTH - (PSP_SCREEN_WIDTH - 435) / 2;
vertices[1].y = PSP_SCREEN_HEIGHT;
vertices[1].z = 0;
break;
case STRETCHED_480X272:
vertices[0].x = 0;
vertices[0].y = 0;
vertices[0].z = 0;
vertices[1].x = PSP_SCREEN_WIDTH;
vertices[1].y = PSP_SCREEN_HEIGHT;
vertices[1].z = 0;
break;
case CENTERED_362X272:
vertices[0].x = (PSP_SCREEN_WIDTH - 362) / 2;
vertices[0].y = 0;
vertices[0].z = 0;
vertices[1].x = PSP_SCREEN_WIDTH - (PSP_SCREEN_WIDTH - 362) / 2;
vertices[1].y = PSP_SCREEN_HEIGHT;
vertices[1].z = 0;
break;
}
if (_shakePos) {
vertices[0].y += _shakePos;
vertices[1].y += _shakePos;
}
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
if (_screenWidth == 640) {
// 2nd draw
Vertex *vertices2 = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
sceGuTexImage(0, 512, 512, _screenWidth, _offscreen+512);
vertices2[0].u = 512 + 0.5f;
vertices2[0].v = vertices[0].v;
vertices2[1].u = vertices[1].u;
vertices2[1].v = _screenHeight - 0.5f;
vertices2[0].x = vertices[0].x + (vertices[1].x - vertices[0].x) * 511 / 640;
vertices2[0].y = 0;
vertices2[0].z = 0;
vertices2[1].x = vertices[1].x;
vertices2[1].y = vertices[1].y;
vertices2[1].z = 0;
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices2);
}
// draw overlay
if (_overlayVisible) {
Vertex *vertOverlay = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
vertOverlay[0].x = 0;
vertOverlay[0].y = 0;
vertOverlay[0].z = 0;
vertOverlay[1].x = PSP_SCREEN_WIDTH;
vertOverlay[1].y = PSP_SCREEN_HEIGHT;
vertOverlay[1].z = 0;
vertOverlay[0].u = 0.5f;
vertOverlay[0].v = 0.5f;
vertOverlay[1].u = _overlayWidth - 0.5f;
vertOverlay[1].v = _overlayHeight - 0.5f;
sceGuTexMode(GU_PSM_4444, 0, 0, 0); // 16-bit image
sceGuDisable(GU_ALPHA_TEST);
sceGuEnable(GU_BLEND);
//sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
sceGuBlendFunc(GU_ADD, GU_FIX, GU_ONE_MINUS_SRC_ALPHA, 0xFFFFFFFF, 0);
if (_overlayWidth > 320)
sceGuTexImage(0, 512, 512, _overlayWidth, _overlayBuffer);
else
sceGuTexImage(0, 512, 256, _overlayWidth, _overlayBuffer);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,vertOverlay);
// need to render twice for textures > 512
if ( _overlayWidth > 512) {
Vertex *vertOverlay2 = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
sceGuTexImage(0, 512, 512, _overlayWidth, _overlayBuffer + 512);
vertOverlay2[0].u = 512 + 0.5f;
vertOverlay2[0].v = vertOverlay[0].v;
vertOverlay2[1].u = vertOverlay[1].u;
vertOverlay2[1].v = _overlayHeight - 0.5f;
vertOverlay2[0].x = PSP_SCREEN_WIDTH * 512 / 640;
vertOverlay2[0].y = 0;
vertOverlay2[0].z = 0;
vertOverlay2[1].x = PSP_SCREEN_WIDTH;
vertOverlay2[1].y = PSP_SCREEN_HEIGHT;
vertOverlay2[1].z = 0;
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertOverlay2);
}
sceGuDisable(GU_BLEND);
}
// draw mouse
if (_mouseVisible) {
sceGuTexMode(GU_PSM_T8, 0, 0, 0); // 8-bit image
sceGuClutMode(GU_PSM_5551, 0, 0xFF, 0);
sceGuClutLoad(32, _cursorPaletteDisabled ? mouseClut : cursorPalette); // upload 32*8 entries (256)
sceGuAlphaFunc(GU_GREATER, 0, 0xFF);
sceGuEnable(GU_ALPHA_TEST);
sceGuTexImage(0, MOUSE_SIZE, MOUSE_SIZE, MOUSE_SIZE, _mouseBuf);
sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
Vertex *vertMouse = (Vertex *)sceGuGetMemory(2 * sizeof(Vertex));
vertMouse[0].u = 0.5f;
vertMouse[0].v = 0.5f;
vertMouse[1].u = _mouseWidth - 0.5f;
vertMouse[1].v = _mouseHeight - 0.5f;
//adjust cursor position
int mX = _mouseX - _mouseHotspotX;
int mY = _mouseY - _mouseHotspotY;
if (_overlayVisible) {
float scalex, scaley;
scalex = (float)PSP_SCREEN_WIDTH /_overlayWidth;
scaley = (float)PSP_SCREEN_HEIGHT /_overlayHeight;
vertMouse[0].x = mX * scalex;
vertMouse[0].y = mY * scaley;
vertMouse[0].z = 0;
vertMouse[1].x = vertMouse[0].x + _mouseWidth * scalex;
vertMouse[1].y = vertMouse[0].y + _mouseHeight * scaley;
vertMouse[1].z = 0;
} else
switch (_graphicMode) {
case CENTERED_320X200:
vertMouse[0].x = (PSP_SCREEN_WIDTH - 320) / 2 + mX;
vertMouse[0].y = (PSP_SCREEN_HEIGHT - 200) / 2 + mY;
vertMouse[0].z = 0;
vertMouse[1].x = vertMouse[0].x + _mouseWidth;
vertMouse[1].y = vertMouse[0].y + _mouseHeight;
vertMouse[1].z = 0;
break;
case CENTERED_435X272:
{
float scalex, scaley;
scalex = 435.0f / _screenWidth;
scaley = 272.0f / _screenHeight;
vertMouse[0].x = (PSP_SCREEN_WIDTH - 435) / 2 + mX * scalex;
vertMouse[0].y = mY * scaley;
vertMouse[0].z = 0;
vertMouse[1].x = vertMouse[0].x + _mouseWidth * scalex;
vertMouse[1].y = vertMouse[0].y + _mouseHeight * scaley;
vertMouse[1].z = 0;
}
break;
case CENTERED_362X272:
{
float scalex, scaley;
scalex = 362.0f / _screenWidth;
scaley = 272.0f / _screenHeight;
vertMouse[0].x = (PSP_SCREEN_WIDTH - 362) / 2 + mX * scalex;
vertMouse[0].y = mY * scaley;
vertMouse[0].z = 0;
vertMouse[1].x = vertMouse[0].x + _mouseWidth * scalex;
vertMouse[1].y = vertMouse[0].y + _mouseHeight * scaley;
vertMouse[1].z = 0;
}
break;
case STRETCHED_480X272:
{
float scalex, scaley;
scalex = (float)PSP_SCREEN_WIDTH / _screenWidth;
scaley = (float)PSP_SCREEN_HEIGHT / _screenHeight;
vertMouse[0].x = mX * scalex;
vertMouse[0].y = mY * scaley;
vertMouse[0].z = 0;
vertMouse[1].x = vertMouse[0].x + _mouseWidth * scalex;
vertMouse[1].y = vertMouse[0].y + _mouseHeight * scaley;
vertMouse[1].z = 0;
}
break;
}
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertMouse);
}
if (_keyboardVisible) {
_keyboard->render();
}
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuSwapBuffers();
}
void OSystem_PSP::clearOverlay() {
PSPDebugTrace("clearOverlay\n");
bzero(_overlayBuffer, _overlayWidth * _overlayHeight * sizeof(OverlayColor));
sceKernelDcacheWritebackAll();
}
void OSystem_PSP::grabOverlay(OverlayColor *buf, int pitch) {
int h = _overlayHeight;
OverlayColor *src = _overlayBuffer;
do {
memcpy(buf, src, _overlayWidth * sizeof(OverlayColor));
src += _overlayWidth;
buf += pitch;
} while (--h);
}
void OSystem_PSP::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
PSPDebugTrace("copyRectToOverlay\n");
//Clip the coordinates
if (x < 0) {
w += x;
buf -= x;
x = 0;
}
if (y < 0) {
h += y;
buf -= y * pitch;
y = 0;
}
if (w > _overlayWidth - x) {
w = _overlayWidth - x;
}
if (h > _overlayHeight - y) {
h = _overlayHeight - y;
}
if (w <= 0 || h <= 0)
return;
OverlayColor *dst = _overlayBuffer + (y * _overlayWidth + x);
if (_overlayWidth == pitch && pitch == w) {
memcpy(dst, buf, h * w * sizeof(OverlayColor));
} else {
do {
memcpy(dst, buf, w * sizeof(OverlayColor));
buf += pitch;
dst += _overlayWidth;
} while (--h);
}
sceKernelDcacheWritebackAll();
}
int16 OSystem_PSP::getOverlayWidth() {
return _overlayWidth;
}
int16 OSystem_PSP::getOverlayHeight() {
return _overlayHeight;
}
void OSystem_PSP::grabPalette(byte *colors, uint start, uint num) {
uint i;
uint16 color;
for (i = start; i < start + num; i++) {
color = _palette;
*colors++ = ((color & 0x1F) << 3);
*colors++ = (((color >> 5) & 0x1F) << 3);
*colors++ = (((color >> 10) & 0x1F) << 3);
*colors++ = (color & 0x8000 ? 255 : 0);
}
}
void OSystem_PSP::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
//TODO: handle cursorTargetScale
_mouseWidth = w;
_mouseHeight = h;
_mouseHotspotX = hotspotX;
_mouseHotspotY = hotspotY;
_mouseKeyColour = keycolor & 0xFF;
memcpy(mouseClut, _palette, 256 * sizeof(unsigned short));
mouseClut[_mouseKeyColour] = 0;
for (unsigned int i = 0; i < h; i++)
memcpy(_mouseBuf + i * MOUSE_SIZE, buf + i * w, w);
sceKernelDcacheWritebackAll();
}