Coder Social home page Coder Social logo

devkitpro / citro3d Goto Github PK

View Code? Open in Web Editor NEW
236.0 24.0 31.0 281 KB

Homebrew PICA200 GPU wrapper library for Nintendo 3DS

License: zlib License

Makefile 6.44% C 68.04% C++ 25.53%
gpu pica200 nintendo nintendo-3ds libctru ctrulib devkitpro homebrew graphics

citro3d's Introduction

citro3d

citro3d is a library that provides an easy to use stateful interface to the PICA200 GPU of the Nintendo 3DS. It tries to expose hardware functionality in the way that is most natural and convenient to the GPU and the user, therefore deviating from openGL.

Setup

citro3d can be built and installed using the following command:

make install

License

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

citro3d's People

Contributors

cruel avatar fincs avatar mtheall avatar oreo639 avatar tommai78101 avatar wintermute avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

citro3d's Issues

Missing triangles when using the renderqueue system

I experienced a problem with the render queue system, a few triangles won't render(only a two or three), which one depend on the view angle.
By flushing the whole linear heap it reduced the artefact. When 3D is disabled it reduces the artefact, so it has something with the amount of draw calls and/or the amount triangles(Also when 3D is enabled the triangles flicker, because won't get drawn in only one frame).

Finally by moving from the render queue system to manually using render buffers everything worked as it should.

You can find the relevant code here: https://github.com/RSDuck/Craftus3DS/blob/master/source/craftus/render/render.c(look at the history to see how it was before)

Binding programs without drawing anything can result in inconsistent uniform state

  1. Bind a program with a geometry shader.
  2. Set the first uniform in the geometry shader to value A.
  3. Without rendering anything, bind a different program without a geometry shader.
  4. Set the first uniform in the vertex shader to value B.
  5. Render something. The results will use value A.

Adding a C3D_UpdateUniforms(GPU_GEOMETRY_SHADER) between steps 2 and 3 fixes the problem.

If I understand the internals correctly, the problem is that the C3D_{FV,IV,Bool}UnifDirty flags don't get cleared when binding a new program.

Build issues with updated devkitpro install AND latest ctrulib installed

arm-none-eabi-gcc -MMD -MP -MF /c/Projects/citro3d/build/attribs.d -g -Wall -Wextra -Werror -O2 -mword-relocations -fomit-frame-pointer -ffunction-sections -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -I/c/Projects/citro3d/include -I/c/devkitPro/libctru/include -I/c/Projects/citro3d/build -DARM11 -D_3DS -DCITRO3D_BUILD -c /c/Projects/citro3d/source/attribs.c -o attribs.o
base.c
arm-none-eabi-gcc -MMD -MP -MF /c/Projects/citro3d/build/base.d -g -Wall -Wextra -Werror -O2 -mword-relocations -fomit-frame-pointer -ffunction-sections -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -I/c/Projects/citro3d/include -I/c/devkitPro/libctru/include -I/c/Projects/citro3d/build -DARM11 -D_3DS -DCITRO3D_BUILD -c /c/Projects/citro3d/source/base.c -o base.o
c:/Projects/citro3d/source/base.c: In function 'C3Di_FinalizeFrame':
c:/Projects/citro3d/source/base.c:275:2: error: 'GPUCMD_Finalize' is deprecated [-Werror=deprecated-declarations]
GPUCMD_Finalize();
^~~~~~~~~~~~~~~
In file included from c:/devkitPro/libctru/include/3ds.h:69:0,
from c:/Projects/citro3d/include/c3d/types.h:3,
from c:/Projects/citro3d/include/c3d/attribs.h:2,
from c:/Projects/citro3d/source/internal.h:2,
from c:/Projects/citro3d/source/base.c:1:
c:/devkitPro/libctru/include/3ds/gpu/gpu.h:81:17: note: declared here
DEPRECATED void GPUCMD_Finalize(void);
^~~~~~~~~~~~~~~
cc1.exe: all warnings being treated as errors
make[1]: *** [base.o] Error 1
make: *** [build] Error 2

Question: Is it possible to change a render target's frame buffer format mid-program?

I'm trying to improve a program that can run different classic adventure games, each having their own color format(s) under which they run. Some of the more graphically-intensive games that have a 16-bit native color format (namely RGB565) run slowly on the 3DS because they're being converted up to RGBA8 so they can be passed to the render target.

I can't just change the program to run in a 16-bit color format because some of the games have a native 32-bit color format, so I think the best solution would be to change the render target's color buffer appropriately when a game is started. Is this even possible to do with citro3d? If so, do you have any suggestions on how I should go about it? I've been trying on my own, but I've not had any luck.

Here's the backend source for reference, and here is what I've done so far: BallM4788/scummvm@08e9557. Most of the relevant code is in "osystem-graphics.cpp," "sprite.h," and "sprite.cpp." "OSystem_3DS::initGraphics" is called during startup, and "OSystem_3DS::initSize" is called when loading up a game.

In what I've done so far, everything works fine with games that are non-16-bit or can adapt to 32-bit, but attempting to start up a 16-bit game (in my case, I've been using Riven for testing), a black screen shows, but the 3DS doesn't crash. The only way to get back to the 3DS home screen at that point is to hold the power button until the 3DS turns off and then turn it back on again.

