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

Author Topic: RenderTextures and dynamic memory  (Read 8333 times)

0 Members and 1 Guest are viewing this topic.

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
RenderTextures and dynamic memory
« on: January 13, 2013, 01:11:06 am »
I have an issue with how things are rendering. When I delete a RenderTexture, the screen is never cleared, and nothing ever renders. I checked if RenderWindow::clear() is even called by outputting text after the method is called, and looks like it is. If I comment out the line that deletes the RenderTexture, everything works fine.


        sf::Vertex * sh = new sf::Vertex[3];
        sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
        sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
        sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

        sf::RenderTexture * shipRTex = new sf::RenderTexture; //A RenderTexture due to be deleted
        if(!shipRTex->create(64,64)){
                return -1;
        }
        shipRTex->draw(sh, 3, sf::Triangles);
        shipRTex->setSmooth(false);
        shipRTex->display();

        sf::Texture shipTex; //This will replace the RenderTexture
        if(!shipTex.create(64,64)){
                return -1;
        }
        shipTex = shipRTex->getTexture(); //Replacing

        sf::Sprite ship(shipTex);
        ship.setColor(sf::Color(255,255,255,255));
        ship.setOrigin(32, 32);
        ship.setScale(1.f/8.f, 1.f/8.f);
        ship.setPosition(window.getSize().x/2, window.getSize().y/2);

        delete[] sh;
        delete shipRTex; //Everything renders fine without this line
 

I checked to see if this was because RenderTexture::getTexture() only points to a texture, (which makes no sense because a copy is made to replace it, but I decided to try it anyway) so I tried deleting shipTex to see what would happen if the sprite no longer had something to render. A white square appeared, but it didn't cause the problems deleting shipRTex did. I wondered if it was because I had not called Texture::create(), but that didn't help. I finally ran out of ideas and I came here. Do you have any idea about what could be causing this?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11038
    • View Profile
    • development blog
    • Email
Re: RenderTextures and dynamic memory
« Reply #1 on: January 13, 2013, 01:21:40 am »
Could you please provide complete and minimal example?

Because from the text and the posted source it's not clear when the RenderTexture gets deleted.
Also could you specify what you mean by "the screen is never cleared, and nothing ever renders"?

