Compare commits

...

19 Commits

Author SHA1 Message Date
Dave Murphy
9f21cf7b38
libctru 1.7.1 2023-10-28 21:06:58 +01:00
fincs
00396e8a99
Fix for libctru v2.3.0 2023-10-28 21:57:00 +02:00
oreo639
66a0594e5d Add C3D_LightEnvBumpNormalZ()
Used to configure whether the Z component of the normal map is used or if
the Z component is reconstructed based on the XY components of the normal map.
2023-08-12 16:52:36 +02:00
oreo639
e8825650c6 Correct typo in tex3ds docs 2022-08-06 11:43:21 +02:00
fincs
e2992d276f
Fix #58 2022-05-28 21:14:55 +02:00
fincs
b6d0b7d876
citro3d v1.7.0 2022-01-28 23:49:36 +01:00
fincs
bbe09c4265
Implement VRAM bank awareness for rendertarget allocations 2021-08-26 23:46:07 +02:00
fincs
a491a8eb79
Use __3DS__ instead of _3DS 2021-08-07 13:11:39 +02:00
fincs
c7425b653e
Remove spurious warning 2021-04-29 17:54:15 +02:00
fincs
100ebd4067
citro3d v1.6.2 2020-12-19 17:19:38 +01:00
fincs
03235602cd
Add C3D_RenderTargetDetachOutput (called automatically on render target destroy) 2020-09-28 23:33:02 +02:00
fincs
4e02e27222
Bump version for release 2020-07-16 16:13:45 +02:00
fincs
05e8039b7f
Tell the compiler we don't check errno when calling math.h functions (work around a C stdlib design flaw) 2020-07-10 13:22:33 +02:00
fincs
f4367ad55d
Use gfxScreenSwapBuffers; implement left->right eye duplication with it 2020-07-07 13:08:56 +02:00
fincs
bbbadebeae
Pause the VBlank counters while the application is suspended 2020-07-06 20:21:03 +02:00
fincs
7999093588
Bump version for release 2020-05-10 01:18:22 +02:00
fincs
dcb3aac861
base/renderqueue: Clean up initialization code 2020-05-05 16:57:18 +02:00
fincs
3d566ac8da
Delete long-since obsolete flush functions 2020-05-05 01:06:36 +02:00
fincs
f2850e3bfe
renderqueue: Remove overengineered transfer system now that we know GSP actually processes framebuffer swaps at vblank... 2020-05-04 22:23:49 +02:00
14 changed files with 138 additions and 166 deletions

View File

@ -9,8 +9,8 @@ endif
include $(DEVKITARM)/3ds_rules include $(DEVKITARM)/3ds_rules
export CITRO3D_MAJOR := 1 export CITRO3D_MAJOR := 1
export CITRO3D_MINOR := 5 export CITRO3D_MINOR := 7
export CITRO3D_PATCH := 0 export CITRO3D_PATCH := 1
VERSION := $(CITRO3D_MAJOR).$(CITRO3D_MINOR).$(CITRO3D_PATCH) VERSION := $(CITRO3D_MAJOR).$(CITRO3D_MINOR).$(CITRO3D_PATCH)
@ -31,11 +31,11 @@ INCLUDES := include
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -g -Wall -Werror -mword-relocations \ CFLAGS := -g -Wall -Wno-sizeof-array-div -Werror -mword-relocations \
-ffunction-sections -fdata-sections \ -ffunction-sections -fdata-sections \
$(ARCH) $(BUILD_CFLAGS) $(ARCH) $(BUILD_CFLAGS)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DCITRO3D_BUILD CFLAGS += $(INCLUDE) -D__3DS__ -DCITRO3D_BUILD
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
@ -114,7 +114,7 @@ debug:
lib/libcitro3d.a : lib release $(SOURCES) $(INCLUDES) lib/libcitro3d.a : lib release $(SOURCES) $(INCLUDES)
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \ @$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
BUILD_CFLAGS="-DNDEBUG=1 -O2 -fomit-frame-pointer" \ BUILD_CFLAGS="-DNDEBUG=1 -O2 -fomit-frame-pointer -fno-math-errno" \
DEPSDIR=$(CURDIR)/release \ DEPSDIR=$(CURDIR)/release \
--no-print-directory -C release \ --no-print-directory -C release \
-f $(CURDIR)/Makefile -f $(CURDIR)/Makefile