[Hardware Quirk] GPU hangs if one shader program has a geo component and the other doesn't

In working this demo using two different shader programs to draw a scene, I was getting a hard GPU hang on real hardware (and not on Citra). I narrowed the cause down to one shader I was using having a geo part as well as a vertex part and the other one just having a vertex part. If you flip-flopped which shader you used every frame, there'd be no issue.

Here's a demonstration based on the composite_scene example. This exhibits the same behavior I was running into. However, I just went and made another one based on the lenny example and this one doesn't seem to hang. Is something done in citro2d the culprit? Or is the lenny-based example not hanging because the shader programs are basically the same aside from the geo part?

I was told to submit an issue here. Hopefully this helps out!

parallel calls to C3D_SyncDisplayTransfer and gspWaitForVBlank cause lockup

I have the following issue: My homebrew consists of two threads, one thread drawing textures to the screen inbetween calls to gspWaitForVBlank, the other thread setting up the textures. Now, I'm facing the issue that I have random lockups and the backtraces from gdb always look like this:

Thread 1 (drawing thread):

Thread 7 (Thread 266):
#0  svcArbitrateAddress ()
    at /home/fincs/pacman-packages/libctru/src/ctrulib-1.6.0/libctru/source/svc.s:250
#1  0x002a993c in LightEvent_Wait (event=0x173458c <gspEvents+16>,
    event@entry=0x17213a4 <runThread>)
    at /home/fincs/pacman-packages/libctru/src/ctrulib-1.6.0/libctru/source/synchronization.c:206
#2  0x002aed88 in gspWaitForEvent (id=id@entry=GSPGPU_EVENT_VBlank0,
    nextEvent=nextEvent@entry=true)
    at /home/fincs/pacman-packages/libctru/src/ctrulib-1.6.0/libctru/source/services/gspgpu.c:86
#3  0x002604c0 in videoThread (data=<optimized out>)
    at src/video/n3ds/SDL_n3dsvideo.c:549
[...]

Thread 2 (texture setup & main thread):

Thread 1 (Thread 243):
#0  svcArbitrateAddress ()
    at /home/fincs/pacman-packages/libctru/src/ctrulib-1.6.0/libctru/source/svc.s:250
#1  0x002aede8 in gspWaitForAnyEvent ()
    at /home/fincs/pacman-packages/libctru/src/ctrulib-1.6.0/libctru/source/services/gspgpu.c:106
#2  0x002a602c in C3Di_WaitAndClearQueue (timeout=<optimized out>)
    at /home/fincs/pacman-packages/citro3d/src/source/renderqueue.c:132
#3  0x002a66d4 in C3Di_SafeDisplayTransfer (flags=3, outdim=33554944,
    outadr=0x30a2ba00, indim=33554944, inadr=0x3092ba00)
    at /home/fincs/pacman-packages/citro3d/src/source/renderqueue.c:442
#4  C3D_SyncDisplayTransfer (inadr=0x3092ba00, indim=33554944,
    outadr=0x30a2ba00, outdim=33554944, flags=3)
    at /home/fincs/pacman-packages/citro3d/src/source/renderqueue.c:442
#5  0x0025f6e8 in drawBuffers (this=<optimized out>)
    at src/video/n3ds/SDL_n3dsvideo.c:566
[...]

Is this a C3D-bug? Or am I doing something wrong?

Softlock when nothing is drawn

Specifically, if I have Citro render the top screen render target, but I don't draw anything, it will go through two cycles before soft locking. Removing this rendertarget stuff in aptMainLoop fixes this (which broke my FPS timer :P)

Emulation on Citra

