Homebrew Homebrew Development

filfat

CTO @ Nordcom Group Inc.
Member
Joined
Nov 24, 2012
Messages
1,261
Trophies
1
Location
Gothenburg, Sweden
Website
www.sweetsideofsweden.com
XP
1,749
Country
Sweden
is the image tiled for the GPU or not? And what exactly do you mean by cutting? Grabbing a small sub-section of the pixels of the image?

Like a sprite sheet, im trying to cut a bitmap image with sections x,y & h,w

It depends on how the image buffer is made and also on how you want to crop your image.
For example, let's say that you have a row-major order buffer and you want to do a horizontal cut you can do something like this:
Code:
u8 *buffer; //Let's assume that it is already filled and it is a 24bit/pixel buffer
u16 width, height; //Already assigned to a certain value. Height isn't really necessary, but could be useful to check if we want to cut more than we can
u16 startRow; //The starting row from where you want to start your cut
u16 cutHeight; //The number of rows that you want to cut from your buffer
u8 *newBuffer; //The buffer containing the new image
 
newBuffer = (u8 *)malloc(width * cutHeight * 3); //Allocate the new buffer
 
memcpy(newBuffer, &buffer[width * startRow * 3], width * cutHeight * 3); //Copy the cropped image in the new buffer
Please note that you should do some checks to ensure to you are not trying to make a cut outside of the image buffer.
The same code can be easily modified to made vertical cut on a column-major order buffer.

In the case of vertical cuts on row-major order buffers (or horizontal ones on column-major order buffers) you should cycle through the buffer using two nested for loops and copy one pixel at a time


Looks great, will just have to implement vertical cutting too :)
 

Aurelio

Well-Known Member
Newcomer
Joined
Jun 25, 2008
Messages
64
Trophies
0
XP
834
Country
Italy
Like a sprite sheet, im trying to cut a bitmap image with sections x,y & h,w

hmm in this case you could do something like this:
Code:
u8 *buffer; //Let's assume that it is already filled and it is a 24bit/pixel buffer
u16 width, height; //Already assigned to a certain value. Height isn't really necessary, but could be useful to check if we want to cut more than we can
u16 x, y; //The starting point from where you want to start your cut
u16 cutWidth, cutHeight; //The dimension of the rectangle that you want to cut
u8 *newBuffer; //The buffer containing the new image
 
newBuffer = (u8 *)malloc(cutWidth * cutHeight * 3); //Allocate the new buffer
 
for (int i = 0; i < cutHeight; i++)
{
    memcpy(&newBuffer[cutWidth * i * 3], &buffer[(x + width * (i + y)) * 3], cutWidth * 3); //Copy a single row in the new buffer
}
 

Helreizer543

Well-Known Member
Newcomer
Joined
Nov 24, 2014
Messages
49
Trophies
0
Age
102
XP
119
Country
United States
hmm in this case you could do something like this:
Code:
u8 *buffer; //Let's assume that it is already filled and it is a 24bit/pixel buffer
u16 width, height; //Already assigned to a certain value. Height isn't really necessary, but could be useful to check if we want to cut more than we can
u16 x, y; //The starting point from where you want to start your cut
u16 cutWidth, cutHeight; //The dimension of the rectangle that you want to cut
u8 *newBuffer; //The buffer containing the new image
 
newBuffer = (u8 *)malloc(cutWidth * cutHeight * 3); //Allocate the new buffer
 
for (int i = 0; i < cutHeight; i++)
{
    memcpy(&newBuffer[cutWidth * i * 3], &buffer[(x + width * (i + y)) * 3], cutWidth * 3); //Copy a single row in the new buffer
}
I'm not sure this is true for everyone but my x and y are swapped so unless you switch them in the for loop. um is there any way to copy from the top left going down instead of copying from the bottom up?[/code][/quote]
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Is it possible to pass arguments to a secondary thread?

I'm just trying to put streaming src for my audio system to a secondary thread but i get a crash on creating thread:

Thread creation:
Code:
u32 *threadStack = (u32*)memalign(32, 4096);
        Result ret = svcCreateThread(&streamThread, streamCode, (u32)src, &threadStack[1024], 0x3f, 0);

streamCode:
Code:
void streamCode(u32 arg){
    wav* src = (wav*)arg;
    while(!closeStream){
 
    //if (src->encoding == CSND_ENCODING_VORBIS) return lua_streamOgg(L);
    u32 bytesRead;
    u32 control;
    if (src->encoding == CSND_ENCODING_IMA_ADPCM) control = (src->samplerate / 2) * ((osGetTime() - src->tick) / 1000);
    else control = src->samplerate * src->bytepersample * ((osGetTime() - src->tick) / 1000);
    if (((control) >= (src->size - src->startRead)) && (src->isPlaying)){
        if (src->streamLoop){
            src->tick = osGetTime();
            src->moltiplier = 1;
        }else{
            src->isPlaying = false;
            src->tick = (osGetTime()-src->tick);
            src->moltiplier = 1;
            CSND_setchannel_playbackstate(src->ch, 0);
            if (src->audiobuf2 != NULL) CSND_setchannel_playbackstate(src->ch2, 0);
            CSND_sharedmemtype0_cmdupdatestate(0);
        }
        if (src->audiobuf2 == NULL){
            FSFILE_Read(src->sourceFile, &bytesRead, src->startRead, src->audiobuf, src->mem_size);
            u64 i = 0;
            if (src->big_endian){
            while (i < (src->mem_size)){
                u8 tmp = src->audiobuf[i];
                src->audiobuf[i] = src->audiobuf[i+1];
                src->audiobuf[i+1] = tmp;
                i=i+2;
            }
            }
        }else{
            u8* tmp_buffer = (u8*)linearAlloc(src->mem_size);
            FSFILE_Read(src->sourceFile, &bytesRead, src->startRead, tmp_buffer, src->mem_size);
            u32 size_tbp = src->mem_size;
            u32 off=0;
            u32 i=0;
            u16 z;
            if (src->big_endian){
            while (i < size_tbp){
                z=0;
                while (z < (src->bytepersample/2)){
                    src->audiobuf[off+z] = tmp_buffer[i+(src->bytepersample/2)-z-1];
                    src->audiobuf2[off+z] = tmp_buffer[i+(src->bytepersample)-z-1];
                    z++;
                }
                i=i+src->bytepersample;
                off=off+(src->bytepersample/2);
            }
            }else{
            while (i < size_tbp){
                z=0;
                while (z < (src->bytepersample/2)){
                    src->audiobuf[off+z] = tmp_buffer[i+z];
                    src->audiobuf2[off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                    z++;
                }
                i=i+src->bytepersample;
                off=off+(src->bytepersample/2);
            }
            }
            linearFree(tmp_buffer);
        }
    }else if (((control) > ((src->mem_size / 2) * src->moltiplier)) && (src->isPlaying)){
        if ((src->moltiplier % 2) == 1){
            //Update and flush first half-buffer
            if (src->audiobuf2 == NULL){
                if (src->encoding == CSND_ENCODING_IMA_ADPCM){ //ADPCM Decoding TODO
                    u32 buffer_headers_num = ((src->mem_size)/2) / src->bytepersample;
                    u8* tmp_audiobuf = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), tmp_audiobuf, (src->mem_size)/2);
                    int z=0,i=0;
                    while (i < (src->mem_size/2)){
                        src->audiobuf[z] = tmp_audiobuf[i];
                        z++;
                        i++;
                        if ((i % src->bytepersample) == 0) i=i+4;
                    }
                    linearFree(tmp_audiobuf);
                }else{ //PCM-16 Decoding
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), src->audiobuf, (src->mem_size)/2);
                u64 i = 0;
                if (bytesRead != ((src->mem_size)/2)){
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead, src->audiobuf, (src->mem_size)/2);
                src->moltiplier = src->moltiplier + 1;
                }
                if (src->big_endian){
                while (i < ((src->mem_size)/2)){
                    u8 tmp = src->audiobuf[i];
                    src->audiobuf[i] = src->audiobuf[i+1];
                    src->audiobuf[i+1] = tmp;
                    i=i+2;
                }
                }
                }
                src->moltiplier = src->moltiplier + 1;
            }else{
                u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size/2)*(src->moltiplier + 1), tmp_buffer, (src->mem_size)/2);
                if (bytesRead != ((src->mem_size)/2)){
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead, tmp_buffer, (src->mem_size)/2);
                src->moltiplier = src->moltiplier + 1;
                }
                src->moltiplier = src->moltiplier + 1;
                u32 size_tbp = (src->mem_size)/2;
                u32 off=0;
                u32 i=0;
                u16 z;
                if (src->big_endian){
            while (i < size_tbp){
                z=0;
                while (z < (src->bytepersample/2)){
                    src->audiobuf[off+z] = tmp_buffer[i+(src->bytepersample/2)-z-1];
                    src->audiobuf2[off+z] = tmp_buffer[i+(src->bytepersample)-z-1];
                    z++;
                }
                i=i+src->bytepersample;
                off=off+(src->bytepersample/2);
            }
            }else{
                while (i < size_tbp){
                    z=0;
                    while (z < (src->bytepersample/2)){
                        src->audiobuf[off+z] = tmp_buffer[i+z];
                        src->audiobuf2[off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                        z++;
                    }
                    i=i+src->bytepersample;
                    off=off+(src->bytepersample/2);
                }
                }
                linearFree(tmp_buffer);
            }
        }else{
            u32 bytesRead;
            //Update and flush second half-buffer
            if (src->audiobuf2 == NULL){
                if (src->encoding == CSND_ENCODING_IMA_ADPCM){ // ADPCM Decoding TODO
                    u32 buffer_headers_num = ((src->mem_size)/2) / src->bytepersample;
                    u8* tmp_audiobuf = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), tmp_audiobuf, (src->mem_size)/2);
                    int z=0,i=0;
                    while (i < (src->mem_size/2)){
                        src->audiobuf[z+(src->mem_size/2)] = tmp_audiobuf[i];
                        z++;
                        i++;
                        if ((i % src->bytepersample) == 0) i=i+4;
                    }
                    linearFree(tmp_audiobuf);
                }else{ // PCM-16 Decoding
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), src->audiobuf+((src->mem_size)/2), (src->mem_size)/2);
                if (src->big_endian){
                    u64 i = 0;
                    while (i < ((src->mem_size)/2)){
                        u8 tmp = src->audiobuf[i+((src->mem_size)/2)];
                        src->audiobuf[i+((src->mem_size)/2)] = src->audiobuf[i+((src->mem_size)/2)+1];
                        src->audiobuf[i+((src->mem_size)/2)+1] = tmp;
                        i=i+2;
                    }
                }
                }
                src->moltiplier = src->moltiplier + 1;
            }else{
                u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size/2)*(src->moltiplier + 1), tmp_buffer, (src->mem_size)/2);
                src->moltiplier = src->moltiplier + 1;
                u32 size_tbp = (src->mem_size)/2;
                u32 off=0;
                u32 i=0;
                u16 z;
                if (src->big_endian){
            while (i < size_tbp){
                z=0;
                while (z < (src->bytepersample/2)){
                    src->audiobuf[(src->mem_size)/4+off+z] = tmp_buffer[i+(src->bytepersample/2)-z-1];
                    src->audiobuf2[(src->mem_size)/4+off+z] = tmp_buffer[i+(src->bytepersample)-z-1];
                    z++;
                }
                z=0;
                i=i+src->bytepersample;
                off=off+(src->bytepersample/2);
            }
            }else{
                while (i < size_tbp){
                    z=0;
                    while (z < (src->bytepersample/2)){
                        src->audiobuf[(src->mem_size)/4+off+z] = tmp_buffer[i+z];
                        src->audiobuf2[(src->mem_size)/4+off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                        z++;
                    }
                i=i+src->bytepersample;
                off=off+(src->bytepersample/2);
                }
                }
                linearFree(tmp_buffer);
            }
        }
    }
       
    }
    svcExitThread();
}
 