Why do you have to allocate the render texture dynamically?
Have you ever considered using a smart pointer/RAII over manual calling delete? For instance if the posted code failt to create the texture, but the render texture got created, the the render texture will never get deleted, since you directly return with -1 and thus you create a memory leak. Maybe you could talk a look at this discussion.
(Disclaimer: It doesn't mean it would fix the problem, but it would just make your code safer.) ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #2 on: January 13, 2013, 01:51:31 am »
Why do you have to allocate the render texture dynamically?

You know, I don't think I do.

I just started a sort of experiment, seeing if I could. I have been a "beginner" in using C++ for maybe over a year, and only in the past few weeks have I found out what C++ can really do. I was unaware of a lot of features, and now I know a lot of them, but I hardly know what they do other than what they appear to do on the surface.

The truth is, when you replied and started suggesting things, you put a bit too much faith in my understanding of this, but that's no fault of yours, my friend. It is mine.

I think I put myself in a situation where I need help but don't know how to ask for it.

I think I need a list of things to understand how to fix my problem, because I don't know what I don't know:
  • What you need for a complete and minimal example
  • What's a smart pointer, what does it do? How should I use it? And when?
  • Where can I find a more in-depth resource for learning C++? (Google could hardly help because I don't know enough to know what to search for.)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11038
    • View Profile
    • development blog
    • Email
AW: Re: RenderTextures and dynamic memory
« Reply #3 on: January 13, 2013, 02:14:16 am »
  • What you need for a complete and minimal example
  • What's a smart pointer, what does it do? How should I use it? And when?
  • Where can I find a more in-depth resource for learning C++? (Google could hardly help because I don't know enough to know what to search for.)
That's quite alright, everyone as to start somewhere. ;)

A minimal and complete example is a full progam that I can give my compiler and it will compile and run. It of course should also reproduce the problem. Your posted code is neatly complete, it just lacks the definition of the window and how you draw things to it. Addituonally everything should be wrapped into the main function.

Just google the term smart pointer in relation to C++ to get a better understanding of what it is.

SFML is a library that actually requires some basic knowledge in C++, you might still miss so of those basis. To really get into C++ there's no other way around than reading a good book. A list of good books can be found here.

In C++ unlike Java or PHP you don't instanciate classes only with new. You can simply create them on the application's stack, e.g.
sf::Texture tex;
tex.create(...);
// ...
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #4 on: January 13, 2013, 03:02:02 am »
Here is a complete example, which demonstrates the problem, with a whole lot of stuff taken out so as to avoid distracting from the focus of the problem. It's not quite as minimal as I would want it, but I wanted to keep the graphical stuff mostly the same.

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

int main(){

        sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);

        sf::Vertex * sh = new sf::Vertex[3];
        sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
        sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
        sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

        sf::RenderTexture * shipRTex = new sf::RenderTexture;
        if(!shipRTex->create(64,64)){
                return -1;
        }
        shipRTex->draw(sh, 3, sf::Triangles);
        shipRTex->setSmooth(false);
        shipRTex->display();

        sf::Texture shipTex;
        if(!shipTex.create(64,64)){
                return -1;
        }
        shipTex = shipRTex->getTexture();

        sf::Sprite ship(shipTex);
        ship.setColor(sf::Color(255,255,255,255));
        ship.setOrigin(32, 32);
        ship.setScale(1.f/4.f, 1.f/4.f);
        ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);

        delete[] sh;
        delete shipRTex; //That pesky line
       
        window.setVerticalSyncEnabled(true);
        window.setFramerateLimit(60);

        while (window.isOpen()){
                sf::Event event;
                while (window.pollEvent(event)){
                        if(event.type == sf::Event::Closed){
                                window.close();
                        }
                }

                window.clear(sf::Color(127,63,31,255));
                window.draw(ship);
                window.display();

        }

        return 0;
}

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: RenderTextures and dynamic memory
« Reply #5 on: January 13, 2013, 05:21:34 am »
It works for me.
Back to C++ gamedev with SFML in May 2023

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #6 on: January 13, 2013, 05:34:22 am »
It works for me.

oh no

ohhhhh nooooo

The implications of what you have just told me are terrible.

If what you say is true, there is about a 33.33% chance that it's a matter that is out of my hands.

The meaning of this could be:
  • It's the version of SFML I'm using. (I can fix it.)
  • I can change my code to work for everyone. (Fixable.)
  • It's my computer. (I can't fix it.)

Of course, it depends on what you say "works" is. Does a orange triangle appear on a brown-orange background? Or does a window open that never appears to have RendorWindow::clear() called on it?

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: RenderTextures and dynamic memory
« Reply #7 on: January 13, 2013, 05:39:38 am »
See attachment.
First of all, try adding
shipRTex->clear();
before
shipRTex->draw(sh, 3, sf::Triangles);

[attachment deleted by admin]
« Last Edit: January 13, 2013, 05:42:08 am by FRex »
Back to C++ gamedev with SFML in May 2023

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #8 on: January 13, 2013, 05:51:04 am »
Yeah, that's what it should look like.

First of all, try adding
shipRTex->clear();
before
shipRTex->draw(sh, 3, sf::Triangles);

I just tried that now, but it didn't help. Thank you though.

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: RenderTextures and dynamic memory
« Reply #9 on: January 13, 2013, 06:05:33 am »
It must work unless you have something extremely exotic for gpu.
It would work on my integrated crappy intel laptop card, so get freshest SFM and drivers for your card.
Back to C++ gamedev with SFML in May 2023

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #10 on: January 13, 2013, 10:26:17 am »
I went about the intense and very difficult task (for a beginner, at least) of getting the latest release of SFML, and then building it. I was successful. I looked went and built my project again, and the problem wasn't fixed. I commented out that one, troublesome line, and I found that the triangle was in a black box. I modified the code to no longer need the dynamic memory stuff (something that fixes my problem, but does not give me a solution to the problem I encountered), and the box remained. I remembered a line that had been entered into the code recently, and I got rid of it. No more box. The box-causing line was:
shipRTex.clear();

:|

I would normally be okay with this, except I don't think it behaved like that before I updated SFML.

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: RenderTextures and dynamic memory
« Reply #11 on: January 13, 2013, 10:32:20 am »
clear is clearing with black, clear(sf::Color::Transparent) to not have black box.
Back to C++ gamedev with SFML in May 2023

awsumpwner27

  • Newbie
  • *
  • Posts: 27
    • View Profile
Re: RenderTextures and dynamic memory
« Reply #12 on: January 13, 2013, 10:42:03 am »
clear is clearing with black, clear(sf::Color::Transparent) to not have black box.
Ah, that makes sense.

I think I'll retire for the evening now, and I'll also ignore this problem while I continue to develop my project. However, I still want to know why it happens. Because as a person who wishes to learn from mistakes, I need to know what went wrong. How does a change in memory relate to the rendering of something on a window? What causes what? Is it direct? Is it a long chain of unfortunate events? Maybe I'll know one day, but for now, I need rest. Goodnight folks.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11038
    • View Profile
    • development blog
    • Email
Re: RenderTextures and dynamic memory
« Reply #13 on: January 13, 2013, 04:10:37 pm »
How does a change in memory relate to the rendering of something on a window?
The window you see is just the representation of some memory in the GPU. A render texture is basically nothing else than a window that doesn't get draw to the screen, but is only kept in memory.
So when you look at the chain RenderTexture -> Texture -> Window you see the connection between. But it seems like on your GPU textures are handeled oddly and when you actually copy from the render texture into a normal texture, it somehow still links to the render texture. Now when you delete the render texture before drawing it to the screen, the copied texture seems to be also affected by the deletion and thus shows nothing.

What causes what? Is it direct?
Hard to say... It works for FRex on an Intel GPU and for me on an AMD GPU, so it really seems to be a problem with your PC or at least with the graphics card or its driver. (Is the driver up-to-date?)

What happens if you delete the render texture after the application execution? E.g.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

int main(){

    sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);

    sf::Vertex * sh = new sf::Vertex[3];
    sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
    sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
    sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

    sf::RenderTexture * shipRTex = new sf::RenderTexture;
    if(!shipRTex->create(64,64)){
        return -1;
    }
    shipRTex->clear(sf::Color::Transparent);
    shipRTex->draw(sh, 3, sf::Triangles);
    shipRTex->setSmooth(false);
    shipRTex->display();

    sf::Texture shipTex;
    if(!shipTex.create(64,64)){
        return -1;
    }
    shipTex = shipRTex->getTexture();

    sf::Sprite ship(shipTex);
    ship.setColor(sf::Color(255,255,255,255));
    ship.setOrigin(32, 32);
    ship.setScale(1.f/4.f, 1.f/4.f);
    ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
   
    window.setVerticalSyncEnabled(true);
    window.setFramerateLimit(60);

    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)){
            if(event.type == sf::Event::Closed){
                window.close();
            }
        }

        window.clear(sf::Color(127,63,31,255));
        window.draw(ship);
        window.display();

    }

    delete[] sh;
    delete shipRTex; //That pesky line

    return 0;
}
Note: The application will have a memory leak, if render texture fails to be created.

But as I said the dynamic allocation with new/delete is kind of depreciated in C++. If you don't have to create the render texture on the fly you could just create everything on the applications stack:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