Apparently the solution is to fool the render targets by applying a completely transparent texture at all times--something I'd rather not do. I've tested both builds on my 3DS and they behave as shown on Citra.

public functions changed to inline static

Hello !

I'm working on cpp3ds so it will be compatible with the 1.3.0 and there is some strange changes in the lib.

A lot of functions changed and have "static inline" instead of being defined in .h (like C3D_TexInit)
Those functions are not used at all in citro3d, so I suppose they were created for external use.

I'm not a pro on the C language, but after I googled, if I understand well, inline static are used to enhance performance when the function is used a lot in the code. And so inline functions are not visible outside of the file itself.

So why can't we use those functions, if they are not used at all in the code ? Is there a way to call them ? Will they be removed ? Or was it an error ?

`C3D_SetScissor` does not work as intended?

The arguments to C3D_SetScissor after the first are left, right, top, bottom. Calling the function like this in the gpusprites example in the examples repo:

C3D_SetScissor(GPU_SCISSOR_NORMAL, 0, 0, 400, 240);

...yields:

image

...which is not what I would expect (a no-op in this case). It renders the same way on console. Is there a bug here?

Texture init fails when default data pointer is not null

I'm referring to this line. This is what I expect to work:

C3D_Tex tex;
C3D_TexInit(&tex, 64, 64, GPU_RGB8);

However it will fail depending on the initial value of the data pointer. At the moment, I just use tex.data = NULL; before it. Perhaps it's better to trust the user won't initialize multiple times instead of requiring the struct to be zero'd?

[Hardware Quirk] BufInfo_Add stride behaves strangely on hardware

It looks like when the stride given to BufInfo_Add is larger than the attribute, behavior is very unstable. It will often crash depending on what stride you use, or simply display incorrect data. It will run fine on Citra.

Examples:

AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 2);

// No crash
BufInfo_Add(mBufferInfo, data, sizeof(float) * 2, 1, 0x0);

// Crash
BufInfo_Add(mBufferInfo, data, sizeof(float) * 4, 1, 0x0);

C3D_TexEnvOp() regarding alpha channel - writing into wrong spots

Based on the source code for the texture environment structures, you have RGB and Alpha separated. That's correct for most parts, but the operand has a slight overlap and a 1-bit separation with Alpha. In sections of 4-byte word (0:31), RGB operand components R, G, and B cover bits 0:3, 4:7, and 8:11. The Alpha operand structure does not follow this, but leaks into the previous first half of the word type, starting with 12:14 for the first component, then skips a bit to set 16:18 for the 2nd component, then another bit skip for 20:22 with the 3rd component. Found this out when attempting to use ONE_MINUS_SRC_ALPHA with the first component and nothing changed. Manually added 0x1000 to opRGB after setting up the overall texture combiner, and it worked in flipping the alpha values of a texture.

Missing texture formats

Currently, these are the valid formats used in citro3D within texture.c

RGBA8, RGB8, RGBA5551, RGB565, RGBA4

It is missing the others like L8 (this particular one has a size of 1). This is not only important because people might use these other formats, but because this issue is linked to the 2nd part of the last issue I brought up (which currently displays a black cube). Added L8 as a valid format with a return value of 1, then made alterations to the other project, and now it's displaying what it should.

is C3D_FrameBufTransfer a blit operation ?

Hi,
I am posting because i was working on porting godot 4 to the 3ds and godot 4 works via render lists that are then blit on the appropriate windows at the end of a frame.
the concept works, but i am not too sure about where to go about it on citro3d, i imagine that each godot rendertarget would use a C3D_RenderTarget or a C3D_FrameBuf, however, i am not too sure about how i am supposed to blit all of them to the screen's framebuf at the end. I don't see any examples of this type of stuff

i checked c3d's source and noticed that in frameend, c3d_framebuftransfer is used, i'm wondering if it is what i would need

Offscreen Rendertargets

Hey I was wondering: is it possible to make offscreen rendertargets?

For example, I want to draw something once to the rendertarget and then later draw it as one big image. My current code doesn't work, and I'm not sure that it's doable right now.

See here for more details.

Also, code:

