Compare commits

..

No commits in common. "master" and "v1.5.0" have entirely different histories.

14 changed files with 166 additions and 138 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 := 7 export CITRO3D_MINOR := 5
export CITRO3D_PATCH := 1 export CITRO3D_PATCH := 0
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 -Wno-sizeof-array-div -Werror -mword-relocations \ CFLAGS := -g -Wall -Werror -mword-relocations \
-ffunction-sections -fdata-sections \ -ffunction-sections -fdata-sections \
$(ARCH) $(BUILD_CFLAGS) $(ARCH) $(BUILD_CFLAGS)
CFLAGS += $(INCLUDE) -D__3DS__ -DCITRO3D_BUILD CFLAGS += $(INCLUDE) -DARM11 -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 -fno-math-errno" \ BUILD_CFLAGS="-DNDEBUG=1 -O2 -fomit-frame-pointer" \
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,6 +11,7 @@ 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);
@ -33,6 +34,23 @@ 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,14 +77,6 @@ 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,12 +13,7 @@
* 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 (6.28318530717958647692528676655900576) #define M_TAU (2*M_PI)
// 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,11 +64,6 @@ 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 CTR_ALIGN(8) typedef struct ALIGN(8)
{ {
u16 width; u16 width;
u16 height; u16 height;

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#if defined(__3DS__) || defined(_3DS) #ifdef _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,6 +8,14 @@ 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;
@ -42,12 +50,10 @@ 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;
@ -96,6 +102,10 @@ 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
@ -127,7 +137,6 @@ 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;
@ -327,6 +336,25 @@ 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;
@ -339,8 +367,11 @@ void C3D_Fini(void)
if (!(ctx->flags & C3DiF_Active)) if (!(ctx->flags & C3DiF_Active))
return; return;
aptUnhook(&hookCookie);
C3Di_RenderQueueExit(); C3Di_RenderQueueExit();
aptUnhook(&hookCookie);
gxCmdQueueStop(&ctx->gxQueue);
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,18 +124,6 @@ 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);
@ -152,9 +140,3 @@ 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,14 +250,6 @@ 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,16 +8,22 @@ 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 bool needSwapTop, needSwapBot, isTopStereo; static u8 frameStage;
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;
@ -31,12 +37,44 @@ 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]++;
} }
@ -57,18 +95,12 @@ static void onQueueFinish(gxCmdQueue_s* queue)
gxCmdQueueClear(queue); gxCmdQueueClear(queue);
} }
} }
else if (frameStage & STAGE_WAIT_TRANSFER)
frameStage &= ~STAGE_WAIT_TRANSFER;
else else
{ {
if (needSwapTop) u8 needs = frameStage & STAGE_HAS_ANY_TRANSFER;
{ frameStage = (frameStage&~STAGE_HAS_ANY_TRANSFER) | (needs<<3);
gfxScreenSwapBuffers(GFX_TOP, isTopStereo);
needSwapTop = false;
}
if (needSwapBot)
{
gfxScreenSwapBuffers(GFX_BOTTOM, false);
needSwapBot = false;
}
} }
} }
@ -94,60 +126,72 @@ 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;
} }
void C3Di_RenderQueueEnableVBlank(void) static void C3Di_RenderQueueInit(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);
} }
void C3Di_RenderQueueDisableVBlank(void) static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target);
{
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;
@ -162,17 +206,13 @@ 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;
} }
@ -197,15 +237,13 @@ 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);
GPUCMD_SetBuffer(NULL, 0, 0);
osTickCounterUpdate(&cpuTime);
inFrame = false; inFrame = false;
osTickCounterUpdate(&cpuTime);
// 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))
@ -217,24 +255,16 @@ 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;
C3D_FrameBufTransfer(&target->frameBuf, target->screen, target->side, target->transferFlags); frameStage |= STAGE_HAS_TRANSFER(i);
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);
@ -277,6 +307,8 @@ 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));
@ -284,10 +316,7 @@ 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);
size_t depthSize = C3D_CalcDepthBufSize(width,height,depthFmtReal); depthBuf = vramAlloc(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;
} }
@ -316,7 +345,8 @@ _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 (!addrIsVRAM(tex->data)) return NULL; // Render targets must be in VRAM if (!checkRenderQueueInit()) return NULL;
C3D_RenderTarget* target = C3Di_RenderTargetNew(); C3D_RenderTarget* target = C3Di_RenderTargetNew();
if (!target) return NULL; if (!target) return NULL;
@ -326,10 +356,7 @@ 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);
size_t depthSize = C3D_CalcDepthBufSize(fb->width,fb->height,depthFmtReal); void* depthBuf = vramAlloc(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);
@ -362,10 +389,7 @@ 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) C3Di_WaitAndClearQueue(-1);
C3D_RenderTargetDetachOutput(target);
else
C3Di_WaitAndClearQueue(-1);
C3Di_RenderTargetDestroy(target); C3Di_RenderTargetDestroy(target);
} }
@ -375,19 +399,12 @@ 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->transferFlags = transferFlags;
target->linked = true; target->screen = screen;
target->transferFlags = transferFlags; target->side = side;
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,6 +30,12 @@ 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 \
-ffunction-sections \ -fomit-frame-pointer -ffunction-sections \
$(ARCH) $(ARCH)
CFLAGS += $(INCLUDE) -D__3DS__ CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++11 CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++11