Helreizer543

Well-Known Member
Newcomer
Joined
Nov 24, 2014
Messages
49
Trophies
0
Age
102
XP
119
Country
United States
Is it possible to pass arguments to a secondary thread?

I'm just trying to put streaming src for my audio system to a secondary thread but i get a crash on creating thread:

Thread creation:
Code:
u32 *threadStack = (u32*)memalign(32, 4096);
        Result ret = svcCreateThread(&streamThread, [U]streamCode[/U], (u32)src, &threadStack[1024], 0x3f, 0);

shouldn't you pass an arg through streamCode()? otherwise your just calling stream code with no parameters? right
nevermind.
 

Helreizer543

Well-Known Member
Newcomer
Joined
Nov 24, 2014
Messages
49
Trophies
0
Age
102
XP
119
Country
United States
upon further research...
are you allocating enough memory for the stack size?
the ctrulib example passes a pointer through their stream code equivalant.
are you using svcCreateEvent? ctrulib has an example where they pass an argument so I would believe its possible.
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
upon further research...
are you allocating enough memory for the stack size?
the ctrulib example passes a pointer through their stream code equivalant.
are you using svcCreateEvent? ctrulib has an example where they pass an argument so I would believe its possible.

Don't need events so no, i'm not using them.
I tried also to change streamCode with a simple waitVblank and still crashes (both Citra and real HW) and i also tried to execute ctrulib sample and i get black screen freeze on both Citra and real HW.
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,032
Country
United States
Don't need events so no, i'm not using them.
I tried also to change streamCode with a simple waitVblank and still crashes (both Citra and real HW) and i also tried to execute ctrulib sample and i get black screen freeze on both Citra and real HW.
I agree with Helreizer543- increase your stack size. I doubt 4k is enough. also your thread never sleeps - you need to call svcSleepThread even if it for 1 ns. otherwise the main thread will not get to run again. I think with processorid of 0 you are just running on the main thread processor so it is particularly important.
you are probably going to have to resort to adding some printf and svcSleepThread calls (so you can see your prints before it dies) throughout that code and see where it dies. debugging really sucks on the 3ds. I have even go so far as to film the screen when debugging to trace all the print messages - since they are gone when it dies.
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
I agree with Helreizer543- increase your stack size. I doubt 4k is enough. also your thread never sleeps - you need to call svcSleepThread even if it for 1 ns. otherwise the main thread will not get to run again. I think with processorid of 0 you are just running on the main thread processor so it is particularly important.
you are probably going to have to resort to adding some printf and svcSleepThread calls (so you can see your prints before it dies) throughout that code and see where it dies. debugging really sucks on the 3ds. I have even go so far as to film the screen when debugging to trace all the print messages - since they are gone when it dies.