int Graphics::SetCanvas(lua_State * L)
{
	if (!lua_isnoneornil(L, 1))
	{	
		Canvas * self = (Canvas *)luaobj_checkudata(L, 1, LUAOBJ_TYPE_CANVAS);

		lastCanvas = self;
				
		C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
		
		C3D_FrameDrawOn(self->GetTarget()->GetTarget());
		
		//C3D_SetFrameBuf(&self->GetTarget()->GetTarget()->frameBuf);
	
		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, projection_desc, self->GetTarget()->GetProjection());

		self->GetTarget()->Clear(graphicsGetBackgroundColor());
	}
	else
	{
		if (lastCanvas == nullptr)
			return 0;

		C3D_FrameBuf * fb = &lastCanvas->GetTarget()->GetTarget()->frameBuf;
		lastCanvas->SetTexture(fb);

		C3D_FrameSync();
	}

	return 0;
}

Crash when switching from non-800px mode to 800px mode?

I'm not sure if this is meant to be supported, but if I try to change between 400px mode and 800px mode (i.e. C3D_RenderTargetDelete / C3D_RenderTargetCreate) my console crashes - crash_dump_00000001.dmp.gz

a) is this a supported behaviour
b) are there some steps I'm not doing?

I'm doing something along the lines of:

    if (gTarget != NULL) // top left screen
    {
        C3D_RenderTargetDelete(gTarget);
        gTarget = NULL;
    }
    if (gTargetRight != NULL) // top right screen
    {
        C3D_RenderTargetDelete(gTargetRight);
        gTargetRight = NULL;
    }

    /// am I missing some steps??

    bool useAA = gfx_config.useAA;
    bool useWide =  gfx_config.useWide; // e.g. toggling between false to true = crash

    u32 transferFlags =
        GX_TRANSFER_FLIP_VERT(0) |
        GX_TRANSFER_OUT_TILED(0) |
        GX_TRANSFER_RAW_COPY(0) |
        GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
        GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8);

    if (useAA && !useWide)
        transferFlags |= GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_XY);
    else if (useAA && useWide)
        transferFlags |= GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_X);
    else
        transferFlags |= GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO);

    int width = useAA || useWide ? 800 : 400;
    int height = useAA ? 480 : 240;

    gTarget  = C3D_RenderTargetCreate(height, width, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
    C3D_RenderTargetSetOutput(gTarget,  GFX_TOP, GFX_LEFT,  transferFlags);

    if (!useWide)
    {
        gTargetRight = C3D_RenderTargetCreate(height, width, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
        C3D_RenderTargetSetOutput(gTargetRight, GFX_TOP, GFX_RIGHT, transferFlags);
        gfxSet3D(true);
    }
    else
    {
        gfxSetWide(true);
    }

The code is from the 3ds sm64 port...

strange soft lock

it run follow step:

Loop:

while (aptMainLoop())
{
        gspWaitForVBlank();
        PPGraphics::Get()->BeginRender();
        PPGraphics::Get()->RenderOn(GFX_TOP);
	sm->UpdateFrameTracker();   // Step 1 
	PPGraphics::Get()->DrawTopScreenSprite(); // Step 2
        PPGraphics::Get()->EndRender();
}

1, Update frame function

void PPGraphics::UpdateTopScreenSprite(u8* data, u32 size, u32 width, u32 height)
{
	mTopScreenSprite->width = width;
	mTopScreenSprite->height = height;

	u8* linearData = (u8*)linearAlloc(sizeof(u8) * size);
	memcpy(linearData, data, size);

	if(!mTopScreenSprite->initialized)
	{
		mTopScreenSprite->initialized = true;
		GSPGPU_FlushDataCache(linearData, size);
		C3D_TexInit(&mTopScreenSprite->spriteTexture, width, height, GPU_RGB8);
		u32 dim = GX_BUFFER_DIM(width, height);
		C3D_SafeDisplayTransfer((u32*)linearData, dim, (u32*)mTopScreenSprite->spriteTexture.data, dim, TEXTURE_TRANSFER_FLAGS);
		gspWaitForPPF();
		C3D_TexSetFilter(&mTopScreenSprite->spriteTexture, GPU_LINEAR, GPU_NEAREST);

	}else
	{
		GSPGPU_FlushDataCache(linearData, size);
		u32 dim = GX_BUFFER_DIM(width, height);
		C3D_SafeDisplayTransfer((u32*)linearData, dim, (u32*)mTopScreenSprite->spriteTexture.data, dim, TEXTURE_TRANSFER_FLAGS);
		gspWaitForPPF();
		C3D_TexSetFilter(&mTopScreenSprite->spriteTexture, GPU_LINEAR, GPU_NEAREST);
	}
	linearFree(linearData);
}

2, Draw frame if texture is initialized


void PPGraphics::DrawTopScreenSprite()
{
	if (!mTopScreenSprite->initialized) {
		return;
	}
	
	ppVertexPosTex* vertices = (ppVertexPosTex*)allocMemoryPoolAligned(sizeof(ppVertexPosTex) * 4, 8);
	if (!vertices)
		return; // out of memory in pool
	float x = 0, y = 0, w = 400.0f, h = 240.0f;
	// set position
	vertices[0].position = (ppVector3) { x, y, 0.5f };
	vertices[1].position = (ppVector3) { x + w, y, 0.5f };
	vertices[2].position = (ppVector3) { x, y + h, 0.5f };
	vertices[3].position = (ppVector3) { x + w, y + h, 0.5f };

	// set color
	vertices[0].textcoord = (ppVector2) { 0.0f, 0.0f };
	vertices[1].textcoord = (ppVector2) { 1.0f, 0.0f };
	vertices[2].textcoord = (ppVector2) { 0.0f, 1.0f};
	vertices[3].textcoord = (ppVector2) { 1.0f, 1.0f };

	// setup env
	C3D_TexBind(getTextUnit(GPU_TEXUNIT0), &mTopScreenSprite->spriteTexture);
	C3D_TexEnv* env = C3D_GetTexEnv(0);
	C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, 0, 0);
	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
	C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);

	C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
	AttrInfo_Init(attrInfo);
	AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3);
	AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2);

	C3D_BufInfo* bufInfo = C3D_GetBufInfo();
	BufInfo_Init(bufInfo);
	BufInfo_Add(bufInfo, vertices, sizeof(ppVertexPosTex), 2, 0x10);

	C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);
}

