diff --git a/Makefile b/Makefile index 4eda78b..7ef0a7e 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ IMAGES = common \ gpu/texture-overflow \ gpu/mask-bit \ gpu/gp0-e1 \ + gpu/vram-to-vram-overlap \ gte-fuzz \ spu/test \ spu/stereo \ diff --git a/README.md b/README.md index dd7c9dc..014ac8d 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,23 @@ Collection of PlayStation 1 tests for emulator development and hardware verifica ## Tests -Name | Description ----------------------|------------ -gpu/bandwidth | Measure GPU/VRAM bandwidth -gpu/benchmark | Simple GPU test to benchmark rasteriser -gpu/quad | Semi-transparent polygon commands - for testing fill rules and transparency handling -gpu/transparency | Draws rectangles with 4 semi-transparent blending modes -gpu/triangle | Draws Gouroud shaded equilateral triangle -gpu/lines | Draws lines using different modes - for verifying Bresenham implementation, color blending, polyline handling -gpu/rectangles | Draws all combinations of Rectangle commands -gpu/texture-overflow | Draws textured rectangle with UV overflowing VRAM width -gpu/mask-bit | Check Mask bit behavior during VRAM copy operations -gpu/gp0-e1 | Check if GP0_E1, GPUSTAT and polygon render uses the same register internally -gte-fuzz | Executes GTE opcodes with random parameters, can be used to verify against real console -spu/test | Check SPU behavior (data is lost randomly on 32bit access, ok on 16bit) -spu/stereo | Play samples on first two voices -timers | Run Timer0,1,2 using various clock sources and sync modes and time them using busy loops and vblank interrupt +Name | Description +-------------------------|------------ +gpu/bandwidth | Measure GPU/VRAM bandwidth +gpu/benchmark | Simple GPU test to benchmark rasteriser +gpu/quad | Semi-transparent polygon commands - for testing fill rules and transparency handling +gpu/transparency | Draws rectangles with 4 semi-transparent blending modes +gpu/triangle | Draws Gouroud shaded equilateral triangle +gpu/lines | Draws lines using different modes - for verifying Bresenham implementation, color blending, polyline handling +gpu/rectangles | Draws all combinations of Rectangle commands +gpu/texture-overflow | Draws textured rectangle with UV overflowing VRAM width +gpu/mask-bit | Check Mask bit behavior during VRAM copy operations +gpu/gp0-e1 | Check if GP0_E1, GPUSTAT and polygon render uses the same register internally +gpu/vram-to-vram-overlap | Test GP0(80) VRAM-VRAM copy behaviour in overlapping rects +gte-fuzz | Executes GTE opcodes with random parameters, can be used to verify against real console +spu/test | Check SPU behavior (data is lost randomly on 32bit access, ok on 16bit) +spu/stereo | Play samples on first two voices +timers | Run Timer0,1,2 using various clock sources and sync modes and time them using busy loops and vblank interrupt Note: Make sure your PS-EXE loaded does set default value for Stack Pointer - these .exes has SP set to 0. @@ -39,6 +40,7 @@ diffvram | Diff two images and write diff png if image contents aren + ## Build diff --git a/common/gpu.c b/common/gpu.c index 91b3abc..ad8deb5 100644 --- a/common/gpu.c +++ b/common/gpu.c @@ -6,7 +6,7 @@ DRAWENV draw; void setResolution(int w, int h) { SetDefDispEnv(&disp, 0, 0, w, h); - SetDefDrawEnv(&draw, 0, 0, w, h); + SetDefDrawEnv(&draw, 0, 0, 1024, 512); PutDispEnv(&disp); PutDrawEnv(&draw); @@ -106,3 +106,19 @@ uint32_t vramGet(int x, int y) { return readGPU(); } + +void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + VRAM2VRAM buf = {0}; + setcode(&buf, 0x80); // VRAM -> VRAM + setlen(&buf, 4); + + buf.x0 = srcX; + buf.y0 = srcY; + buf.x1 = dstX; + buf.y1 = dstY; + buf.w = w; + buf.h = h; + + DrawPrim(&buf); +} diff --git a/common/gpu.h b/common/gpu.h index 69675b8..7867909 100644 --- a/common/gpu.h +++ b/common/gpu.h @@ -36,6 +36,7 @@ void writeGP1(uint8_t cmd, uint32_t data); uint32_t readGPU(); void vramPut(int x, int y, uint16_t pixel); uint32_t vramGet(int x, int y); +void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h); #ifdef __cplusplus } diff --git a/gpu/vram-to-vram-overlap/Makefile b/gpu/vram-to-vram-overlap/Makefile new file mode 100644 index 0000000..54e6e19 --- /dev/null +++ b/gpu/vram-to-vram-overlap/Makefile @@ -0,0 +1,3 @@ +include ../../common-test.mk + +TARGET = vram-to-vram-overlap.elf \ No newline at end of file diff --git a/gpu/vram-to-vram-overlap/font.c b/gpu/vram-to-vram-overlap/font.c new file mode 100644 index 0000000..abf50c0 --- /dev/null +++ b/gpu/vram-to-vram-overlap/font.c @@ -0,0 +1,67 @@ +#include +#include +#include + +const int fontPosX = 960; +const int fontPosY = 0; + +int fontCharX = 0; +int fontCharY = 0; + +// TODO: refactor font handling to use SDK functions +void FntInit() { + FntLoad(fontPosX, fontPosY); +} + +void FntPos(int x, int y) { + fontCharX = x; + fontCharY = y; +} + +void FntChar(char c) { + if (c == '\n') { + fontCharX = 0; + fontCharY += 8; + return; + } + if (c >= ' ') { + DR_TPAGE e; + unsigned short texpage = getTPage(/* bits */ 0, /* semi transparency */ 0, fontPosX, fontPosY); + setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 1, texpage); + DrawPrim(&e); + + if (c >= 96) { + c &= ~(1<<5); // To lower + } + char pos = c - 33; + int u = pos%16; + int v = pos/16; + + SPRT_8 t; + setSprt8(&t); + setXY0(&t, fontCharX, fontCharY); + setUV0(&t, u*8, v*8); + setClut(&t, fontPosX, 32); + setRGB0(&t, 255, 255, 255); + + DrawPrim(&t); + } + + fontCharX += 8; + if (fontCharX > 1024) { + fontCharX = 0; + fontCharY += 8; + } +} + +void FntPrintf(const char* format, ...) { + char buffer[256]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + + int len = strlen(buffer); + for (int i = 0; i +#include "font.h" + +// 24 bit to 15 bit value +constexpr uint16_t rgb(uint8_t r, uint8_t g, uint8_t b) { + uint16_t c = 0; + c |= ((r >> 3) & 0x1f); + c |= ((g >> 3) & 0x1f) << 5; + c |= ((b >> 3) & 0x1f) << 10; + return c; +} + +constexpr uint16_t randomColor(int c) { + rgb(64+(c*432)%192, 64+(c*127)%192, 64+(c*941)%192); +} + +// Write sizexsize rect to vram +void writeRect(int dstX, int dstY, int size) { + for (int y = 0; y