Homebrew Best way to draw pixel buffer

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
Hello,

I want to draw raw RGBA buffer to screen. Until now, I used sf2d, but it seems overkill for this task: I have to create and free textures all the time.
Code:
sf2d_texture* top_screen = sf2d_create_texture(400, 240, TEXFMT_RGBA8, SF2D_PLACE_RAM);
sf2d_fill_texture_from_RGBA8(top_screen, buffer, 400, 240);
sf2d_texture_tile32(top_screen);
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sf2d_draw_texture(top_screen,0,0);
sf2d_end_frame();
sf2d_swapbuffers();
sf2d_free_texture(top_screen);

So, I tried do use gfx directly. For my opinion, the code looks much better this way: I save allocating and deallocating memory all over the time.
Code:
memcpy(gfxGetFramebuffer(GFX_TOP,GFX_LEFT,0,0), buffer, 4*240*400);
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();

However, I have the following problem: When I suspend the cia, the top screen turns black. With sf2d this problem did not exist. I've created a minimal example to demonstrate the problem:
Code:
#include <3ds.h>

#define WIDTH 240
#define HEIGHT 400

void fill_buffer(u32* buffer, u32 color) {
    int x,y;
    for (y=0;y<HEIGHT;y++) {
        for (x=0;x<WIDTH;x++) {
            buffer[x+y*WIDTH] = color;
        }
    }
}

int main() {
    gfxInit(GSP_RGBA8_OES, GSP_RGBA8_OES, false);
    gfxSetDoubleBuffering(GFX_TOP,1);
    while(aptMainLoop()) {
        hidScanInput();
        // fill top screen with red
        fill_buffer((u32*)gfxGetFramebuffer(GFX_TOP,GFX_LEFT,0,0), 0xFF0000FF);
        gfxFlushBuffers();
        gfxSwapBuffers();
        gspWaitForVBlank();
    }
    gfxExit();
    return 0;
}

What can I do to fix the issue? And notably, is using gfx this way really better to solve my task? I.e., what is the best (i.e. fastest) way to copy a pixel buffer to screen? Should I use citro3d (is there a minimal example)?
 
Last edited by bayleef,

elhobbs

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

I want to draw raw RGBA buffer to screen. Until now, I used sf2d, but it seems overkill for this task: I have to create and free textures all the time.
Code:
sf2d_texture* top_screen = sf2d_create_texture(400, 240, TEXFMT_RGBA8, SF2D_PLACE_RAM);
sf2d_fill_texture_from_RGBA8(top_screen, buffer, 400, 240);
sf2d_texture_tile32(top_screen);
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sf2d_draw_texture(top_screen,0,0);
sf2d_end_frame();
sf2d_swapbuffers();
sf2d_free_texture(top_screen);

So, I tried do use gfx directly. For my opinion, the code looks much better this way: I save allocating and deallocating memory all over the time.
Code:
memcpy(gfxGetFramebuffer(GFX_TOP,GFX_LEFT,0,0), buffer, 4*240*400);
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();

However, I have the following problem: When I suspend the cia, the top screen turns black. With sf2d this problem did not exist. I've created a minimal example to demonstrate the problem:
Code:
#include <3ds.h>

#define WIDTH 240
#define HEIGHT 400

void fill_buffer(u32* buffer, u32 color) {
    int x,y;
    for (y=0;y<HEIGHT;y++) {
        for (x=0;x<WIDTH;x++) {
            buffer[x+y*WIDTH] = color;
        }
    }
}

int main() {
    gfxInit(GSP_RGBA8_OES, GSP_RGBA8_OES, false);
    gfxSetDoubleBuffering(GFX_TOP,1);
    while(aptMainLoop()) {
        hidScanInput();
        // fill top screen with red
        fill_buffer((u32*)gfxGetFramebuffer(GFX_TOP,GFX_LEFT,0,0), 0xFF0000FF);
        gfxFlushBuffers();
        gfxSwapBuffers();
        gspWaitForVBlank();
    }
    gfxExit();
    return 0;
}

What can I do to fix the issue? And notably, is using gfx this way really better to solve my task? I.e., what is the best (i.e. fastest) way to copy a pixel buffer to screen? Should I use citro3d (is there a minimal example)?
It depends on what you are trying to do. If there is no texture reuse and no transforms (scaling,rotation, skew, etc)of the objects you are displaying then it is probably best to draw directly to the framebuffer. also depending on what you are doing it may not matter at all. If drawing to the framebuffer is easier then do it. If performance becomes an issue then figure out where the issue is and address it.
 

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
It depends on what you are trying to do. If there is no texture reuse and no transforms (scaling,rotation, skew, etc)of the objects you are displaying then it is probably best to draw directly to the framebuffer. also depending on what you are doing it may not matter at all. If drawing to the framebuffer is easier then do it. If performance becomes an issue then figure out where the issue is and address it.
Okay, I could reuse a lot of very small textures (causing a lot of memory overhead due to minimal texture size) and – partially – some larger parts, but it would be really complicated. Thus, I really should draw to buffer directly.

How could I fix the issue with the black screen? Is it a bug in ctrulib or am I doing something wrong?
 
Last edited by bayleef,

nop90

Well-Known Member
Member
Joined
Jan 11, 2014
Messages
1,556
Trophies
0
Location
Rome
XP
3,036
Country
Italy
After suspending the app the framebuffer position in memory may change. Get again the framebuffer pointer when returning to the app.
 

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
After suspending the app the framebuffer position in memory may change. Get again the framebuffer pointer when returning to the app.
I do so (see minimal example in original post). After return, everything is fine. The screen where the frozen app should be displayed in background (home menu screen) only shows a black background (instead of a red one).
 

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
I've solved the problem. If anybody runs into the same problem: The problem was caused by the frame buffer format. When replacing GSP_RGBA8_OES by GSP_BGR8_OES, everything works fine. So, it may be a ctrulib (or a Nintendo) bug.
 

nop90

Well-Known Member
Member
Joined
Jan 11, 2014
Messages
1,556
Trophies
0
Location
Rome
XP
3,036
Country
Italy
Or maybe could be a problem with the value of the alpha channel.

If you write directly in the framebuffer, it can't be a ctrulib bug. And such a bug in the firmware is unlikely.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • No one is chatting at the moment.
    Sonic Angel Knight @ Sonic Angel Knight: :ninja: