Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Maybe found a bug on the r-pi, or doing something stupid  (Read 1643 times)

0 Members and 1 Guest are viewing this topic.

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Maybe found a bug on the r-pi, or doing something stupid
« on: August 30, 2023, 06:59:58 am »
I'm trying to figure out if the raspberry Pi has the GPU to run an application at 1080p, and I started off just setting up a 1080x1920 texture (my monitor is rotated :) and drawing it. All well and good - takes about 9ms, which is glacial in desktop terms but perfectly adequate for my purposes.

Then I tried setting up a background texture - with the idea that in the real world, I'd update just parts of the background texture as they change, and then blit the background to the window. Figures were still good, but I wasn't seeing the effect I was expecting on the raspberry Pi. Here's the code:

#include <SFML/Graphics.hpp>

int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(1080, 1920), "SFML window");
    // Load a sprite to display
    sf::Texture texture;
    if (!texture.loadFromFile("/users/simon/Downloads/bg.jpg"))
        return EXIT_FAILURE;
    sf::Sprite sprite(texture);

        sf::RenderTexture backing;
        if (!backing.create(1080,1920))
                return EXIT_FAILURE;
               
        backing.draw(sprite);
       
        sf::Clock cron;
        int msecs = 0;
        int frames = 0;
       
    // Start the game loop
    while (window.isOpen())
    {
                msecs += cron.restart().asMilliseconds();
       
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window: exit
            if (event.type == sf::Event::Closed)
                window.close();
        }
       
        int w = random() % 320 + 320;
        int h = random() % 200 + 200;
        int x = random() % (1080-w);
        int y = random() % (1920-h);
       
        sf::RectangleShape rs(sf::Vector2f(w,h));
        rs.setPosition(sf::Vector2f(x,y));
        rs.setOutlineColor(sf::Color(255, 0, 0, 255));
        rs.setFillColor(sf::Color(0,0,0,0));
        rs.setOutlineThickness(1);
               
                backing.draw(rs);
                backing.display();
       
                const sf::Texture& backingTexture = backing.getTexture();
                sf::Sprite BG(backingTexture);

        // Clear screen
        window.clear();
       
        // Draw the backing-texture sprite
        window.draw(BG);
       
        // Update the window
        window.display();
       
        // Aggregate/calculate frame rate
        frames ++;
        if (frames == 100)
                {
                fprintf(stderr, "Frame time: %d.%02d msecs = %5.3f fps\n", msecs/100, msecs%100, (100000.0f/msecs));
                frames = 0;
                msecs = 0;
                }
    }
    return EXIT_SUCCESS;
}
 

... and since I'm not clearing the background texture at all, I'd expect this to steadily turn red as time went by. On the Mac, this is what happens. On the Pi, I only ever see about 50 (?) rectangles drawn (this is more obvious when you remove the setFillColor() call) - and they're frequently the same rectangles as well...

It's not just a crappy random number generator on the Pi because there's a flickering effect as rectangles are drawn then erased then redrawn ad infinitum. What I'm seeing would be what you expect if

(a) there was a call to srandom() at the start of every render loop.   
(b) the backing texture was being cleared at the start of every render loop

So am I "holding this wrong" or is this a bug ?

FYI: this is self-compiled SFML 2.6.0 on an up-to-date r-pi bullseye...
@raspberrypi:~/src/SFML-2.6.0 $ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
 
... (without DRM, which I couldn't get to work, it just complained about permissions whenever I ran a compiled app), and without warnings=errors (because there's a few of those regarding tests being the same on both branches with gcc10, as well as the occasional type mismatch between variable and method/function signature)
« Last Edit: August 31, 2023, 11:45:52 am by eXpl0it3r »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #1 on: August 30, 2023, 03:28:17 pm »
Render Targets (render textures included) are double buffered so when you display it, you start drawing on the other one that was there before you drew it. This gives an "alternating effect". There's very little reason to not completely clear the target (texture) each time before drawing (technically, after displaying/swapping) unless what you're drawing completely covers the target.