View File

@ -11,7 +11,6 @@ enum
}; };
bool C3D_Init(size_t cmdBufSize); bool C3D_Init(size_t cmdBufSize);
void C3D_FlushAsync(void);
void C3D_Fini(void); void C3D_Fini(void);
float C3D_GetCmdBufUsage(void); float C3D_GetCmdBufUsage(void);
@ -34,23 +33,6 @@ static inline void C3D_ImmDrawRestartPrim(void)
GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1); GPUCMD_AddWrite(GPUREG_RESTART_PRIMITIVE, 1);
} }
static inline void C3D_FlushAwait(void)
{
gspWaitForP3D();
}
static inline void C3D_Flush(void)
{
C3D_FlushAsync();
C3D_FlushAwait();
}
static inline void C3D_VideoSync(void)
{
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false);
gfxSwapBuffersGpu();
}
// Fixed vertex attributes // Fixed vertex attributes
C3D_FVec* C3D_FixedAttribGetWritePtr(int id); C3D_FVec* C3D_FixedAttribGetWritePtr(int id);

View File

@ -77,6 +77,14 @@ enum
void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector); void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector);
void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode); void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode);
void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit); void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit);
/**
* @brief Configures whether to use the z component of the normal map.
* @param[out] env Pointer to light environment structure.
* @param[in] enable false if the z component is reconstructed from the xy components
* of the normal map, true if the z component is taken from the normal map.
*/
void C3D_LightEnvBumpNormalZ(C3D_LightEnv *env, bool enable);
void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode); void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode);
void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit); void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit);
void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp); void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp);

View File