How to enable C3D_FRAME_SYNCDRAW while still keeping 60fps

Hi, I am posting here because I've been maintaining the godot port for 3ds and I am right now having some issues
basically whenever C3D_FRAME_SYNCDRAW is used, it becomes impossible to reach more than 30fps, even on new 3ds with osSetSpeedupEnable(true);
it's a problem as technically the games can reach the 60 fps without even screen tearing on new 3ds, but I still need vsync in case an O3ds is playing

it happens even on very lightweight scenes. I also tried to set C3D_FrameRate(60); but it didn't change much

Using GX / GXQueue functions while using Citro3D

Perhaps this is more of a question than anything, but how would one go about using non-Citro3D GX functions while Citro3D is in use? I'm looking through the code of both ctrulib and Citro3D, and it's confusing me. On initialization, Citro3D binds a queue for its renderqueue and then runs it. In one sense it has nothing to run, but it does make the queue active. This led me to think that I could just add my commands because with the queue being active, it'll run them as I add them and all would be good. But then I began looking at the Safe functions and the onQueueFinish callback with regard to GX commands within a frame (that is, between FrameBegin and FrameEnd, which has the InFrame variable set).

They begin by waiting and clearing the queue (which stops the queue and makes it inactive, which is fine because they start them up again after the specific command is added), set the InSafeTransfer variable, add the command, then runs them. But, with how the callback is designed, the completion of the queue would cause it to become inactive, meaning later non-Citro3D GX commands would not run automatically. From my understanding, this is due to the queue being stopped in the callback (because both InSafeTransfer and InFrame are set as true in this case), and with no access to the bound queue to execute the gxCmdQueueRun function manually, the execution of these non-Citro3D GX commands would have to wait until Citro3D runs it itself. This creates another problem if another Safe call was made, if my understanding of the code is correct. If another call to a Safe function is done while non-Citro3D GX commands were added to the queue and the queue is not active, it would basically toss those commands out (via clearing the queue) to prep itself for the Safe command.

It seems like if I am wanting to use non-Citro3D GX functions within a frame, then I can't use the Safe functions whatsoever within the frame too unless they were at the very end. Or, maybe I'm just not understanding how the queue works, or how Citro3D utilizes it.

Off screen Target Corruption

I've come across a few other issues since I asked about how to make these. If I make the texture to render to in RAM there's very few missing spots of pixels in the first one, but subsequent ones may not render everything properly (missing pixels).

Placing the texture inside VRAM causes heavy garbage to be generated (and in some cases, VRAM corruption or something since I see home menu graphics appear).

I'm not sure what I'm doing wrong.. I start the frame, draw on the target, do the Mtx4x4 on the projection and after this is done, call end frame. Any ideas to fix this?

Question about BufInfo_Add() from C3D

Hi there
So I'm making a Minecraft like voxel engine for the Nintendo 3DS and I know that it's and old console but still fun to program. Anyway after implementing a chunk mesh building system, I notices that some of the vertices don't get drawn and I'm suspecting that it could have something to do with the u64 permutation value which is the las argument of the BuffInfoAdd function. I'm not sure exactly what that value is. ATM it is set to 0x210 (528) which is a random value i found in one of the examples. So my question is what exactly is this value and how to I determine what to make it?

Thanks for the time taken to answer my question

Latest update slowed down drawing by ~50%

Hi. I just updated citro3d to the latest on my machine, it appears that GPU performance for drawing (at least using citro2d?) has dramatically slowed down.

I discovered this working with my own homebrew that uses citro2d (trying on real hardware and on Citra), but you can see the effect yourself with the gpusprites example (c22c354, dcb3aac). (I didn't try the gpusprites example on real hardware.)

I'm sure you made the change with the hopes of performance improvements - hopefully it's just something small and you can get what you were looking for with that change!

Build fails for version with renderqueue

Library compilation failed for versions after (and including) 39a71a5

arm-none-eabi-gcc -MMD -MP -MF ~/work/_3ds/citro3d/build/renderqueue.d -g -Wall -Werror -O2 -mword-relocations -fomit-frame-pointer -ffunction-sections -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -I~/work/_3ds/citro3d/include -I~/devkitPro/libctru/include -I~/work/_3ds/citro3d/build -DARM11 -D_3DS -DCITRO3D_BUILD -c ~/work/_3ds/citro3d/source/renderqueue.c -o renderqueue.o
~/work/_3ds/citro3d/source/renderqueue.c: In function 'performDraw':
~/work/_3ds/citro3d/source/renderqueue.c:27:2: error: implicit declaration of function 'gspSetEventCallback' [-Werror=implicit-function-declaration]
  gspSetEventCallback(GSPGPU_EVENT_P3D, onRenderFinish, NULL, true);
  ^
~/work/_3ds/citro3d/source/renderqueue.c: In function 'performTransfer':
~/work/_3ds/citro3d/source/renderqueue.c:36:3: error: implicit declaration of function 'gfxConfigScreen' [-Werror=implicit-function-declaration]
   gfxConfigScreen(transferQueue->screen, false);
   ^
~/work/_3ds/citro3d/source/renderqueue.c: In function 'onVBlank0':
~/work/_3ds/citro3d/source/renderqueue.c:99:6: error: implicit declaration of function 'gfxIs3D' [-Werror=implicit-function-declaration]
  if (gfxIs3D())
      ^
~/work/_3ds/citro3d/source/renderqueue.c: In function 'C3D_RenderTargetDelete':
~/work/_3ds/citro3d/source/renderqueue.c:314:3: error: implicit declaration of function 'gspWaitForAnyEvent' [-Werror=implicit-function-declaration]
   gspWaitForAnyEvent();
   ^
cc1: all warnings being treated as errors
make[1]: *** [renderqueue.o] Error 1

Use-after-free in C3D_BindProgram

Freeing a shaderProgram_s that was previously bound using C3D_BindProgram will cause the next call to C3D_BindProgram to crash, even if the original program was never used after freeing it.

The problem is C3D_Context carries around a reference to the old program for tracking dirty state, however that reference becomes invalid when that program is freed.

What makes this problem even worse is that you can't unbind a program, e.g. by calling C3D_BindProgram(nullptr), since there's no null check in that function.

example not working and help needed

The example program compiles with errors, and I assume this is due to it being outdated compared to citro3d itself. And because of this, I am stuck, as I was trying to learn how to use citro3d.

Seriously though, if the people of the 3ds homebrew scene are so adamant about using citro3d instead of things like pp2d sf2d etc, then there needs to be a way to learn how to use it. @

compilation error

This enum...
typedef enum
{
GPU_RGBA8 = 0x0, ///< 8-bit Red + 8-bit Green + 8-bit Blue + 8-bit Alpha
GPU_RGB8 = 0x1, ///< 8-bit Red + 8-bit Green + 8-bit Blue
GPU_RGBA5551 = 0x2, ///< 5-bit Red + 5-bit Green + 5-bit Blue + 1-bit Alpha
GPU_RGB565 = 0x3, ///< 5-bit Red + 6-bit Green + 5-bit Blue
GPU_RGBA4 = 0x4, ///< 4-bit Red + 4-bit Green + 4-bit Blue + 4-bit Alpha
GPU_LA8 = 0x5, ///< 8-bit Luminance + 8-bit Alpha
GPU_HILO8 = 0x6, ///< 8-bit Hi + 8-bit Lo
GPU_L8 = 0x7, ///< 8-bit Luminance
GPU_A8 = 0x8, ///< 8-bit Alpha
GPU_LA4 = 0x9, ///< 4-bit Luminance + 4-bit Alpha
GPU_L4 = 0xA, ///< 4-bit Luminance
GPU_ETC1 = 0xB, ///< ETC1 texture compression
GPU_ETC1A4 = 0xC, ///< ETC1 texture compression + 4-bit Alpha
} GPU_TEXCOLOR;

...does not define GPU_A4...

which causes this error...
c:/ ... /citro3d/source/texture.c:25:8: error: 'GPU_A4' undeclared (first use in this function)
case GPU_A4:
^

install fails

I've tried the release and the latest commit, they both fail with the same errors:

C:\Users\scuba\Downloads\citro3d-1.3.0>make install
attribs.c
arm-none-eabi-gcc -MMD -MP -MF /c/Users/scuba/Downloads/citro3d-1.3.0/release/attribs.d -g -Wall -Werror -mword-relocations -ffunction-sections -fdata-sections -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -DNDEBUG=1 -O2 -fomit-frame-pointer -I/c/Users/scuba/Downloads/citro3d-1.3.0/include -I/c/devkitPro/libctru/include -I. -DARM11 -D_3DS -DCITRO3D_BUILD -c /c/Users/scuba/Downloads/citro3d-1.3.0/source/attribs.c -o attribs.o
In file included from c:/Users/scuba/Downloads/citro3d-1.3.0/source/internal.h:8:0,
from c:/Users/scuba/Downloads/citro3d-1.3.0/source/attribs.c:1:
c:/Users/scuba/Downloads/citro3d-1.3.0/include/c3d/fog.h:18:21: error: unknown type name 'GPU_FOGMODE'
void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip);
^~~~~~~~~~~
c:/Users/scuba/Downloads/citro3d-1.3.0/include/c3d/fog.h:18:42: error: unknown type name 'GPU_GASMODE'
void C3D_FogGasMode(GPU_FOGMODE fogMode, GPU_GASMODE gasMode, bool zFlip);
^~~~~~~~~~~
In file included from c:/Users/scuba/Downloads/citro3d-1.3.0/source/attribs.c:1:0:
c:/Users/scuba/Downloads/citro3d-1.3.0/source/internal.h:33:2: error: unknown type name 'gxCmdQueue_s'
gxCmdQueue_s gxQueue;
^~~~~~~~~~~~
make[1]: *** [attribs.o] Error 1
make: *** [lib/libcitro3d.a] Error 2

