Compare commits

...

24 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
fincs
c22c354f1a Bump version for release 2019-01-02 00:29:47 +01:00
fincs
9d51a9445d Gas changes:
- Separate gas reg writes according to stages
- Related: Properly support C3D_GasAccMax
- Add C3D_GasBeginAcc
- Set correct gas depth function matching depth test in C3Di_EffectBind
2018-05-23 13:54:49 +02:00
fincs
ebf41b6436 Make sure framebuffer is flushed/reinitialized before changing program 2018-05-22 21:23:17 +02:00
fincs
8d8979947e Remove deprecated functionality 2018-05-22 16:56:19 +02:00
fincs
81ca5d3575 Begin adding Gas rendering support {incomplete/not fully RE'd} 2018-05-22 16:25:40 +02:00
19 changed files with 386 additions and 240 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.*/
*~
*.3dsx
*.elf

View File

@ -9,8 +9,8 @@ endif
include $(DEVKITARM)/3ds_rules
export CITRO3D_MAJOR := 1
export CITRO3D_MINOR := 4
export CITRO3D_PATCH := 0
export CITRO3D_MINOR := 7
export CITRO3D_PATCH := 1
VERSION := $(CITRO3D_MAJOR).$(CITRO3D_MINOR).$(CITRO3D_PATCH)
@ -31,11 +31,11 @@ INCLUDES := include
#---------------------------------------------------------------------------------
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 \
$(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
@ -114,7 +114,7 @@ debug:
lib/libcitro3d.a : lib release $(SOURCES) $(INCLUDES)
@$(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 \
--no-print-directory -C release \
-f $(CURDIR)/Makefile

View File

@ -11,7 +11,6 @@ enum
};
bool C3D_Init(size_t cmdBufSize);
void C3D_FlushAsync(void);
void C3D_Fini(void);
float C3D_GetCmdBufUsage(void);
@ -34,23 +33,6 @@ static inline void C3D_ImmDrawRestartPrim(void)
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
C3D_FVec* C3D_FixedAttribGetWritePtr(int id);

View File

@ -7,6 +7,12 @@ typedef struct
u32 data[128];
} C3D_FogLut;
typedef struct
{
u32 diff[8];
u32 color[8];
} C3D_GasLut;
static inline float FogLut_CalcZ(float depth, float near, float far)
{
return far*near/(depth*(far-near)+near);
@ -18,3 +24,16 @@ void FogLut_Exp(C3D_FogLut* lut, float density, float gradient, float near, floa
void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip);
void C3D_FogColor(u32 color);
void C3D_FogLutBind(C3D_FogLut* lut);
void GasLut_FromArray(C3D_GasLut* lut, const u32 data[9]);
void C3D_GasBeginAcc(void);
void C3D_GasDeltaZ(float value);
void C3D_GasAccMax(float value);
void C3D_GasAttn(float value);
void C3D_GasLightPlanar(float min, float max, float attn);
void C3D_GasLightView(float min, float max, float attn);
void C3D_GasLightDirection(float dotp);
void C3D_GasLutInput(GPU_GASLUTINPUT input);
void C3D_GasLutBind(C3D_GasLut* lut);

View File

@ -77,6 +77,14 @@ enum
void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector);
void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode);
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_LightEnvShadowSel(C3D_LightEnv* env, int texUnit);
void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp);

View File

@ -13,7 +13,12 @@
* The one true circumference-to-radius ratio.
* 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

View File

@ -14,9 +14,7 @@ struct C3D_RenderTarget_tag
bool linked;
gfxScreen_t screen;
gfx3dSide_t side;
C3D_ClearBits clearBits;
u32 transferFlags;
u32 clearColor, clearDepth;
};
// Flags for C3D_FrameBegin
@ -64,18 +62,18 @@ public:
C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt);
C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt);
void C3D_RenderTargetDelete(C3D_RenderTarget* target);
C3D_DEPRECATED void C3D_RenderTargetSetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth);
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)
{
C3D_FrameBufClear(&target->frameBuf, clearBits, clearColor, clearDepth);
}
C3D_DEPRECATED void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags);
C3D_DEPRECATED void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags);
C3D_DEPRECATED void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1);
void C3D_SyncDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags);
void C3D_SyncTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags);
void C3D_SyncMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1);

View File

