Homebrew Homebrew Development

MasterFeizz

Well-Known Member
Member
Joined
Oct 15, 2015
Messages
1,098
Trophies
1
Age
29
XP
3,710
Country
United States
I must have misinterpreted your response as I took it as my thread example shouldn't work. I was just going by your suggestion to @Badda to use svcSleepThread(1) but I see that isn't sufficient in my case. I've just tried setting both threads to sleep for 100000000 and the Home button works!

I'll see if I can augment this into my code and if not I'll fallback on your suggestion to put it in a common function. I could probably just write a wrapper for hidScanInput to manage that for me since I know that's called everywhere regardless if a frame is rendered.

Thanks for taking the time to help me out!

Trust me, do the wrapper.

--------------------- MERGED ---------------------------

Okay, I got it working to the point where it will not request another update if it's already busy.
However, one thing I don't understand is that as a test I cannot block until it finishes.

Code:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <3ds.h>

int ShowError( const char* ErrorText, ... );
void RenderThread( void* Pram );
void Cleanup( void );

Handle RenderThreadReadyEvent = 0;
Handle RenderThreadUpdateEvent = 0;

Handle RenderThreadBusyMutex = 0;

Thread RenderThreadHandle = NULL;

volatile bool RenderThreadRun = false;

int ShowError( const char* ErrorText, ... ) {
    static char Buffer[ 1024 ];
    errorConf Err;
    va_list Argp;

    va_start( Argp, ErrorText );
        vsnprintf( Buffer, sizeof( Buffer ), ErrorText, Argp );
    va_end( Argp );

    errorInit( &Err, ERROR_TEXT_WORD_WRAP, CFG_LANGUAGE_EN );
    errorText( &Err, Buffer );
    errorDisp( &Err );

    return 1;
}

void RenderThread( void* Pram ) {
    gfxInitDefault( );
    consoleInit( GFX_BOTTOM, NULL );

    svcSignalEvent( RenderThreadReadyEvent );

    while ( RenderThreadRun ) {
        svcWaitSynchronization( RenderThreadUpdateEvent, INT64_MAX );
        svcClearEvent( RenderThreadUpdateEvent );

        svcWaitSynchronization( RenderThreadBusyMutex, INT64_MAX );
            svcSleepThread( 1 * ( 1e+9 ) );
        svcReleaseMutex( RenderThreadBusyMutex );
    }

    gfxExit( );

    threadExit( 0 );
}

void Cleanup( void ) {
    if ( RenderThreadHandle ) {
        RenderThreadRun = false;

        threadJoin( RenderThreadHandle, UINT64_MAX );
        threadFree( RenderThreadHandle );
    }

    svcCloseHandle( RenderThreadReadyEvent );
    svcCloseHandle( RenderThreadUpdateEvent );
    svcCloseHandle( RenderThreadBusyMutex );
}

int main( void ) {
    uint32_t Keys_Down = 0;
    uint64_t a, b = 0;

    atexit( Cleanup );

    svcCreateEvent( &RenderThreadReadyEvent, RESET_ONESHOT );
    svcCreateEvent( &RenderThreadUpdateEvent, RESET_ONESHOT );
    svcCreateMutex( &RenderThreadBusyMutex, false );

    RenderThreadRun = true;
    RenderThreadHandle = threadCreate( RenderThread, NULL, 4096, 0x20, 1, false );

    if ( RenderThreadHandle == NULL ) {
        return ShowError( "Failed to create rendering thread" );
    }

    // Wait for render thread to complete init
    svcWaitSynchronization( RenderThreadReadyEvent, INT64_MAX );
    svcClearEvent( RenderThreadReadyEvent );

    printf( "Render thread ready.\n" );

    while ( aptMainLoop( ) ) {
        gspWaitForVBlank( );
        gfxSwapBuffers( );

        hidScanInput( );
        Keys_Down = hidKeysDown( );

        if ( Keys_Down & KEY_A ) {
            if ( svcWaitSynchronization( RenderThreadBusyMutex, 0 ) != 0 ) {
                printf( "Render thread busy, try again later.\n" );
            } else {
                // Clear mutex in case we locked it while peeking at it
                svcReleaseMutex( RenderThreadBusyMutex );

                a = svcGetSystemTick( );
                    // Tell the render thread to do the thing
                    svcSignalEvent( RenderThreadUpdateEvent );

                    // Wait for render thread to finish
                    svcWaitSynchronization( RenderThreadBusyMutex, INT64_MAX );
                    svcReleaseMutex( RenderThreadBusyMutex );
                b = svcGetSystemTick( );

                svcReleaseMutex( RenderThreadBusyMutex );

                printf( "Operation took %.2fms\n", ( ( float ) ( b - a ) ) / ( float ) CPU_TICKS_PER_MSEC );
            }
        }

        if ( Keys_Down & KEY_START ) {
            break;
        }
    }

    return 0;
}