@ -13,7 +13,12 @@
* The one true circumference-to-radius ratio. * The one true circumference-to-radius ratio.
* See http://tauday.com/tau-manifesto * See http://tauday.com/tau-manifesto
*/ */
#define M_TAU (2*M_PI) #define M_TAU (6.28318530717958647692528676655900576)
// Define the legacy circle constant as well
#ifndef M_PI
#define M_PI (M_TAU/2)
#endif
/** /**
* @brief Convert an angle from revolutions to radians * @brief Convert an angle from revolutions to radians

View File

@ -64,6 +64,11 @@ C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face,
void C3D_RenderTargetDelete(C3D_RenderTarget* target); void C3D_RenderTargetDelete(C3D_RenderTarget* target);
void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags); void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags);
static inline void C3D_RenderTargetDetachOutput(C3D_RenderTarget* target)
{
C3D_RenderTargetSetOutput(NULL, target->screen, target->side, 0);
}
static inline void C3D_RenderTargetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth) static inline void C3D_RenderTargetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth)
{ {
C3D_FrameBufClear(&target->frameBuf, clearBits, clearColor, clearDepth); C3D_FrameBufClear(&target->frameBuf, clearBits, clearColor, clearDepth);

View File

@ -41,7 +41,7 @@ typedef struct
}; };
} C3D_Tex; } C3D_Tex;
typedef struct ALIGN(8) typedef struct CTR_ALIGN(8)
{ {
u16 width; u16 width;
u16 height; u16 height;

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#ifdef _3DS #if defined(__3DS__) || defined(_3DS)
#include <3ds.h> #include <3ds.h>
#else #else
#include <stdbool.h> #include <stdbool.h>

View File

@ -38,7 +38,7 @@ extern "C" {
#endif #endif
/** @brief Subtexture /** @brief Subtexture
* @note If top > bottom, the subtexture is rotated 1/4 revolution counter-clockwise * @note If top < bottom, the subtexture is rotated 1/4 revolution counter-clockwise
*/ */
typedef struct Tex3DS_SubTexture typedef struct Tex3DS_SubTexture
{ {

View File

@ -8,14 +8,6 @@ C3D_Context __C3D_Context;
static aptHookCookie hookCookie; static aptHookCookie hookCookie;
__attribute__((weak)) void C3Di_RenderQueueWaitDone(void)
{
}
__attribute__((weak)) void C3Di_RenderQueueExit(void)
{
}
__attribute__((weak)) void C3Di_LightEnvUpdate(C3D_LightEnv* env) __attribute__((weak)) void C3Di_LightEnvUpdate(C3D_LightEnv* env)
{ {
(void)env; (void)env;
@ -50,10 +42,12 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
case APTHOOK_ONSUSPEND: case APTHOOK_ONSUSPEND:
{ {
C3Di_RenderQueueWaitDone(); C3Di_RenderQueueWaitDone();
C3Di_RenderQueueDisableVBlank();
break; break;
} }
case APTHOOK_ONRESTORE: case APTHOOK_ONRESTORE:
{ {
C3Di_RenderQueueEnableVBlank();
ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_FrameBuf ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_FrameBuf
| C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode | C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode
| C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv | C3DiF_Gas; | C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv | C3DiF_Gas;
@ -102,10 +96,6 @@ bool C3D_Init(size_t cmdBufSize)
return false; return false;
} }
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
GX_BindQueue(&ctx->gxQueue);
gxCmdQueueRun(&ctx->gxQueue);
ctx->flags = C3DiF_Active | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_Effect | C3DiF_TexStatus | C3DiF_TexAll; ctx->flags = C3DiF_Active | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_Effect | C3DiF_TexStatus | C3DiF_TexAll;
// TODO: replace with direct struct access // TODO: replace with direct struct access
@ -137,6 +127,7 @@ bool C3D_Init(size_t cmdBufSize)
ctx->fixedAttribDirty = 0; ctx->fixedAttribDirty = 0;
ctx->fixedAttribEverDirty = 0; ctx->fixedAttribEverDirty = 0;
C3Di_RenderQueueInit();
aptHook(&hookCookie, C3Di_AptEventHook, NULL); aptHook(&hookCookie, C3Di_AptEventHook, NULL);
return true; return true;
@ -336,25 +327,6 @@ bool C3Di_SplitFrame(u32** pBuf, u32* pSize)
return true; return true;
} }
void C3D_FlushAsync(void)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
u32* cmdBuf;
u32 cmdBufSize;
C3Di_SplitFrame(&cmdBuf, &cmdBufSize);
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
//take advantage of GX_FlushCacheRegions to flush gsp heap
extern u32 __ctru_linear_heap;
extern u32 __ctru_linear_heap_size;
GX_FlushCacheRegions(cmdBuf, cmdBufSize*4, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0);
GX_ProcessCommandList(cmdBuf, cmdBufSize*4, 0x0);
}
float C3D_GetCmdBufUsage(void) float C3D_GetCmdBufUsage(void)
{ {
return C3Di_GetContext()->cmdBufUsage; return C3Di_GetContext()->cmdBufUsage;
@ -367,11 +339,8 @@ void C3D_Fini(void)
if (!(ctx->flags & C3DiF_Active)) if (!(ctx->flags & C3DiF_Active))
return; return;
C3Di_RenderQueueExit();
aptUnhook(&hookCookie); aptUnhook(&hookCookie);
gxCmdQueueStop(&ctx->gxQueue); C3Di_RenderQueueExit();
gxCmdQueueWait(&ctx->gxQueue, -1);
GX_BindQueue(NULL);
free(ctx->gxQueue.entries); free(ctx->gxQueue.entries);
linearFree(ctx->cmdBuf); linearFree(ctx->cmdBuf);
ctx->flags = 0; ctx->flags = 0;

View File

@ -124,6 +124,18 @@ static inline bool C3Di_TexIs2D(C3D_Tex* tex)
return !typeIsCube(C3D_TexGetType(tex)); return !typeIsCube(C3D_TexGetType(tex));
} }
static inline bool addrIsVRAM(const void* addr)
{
u32 vaddr = (u32)addr;
return vaddr >= OS_VRAM_VADDR && vaddr < OS_VRAM_VADDR + OS_VRAM_SIZE;
}
static inline vramAllocPos addrGetVRAMBank(const void* addr)
{
u32 vaddr = (u32)addr;
return vaddr < OS_VRAM_VADDR + OS_VRAM_SIZE/2 ? VRAM_ALLOC_A : VRAM_ALLOC_B;
}
void C3Di_UpdateContext(void); void C3Di_UpdateContext(void);
void C3Di_AttrInfoBind(C3D_AttrInfo* info); void C3Di_AttrInfoBind(C3D_AttrInfo* info);
void C3Di_BufInfoBind(C3D_BufInfo* info); void C3Di_BufInfoBind(C3D_BufInfo* info);
@ -140,3 +152,9 @@ void C3Di_LoadShaderUniforms(shaderInstance_s* si);
void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type); void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type);
bool C3Di_SplitFrame(u32** pBuf, u32* pSize); bool C3Di_SplitFrame(u32** pBuf, u32* pSize);
void C3Di_RenderQueueInit(void);
void C3Di_RenderQueueExit(void);
void C3Di_RenderQueueWaitDone(void);
void C3Di_RenderQueueEnableVBlank(void);
void C3Di_RenderQueueDisableVBlank(void);

View File

@ -250,6 +250,14 @@ void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit)
env->flags |= C3DF_LightEnv_Dirty; env->flags |= C3DF_LightEnv_Dirty;
} }
void C3D_LightEnvBumpNormalZ(C3D_LightEnv *env, bool usez) {
if (usez)
env->conf.config[0] |= BIT(30);
else
env->conf.config[0] &= ~BIT(30);
env->flags |= C3DF_LightEnv_Dirty;
}
void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode) void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode)
{ {
mode &= 0xF<<16; mode &= 0xF<<16;

View File

@ -8,22 +8,16 @@ static C3D_RenderTarget *linkedTarget[3];
static TickCounter gpuTime, cpuTime; static TickCounter gpuTime, cpuTime;
#define STAGE_HAS_TRANSFER(n) BIT(0+(n))
#define STAGE_HAS_ANY_TRANSFER (7<<0)
#define STAGE_NEED_TRANSFER(n) BIT(3+(n))
#define STAGE_NEED_TOP_TRANSFER (STAGE_NEED_TRANSFER(0)|STAGE_NEED_TRANSFER(1))
#define STAGE_NEED_BOT_TRANSFER STAGE_NEED_TRANSFER(2)
#define STAGE_WAIT_TRANSFER BIT(6)
static bool initialized;
static bool inFrame, inSafeTransfer, measureGpuTime; static bool inFrame, inSafeTransfer, measureGpuTime;
static u8 frameStage; static bool needSwapTop, needSwapBot, isTopStereo;
static float framerate = 60.0f; static float framerate = 60.0f;
static float framerateCounter[2] = { 60.0f, 60.0f }; static float framerateCounter[2] = { 60.0f, 60.0f };
static u32 frameCounter[2]; static u32 frameCounter[2];
static void (* frameEndCb)(void*); static void (* frameEndCb)(void*);
static void* frameEndCbData; static void* frameEndCbData;
static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target);
static bool framerateLimit(int id) static bool framerateLimit(int id)
{ {
framerateCounter[id] -= framerate; framerateCounter[id] -= framerate;
@ -37,44 +31,12 @@ static bool framerateLimit(int id)
static void onVBlank0(C3D_UNUSED void* unused) static void onVBlank0(C3D_UNUSED void* unused)
{ {
if (frameStage & STAGE_NEED_TOP_TRANSFER)
{
C3D_RenderTarget *left = linkedTarget[0], *right = linkedTarget[1];
if (left && !(frameStage&STAGE_NEED_TRANSFER(0)))
left = NULL;
if (right && !(frameStage&STAGE_NEED_TRANSFER(1)))
right = NULL;
if (gfxIs3D() && !right)
right = left;
frameStage &= ~STAGE_NEED_TOP_TRANSFER;
if (left || right)
{
frameStage |= STAGE_WAIT_TRANSFER;
if (left)
C3D_FrameBufTransfer(&left->frameBuf, GFX_TOP, GFX_LEFT, left->transferFlags);
if (right)
C3D_FrameBufTransfer(&right->frameBuf, GFX_TOP, GFX_RIGHT, right->transferFlags);
gfxConfigScreen(GFX_TOP, false);
}
}
if (framerateLimit(0)) if (framerateLimit(0))
frameCounter[0]++; frameCounter[0]++;
} }
static void onVBlank1(C3D_UNUSED void* unused) static void onVBlank1(C3D_UNUSED void* unused)
{ {
if (frameStage & STAGE_NEED_BOT_TRANSFER)
{
frameStage &= ~STAGE_NEED_BOT_TRANSFER;
C3D_RenderTarget* target = linkedTarget[2];
if (target)
{
frameStage |= STAGE_WAIT_TRANSFER;
C3D_FrameBufTransfer(&target->frameBuf, GFX_BOTTOM, GFX_LEFT, target->transferFlags);
gfxConfigScreen(GFX_BOTTOM, false);
}
}
if (framerateLimit(1)) if (framerateLimit(1))
frameCounter[1]++; frameCounter[1]++;
} }
@ -95,12 +57,18 @@ static void onQueueFinish(gxCmdQueue_s* queue)
gxCmdQueueClear(queue); gxCmdQueueClear(queue);
} }
} }
else if (frameStage & STAGE_WAIT_TRANSFER)
frameStage &= ~STAGE_WAIT_TRANSFER;
else else
{ {
u8 needs = frameStage & STAGE_HAS_ANY_TRANSFER; if (needSwapTop)
frameStage = (frameStage&~STAGE_HAS_ANY_TRANSFER) | (needs<<3); {
gfxScreenSwapBuffers(GFX_TOP, isTopStereo);
needSwapTop = false;
}
if (needSwapBot)
{
gfxScreenSwapBuffers(GFX_BOTTOM, false);
needSwapBot = false;
}
} }
} }
@ -126,72 +94,60 @@ static bool C3Di_WaitAndClearQueue(s64 timeout)
gxCmdQueue_s* queue = &C3Di_GetContext()->gxQueue; gxCmdQueue_s* queue = &C3Di_GetContext()->gxQueue;
if (!gxCmdQueueWait(queue, timeout)) if (!gxCmdQueueWait(queue, timeout))
return false; return false;
if (timeout==0 && frameStage)
return false;
while (frameStage)
gspWaitForAnyEvent();
gxCmdQueueStop(queue); gxCmdQueueStop(queue);
gxCmdQueueClear(queue); gxCmdQueueClear(queue);
return true; return true;
} }
static void C3Di_RenderQueueInit(void) void C3Di_RenderQueueEnableVBlank(void)
{ {
gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, NULL, false); gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, NULL, false);
gspSetEventCallback(GSPGPU_EVENT_VBlank1, onVBlank1, NULL, false); gspSetEventCallback(GSPGPU_EVENT_VBlank1, onVBlank1, NULL, false);
gxCmdQueueSetCallback(&C3Di_GetContext()->gxQueue, onQueueFinish, NULL);
} }
static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target); void C3Di_RenderQueueDisableVBlank(void)
{
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, false);
gspSetEventCallback(GSPGPU_EVENT_VBlank1, NULL, NULL, false);
}
void C3Di_RenderQueueInit(void)
{
C3D_Context* ctx = C3Di_GetContext();
C3Di_RenderQueueEnableVBlank();
GX_BindQueue(&ctx->gxQueue);
gxCmdQueueSetCallback(&ctx->gxQueue, onQueueFinish, NULL);
gxCmdQueueRun(&ctx->gxQueue);
}
void C3Di_RenderQueueExit(void) void C3Di_RenderQueueExit(void)
{ {
int i; int i;
C3D_RenderTarget *a, *next; C3D_RenderTarget *a, *next;
if (!initialized)
return;
C3Di_WaitAndClearQueue(-1); C3Di_WaitAndClearQueue(-1);
gxCmdQueueSetCallback(&C3Di_GetContext()->gxQueue, NULL, NULL);
GX_BindQueue(NULL);
C3Di_RenderQueueDisableVBlank();
for (i = 0; i < 3; i ++)
linkedTarget[i] = NULL;
for (a = firstTarget; a; a = next) for (a = firstTarget; a; a = next)
{ {
next = a->next; next = a->next;
C3Di_RenderTargetDestroy(a); C3Di_RenderTargetDestroy(a);
} }
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, false);
gspSetEventCallback(GSPGPU_EVENT_VBlank1, NULL, NULL, false);
gxCmdQueueSetCallback(&C3Di_GetContext()->gxQueue, NULL, NULL);
for (i = 0; i < 3; i ++)
linkedTarget[i] = NULL;
initialized = false;
} }
void C3Di_RenderQueueWaitDone(void) void C3Di_RenderQueueWaitDone(void)
{ {
if (!initialized)
return;
C3Di_WaitAndClearQueue(-1); C3Di_WaitAndClearQueue(-1);
} }
static bool checkRenderQueueInit(void)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return false;
if (!initialized)
{
C3Di_RenderQueueInit();
initialized = true;
}
return true;
}
float C3D_FrameRate(float fps) float C3D_FrameRate(float fps)
{ {
float old = framerate; float old = framerate;
@ -206,13 +162,17 @@ float C3D_FrameRate(float fps)
bool C3D_FrameBegin(u8 flags) bool C3D_FrameBegin(u8 flags)
{ {
C3D_Context* ctx = C3Di_GetContext();
if (inFrame) return false; if (inFrame) return false;
if (flags & C3D_FRAME_SYNCDRAW) if (flags & C3D_FRAME_SYNCDRAW)
C3D_FrameSync(); C3D_FrameSync();
if (!C3Di_WaitAndClearQueue((flags & C3D_FRAME_NONBLOCK) ? 0 : -1)) if (!C3Di_WaitAndClearQueue((flags & C3D_FRAME_NONBLOCK) ? 0 : -1))
return false; return false;
inFrame = true; inFrame = true;
osTickCounterStart(&cpuTime); osTickCounterStart(&cpuTime);
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
return true; return true;
} }
@ -237,13 +197,15 @@ void C3D_FrameSplit(u8 flags)
void C3D_FrameEnd(u8 flags) void C3D_FrameEnd(u8 flags)
{ {
C3D_Context* ctx = C3Di_GetContext(); C3D_Context* ctx = C3Di_GetContext();
if (!inFrame) return;
if (frameEndCb) if (frameEndCb)
frameEndCb(frameEndCbData); frameEndCb(frameEndCbData);
C3D_FrameSplit(flags); C3D_FrameSplit(flags);
inFrame = false; GPUCMD_SetBuffer(NULL, 0, 0);
osTickCounterUpdate(&cpuTime); osTickCounterUpdate(&cpuTime);
inFrame = false;
// Flush the entire linear memory if the user did not explicitly mandate to flush the command list // Flush the entire linear memory if the user did not explicitly mandate to flush the command list
if (!(flags & GX_CMDLIST_FLUSH)) if (!(flags & GX_CMDLIST_FLUSH))
@ -255,16 +217,24 @@ void C3D_FrameEnd(u8 flags)
int i; int i;
C3D_RenderTarget* target; C3D_RenderTarget* target;
isTopStereo = false;
for (i = 2; i >= 0; i --) for (i = 2; i >= 0; i --)
{ {
target = linkedTarget[i]; target = linkedTarget[i];
if (!target || !target->used) if (!target || !target->used)
continue; continue;
target->used = false; target->used = false;
frameStage |= STAGE_HAS_TRANSFER(i); C3D_FrameBufTransfer(&target->frameBuf, target->screen, target->side, target->transferFlags);
if (target->screen == GFX_TOP)
{
needSwapTop = true;
if (target->side == GFX_RIGHT)
isTopStereo = true;
}
else if (target->screen == GFX_BOTTOM)
needSwapBot = true;
} }
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
measureGpuTime = true; measureGpuTime = true;
osTickCounterStart(&gpuTime); osTickCounterStart(&gpuTime);
gxCmdQueueRun(&ctx->gxQueue); gxCmdQueueRun(&ctx->gxQueue);
@ -307,8 +277,6 @@ static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target)
C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt) C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt)
{ {
if (!checkRenderQueueInit()) goto _fail0;
GPU_DEPTHBUF depthFmtReal = GPU_RB_DEPTH16; GPU_DEPTHBUF depthFmtReal = GPU_RB_DEPTH16;
void* depthBuf = NULL; void* depthBuf = NULL;
void* colorBuf = vramAlloc(C3D_CalcColorBufSize(width,height,colorFmt)); void* colorBuf = vramAlloc(C3D_CalcColorBufSize(width,height,colorFmt));
@ -316,7 +284,10 @@ C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF col
if (C3D_DEPTHTYPE_OK(depthFmt)) if (C3D_DEPTHTYPE_OK(depthFmt))
{ {
depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt); depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt);
depthBuf = vramAlloc(C3D_CalcDepthBufSize(width,height,depthFmtReal)); size_t depthSize = C3D_CalcDepthBufSize(width,height,depthFmtReal);
vramAllocPos vramBank = addrGetVRAMBank(colorBuf);
depthBuf = vramAllocAt(depthSize, vramBank ^ VRAM_ALLOC_ANY); // Attempt opposite bank first...
if (!depthBuf) depthBuf = vramAllocAt(depthSize, vramBank); // ... if that fails, attempt same bank
if (!depthBuf) goto _fail1; if (!depthBuf) goto _fail1;
} }
@ -345,8 +316,7 @@ _fail0:
C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt) C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt)
{ {
if (!checkRenderQueueInit()) return NULL; if (!addrIsVRAM(tex->data)) return NULL; // Render targets must be in VRAM
C3D_RenderTarget* target = C3Di_RenderTargetNew(); C3D_RenderTarget* target = C3Di_RenderTargetNew();
if (!target) return NULL; if (!target) return NULL;
@ -356,7 +326,10 @@ C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face,
if (C3D_DEPTHTYPE_OK(depthFmt)) if (C3D_DEPTHTYPE_OK(depthFmt))
{ {
GPU_DEPTHBUF depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt); GPU_DEPTHBUF depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt);
void* depthBuf = vramAlloc(C3D_CalcDepthBufSize(fb->width,fb->height,depthFmtReal)); size_t depthSize = C3D_CalcDepthBufSize(fb->width,fb->height,depthFmtReal);
vramAllocPos vramBank = addrGetVRAMBank(tex->data);
void* depthBuf = vramAllocAt(depthSize, vramBank ^ VRAM_ALLOC_ANY); // Attempt opposite bank first...
if (!depthBuf) depthBuf = vramAllocAt(depthSize, vramBank); // ... if that fails, attempt same bank
if (!depthBuf) if (!depthBuf)
{ {
free(target); free(target);
@ -389,7 +362,10 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target)
{ {
if (inFrame) if (inFrame)
svcBreak(USERBREAK_PANIC); // Shouldn't happen. svcBreak(USERBREAK_PANIC); // Shouldn't happen.
C3Di_WaitAndClearQueue(-1); if (target->linked)
C3D_RenderTargetDetachOutput(target);
else
C3Di_WaitAndClearQueue(-1);
C3Di_RenderTargetDestroy(target); C3Di_RenderTargetDestroy(target);
} }
@ -399,12 +375,19 @@ void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx
if (screen==GFX_BOTTOM) id = 2; if (screen==GFX_BOTTOM) id = 2;
else if (side==GFX_RIGHT) id = 1; else if (side==GFX_RIGHT) id = 1;
if (linkedTarget[id]) if (linkedTarget[id])
{
linkedTarget[id]->linked = false; linkedTarget[id]->linked = false;
if (!inFrame)
C3Di_WaitAndClearQueue(-1);
}
linkedTarget[id] = target; linkedTarget[id] = target;
target->linked = true; if (target)
target->transferFlags = transferFlags; {
target->screen = screen; target->linked = true;
target->side = side; target->transferFlags = transferFlags;
target->screen = screen;
target->side = side;
}
} }
static void C3Di_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags) static void C3Di_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)

View File

@ -30,12 +30,6 @@ static inline size_t fmtSize(GPU_TEXCOLOR fmt)
} }
} }
static inline bool addrIsVRAM(const void* addr)
{
u32 vaddr = (u32)addr;
return vaddr >= 0x1F000000 && vaddr < 0x1F600000;
}
static inline bool checkTexSize(u32 size) static inline bool checkTexSize(u32 size)
{ {
if (size < 8 || size > 1024) if (size < 8 || size > 1024)

View File

@ -47,10 +47,10 @@ ICON :=
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -g -Wall -O3 -mword-relocations \ CFLAGS := -g -Wall -O3 -mword-relocations \
-fomit-frame-pointer -ffunction-sections \ -ffunction-sections \
$(ARCH) $(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS CFLAGS += $(INCLUDE) -D__3DS__
CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++11 CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++11