I'm having problem also with sample: https://github.com/smealum/ctrulib/blob/master/examples/threads/event/source/main.c
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,032
Country
United States

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
are you using the latest ctrulib from git? there was an update a few days ago to fix an issue that was causing things to hang on some systems.

it is not the prettiest code, but I have a streaming sound example using threading in prboom3ds. it streams doom music.

I'm not using latest ctrulib cause csnd syntax is heavly different from the ones i use. Anyway, svc funcs implementations are the same between mine and latest ctrulib revisions.
 

smealum

growing up sucks.
Member
Joined
May 1, 2006
Messages
635
Trophies
2
Age
31
Location
SF
Website
www.smealum.net
XP
2,516
Country
United States
Has anyone been able to use definable uniforms with the geometry shader? I'm attempting to improve BlargSNES by using less input for rendering each tile from 2 vertices to 1. When using a constant uniform with the needed information, it works, but when I take it out and put it in the program code alongside other uniform functions (those which are used for the vertex shader), I get a blank screen, even when using the same values used for when the uniform was constant within the shader.

there used to be a bug in ctrulib that prevented geoshader uniforms from being set properly; should be fixed now.
 

DiscostewSM

Well-Known Member
Member
Joined
Feb 10, 2009
Messages
5,484
Trophies
2
Location
Sacramento, California
Website
lazerlight.x10.mx
XP
5,488
Country
United States
Figured out the uniform stuff for geometry shaders, but now I've got another problem. I was originally using an older ctrulib build that incorporated some custom shader code to include geometry shader support, but now I want to use the more up-to-date version that supposedly has that support built-in from the gpu-revamp. Unfortunately, the changes I made to use them is not working. I'd parse the files, init the structures, assign the vertex and geometry attributes, and then use the shaders when needed. This results in the top-screen flickering between black and grey, slowing down everything. I'm basing my changes on both the gpu example for ctrulib, as well as portal3DS.