vertex data changed every frame, but lost last triangles

I write a metaball. The vertex data will be changed every frame, some hole in holes, like screenshot.
when I stop change vertex data, it ok.
C3D_DrawArrays(GPU_TRIANGLES, 0, metaballs->numVertices);
I think numVertices is not upload correct number, less. Then I add some, will better.
C3D_DrawArrays(GPU_TRIANGLES, 0, metaballs->numVertices+120);
wechat_1465712036

GPU_A4 undeclared

when compiling citro 3D with the correct environment variables set I get the following error:

arm-none-eabi-gcc -MMD -MP -MF /home/morten/citro3d/build/texture.d -g -Wall -Werror -O2 -mword-relocations -fomit-frame-pointer -ffunction-sections -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -I/home/morten/citro3d/include -I/home/morten/devkitPro/libctru/include -I/home/morten/citro3d/build -DARM11 -D_3DS -DCITRO3D_BUILD -c /home/morten/citro3d/source/texture.c -o texture.o 
/home/morten/citro3d/source/texture.c: In function 'fmtSize':
/home/morten/citro3d/source/texture.c:25:8: error: 'GPU_A4' undeclared (first use in this function)
   case GPU_A4:

GPU_A4 is only found once in this project, namely in this source file and this location. It is never defined in any part of the source.

Hangs When Using Geometry Shader In Combination With 3D Drawing

To begin, I draw sprites using the geometry shader. I often draw 2D in 3D in various orders to achieve certain effects, such as 2D Background -> 3D Model -> Text. It seems that drawing in certain orders causes citro3D to hang, such that the main thread gets stuck in a loop. I didn't have this issue when I'd draw using only a vertex shader, so I'm sure it is related to me using the geometry shader. Under normal circumstances, the shader program works as expected. It is only when I draw sprites, and then draw a model that citro3D hangs. When drawing models, I use C3D_DrawElements to draw triangles with an index buffer. Whenever it hangs, I can no longer trigger the Luma menu, and must hard power off my 3DS.

