SFML community forums

Help => Graphics => Topic started by: awsumpwner27 on January 13, 2013, 01:11:06 am

Title: RenderTextures and dynamic memory
Post by: awsumpwner27 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?
Title: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r 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 (http://en.sfml-dev.org/forums/index.php?topic=9359.0).
(Disclaimer: It doesn't mean it would fix the problem, but it would just make your code safer.) ;)
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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:
Title: AW: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r 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 (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list?page=2).

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(...);
// ...
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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;
}
Title: Re: RenderTextures and dynamic memory
Post by: FRex on January 13, 2013, 05:21:34 am
It works for me.
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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:

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?
Title: Re: RenderTextures and dynamic memory
Post by: FRex 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]
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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.
Title: Re: RenderTextures and dynamic memory
Post by: FRex 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.
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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.
Title: Re: RenderTextures and dynamic memory
Post by: FRex on January 13, 2013, 10:32:20 am
clear is clearing with black, clear(sf::Color::Transparent) to not have black box.
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 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.
Title: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r 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.
Title: Re: RenderTextures and dynamic memory
Post by: FRex 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.

Title: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r on January 13, 2013, 05:17:48 pm
It requires clear on integrated intel in a laptop.
Yeah well not calling clear is wrong anyways, although it sometimes works. ;)
Title: Re: RenderTextures and dynamic memory
Post by: FRex on January 13, 2013, 05:22:54 pm
'We' discovered it after I ran the snippet you posted that didn't contain clear in it. :P
Title: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r on January 13, 2013, 05:34:18 pm
I never posted code without the clear in it. ;)
All the snippets above that show different variants contain all the clear call. :)
Title: Re: RenderTextures and dynamic memory
Post by: awsumpwner27 on January 13, 2013, 09:21:01 pm
I ran some of those examples. It would appear that any code that gets rid of shipRTex before the declaration of the Sprite ship produces a window which appears to never be cleared. (i.e. It's a window that displays what used to be on the screen before it appeared, rather than what I want to be drawn there.)

Also, for some information on my graphics card, I'll quote an earlier thread.

I checked out the examples, and I was disappointed to find out that the Shader example didn't work. I updated my graphics driver, hoping that it would make a difference, but it didn't. I got this computer about 4 years ago, and apparently I'm using a "Intel(R) G33/G31 Express Chipset Family" graphics card. Also, the driver update I got was about 3 years old. :|

So, what are my options?

Also, if it's relevant, I recently found out that I'm using OpenGL version 1.4.0

ugh
Title: Re: RenderTextures and dynamic memory
Post by: eXpl0it3r on January 13, 2013, 10:55:07 pm
I ran some of those examples. It would appear that any code that gets rid of shipRTex before the declaration of the Sprite ship produces a window which appears to never be cleared. (i.e. It's a window that displays what used to be on the screen before it appeared, rather than what I want to be drawn there.)
Sounds strange... :-\

I'm using a "Intel(R) G33/G31 Express Chipset Family" graphics card.
Also, if it's relevant, I recently found out that I'm using OpenGL version 1.4.0
Well the only thing I could say is: Get a newer piece of hardware... ;)
I know, I know you probably don't have the money etc. but it's just that you can't expect that much graphical stuff will work... If you want some very simple graphics, your CPU might be more reliable and thus I'd suggest to take a look at SDL (not the newest version), which makes use of the CPU rather then the GPU...
Title: Re: RenderTextures and dynamic memory
Post by: FRex on January 14, 2013, 06:17:15 am
Quote
I never posted code without the clear in it. ;)
http://en.sfml-dev.org/forums/index.php?topic=9139.msg63009#msg63009
In case you're looking for code, scroll up to your previous post. ;D
Quote
SDL
>:(
Quote
I'm using a "Intel(R) G33/G31 Express Chipset Family"
Mine is labeled similarly(I don't remember the G and numbers) and it has even bigger problems on Linux and almost no problems on Windows.