Remember, this is with blargSNES.

there used to be a bug in ctrulib that prevented geoshader uniforms from being set properly; should be fixed now.

Didn't think it was a bug, but simply that everything was forced to be used for just vertex shaders. Then again, I updated to the newer ctrulib build that granted this, but have had to retain some of the old code like parsing shaders and using them just to make blargSNES work, when I want to use what ctrulib offers.
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,032
Country
United States
Are you using the latest aemstro? I had a similar issue where I was not setting the outmap mask correctly in the shader. I was setting it to 0 which worked on the pre gpu revamp ctrulib but stopped working with the new code.
 

DiscostewSM

Well-Known Member
Member
Joined
Feb 10, 2009
Messages
5,484
Trophies
2
Location
Sacramento, California
Website
lazerlight.x10.mx
XP
5,488
Country
United States
Are you using the latest aemstro? I had a similar issue where I was not setting the outmap mask correctly in the shader. I was setting it to 0 which worked on the pre gpu revamp ctrulib but stopped working with the new code.


Prior to the newest aemstro and gpu_revamp, the outmap for the emulator's shaders didn't have a mask (but worked fine), but since using the newest aemstro, I had included them for proper compiling. Whether I did it correctly, I'm not sure, but when using the newest ctrulib build but incorporating the old parser and useProgram functions, it works fine, but the new method for handling shaders does not. This is what is set for all shaders used by blargSNES since using the newest version of aemstro and ctrulib.

; setup outmap
.out o0, result.position, 0xF
.out o1, result.color, 0xF
.out o2, result.texcoord0, 0x3
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Finally got threads working (i had to update devkitARM) but now i'm having a strange issue, during audio streaming, i get random crashes (specially with OGG streaming), does someone knows why? This is my actual sound module (streaming functions are streamWAV and streamOGG, they are called by lua_playWav and closed by lua_closeWav).

http://pastebin.com/5hu0gpqY
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,032
Country
United States
Finally got threads working (i had to update devkitARM) but now i'm having a strange issue, during audio streaming, i get random crashes (specially with OGG streaming), does someone knows why? This is my actual sound module (streaming functions are streamWAV and streamOGG, they are called by lua_playWav and closed by lua_closeWav).

http://pastebin.com/5hu0gpqY
I didn't review the whole thing but I do not think linearAlloc or linearFree are thread safe.
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,032
Country
United States
You could create a mutex to sync access or you could avoid the situation entirely and allocate the buffers before the thread starts. One solution to this problem is a circular buffer and a looping sound. Just keep filling the buffer so you are always a bit ahead of the playback position enough so that it will not catch up before the next time around. I have have found the system ticks to drift quite a bit ( or errors on my part) so I like to use the CSND buffer position. It doesn't need to be precise you just need to keep ahead of the playback. Enough samples for .1 seconds is what I usually use. Since this is on the 3ds make sure the thread sleeps a bit each pass.
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
linearAlloc is used before thread starts infact and i use what you said, when audiobuffers is executed for an half, i updated first half and when audiobuffers is restarting through CSND_LOOP_ENABLE i flush second half.

EDIT: It seems chaning the mode i call the stream solved the problem, thanks for the help elhobbs.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Xdqwerty @ Xdqwerty: @SylverReZ, lol +1