int main(){

    sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);

    sf::Vertex sh[3];
    sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
    sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
    sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

    sf::RenderTexture shipRTex;
    if(!shipRTex.create(64,64)){
        return -1;
    }
                shipRTex->clear(sf::Color::Transparent);
    shipRTex.draw(sh, 3, sf::Triangles);
    shipRTex.setSmooth(false);
    shipRTex.display();

    sf::Texture shipTex;
    if(!shipTex.create(64,64)){
        return -1;
    }
    shipTex = shipRTex.getTexture();

    sf::Sprite ship(shipTex);
    ship.setColor(sf::Color(255,255,255,255));
    ship.setOrigin(32, 32);
    ship.setScale(1.f/4.f, 1.f/4.f);
    ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);

    window.setVerticalSyncEnabled(true);
    window.setFramerateLimit(60);

    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)){
            if(event.type == sf::Event::Closed){
                window.close();
            }
        }

        window.clear(sf::Color(127,63,31,255));
        window.draw(ship);
        window.display();

    }

    return 0;
}
 
Note: Since everything is on the stack, there won't be any memory issue.

Or if you really need dynamic memory, then you should make use of the STL with vector and unique_ptr (or if unnecessary shared_ptr):
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#include <memory> // unique_ptr
#include <vector>

int main(){

    sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);

    std::vector<sf::Vertex> sh(3);
    sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
    sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
    sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

    std::unique_ptr<sf::RenderTexture> shipRTex(new sf::RenderTexture);
    if(!shipRTex->create(64,64)){
        return -1;
    }
                shipRTex->clear(sf::Color::Transparent);
    shipRTex->draw(sh.data(), sh.size(), sf::Triangles);
    shipRTex->setSmooth(false);
    shipRTex->display();

    sf::Texture shipTex;
    if(!shipTex.create(64,64)){
        return -1;
    }
    shipTex = shipRTex->getTexture();

    sf::Sprite ship(shipTex);
    ship.setColor(sf::Color(255,255,255,255));
    ship.setOrigin(32, 32);
    ship.setScale(1.f/4.f, 1.f/4.f);
    ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);

    window.setVerticalSyncEnabled(true);
    window.setFramerateLimit(60);

    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)){
            if(event.type == sf::Event::Closed){
                window.close();
            }
        }

        window.clear(sf::Color(127,63,31,255));
        window.draw(ship);
        window.display();

    }

    return 0;
}
 
Note: Since unique_ptr is an RAII object, the resources will automatically get released when the scope is left.

But I think your idea was to free the memory as soon as possible, thus when the render texture isn't needed anymore. This could also be easily done with smart pointers and some brackets:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>

#include <memory> // unique_ptr
#include <vector>

int main(){

    sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);

    sf::Texture shipTex;
    if(!shipTex.create(64,64)){
        return -1;
    }

    // RenderTexture scope
    {
        std::vector<sf::Vertex> sh(3);
        sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
        sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
        sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));

        std::unique_ptr<sf::RenderTexture> shipRTex(new sf::RenderTexture);
        if(!shipRTex->create(64,64)){
            return -1;
        }
        shipRTex->clear(sf::Color::Transparent);
        shipRTex->draw(sh.data(), sh.size(), sf::Triangles);
        shipRTex->setSmooth(false);
        shipRTex->display();


        shipTex = shipRTex->getTexture();
    }

    sf::Sprite ship(shipTex);
    ship.setColor(sf::Color(255,255,255,255));
    ship.setOrigin(32, 32);
    ship.setScale(1.f/4.f, 1.f/4.f);
    ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);

    window.setVerticalSyncEnabled(true);
    window.setFramerateLimit(60);

    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)){
            if(event.type == sf::Event::Closed){
                window.close();
            }
        }

        window.clear(sf::Color(127,63,31,255));
        window.draw(ship);
        window.display();

    }

    return 0;
}
 

Would be interesting to see which versions work and which don't.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: RenderTextures and dynamic memory
« Reply #14 on: January 13, 2013, 05:01:15 pm »
Welcome to the neverending adventure of troubleshooting gpu problems!
Quote
Hard to say... It works for FRex on an Intel GPU and for me on an AMD GPU
It requires clear on integrated intel in a laptop. And works as is on GeForce 440 in normal pc.

Back to C++ gamedev with SFML in May 2023