Homebrew Drawing issues with my GBA Program

Kirbedev

Member
OP
Newcomer
Joined
Nov 13, 2022
Messages
5
Trophies
0
Age
16
XP
77
Country
United States
Not sure if this belongs here but I am having an issues with devkitpro and my gba program. I created a function in my `.h` file, which looks like this:
C:
void draw_rect_f(int x, int y, int w, int h, int color)
{
    // Draw a filled rectangle
    for (int i = 0; i < w; i++) {
        for (int j = 0; j < h; j++) {
            ((unsigned short*)0x06000000)[(y + j) * 240 + x + i] = color;
        }
    }
}

I know DMA is probably a better method, but I have no flippin' clue how to get that working. But here's the issue:
Calling
Code:
VBlankIntrWait()
at the end of my main loop causes my shapes to draw at the exact same position every frame, and when I remove it they do move, but with extreme screen tearing, which leads me to believe the rectangles are not drawn/updated fast enough.
C++:
    // ...

    // Main loop
    while (1) {
        // Clear background
        draw_rect_f(0, 0, 240, 160, rgb(200, 75, 75));

        // Update snake
        snake.update();

        // Wait for vblank
        VBlankIntrWait();
    }

What should I do?
 

Adam0x48

New Member
Newbie
Joined
Mar 31, 2023
Messages
1
Trophies
0
Age
21
XP
26
Country
Canada
For a quick and dirty method:
C:
#define REG_VCOUNT (*(volatile unsigned short*)(0x04000006))
void vsync()
{
    while(REG_VCOUNT >= SCREEN_H);
    while (REG_VCOUNT < SCREEN_H);
}
This is considered a bad method because it uses CPU instructions in order to wait, consuming battery.
VBlankIntrWait() is better because it powers down the CPU while it's waiting.
You need to initialize some stuff to get interrupt calls to work. I can't post links yet apparently but look up "tonc GBA" and search for the "Hardware interrupts" page.
The main things you're gonna need from there areirq_init() and irq_add(). Then, go to the "Bios Calls" page, and find the section on VBlankIntrWait to put it all together in a simple demo program. This stuff goes way further than drawing a little rectangle so if you have any questions, don't hesitate to ask.
 
Last edited by Adam0x48,
  • Like
Reactions: Kirbedev

Kirbedev

Member
OP
Newcomer
Joined
Nov 13, 2022
Messages
5
Trophies
0
Age
16
XP
77
Country
United States
For a quick and dirty method:
C:
#define REG_VCOUNT (*(volatile unsigned short*)(0x04000006))
void vsync()
{
    while(REG_VCOUNT >= SCREEN_H);
    while (REG_VCOUNT < SCREEN_H);
}
This is considered a bad method because it uses CPU instructions in order to wait, consuming battery.
VBlankIntrWait() is better because it powers down the CPU while it's waiting.
You need to initialize some stuff to get interrupt calls to work. I can't post links yet apparently but look up "tonc GBA" and search for the "Hardware interrupts" page.
The main things you're gonna need from there areirq_init() and irq_add(). Then, go to the "Bios Calls" page, and find the section on VBlankIntrWait to put it all together in a simple demo program. This stuff goes way further than drawing a little rectangle so if you have any questions, don't hesitate to ask.
Hello!

I really appreciate the response, and I apologize for taking so long to reply.

The part I am struggling with is what I need to define and use to set a specific pixel to a specific color.
While Tonc goes into great detail about how this stuff works, it doesn't seem to specify how a pixel is set. The DMA page it provides looks into displaying images, and doesn't seem to cover this particular use case.

I would greatly appreciate it if you could help point me in the right direction. Thanks in advance.
 

Coto

-
Member
Joined
Jun 4, 2010
Messages
2,979
Trophies
2
XP
2,565
Country
Chile
#include "nds/ndstypes.h"
C++:
    // ...

    // Main loop
    while (1) {
        // Clear background
        dmaFillHalfWords (rgb(200, 75, 75), (void *)0x06000000, (240 * 160 * sizeof(u16)));

        // Update snake
        snake.update();

        // Wait for vblank
        VBlankIntrWait();
    }

This should work. sizeof(u16) is 2 bytes, or a halfword. Because GBA pixel format is 15bit RGB value

If the RGB conversion doesn't work, try using
Code:
#define        RGB(r,g,b)    ( ((r)&31) | (((g)&31)<<5) | (((b)&31)<<10) )
 
  • Like
Reactions: Kirbedev

Kirbedev

Member
OP
Newcomer
Joined
Nov 13, 2022
Messages
5
Trophies
0
Age
16
XP
77
Country
United States
This should work. sizeof(u16) is 2 bytes, or a halfword. Because GBA pixel format is 15bit RGB value

If the RGB conversion doesn't work, try using
Code:
#define        RGB(r,g,b)    ( ((r)&31) | (((g)&31)<<5) | (((b)&31)<<10) )
Thanks for the response. I included ndstypes (installed libnds from the graphic devkitpro installer) but it says dmaFillHalfWords is undefined. When I highlight it in visual studio, it says it's an int, rather than an errorType. What am I missing?
 

Kirbedev

Member
OP
Newcomer
Joined
Nov 13, 2022
Messages
5
Trophies
0
Age
16
XP
77
Country
United States
try adding dma.h

Code:
#include "dma.h"
Strange... it's valid now, but compiling the program raises a number of errors:

Code:
C:\devkitPro\libnds\include\nds\dma.h: In function 'dmaFillWords':
C:\devkitPro\libnds\include\nds\dma.h:216:9: warning: implicit declaration of function 'DMA_FILL'; did you mean 'DMA_FIFO'? [-Wimplicit-function-declaration]
  216 |         DMA_FILL(3) = value;
      |         ^~~~~~~~
      |         DMA_FIFO
C:\devkitPro\libnds\include\nds\dma.h:216:21: error: lvalue required as left operand of assignment
  216 |         DMA_FILL(3) = value;
      |                     ^
C:\devkitPro\libnds\include\nds\dma.h:217:30: error: lvalue required as unary '&' operand
  217 |         DMA_SRC(3) = (uint32)&DMA_FILL(3);
      |                              ^
C:\devkitPro\libnds\include\nds\dma.h: In function 'dmaFillHalfWords':
C:\devkitPro\libnds\include\nds\dma.h:238:21: error: lvalue required as left operand of assignment
  238 |         DMA_FILL(3) = (uint32)value;
      |                     ^
C:\devkitPro\libnds\include\nds\dma.h:239:30: error: lvalue required as unary '&' operand
  239 |         DMA_SRC(3) = (uint32)&DMA_FILL(3);
      |                              ^
 

Coto

-
Member
Joined
Jun 4, 2010
Messages
2,979
Trophies
2
XP
2,565
Country
Chile
you're either passing an instance of variable "0x06000000" (like a pointer), or your devkit environment is broken. Try reinstalling the environment or ask in their forums.

edit: NVM, you've used a NDS header of DMA, which of course cause errors as your target is GBA. Try to replace "dma.h" with whatever header DMA bits for your GBA environment has.

Or you could give it a go to this (first example):
https://austinjadams.com/blog/autograding-gba-dma/
(in the 'u16 color = RED;' would go your 'rgb(200, 75, 75);' as you're using that RGB15 color value repeated on the DMA controller, to overwrite the whole 0x06000000 VRAM, pixel by pixel)


or this:
https://www.coranac.com/tonc/text/dma.htm
 
Last edited by Coto,
  • Like
Reactions: Kirbedev

Kirbedev

Member
OP
Newcomer
Joined
Nov 13, 2022
Messages
5
Trophies
0
Age
16
XP
77
Country
United States
In the end I just used Butano with a custom .h file that defined some addresses. Everything works now. Thanks for the help though!

P.S. You have no idea how good it feels to use C++ again after hours of fumbling away in C
 
Last edited by Kirbedev,
  • Like
Reactions: Coto

Coto

-
Member
Joined
Jun 4, 2010
Messages
2,979
Trophies
2
XP
2,565
Country
Chile
In the end I just used Butano with a custom .h file that defined some addresses. Everything works now. Thanks for the help though!

P.S. You have no idea how good it feels to use C++ again after hours of fumbling away in C
C++ is not as portable as C, besides, it's about 50% slower when functions due to vtables. But it's way easier to get things working at first, due to STD (the library)

edit: lol
 

ghjfdtg

Well-Known Member
Member
Joined
Jul 13, 2014
Messages
1,378
Trophies
1
XP
3,347
Country
C++ can be just as fast as C. It's all down to how you write your code. You can avoid vtables in most cases if you know how.
 

Coto

-
Member
Joined
Jun 4, 2010
Messages
2,979
Trophies
2
XP
2,565
Country
Chile
C++ can be just as fast as C. It's all down to how you write your code. You can avoid vtables in most cases if you know how.
That's rather vague, and false. Do not confuse devs.

C++ is slower on NDS and I can prove it.
I've ported pool / snooker games to NDS (it's just not public due to engine barely fitting in EWRAM) and they cause a 50% decrease in speed the moment name mangling and usage of STD libraries take place. Let alone virtual / friend classes.

on C it's fast, stable and reduces about 400K ~ of memory, libraries at the expense of reimplementing most of the platform specifics yourself.

You could also do C in C++ to speed up things, but it'll never be as fast as pure C code. And i've done that as well


This game needs at least 100mhz to run, but i've made it run at 66mhz through heavy usage of standard OpenGL displaylists and C. On C++ speed would have been unacceptable, like I said, again, 50% slower.


This NDS SnakeGL port is in C++ and CPU is near 100% just because it's in C++ (and if you run a profiler through Visual Studio 2012 you'll see most of the time spent is on STD libraries traversing across game instances, and looping waiting for timer in milliseconds to reach current framerate)

References:
Source 1
 
Last edited by Coto,

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • BigOnYa @ BigOnYa:
    Towelie runs my farm, he's awesome.
  • SylverReZ @ SylverReZ:
    @K3Nv2, Polly is still around from what I've heard.
  • K3Nv2 @ K3Nv2:
    @SylverReZ, is Pollys alt I knew it
  • BigOnYa @ BigOnYa:
    Yea I see him every once whi!e , incognito
  • SylverReZ @ SylverReZ:
    @K3Nv2, I'm not him. Keep looking.
    +1
  • K3Nv2 @ K3Nv2:
    Still don't know why he left unless someone really hurt his feelings
  • K3Nv2 @ K3Nv2:
    Don't know why people get so emotional online just get over it ffs
    +2
  • BigOnYa @ BigOnYa:
    He was the ass of gbatemp, everyone knocked on him, I honestly felt bad, even though I was guilty myself, but he egged it all on himself,
  • BigOnYa @ BigOnYa:
    But he still here, but under dif name, he pm me sometimes still even.
  • K3Nv2 @ K3Nv2:
    It's like they think we'll be in their bed pissing on it the next day
  • BigOnYa @ BigOnYa:
    I feel like gbatemp should make t-shirts or memorabilia to remember the lost ones. I bet the Polly shirts would sell out quick.
  • K3Nv2 @ K3Nv2:
    Nah that could actually bring lawsuits
  • K3Nv2 @ K3Nv2:
    Tempsuits
  • BigOnYa @ BigOnYa:
    PollySuits
  • BigOnYa @ BigOnYa:
    Your correct, Somebody would be guilty and there would be riots, then they storm the gbatemp capitol,
  • K3Nv2 @ K3Nv2:
    Online or not there are still certain rights that judges would have no issue handing out a warrant over
  • K3Nv2 @ K3Nv2:
    Just look at Kim dotcom
  • BigOnYa @ BigOnYa:
    Honestly I'm scared to, from you, but ok, lemme turn on vpn, virtual machine, private browser first
  • K3Nv2 @ K3Nv2:
    Remember that Alexa robot I gifted you
  • K3Nv2 @ K3Nv2:
    And that laptop Webcam you never tapped up
  • BigOnYa @ BigOnYa:
    That robot is here somewhere, I hear it moving around at night, but I haven't seen it for months.
  • BigOnYa @ BigOnYa:
    Oh that laptop I give to ancientboi, so you been watching him for months, and he's been watching you
  • K3Nv2 @ K3Nv2:
    Oh good more than enough material for the fbi
    +1
  • BigOnYa @ BigOnYa:
    Damn its 5 in morn, I gotta Go wake your mum and send her to work. Check ya later.
    AncientBoi @ AncientBoi: lol