Of course, you only need to update the render texture when it (all or any of it) changes, which is one of its great advantages since you must update the window constantly.
But, since you're updating the render texture every frame, there's very few reasons to not just draw it straight to the window and get the same result.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #2 on: August 30, 2023, 06:16:00 pm »
Ok, it's been a while since I used SFML and I'd forgotten they were double-buffered :)

The actual use-case here is to implement a new version of the old GEM desktop / user interface for a retro project. The AES in GEM maintains a dirty-rect list, so the plan was to have an off-screen texture which persists the areas that don't need to be redrawn, and then just copy that offscreen texture to the window to "render the UI".

I've seen all the repeated warnings about making sure to clear the RenderWindow, which doesn't mesh well with a "only redraw this bit", so wasn't planning on drawing directly into the window itself. The code is just a quick-and-dirty test to see if assumptions held...

I still think something is off here, though. Files are too big to attach, so I put up a video of the Mac running the code above and it did pretty much what I expect.

Here is the same code (with the rs.setFillColor() call commented out to make things clearer) running on the Pi. I only get a small number of rectangles before it's somehow reset (and I don't see how that can happen). It's as if it is drawing rectangles to the screen, not the backing texture and every now and then putting the backing texture to the screen as well (thus resetting the rectangles shown).
« Last Edit: August 30, 2023, 06:19:27 pm by SpacedCowboy »

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #3 on: August 30, 2023, 09:14:58 pm »
replying to my own post here, but I had the chance to test it on a newer (pre-release) version of the Pi OS ("bookworm", not "bullseye") and it worked just like it did on the Mac, so maybe there's a problem with bullseye. Th bookwork version was a lot slower than the bullseye one though and makes it pretty much unusable - I need 60fps not 30fps, on the other hand I need it to, you know, work as well :)

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #4 on: August 30, 2023, 11:12:02 pm »
It's not just render windows; it's any render target. You should always clear, draw and display.
[I can think of a reason where it's not actually necessary but it would be not using those unused parts due to texture rectangles. Still, clearing wouldn't hurt.]

If you want to "only update a bit at a time", you can manually double-buffer the render textures by creating two. Then, on first one, clear it, copy the second one to the first one, then add to the first one. Then, next time, clear the second one, copy the first one to the second one, then add to the second one. Then you repeat.
Of course, each time you should clear, draw (copy and add) and display the render texture you're using.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #5 on: August 30, 2023, 11:32:41 pm »
Thanks for the help :) The thing is that I have two primary constraints.

1) The Pi has limited bandwidth on its internal memory bus, and the GPU shares the bus with the CPU, it doesn't have separate memory. I can't go copying HD-sized textures around so manually double-buffering doesn't sound workable due to the copying requirement. I can get one (1) of these copies per frame and still keep a 60fps frame rate, so that has to be the "update the display from the frame-buffer" pass.

2) I want to try and stick with the same paradigm that the GEM routines were designed for - ideally I'd like to link this up to an emulator later on, and having things work "like they should" will make it easier. GEM didn't double-buffer the screen, it just sent a list of dirty-rects to the application and expected drawing to happen in the primary frame-buffer.

I was drawn to SFML because it has a lot of the low-level graphic API calls with options already built in (eg: draw a rectangle, in a colour, with a fill and a specific line-thickness). It doesn't do dash-patterned lines, but I think I could probably do that in a shader - it may just be that this isn't a good match, and that's ok too, that's sort of what I'm trying to find out...

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Maybe found a bug on the r-pi, or doing something stupid
« Reply #6 on: August 31, 2023, 12:13:52 pm »
It's worth noting that when I say "manually double-buffering" that what I'm suggesting is the 'concept'.
You're not actually "copying" textures around (that's a lot of data!), you'd be simply drawing a rectangle (or sprite) onto one using the other as a texture; it's already usable as a texture.

Sticking with a paradigm is understandable and, of course, fine. You can 'hide' this and make it automatic so that you only every draw to a render texture (and the flipping which one is used can be done automatically - note you don't actually swap the textures, just which one you point to). That said, you're emulating the paradigm and in doing so may need to use others behind-the-scenes.

Good luck with your project; it sounds interesting! :)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*