Homebrew Best way to draw pixel buffer

  • Thread starter Thread starter bayleef
  • Start date Start date
  • Views Views 3,883
  • Replies Replies 7

bayleef

Well-Known Member
Newcomer
Joined
Sep 15, 2015
Messages
83
Reaction score
148
Trophies
0
XP
274
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,
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.
 
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,
After suspending the app the framebuffer position in memory may change. Get again the framebuffer pointer when returning to the app.
 
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).
 
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.
 
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