I would have thought that between the calls to svcGetSystemTick() it would signal the event and block until the render thread clears the busy mutex.

Shouldn't even work without APT_SetAppCpuTimeLimit, but otherwise seems ok.
 
  • Like
Reactions: TarableCode

TarableCode

Well-Known Member
Member
Joined
Mar 2, 2016
Messages
184
Trophies
0
Age
37
XP
319
Country
Canada
Yeah I do my basic testing on citra to spare the hinges on my n3DS and move it to hardware every few times or so.
I don't get why it's not blocking for the duration of the mutex lock though,
svcWaitSynchronization( RenderThreadReadyEvent, INT64_MAX ) seems to return instantly.

Normally this won't be a problem since I'm not planning to block, but for testing it really should so I can measure how speedy it runs.
 

MasterFeizz

Well-Known Member
Member
Joined
Oct 15, 2015
Messages
1,098
Trophies
1
Age
29
XP
3,710
Country
United States
Yeah I do my basic testing on citra to spare the hinges on my n3DS and move it to hardware every few times or so.
I don't get why it's not blocking for the duration of the mutex lock though,
svcWaitSynchronization( RenderThreadReadyEvent, INT64_MAX ) seems to return instantly.

Normally this won't be a problem since I'm not planning to block, but for testing it really should so I can measure how speedy it runs.
If you are testing on citra, then that's probably the problem.
 
  • Like
Reactions: TarableCode

TarableCode

Well-Known Member
Member
Joined
Mar 2, 2016
Messages
184
Trophies
0
Age
37
XP
319
Country
Canada
That was it lol.
*sigh*

Okay so I've been trying to teach myself arm assembly in an attempt to speed up graphics conversion.
I kind of succeeded in a sort of way.

The speed difference between (on o3ds hardware at 30% syscore):
Code:
void Unpack8BPP( const uint8_t* PixelsIn, uint16_t* PixelsOut, size_t InputLength ) {
    while ( InputLength-- ) {
        *PixelsOut++ = ConversionTable_8BPP[ *PixelsIn++ ];
    }
}

This code gives proper output and takes roughly 100ms.

Code:
.arm
.align 2

.extern ConversionTable_8BPP

@ r0: Src
@ r1: Dst
@ r2: Length
@ ----------
@ r3: Table pointer
@.global Unpack8BPP
Unpack8BPP:
    push {r3-r7}
    ldr r3, =ConversionTable_8BPP
Unpack8BPP_Loop:
    ldr r4, [r0], #4    @ AABBCCDD

    mov r5, r4, lsr #16
    and r5, r5, #0xFF

    mov r6, r4, lsr #8
    and r6, r6, #0xFF

    and r7, r4, #0xFF
    mov r4, r4, lsr #24

    @ 54ms
    ldrh r7, [r7,+r3]
    ldrh r6, [r6,+r3]
    ldrh r5, [r5,+r3]
    ldrh r4, [r4,+r3]

    strh r7, [r1], #2
    strh r6, [r1], #2
    strh r5, [r1], #2
    strh r4, [r1], #2

    subs r2, r2, #4
    bne Unpack8BPP_Loop

    pop {r3-r7}
    bx lr

And this takes only ~55ms, but the colours are inverted.

The conversion table is set up by:
Code:
uint16_t ConversionTable_8BPP[ 256 ];

void Init_8BPP( void ) {
    int r = 0;
    int g = 0;
    int b = 0;
    int i = 0;

    for ( i = 0; i < 256; i++ ) {
        r = ( ( uint16_t* ) CLUT_reds )[ i ] >> 11;
        g = ( ( uint16_t* ) CLUT_greens )[ i ] >> 10;
        b = ( ( uint16_t* ) CLUT_blues )[ i ] >> 11;

        ConversionTable_8BPP[ i ] = RGB565( r, g, b );
    }
}

I can understand the assembly straight up not working, but inverted?!
I'm sure my assembly is garbage, but I don't understand why the garbage has molded itself into this form.
 

HiSaturnV

Well-Known Member
Newcomer
Joined
Jan 29, 2021
Messages
45
Trophies
0
Age
24
Website
saturnsh2x2.ml
XP
488
Country
United States
Is it possible to work with raw pixel data in Citro2D? I've taken a look at various examples online, however, all examples I've seen only load textures from a t3x file. Specifically, I was wondering how one would go about loading pixel data into a buffer, having C2D_Image's tex parameter point to said buffer, configuring the subtex parameter properly (I'm lost on this bit in particular), and then drawing the image to the screen. Citro3D documentation is rather sparse, and there don't appear to be any Citro2D functions that automate this process any.
 
  • Like
Reactions: YugamiSekai

DD2XAlpha

Well-Known Member
Newcomer
Joined
Apr 26, 2016
Messages
48
Trophies
0
Age
26
XP
365
Country
Mexico
Hello, I've a project in my mind but I don't know a ton of C (I know C#, python and Javascript xd) and I am trying to request a JSON from an API and I was using the examples given in devkitPro but I wasn't successful when trying to download it hahahaha
 

scoliono

New Member
Newbie
Joined
Mar 27, 2022
Messages
1
Trophies
0
Age
21
Location
San Jose, CA
XP
29
Country
United States
Is it possible to work with raw pixel data in Citro2D? I've taken a look at various examples online, however, all examples I've seen only load textures from a t3x file. Specifically, I was wondering how one would go about loading pixel data into a buffer, having C2D_Image's tex parameter point to said buffer, configuring the subtex parameter properly (I'm lost on this bit in particular), and then drawing the image to the screen. Citro3D documentation is rather sparse, and there don't appear to be any Citro2D functions that automate this process any.
I was wondering how to do this, too. Then I noticed Universal Updater loads images over the network so I was able to find an example. I can't post the link, but look at the implementation of Screenshot::ConvertFromBuffer() in source/utils/screenshot.cpp.
 
  • Like
Reactions: cearp

HiSaturnV

Well-Known Member
Newcomer
Joined
Jan 29, 2021
Messages
45
Trophies
0
Age
24
Website
saturnsh2x2.ml
XP
488
Country
United States
I was wondering how to do this, too. Then I noticed Universal Updater loads images over the network so I was able to find an example. I can't post the link, but look at the implementation of Screenshot::ConvertFromBuffer() in source/utils/screenshot.cpp.
Oh, I originally asked this question here when I was working on getting the Sonic CD port to use the GPU instead of rendering everything in software. Since then I've managed to figure it out as well (check out the code for texture loading here). Thanks for the tip, though, I might check that implementation out.
 

Pikachuk

Well-Known Member
Member
Joined
Mar 19, 2016
Messages
767
Trophies
0
Age
23
Location
Bordeaux
XP
749
Country
France
I've forked and started to maintain the long abandonned godot 3ds port by porting it already from godot 2.1 to godot 2.1.7 RC and fixing issues that makes it now Python 3 compatible

however I'm right now having an issue where I keep getting VFP compilation errors even though I clearly have
'-mfloat-abi=hard' enabled

this is the link to my fork
https://github.com/SeleDreams/godot-3ds

does anyone knows how I could fix it ?
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • K3Nv2 @ K3Nv2:
    I think I did then it broke a few months later
  • Psionic Roshambo @ Psionic Roshambo:
    Used it as a web cam for a day for fun, sooo shitty it was hilarious
  • Psionic Roshambo @ Psionic Roshambo:
    I had two Ken one regular black one and a silver special edition one lol
  • K3Nv2 @ K3Nv2:
    Speaking of old stuff those green og Logitech Xbox controllers still being listed around $100
  • The Real Jdbye @ The Real Jdbye:
    eyetoy was fun yeah
  • The Real Jdbye @ The Real Jdbye:
    super basic, but the minigames were well designed
  • The Real Jdbye @ The Real Jdbye:
    i'm sure there's at least 1 emulator out there that works with it
  • Psionic Roshambo @ Psionic Roshambo:
    I had the PS3 one too and The Eye of Judgement game lol was ass
  • The Real Jdbye @ The Real Jdbye:
    i had eye toy play on ps2
  • K3Nv2 @ K3Nv2:
    Microsoft ruined it with kinect
  • Psionic Roshambo @ Psionic Roshambo:
    @The Real Jdbye, PCSX2 works with any web cam and emulates the EyeToy with it
  • K3Nv2 @ K3Nv2:
    I remember mic support for the n64 being janky
  • K3Nv2 @ K3Nv2:
    Emulation wise
  • Psionic Roshambo @ Psionic Roshambo:
    I had a kinnect.... It blew rotting goat balls
  • Psionic Roshambo @ Psionic Roshambo:
    Ken amazingly DraStic microphone support works better than real hardware lol
  • Psionic Roshambo @ Psionic Roshambo:
    On a phone of course
  • Psionic Roshambo @ Psionic Roshambo:
    Also touch is better.... Well at least better than the launch DS, the lite one improved that a ton
  • K3Nv2 @ K3Nv2:
    Touch
    +1
  • Psionic Roshambo @ Psionic Roshambo:
    I really need to dig out my USB Wii sensor bar and experiment with Wii emulation and synching Wii remotes with BT lol
  • Psionic Roshambo @ Psionic Roshambo:
    Sort of redundant since I have a Wii lol
  • Psionic Roshambo @ Psionic Roshambo:
    With HDMI lol
  • K3Nv2 @ K3Nv2:
    I also have a Wii
  • K3Nv2 @ K3Nv2:
    Tomorrow be may 4th
  • Psionic Roshambo @ Psionic Roshambo:
    Getting Wiid from Street Pharmacist Mario?
  • K3Nv2 @ K3Nv2:
    1tb SD card for whatever reason
    K3Nv2 @ K3Nv2: 1tb SD card for whatever reason