To be more specific, here is a list of tests I've tried and the results.

  • Early 2D Draw (Works)
  • 3D Draw (Works)
  • 2D Draw (Works)
  • Early 2D Draw -> 3D Draw -> 2D Draw (Hangs)
  • 3D Draw -> 2D Draw (Works)
  • Early 2D Draw -> 3D Draw (Hangs)
  • Early 2D Draw (Works)
  • Early 2D Draw -> 2D Draw (Works)
  • 2D Draw -> 3D Draw (Hangs)

Here are the shaders I use.
Vertex Shader: https://pastebin.com/562LdNGk
Geometry Shader: https://pastebin.com/sHLtFUME

Here is the log of code execution.
Log: https://pastebin.com/mMnth0xD

C3D_SetScissor parameter names

At the time of posting this issue, on C3D_SetScissor, the method signature parameters are: left,top,right,bottom
I suggest that they should probably be named left,bottom,right,top instead.
Or maybe x0,y0,x1,y1

Considering the Framebuffer Rotated 90 Degrees Clockwise, calling:

C3D_SetScissor(GPU_SCISSORMODE::GPU_SCISSOR_NORMAL, 20, 40, 80, 160);

Will result in the following clip region being used to render (Black Area):
image

left:20, top:40, right:80, bottom:160 thus makes no sense, as top is below bottom.

Questions regarding Mtx_Translate()

Please be patient with me as I am extremely new to graphics libraries and the math involved in 3D rendering, and frankly have very little idea of what I'm talking about in general.

Background: ScummVM uses a modified version of TinyGL (a stripped-down version of OpenGL) to run several 3D games such as Grim Fandango and Myst 3: Exile on lower-end systems (including the 3DS), provided their ScummVM engine has alternate, TinyGL-specific graphics code. The problem is that attempting to run said 3D games crashes the system. Interestingly, the one 3D game that will run on the 3DS (Westwood's Blade Runner), does not use OpenGL nor TinyGL.

Anyway, there was speculation that the issue might be solved by having the 3DS hardware take over some functions. Since the 3DS backend for ScummVM already uses citro3d for screen rendering, I thought it might be worthwhile to try and write a version of ScummVM's TinyGL implementation that utilizes citro3d. Needless to say, due to tinyGL being column-major and citro3d being row-major, I've been in a slog from the beginning.

What I think I know: Correct me if I'm wrong on any of this. To my understanding, converting between column-major and row-major layout simply requires transposing the matrix (and in citro3d's case, additionally flipping the matrix horizontally to account for PICA200's WZYX ordering). This seemed to work out fine for matrix rotation, as doing this then performing a left-handed MTX_Rotate() produced the same values as TinyGL's glopRotate() (with value positions changed appropriately).

In TinyGL, the translation matrix in its Matrix4::translate() looks like this:

Therefore, I expected that citro3d's translation matrix would be situated like this (but flipped horizontally, of course):

However, according to citro3d's code, a left-sided MTX_Translate() changes every cell's value EXCEPT those in the bottom-row. Additionally, right-handed Mtx_Translate() uses a translation matrix that is a horizontal mirror of TinyGL's translation matrix, changing only the W cells.

Questions:

  1. Is this intentional?
  2. If so, am I not understanding something correctly?
  3. If not, how can I work around this?
  4. Am I going about this all wrong?
  5. Is there anything you think I should know before I continue on this magical journey of mathematics, personal growth, and generally banging my head against a wall?

Uploading of the Reflective Red LUT not happening, plus a question....

On line 91 of the lightenv.c file is a for-loop that counts upward until it reaches 5, then exits. This currently prevents the reflective red LUT from being uploaded because its index is 5. A change to 6 should fix this (as was done for the typo fix of the Nov 8, 2015 commit in a similar situation).

And regarding reflective RGB, there was a test done some time ago that StapleButter (and perhaps you?) were working on to utilize this for a special form of texture. An old project from Nov 4th given to me included a compiled 3dsx that works on Ninjhax 1.1b, showing a 4-color-per-side cube, but doesn't work on Ninjhax 2.6 gamma, which has a completely black cube. Building with the newest libraries (including this with a change tested for reflective red), results in this same black cube for all versions of Ninjhax, including 1.1b. Think we can talk about what's going on?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.