Best way to draw pixel buffer

Discussion in '3DS - Homebrew Development and Emulators' started by bayleef, Oct 16, 2016.

  1. bayleef
    OP

    bayleef Advanced Member

    Newcomer
    83
    147
    Sep 15, 2015
    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, Oct 16, 2016
  2. elhobbs

    elhobbs GBAtemp Advanced Fan

    Member
    783
    292
    Jul 28, 2008
    United States
    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.
     
  3. bayleef
    OP

    bayleef Advanced Member

    Newcomer
    83
    147
    Sep 15, 2015
    Gambia, The
    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, Oct 16, 2016
  4. nop90

    nop90 GBAtemp Maniac

    Member
    1,398
    2,094
    Jan 11, 2014
    Italy
    Rome
    After suspending the app the framebuffer position in memory may change. Get again the framebuffer pointer when returning to the app.
     
  5. bayleef
    OP

    bayleef Advanced Member

    Newcomer
    83
    147
    Sep 15, 2015
    Gambia, The
    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).
     
  6. bayleef
    OP

    bayleef Advanced Member

    Newcomer
    83
    147
    Sep 15, 2015
    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.
     
  7. nop90

    nop90 GBAtemp Maniac

    Member
    1,398
    2,094
    Jan 11, 2014
    Italy
    Rome
    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.
     
  8. bayleef
    OP

    bayleef Advanced Member

    Newcomer
    83
    147
    Sep 15, 2015
    Gambia, The
    I have tried 0x00 and 0xFF as alpha value, always the same result...