mirror of https://github.com/ClassiCube/ClassiCube
GBA: Optimise framebuffer clearing
Measuring in mgBA, time taken reduced from ~52 ms to ~3ms
This commit is contained in:
parent
4bd8d682c9
commit
162bb983ab
|
|
@ -36,15 +36,11 @@ DEPFILES := $(OBJS:%.o=%.d)
|
||||||
# Code generation
|
# Code generation
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
ARCH = -mthumb -mthumb-interwork
|
ARCH = -mthumb -mthumb-interwork
|
||||||
CFLAGS = -g -Wall -O2 -DPLAT_GBA -ffunction-sections -fdata-sections -mcpu=arm7tdmi -mtune=arm7tdmi $(ARCH)
|
CFLAGS = -g -gdwarf-4 -Wall -O2 -DPLAT_GBA -ffunction-sections -fdata-sections -mcpu=arm7tdmi -mtune=arm7tdmi $(ARCH)
|
||||||
ASFLAGS = -g $(ARCH)
|
ASFLAGS = -g $(ARCH)
|
||||||
|
|
||||||
LDFLAGS = -specs=gba.specs -g $(ARCH)
|
LDFLAGS = -specs=gba.specs -g $(ARCH)
|
||||||
|
|
||||||
LIBGBA := $(DEVKITPRO)/libgba
|
|
||||||
INCLUDES += $(foreach dir, $(LIBGBA), -I$(dir)/include)
|
|
||||||
LDFLAGS += $(foreach dir, $(LIBGBA), -L$(dir)/lib)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# Compiler tools
|
# Compiler tools
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,11 @@ void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
|
||||||
static void ClearColorBuffer(void) {
|
static void ClearColorBuffer(void) {
|
||||||
int i, x, y, size = fb_width * fb_height;
|
int i, x, y, size = fb_width * fb_height;
|
||||||
|
|
||||||
|
#ifdef CC_BUILD_GBA
|
||||||
|
/* in mGBA, fast clear takes ~2ms compared to ~52ms of code below */
|
||||||
|
extern void VRAM_FastClear(BitmapCol color);
|
||||||
|
VRAM_FastClear(clearColor);
|
||||||
|
#else
|
||||||
if (cb_stride == fb_width) {
|
if (cb_stride == fb_width) {
|
||||||
for (i = 0; i < size; i++) colorBuffer[i] = clearColor;
|
for (i = 0; i < size; i++) colorBuffer[i] = clearColor;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -140,6 +145,7 @@ static void ClearColorBuffer(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx_ClearBuffers(GfxBuffers buffers) {
|
void Gfx_ClearBuffers(GfxBuffers buffers) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
#define BEG_THUMB_FUNC(name_) \
|
||||||
|
.global name_; \
|
||||||
|
.thumb_func; \
|
||||||
|
.align 2; \
|
||||||
|
name_:
|
||||||
|
|
||||||
|
#define BEG_ARM_FUNC(name_) \
|
||||||
|
.global name_; \
|
||||||
|
.arm; \
|
||||||
|
.align 4; \
|
||||||
|
name_:
|
||||||
|
|
||||||
|
#define END_FUNC(name_) \
|
||||||
|
.size name_, . - name_; \
|
||||||
|
.type name_, %function;
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// FUNCTIONS IN TEXT SECTION
|
||||||
|
// ===============================
|
||||||
|
.section text
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// FUNCTIONS IN IWRAM SECTION
|
||||||
|
// ===============================
|
||||||
|
.section .iwram,"ax",%progbits
|
||||||
|
|
||||||
|
#define R_CUR r0 // r0 = beg address (incremented in function)
|
||||||
|
#define R_END r1 // r1 = end address
|
||||||
|
#define R_VAL r2 // r2 = value to fill
|
||||||
|
|
||||||
|
BEG_ARM_FUNC(fastset_256_bytes)
|
||||||
|
// Spill callee saved registers + LR onto stack
|
||||||
|
stmfd sp!, {r4-r9, lr}
|
||||||
|
|
||||||
|
// Clone 'value' for 'store multi CPU registers' loop
|
||||||
|
mov r3, R_VAL
|
||||||
|
mov r4, R_VAL
|
||||||
|
mov r5, R_VAL
|
||||||
|
mov r6, R_VAL
|
||||||
|
mov r7, R_VAL
|
||||||
|
mov r8, R_VAL
|
||||||
|
mov r9, R_VAL
|
||||||
|
|
||||||
|
fastset_loop:
|
||||||
|
cmp R_CUR, R_END
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
stmltia R_CUR!, {r2-r9}
|
||||||
|
blt fastset_loop
|
||||||
|
|
||||||
|
// Restore saved CPU registers + set PC to LR
|
||||||
|
ldmfd sp!, {r4-r9, pc}
|
||||||
|
END_FUNC(fastset_256_bytes)
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// FUNCTIONS IN EWRAM SECTION
|
||||||
|
// ===============================
|
||||||
|
.section .ewram,"ax",%progbits
|
||||||
|
BEG_THUMB_FUNC(nocash_log)
|
||||||
|
// nocash looks for this specific pattern
|
||||||
|
mov r12, r12
|
||||||
|
b nocash_log_return
|
||||||
|
.short 0x6464, 0x0000
|
||||||
|
.global nocash_msg // Platform_GBA writes directly to this
|
||||||
|
nocash_msg:
|
||||||
|
.space 82
|
||||||
|
|
||||||
|
nocash_log_return:
|
||||||
|
bx lr
|
||||||
|
END_FUNC(nocash_log)
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
.global nocash_log
|
|
||||||
.global nocash_msg
|
|
||||||
|
|
||||||
// BEG nocash_log
|
|
||||||
.section .ewram,"ax",%progbits
|
|
||||||
.thumb_func
|
|
||||||
.align 2
|
|
||||||
|
|
||||||
// nocash looks for this specific pattern
|
|
||||||
nocash_log:
|
|
||||||
mov r12, r12
|
|
||||||
b nocash_log_return
|
|
||||||
.short 0x6464, 0x0000
|
|
||||||
nocash_msg:
|
|
||||||
.space 82
|
|
||||||
|
|
||||||
nocash_log_return:
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.size nocash_log, .-nocash_log
|
|
||||||
.type nocash_log, %function
|
|
||||||
// END nocash_log
|
|
||||||
|
|
@ -13,9 +13,8 @@
|
||||||
#include "../Options.h"
|
#include "../Options.h"
|
||||||
#include "../Animations.h"
|
#include "../Animations.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include "gbadefs.h"
|
#include "gbadefs.h"
|
||||||
|
|
||||||
#include "../../third_party/tinyalloc/tinyalloc.c"
|
#include "../../third_party/tinyalloc/tinyalloc.c"
|
||||||
|
|
@ -203,9 +202,10 @@ void DateTime_CurrentLocal(struct cc_datetime* t) {
|
||||||
void CrashHandler_Install(void) {
|
void CrashHandler_Install(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Process_Abort2(cc_result result, const char* raw_msg) {
|
void Process_Abort2(cc_result result, const char* raw_msg) {
|
||||||
Platform_LogConst(raw_msg);
|
Platform_LogConst(raw_msg);
|
||||||
_exit(0);
|
Process_Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -333,5 +333,10 @@ cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process_Exit(cc_result code) { _exit(code); }
|
extern void bios_soft_reset(void);
|
||||||
|
void Process_Exit(cc_result code) {
|
||||||
|
//*(vu8*)0x03007FFA = 0x00; // controls reset address
|
||||||
|
// TODO jump to start_vector instead?
|
||||||
|
for (;;) { __asm__ volatile(""); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,17 +108,20 @@ void Gamepads_Init(void) {
|
||||||
Input.Sources |= INPUT_SOURCE_GAMEPAD;
|
Input.Sources |= INPUT_SOURCE_GAMEPAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PAUSE_MASK (KEY_A|KEY_B|KEY_START|KEY_SELECT)
|
||||||
void Gamepads_Process(float delta) {
|
void Gamepads_Process(float delta) {
|
||||||
int port = Gamepad_Connect(0x5BA, pad_defaults);
|
int port = Gamepad_Connect(0x5BA, pad_defaults);
|
||||||
int mods = ~REG_KEYINPUT;
|
int mods = ~REG_KEYINPUT;
|
||||||
|
|
||||||
|
// TODO see comment in Platform_GBA.c, doesn't work anyways
|
||||||
|
//if ((mods & PAUSE_MASK) == PAUSE_MASK)
|
||||||
|
// Process_Exit(0);
|
||||||
|
|
||||||
Gamepad_SetButton(port, CCPAD_L, mods & KEY_L);
|
Gamepad_SetButton(port, CCPAD_L, mods & KEY_L);
|
||||||
Gamepad_SetButton(port, CCPAD_R, mods & KEY_R);
|
Gamepad_SetButton(port, CCPAD_R, mods & KEY_R);
|
||||||
|
|
||||||
Gamepad_SetButton(port, CCPAD_1, mods & KEY_A);
|
Gamepad_SetButton(port, CCPAD_1, mods & KEY_A);
|
||||||
Gamepad_SetButton(port, CCPAD_2, mods & KEY_B);
|
Gamepad_SetButton(port, CCPAD_2, mods & KEY_B);
|
||||||
//Gamepad_SetButton(port, CCPAD_3, mods & KEY_X);
|
|
||||||
//Gamepad_SetButton(port, CCPAD_4, mods & KEY_Y);
|
|
||||||
|
|
||||||
Gamepad_SetButton(port, CCPAD_START, mods & KEY_START);
|
Gamepad_SetButton(port, CCPAD_START, mods & KEY_START);
|
||||||
Gamepad_SetButton(port, CCPAD_SELECT, mods & KEY_SELECT);
|
Gamepad_SetButton(port, CCPAD_SELECT, mods & KEY_SELECT);
|
||||||
|
|
@ -133,6 +136,15 @@ void Gamepads_Process(float delta) {
|
||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
*------------------------------------------------------Framebuffer--------------------------------------------------------*
|
*------------------------------------------------------Framebuffer--------------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
|
extern void fastset_256_bytes(char* beg, char* end, int value);
|
||||||
|
|
||||||
|
void VRAM_FastClear(BitmapCol col) {
|
||||||
|
int value = (col << 16) | col;
|
||||||
|
|
||||||
|
char* vram = (char*)MEM_VRAM;
|
||||||
|
fastset_256_bytes(vram, vram + SCREEN_WIDTH * SCREEN_HEIGHT * 2, value);
|
||||||
|
}
|
||||||
|
|
||||||
void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
|
void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
|
||||||
bmp->scan0 = (BitmapCol*)MEM_VRAM;
|
bmp->scan0 = (BitmapCol*)MEM_VRAM;
|
||||||
bmp->width = width;
|
bmp->width = width;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue