So far i did some.. well very basic tests, my target is always 60fps, so i use the RDP rasterizer, i have some question on the bottom of the message, sorry for my english and the long post.
These tests works on real hardware, maybe on CEN64 or MESS, some downloads are attached others on mega.
TEST 1: EXPLOSIONS
Random explosions on screen using textures of 16bits (32x32) with RDP.
Performance without optimizations:
410 at 60fps (NTSC)
507 at 50fps (PAL)
Texture strategy, use the same texture for other sprites without reload TMEM:
480
579
Flush texture disabled:
593
728
Probably there must be other ways to optimize further.
DOWNLOAD
https://mega.nz/#!Rkp2jRgJ!GpFxMwJ3g294r1CjwrmYR6mi-nIq4nhMuINdrsJRPwo
TEST 2: BIGGER EXPLOSIONS
Instead of 2KB explosions these are around 122x96 (22KB), so they are split in several pieces to fit the 4KB cache (i dont use stride function on libdragon, is slower than manage single textures), i wonder if there is an easy way to use 4 or 8bit textures with libdragon (they are limited to 16bit-32bit).
Performance is lower than expected, around 50 explosions at 60fps.
DOWNLOAD
https://mega.nz/#!loAQyQSb!NjiU9HUihztLdVz-ULFNcx8NhmLFnQBYuYk5FHTgFhw
TEST 3: SNOW
RDP rectangles (non textured) of 4x4 with a blue color.
Performance:
5120 rectangles at 60fps
6430 rectangles at 50fps
Use int16 instead of int32:
5600
7120
DOWNLOAD
https://mega.nz/#!R9YEwBSD!_7jzjJd0UXLLDIgvKNxVt0pwtKhSdyJ46QhFRMG7EWA
CONTROLS
A - Increase
B - Decrease
Start - Min
Z - Max
C up - clean buffer with RDP (test 1,2)
C left - clean buffer with CPU (test 1,2)
C down - do not clean (test 1,2)
R - Color rectangles (test 3)
CASTLEVANIA: SOTN OST
The whole soundtrack converted into ogg 44KHz/Stereo/128kbps using libogg, 34 songs, fits on a 64MB cartridge, plays from start to end, can skip songs with c button.
It slowdowns 25fps to sync with the audio (i don't know how to use threads), but since its static background there is no problem at all.
DOWNLOAD (wonder if can be shared?)
https://mega.nz/#!Y9pQjYgC!S3LojMylb3lQ-RWEpdtdVxzCJKy9Td1b9AHr7Sq370w
=> Added get_pixel function, this is already inside the libdragon but i didnt see the function for end users?
GET_PIXEL
Gets a pixel color from a buffer in x/y position.
- Returns a packed color (twice) in 16bits for RDP compatibility.
graphics.c:
Code: Select all
uint32_t get_pixel( display_context_t disp, int x, int y )
{
if( disp == 0 ) { return 0; }
if( __bitdepth == 2 )
{
uint16_t *buffer16 = (uint16_t *)__get_buffer( disp );
uint16_t packed_rdp = __get_pixel( buffer16, x, y );
return packed_rdp | (packed_rdp << 16);
}
else
{
uint32_t *buffer32 = (uint32_t *)__get_buffer( disp );
return __get_pixel( buffer32, x, y );
}
}
Code: Select all
uint32_t get_pixel( display_context_t disp, int x, int y);
- Can be used on a paint program (or those racing games with a menu to select a color for a car)
- Can be used as hidden collision map (since it reads the current buffer)
- Allows users to create new functions
- Can transform color into data to copy block areas or do special effects (VERY SLOW)
TEST
A color table is written on the buffer, the mouse reads the color from the buffer and shows it on the rectangle.
16bit value to RGB conversion (this conversion is not necessary, but just in case)
Code: Select all
color=get_pixel(disp,mouse_x,mouse_y);
// Extract
uint8_t r1 = (color & 0xF800) >> 11; // 63488
uint8_t g1 = (color & 0x7C0) >> 6; // 1984
uint8_t b1 = (color & 0x3E) >> 1; // 62
// Expand to 8-bit
r = r1 << 3;
g = g1 << 3;
b = b1 << 3;
CONTROLS
Joystick - Mouse
A - Set background color with the color selected
R - Alternate white or black letter fonts
Z - Reset background and letter colors
DOWNLOAD
https://mega.nz/#!g5IRgYwA!Mk-vrgPmAi0HhN5aPKPLNDNVnbtdgxFkGXTkmGBmZcg
Added math functions (fget_angle, fget_dist, get_distx, get_disty)
Allows some game logic and this kind of effects..
Since i don't have yet raster effects (buffer) i had to use giant horizontally textures (320x4), so i can move the blocks separately.
- Libdragon won't allow textures beyond 256 wide, they are repeated at this point or mirrored depending on the settings.
The effect is generated in real time (instead of tables) and can be edited:
C left / C right = wave
C up / C down = radius
A / B = Speed
R = hide text
A better gif (graphics sample from Last Blade 2):
DOWNLOAD
https://mega.nz/#!UpIBkJBb!TqZc9F3V8lZS ... 9zsYVEpews
---
I could provide the source code of these examples, but probably the level skills on this board are better than me.
Right now im trying to figure how to add hardware flip to the sprites, it is possible by changing the order of the loading or using mirror S or T coords when drawing, but this code brings me headaches, i simply don't know where to start:
(the code is slightly modified from the source, i have removed texture slots)
rdp.c
Code: Select all
static uint32_t __rdp_load_texture(int mirror_enabled, sprite_t *sprite, int sl, int tl, int sh, int th )
{
/* Invalidate data associated with sprite in cache */
if( flush_strategy == FLUSH_STRATEGY_AUTOMATIC )
{
data_cache_hit_writeback_invalidate( sprite->data, sprite->width * sprite->height * sprite->bitdepth );
}
/* Point the RDP at the actual sprite data */
__rdp_ringbuffer_queue( 0xFD000000 | ((sprite->bitdepth == 2) ? 0x00100000 : 0x00180000) | (sprite->width - 1) );
__rdp_ringbuffer_queue( (uint32_t)sprite->data );
__rdp_ringbuffer_send();
/* Figure out the s,t coordinates of the sprite we are copying out of */
int twidth = sh - sl + 1;
int theight = th - tl + 1;
/* Figure out the power of two this sprite fits into */
uint32_t real_width = __rdp_round_to_power( twidth );
uint32_t real_height = __rdp_round_to_power( theight );
uint32_t wbits = __rdp_log2( real_width );
uint32_t hbits = __rdp_log2( real_height );
/* Because we are dividing by 8, we want to round up if we have a remainder */
int16_t round_amount = (real_width % 8) ? 1 : 0;
/* Instruct the RDP to copy the sprite data out */
__rdp_ringbuffer_queue( 0xF5000000 | ((sprite->bitdepth == 2) ? 0x00100000 : 0x00180000) |
(((((real_width / 8) + round_amount) * sprite->bitdepth) & 0x1FF) << 9));
__rdp_ringbuffer_queue( (mirror_enabled == 1 ? 0x40100 : 0) | (hbits << 14 ) | (wbits << 4) );
__rdp_ringbuffer_send();
/* Copying out only a chunk this time */
__rdp_ringbuffer_queue( 0xF4000000 | (((sl << 2) & 0xFFF) << 12) | ((tl << 2) & 0xFFF) );
__rdp_ringbuffer_queue( (((sh << 2) & 0xFFF) << 12) | ((th << 2) & 0xFFF) );
__rdp_ringbuffer_send();
/* Save sprite width and height for managed sprite commands */
cache.width = twidth - 1;
cache.height = theight - 1;
cache.s = sl;
cache.t = tl;
/* Return the amount of texture memory consumed by this texture */
return ((real_width / 8) + round_amount) * 8 * real_height * sprite->bitdepth;
}
Code: Select all
void rdp_draw_textured_rectangle_scaled( int tx, int ty, int bx, int by, double x_scale, double y_scale )
{
uint16_t s = cache.s << 5;
uint16_t t = cache.t << 5;
/* Cant display < 0, so must clip size and move S,T coord accordingly */
if( tx < 0 )
{
if ( tx < -cache.width ) { return; }
s += (int)(((double)((-tx) << 5)) * (1.0 / x_scale));
tx = 0;
}
if( ty < 0 )
{
t += (int)(((double)((-ty) << 5)) * (1.0 / y_scale));
ty = 0;
}
/* Calculate the scaling constants based on a 6.10 fixed point system */
int xs = (int)((1.0 / x_scale) * 4096.0);
int ys = (int)((1.0 / y_scale) * 1024.0);
/* Set up rectangle position in screen space */
__rdp_ringbuffer_queue( 0xE4000000 | (bx << 14) | (by << 2) );
__rdp_ringbuffer_queue( (tx << 14) | (ty << 2) );
/* Set up texture position and scaling to 1:1 copy */
__rdp_ringbuffer_queue( (s << 16) | t );
__rdp_ringbuffer_queue( (xs & 0xFFFF) << 16 | (ys & 0xFFFF) );
/* Send command */
__rdp_ringbuffer_send();
}