Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9f21cf7b38 | ||
![]() |
00396e8a99 | ||
![]() |
66a0594e5d | ||
![]() |
e8825650c6 | ||
![]() |
e2992d276f | ||
![]() |
b6d0b7d876 | ||
![]() |
bbe09c4265 | ||
![]() |
a491a8eb79 | ||
![]() |
c7425b653e | ||
![]() |
100ebd4067 | ||
![]() |
03235602cd | ||
![]() |
4e02e27222 | ||
![]() |
05e8039b7f | ||
![]() |
f4367ad55d | ||
![]() |
bbbadebeae | ||
![]() |
7999093588 | ||
![]() |
dcb3aac861 | ||
![]() |
3d566ac8da | ||
![]() |
f2850e3bfe |
10
Makefile
10
Makefile
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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,6 +362,9 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target)
|
|||||||
{
|
{
|
||||||
if (inFrame)
|
if (inFrame)
|
||||||
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
||||||
|
if (target->linked)
|
||||||
|
C3D_RenderTargetDetachOutput(target);
|
||||||
|
else
|
||||||
C3Di_WaitAndClearQueue(-1);
|
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;
|
||||||
|
if (target)
|
||||||
|
{
|
||||||
target->linked = true;
|
target->linked = true;
|
||||||
target->transferFlags = transferFlags;
|
target->transferFlags = transferFlags;
|
||||||
target->screen = screen;
|
target->screen = screen;
|
||||||
target->side = side;
|
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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user