@ -46,11 +46,6 @@ static inline void C3D_TexEnvInit(C3D_TexEnv* env)
#define _C3D_DEFAULT(x)
#endif
C3D_DEPRECATED static inline void TexEnv_Init(C3D_TexEnv* env)
{
C3D_TexEnvInit(env);
}
static inline void C3D_TexEnvSrc(C3D_TexEnv* env, C3D_TexEnvMode mode,
GPU_TEVSRC s1,
GPU_TEVSRC s2 _C3D_DEFAULT(GPU_PRIMARY_COLOR),
@ -63,15 +58,6 @@ static inline void C3D_TexEnvSrc(C3D_TexEnv* env, C3D_TexEnvMode mode,
env->srcAlpha = param;
}
C3D_DEPRECATED static inline void C3D_TexEnvOp(C3D_TexEnv* env, C3D_TexEnvMode mode, int o1, int o2, int o3)
{
int param = GPU_TEVOPERANDS(o1, o2, o3);
if ((int)mode & C3D_RGB)
env->opRgb = param;
if ((int)mode & C3D_Alpha)
env->opAlpha = param;
}
static inline void C3D_TexEnvOpRgb(C3D_TexEnv* env,
GPU_TEVOP_RGB o1,
GPU_TEVOP_RGB o2 _C3D_DEFAULT(GPU_TEVOP_RGB_SRC_COLOR),

View File

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

View File

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

View File

@ -38,7 +38,7 @@ extern "C" {
#endif
/** @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
{

View File

@ -8,14 +8,6 @@ C3D_Context __C3D_Context;
static aptHookCookie hookCookie;
__attribute__((weak)) void C3Di_RenderQueueWaitDone(void)
{
}
__attribute__((weak)) void C3Di_RenderQueueExit(void)
{
}
__attribute__((weak)) void C3Di_LightEnvUpdate(C3D_LightEnv* env)
{
(void)env;
@ -36,6 +28,11 @@ __attribute__((weak)) void C3Di_ProcTexDirty(C3D_Context* ctx)
(void)ctx;
}
__attribute__((weak)) void C3Di_GasUpdate(C3D_Context* ctx)
{
(void)ctx;
}
static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
{
C3D_Context* ctx = C3Di_GetContext();
@ -45,22 +42,27 @@ static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param)
case APTHOOK_ONSUSPEND:
{
C3Di_RenderQueueWaitDone();
C3Di_RenderQueueDisableVBlank();
break;
}
case APTHOOK_ONRESTORE:
{
C3Di_RenderQueueEnableVBlank();
ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_FrameBuf
| C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode
| C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv;
| C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv | C3DiF_Gas;
C3Di_DirtyUniforms(GPU_VERTEX_SHADER);
C3Di_DirtyUniforms(GPU_GEOMETRY_SHADER);
ctx->fixedAttribDirty |= ctx->fixedAttribEverDirty;
ctx->gasFlags |= C3DiG_BeginAcc | C3DiG_AccStage | C3DiG_RenderStage;
C3D_LightEnv* env = ctx->lightEnv;
if (ctx->fogLut)
ctx->flags |= C3DiF_FogLut;
if (ctx->gasLut)
ctx->flags |= C3DiF_GasLut;
if (env)
C3Di_LightEnvDirty(env);
C3Di_ProcTexDirty(ctx);
@ -94,10 +96,6 @@ bool C3D_Init(size_t cmdBufSize)
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;
// TODO: replace with direct struct access
@ -129,6 +127,7 @@ bool C3D_Init(size_t cmdBufSize)
ctx->fixedAttribDirty = 0;
ctx->fixedAttribEverDirty = 0;
C3Di_RenderQueueInit();
aptHook(&hookCookie, C3Di_AptEventHook, NULL);
return true;
@ -161,12 +160,6 @@ void C3Di_UpdateContext(void)
int i;
C3D_Context* ctx = C3Di_GetContext();
if (ctx->flags & C3DiF_Program)
{
shaderProgramConfigure(ctx->program, (ctx->flags & C3DiF_VshCode) != 0, (ctx->flags & C3DiF_GshCode) != 0);
ctx->flags &= ~(C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode);
}
if (ctx->flags & C3DiF_FrameBuf)
{
ctx->flags &= ~C3DiF_FrameBuf;
@ -192,6 +185,12 @@ void C3Di_UpdateContext(void)
GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, ctx->scissor, 3);
}
if (ctx->flags & C3DiF_Program)
{
shaderProgramConfigure(ctx->program, (ctx->flags & C3DiF_VshCode) != 0, (ctx->flags & C3DiF_GshCode) != 0);
ctx->flags &= ~(C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode);
}
if (ctx->flags & C3DiF_AttrInfo)
{
ctx->flags &= ~C3DiF_AttrInfo;
@ -233,9 +232,14 @@ void C3Di_UpdateContext(void)
if (ctx->flags & C3DiF_TexStatus)
{
ctx->flags &= ~C3DiF_TexStatus;
GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, ctx->texConfig);
GPUCMD_AddMaskedWrite(GPUREG_TEXUNIT_CONFIG, 0xB, ctx->texConfig);
// Clear texture cache if requested *after* configuring texture units
if (ctx->texConfig & BIT(16))
{
ctx->texConfig &= ~BIT(16);
GPUCMD_AddMaskedWrite(GPUREG_TEXUNIT_CONFIG, 0x4, BIT(16));
}
GPUCMD_AddWrite(GPUREG_TEXUNIT0_SHADOW, ctx->texShadow);
ctx->texConfig &= ~BIT(16); // Remove clear-texture-cache flag
}
if (ctx->flags & (C3DiF_ProcTex | C3DiF_ProcTexColorLut | C3DiF_ProcTexLutAll))
@ -249,7 +253,7 @@ void C3Di_UpdateContext(void)
GPUCMD_AddWrite(GPUREG_FOG_COLOR, ctx->fogClr);
}
if (ctx->flags & C3DiF_FogLut)
if ((ctx->flags & C3DiF_FogLut) && (ctx->texEnvBuf&7) != GPU_NO_FOG)
{
ctx->flags &= ~C3DiF_FogLut;
if (ctx->fogLut)
@ -259,6 +263,9 @@ void C3Di_UpdateContext(void)
}
}
if ((ctx->texEnvBuf&7) == GPU_GAS)
C3Di_GasUpdate(ctx);
if (ctx->flags & C3DiF_TexEnvAll)
{
for (i = 0; i < 6; i ++)
@ -320,25 +327,6 @@ bool C3Di_SplitFrame(u32** pBuf, u32* pSize)
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)
{
return C3Di_GetContext()->cmdBufUsage;
@ -351,11 +339,8 @@ void C3D_Fini(void)
if (!(ctx->flags & C3DiF_Active))
return;
C3Di_RenderQueueExit();
aptUnhook(&hookCookie);
gxCmdQueueStop(&ctx->gxQueue);
gxCmdQueueWait(&ctx->gxQueue, -1);
GX_BindQueue(NULL);
C3Di_RenderQueueExit();
free(ctx->gxQueue.entries);
linearFree(ctx->cmdBuf);
ctx->flags = 0;

View File

@ -93,6 +93,7 @@ void C3Di_EffectBind(C3D_Effect* e)
GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, e->cullMode & 0x3);
GPUCMD_AddIncrementalWrites(GPUREG_DEPTHMAP_SCALE, (u32*)&e->zScale, 2);
GPUCMD_AddIncrementalWrites(GPUREG_FRAGOP_ALPHA_TEST, (u32*)&e->alphaTest, 4);
GPUCMD_AddMaskedWrite(GPUREG_GAS_DELTAZ_DEPTH, 0x8, (u32)GPU_MAKEGASDEPTHFUNC((e->depthTest>>4)&7) << 24);
GPUCMD_AddWrite(GPUREG_BLEND_COLOR, e->blendClr);
GPUCMD_AddWrite(GPUREG_BLEND_FUNC, e->alphaBlend);
GPUCMD_AddWrite(GPUREG_LOGIC_OP, e->clrLogicOp);

184
source/gas.c Normal file
View File

@ -0,0 +1,184 @@
#include "internal.h"
static inline u32 calc_diff(u32 a, u32 b, int pos)
{
float fa = ((a>>pos)&0xFF)/255.0f;
float fb = ((b>>pos)&0xFF)/255.0f;
float x = fb-fa;
u32 diff = 0;
if (x < 0)
{
diff = 0x80;
x = -x;
}
diff |= (u32)(x*0x7F);
return diff<<pos;
}
static inline u32 conv_u8(float x, int pos)
{
if (x < 0.0f) x = 0.0f;
else if (x > 1.0f) x = 1.0f;
return ((u32)x*255)<<pos;
}
static inline u32 color_diff(u32 a, u32 b)
{
return calc_diff(a,b,0) | calc_diff(a,b,8) | calc_diff(a,b,16);
}
void GasLut_FromArray(C3D_GasLut* lut, const u32 data[9])
{
int i;
for (i = 0; i <= 8; i ++)
{
if (i < 8)
lut->color[i] = data[i];
if (i > 0)
lut->diff[i-1] = color_diff(data[i-1], data[i]);
}
}
void C3D_GasBeginAcc(void)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->gasFlags |= C3DiG_BeginAcc;
}
void C3D_GasDeltaZ(float value)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasDeltaZ = (u32)(value*0x100);
ctx->gasFlags |= C3DiG_AccStage;
}
void C3D_GasAccMax(float value)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasAccMax = f32tof16(1.0f / value);
ctx->gasFlags |= C3DiG_SetAccMax;
}
void C3D_GasAttn(float value)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasAttn = f32tof16(value);
ctx->gasFlags |= C3DiG_RenderStage;
}
void C3D_GasLightPlanar(float min, float max, float attn)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasLightXY = conv_u8(min,0) | conv_u8(max,8) | conv_u8(attn,16);
ctx->gasFlags |= C3DiG_RenderStage;
}
void C3D_GasLightView(float min, float max, float attn)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasLightZ = conv_u8(min,0) | conv_u8(max,8) | conv_u8(attn,16);
ctx->gasFlags |= C3DiG_RenderStage;
}
void C3D_GasLightDirection(float dotp)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasLightZColor &= ~0xFF;
ctx->gasLightZColor |= conv_u8(dotp,0);
ctx->gasFlags |= C3DiG_RenderStage;
}
void C3D_GasLutInput(GPU_GASLUTINPUT input)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
ctx->flags |= C3DiF_Gas;
ctx->gasLightZColor &= ~0x100;
ctx->gasLightZColor |= (input&1)<<8;
ctx->gasFlags |= C3DiG_RenderStage;
}
void C3D_GasLutBind(C3D_GasLut* lut)
{
C3D_Context* ctx = C3Di_GetContext();
if (!(ctx->flags & C3DiF_Active))
return;
if (lut)
{
ctx->flags |= C3DiF_GasLut;
ctx->gasLut = lut;
} else
ctx->flags &= ~C3DiF_GasLut;
}
void C3Di_GasUpdate(C3D_Context* ctx)
{
if (ctx->flags & C3DiF_Gas)
{
ctx->flags &= ~C3DiF_Gas;
u32 gasFlags = ctx->gasFlags;
ctx->gasFlags = 0;
if (gasFlags & C3DiG_BeginAcc)
GPUCMD_AddMaskedWrite(GPUREG_GAS_ACCMAX_FEEDBACK, 0x3, 0);
if (gasFlags & C3DiG_AccStage)
GPUCMD_AddMaskedWrite(GPUREG_GAS_DELTAZ_DEPTH, 0x7, ctx->gasDeltaZ);
if (gasFlags & C3DiG_SetAccMax)
GPUCMD_AddWrite(GPUREG_GAS_ACCMAX, ctx->gasAccMax);
if (gasFlags & C3DiG_RenderStage)
{
GPUCMD_AddWrite(GPUREG_GAS_ATTENUATION, ctx->gasAttn);
GPUCMD_AddWrite(GPUREG_GAS_LIGHT_XY, ctx->gasLightXY);
GPUCMD_AddWrite(GPUREG_GAS_LIGHT_Z, ctx->gasLightZ);
GPUCMD_AddWrite(GPUREG_GAS_LIGHT_Z_COLOR, ctx->gasLightZColor);
}
}
if (ctx->flags & C3DiF_GasLut)
{
ctx->flags &= ~C3DiF_GasLut;
if (ctx->gasLut)
{
GPUCMD_AddWrite(GPUREG_GAS_LUT_INDEX, 0);
GPUCMD_AddWrites(GPUREG_GAS_LUT_DATA, (u32*)ctx->gasLut, 16);
}
}
}

View File

@ -52,6 +52,12 @@ typedef struct
u32 fogClr;
C3D_FogLut* fogLut;
u16 gasAttn, gasAccMax;
u32 gasLightXY, gasLightZ, gasLightZColor;
u32 gasDeltaZ : 24;
u32 gasFlags : 8;
C3D_GasLut* gasLut;
C3D_ProcTex* procTex;
C3D_ProcTexLut* procTexLut[3];
C3D_ProcTexColorLut* procTexColorLut;
@ -83,6 +89,8 @@ enum
C3DiF_ProcTex = BIT(15),
C3DiF_ProcTexColorLut = BIT(16),
C3DiF_FogLut = BIT(17),
C3DiF_Gas = BIT(18),
C3DiF_GasLut = BIT(19),
#define C3DiF_ProcTexLut(n) BIT(20+(n))
C3DiF_ProcTexLutAll = 7 << 20,
@ -92,6 +100,14 @@ enum
C3DiF_TexEnvAll = 0x3F << 26,
};
enum
{
C3DiG_BeginAcc = BIT(0),
C3DiG_AccStage = BIT(1),
C3DiG_SetAccMax = BIT(2),
C3DiG_RenderStage = BIT(3),
};
static inline C3D_Context* C3Di_GetContext(void)
{
extern C3D_Context __C3D_Context;
@ -108,6 +124,18 @@ static inline bool C3Di_TexIs2D(C3D_Tex* 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_AttrInfoBind(C3D_AttrInfo* info);
void C3Di_BufInfoBind(C3D_BufInfo* info);
@ -115,6 +143,7 @@ void C3Di_FrameBufBind(C3D_FrameBuf* fb);
void C3Di_TexEnvBind(int id, C3D_TexEnv* env);
void C3Di_SetTex(int unit, C3D_Tex* tex);
void C3Di_EffectBind(C3D_Effect* effect);
void C3Di_GasUpdate(C3D_Context* ctx);
void C3Di_LightMtlBlend(C3D_Light* light);
@ -123,3 +152,9 @@ void C3Di_LoadShaderUniforms(shaderInstance_s* si);
void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type);
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;
}
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)
{
mode &= 0xF<<16;

View File

@ -8,22 +8,16 @@ static C3D_RenderTarget *linkedTarget[3];
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 u8 frameStage;
static bool needSwapTop, needSwapBot, isTopStereo;
static float framerate = 60.0f;
static float framerateCounter[2] = { 60.0f, 60.0f };
static u32 frameCounter[2];
static void (* frameEndCb)(void*);
static void* frameEndCbData;
static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target);
static bool framerateLimit(int id)
{
framerateCounter[id] -= framerate;
@ -37,50 +31,12 @@ static bool framerateLimit(int id)
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);
if (left && left->clearBits)
C3D_FrameBufClear(&left->frameBuf, left->clearBits, left->clearColor, left->clearDepth);
if (right && right != left && right->clearBits)
C3D_FrameBufClear(&right->frameBuf, right->clearBits, right->clearColor, right->clearDepth);
gfxConfigScreen(GFX_TOP, false);
}
}
if (framerateLimit(0))
frameCounter[0]++;
}
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);
if (target->clearBits)
C3D_FrameBufClear(&target->frameBuf, target->clearBits, target->clearColor, target->clearDepth);
gfxConfigScreen(GFX_BOTTOM, false);
}
}
if (framerateLimit(1))
frameCounter[1]++;
}
@ -101,12 +57,18 @@ static void onQueueFinish(gxCmdQueue_s* queue)
gxCmdQueueClear(queue);
}
}
else if (frameStage & STAGE_WAIT_TRANSFER)
frameStage &= ~STAGE_WAIT_TRANSFER;
else
{
u8 needs = frameStage & STAGE_HAS_ANY_TRANSFER;
frameStage = (frameStage&~STAGE_HAS_ANY_TRANSFER) | (needs<<3);
if (needSwapTop)
{
gfxScreenSwapBuffers(GFX_TOP, isTopStereo);
needSwapTop = false;
}
if (needSwapBot)
{
gfxScreenSwapBuffers(GFX_BOTTOM, false);
needSwapBot = false;
}
}
}
@ -132,72 +94,60 @@ static bool C3Di_WaitAndClearQueue(s64 timeout)
gxCmdQueue_s* queue = &C3Di_GetContext()->gxQueue;
if (!gxCmdQueueWait(queue, timeout))
return false;
if (timeout==0 && frameStage)
return false;
while (frameStage)
gspWaitForAnyEvent();
gxCmdQueueStop(queue);
gxCmdQueueClear(queue);
return true;
}
static void C3Di_RenderQueueInit(void)
void C3Di_RenderQueueEnableVBlank(void)
{
gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, 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)
{
int i;
C3D_RenderTarget *a, *next;
if (!initialized)
return;
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)
{
next = a->next;
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)
{
if (!initialized)
return;
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 old = framerate;
@ -212,13 +162,17 @@ float C3D_FrameRate(float fps)
bool C3D_FrameBegin(u8 flags)
{
C3D_Context* ctx = C3Di_GetContext();
if (inFrame) return false;
if (flags & C3D_FRAME_SYNCDRAW)
C3D_FrameSync();
if (!C3Di_WaitAndClearQueue((flags & C3D_FRAME_NONBLOCK) ? 0 : -1))
return false;
inFrame = true;
osTickCounterStart(&cpuTime);
GPUCMD_SetBuffer(ctx->cmdBuf, ctx->cmdBufSize, 0);
return true;
}
@ -243,13 +197,15 @@ void C3D_FrameSplit(u8 flags)
void C3D_FrameEnd(u8 flags)
{
C3D_Context* ctx = C3Di_GetContext();
if (!inFrame) return;
if (frameEndCb)
frameEndCb(frameEndCbData);
C3D_FrameSplit(flags);
inFrame = false;
GPUCMD_SetBuffer(NULL, 0, 0);
osTickCounterUpdate(&cpuTime);
inFrame = false;
// Flush the entire linear memory if the user did not explicitly mandate to flush the command list
if (!(flags & GX_CMDLIST_FLUSH))
@ -261,24 +217,24 @@ void C3D_FrameEnd(u8 flags)
int i;
C3D_RenderTarget* target;
isTopStereo = false;
for (i = 2; i >= 0; i --)
{
target = linkedTarget[i];
if (!target || !target->used)
continue;
target->used = false;
frameStage |= STAGE_HAS_TRANSFER(i);
}
for (target = firstTarget; target; target = target->next)
C3D_FrameBufTransfer(&target->frameBuf, target->screen, target->side, target->transferFlags);
if (target->screen == GFX_TOP)
{
if (!target->used || !target->clearBits)
continue;
target->used = false;
C3D_FrameBufClear(&target->frameBuf, target->clearBits, target->clearColor, target->clearDepth);
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;
osTickCounterStart(&gpuTime);
gxCmdQueueRun(&ctx->gxQueue);
@ -321,8 +277,6 @@ static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target)
C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt)
{
if (!checkRenderQueueInit()) goto _fail0;
GPU_DEPTHBUF depthFmtReal = GPU_RB_DEPTH16;
void* depthBuf = NULL;
void* colorBuf = vramAlloc(C3D_CalcColorBufSize(width,height,colorFmt));
@ -330,7 +284,10 @@ C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF col
if (C3D_DEPTHTYPE_OK(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;
}
@ -359,8 +316,7 @@ _fail0:
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();
if (!target) return NULL;
@ -370,7 +326,10 @@ C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face,
if (C3D_DEPTHTYPE_OK(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)
{
free(target);
@ -403,37 +362,33 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target)
{
if (inFrame)
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
if (target->linked)
C3D_RenderTargetDetachOutput(target);
else
C3Di_WaitAndClearQueue(-1);
C3Di_RenderTargetDestroy(target);
}
void C3D_RenderTargetSetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth)
{
if (!target->frameBuf.colorBuf) clearBits &= ~C3D_CLEAR_COLOR;
if (!target->frameBuf.depthBuf) clearBits &= ~C3D_CLEAR_DEPTH;
C3D_ClearBits oldClearBits = target->clearBits;
target->clearBits = clearBits;
target->clearColor = clearColor;
target->clearDepth = clearDepth;
if (clearBits &~ oldClearBits)
C3D_FrameBufClear(&target->frameBuf, clearBits, clearColor, clearDepth);
}
void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags)
{
int id = 0;
if (screen==GFX_BOTTOM) id = 2;
else if (side==GFX_RIGHT) id = 1;
if (linkedTarget[id])
{
linkedTarget[id]->linked = false;
if (!inFrame)
C3Di_WaitAndClearQueue(-1);
}
linkedTarget[id] = target;
if (target)
{
target->linked = true;
target->transferFlags = transferFlags;
target->screen = screen;
target->side = side;
}
}
static void C3Di_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)
{
@ -459,21 +414,6 @@ static void C3Di_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0,
gxCmdQueueRun(&C3Di_GetContext()->gxQueue);
}
void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)
{
C3Di_SafeDisplayTransfer(inadr, indim, outadr, outdim, flags);
}
void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags)
{
C3Di_SafeTextureCopy(inadr, indim, outadr, outdim, size, flags);
}
void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1)
{
C3Di_SafeMemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1);
}
void C3D_SyncDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)
{
if (inFrame)

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)
{
if (size < 8 || size > 1024)

View File

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