SFML community forums

Help => Graphics => Topic started by: Kipernal on June 22, 2015, 04:33:41 am

Title: RenderTexture reuse
Post by: Kipernal on June 22, 2015, 04:33:41 am
I'm trying to find a way to have one RenderTexture that's reused multiple times throughout one frame.  Basically something like this:

Code: [Select]
// Render stuff to a reusable RenderTexture
// Use the RenderTexture's texture in a sprite

// Clear the RenderTexture, render new stuff to it
// Use the RenderTexture's texture in a different sprite

// Clear the RenderTexture, render new stuff to it
// Use the RenderTexture's texture in a different sprite

// Clear the RenderTexture, render new stuff to it
// Use the RenderTexture's texture in a different sprite

// Clear the RenderTexture, render new stuff to it
// Use the RenderTexture's texture in a different sprite

// (etc.)

My previous attempt just used a ton of RenderTextures, one for each object that needed it, but since they're not lightweight objects like normal textures are (relatively speaking), that gets out of hand really quickly, and causes a crash after too many have been allocated and memory runs out.

After that I tried just allocating a pool of RenderTextures and doling them out to whoever needed them, but RenderTextures can't be resized without arduously destroying and recreating their context (it takes about a quarter of a second on my machine--completely impossible without the user noticing), having a ton of RenderTextures that I might never need uses a lot of memory, and having a fixed size creates an artificial limit that I don't really like hanging over my head.

Finally, I tried just copying the RenderTexture's texture to a new Texture and using that, but even using glCopyImageSubData the performance hit was still too much.

So none of these options are really all that great.  I did try one other thing, but the results were kind of weird:

sf::RenderTexture renderTexture;
renderTexture.create(256, 256);


// RenderWindow creation and event loop boilerplate here
{
        window.clear();
       
        renderTexture.clear(sf::Color::Red);
        renderTexture.display();
        window.draw(QuickSprite{ 0, 0, renderTexture.getTexture() });

        renderTexture.clear(sf::Color::Blue);
        renderTexture.display();
        window.draw(QuickSprite{ 256, 256, renderTexture.getTexture() });

        window.display();
}
 

All this code is supposed to do is draw a red rectangle (via a RenderTexture) on one part of the screen and a blue one on another.  I didn't really expect it to work...and it didn't.  But what caught my attention was that instead of drawing two blue rectangles like I thought (or one of each color like I hoped), it drew two red ones, and I can't imagine why.  I also noticed while trying to figure this out that if I add renderTexture.getTexture().copyToImage() before the call to window.draw it works as I wanted, drawing a red and blue rectangle.  Specifically glGetTexImage does some magic to get it working, but that's a hack and I'm like 99% sure that even if it wasn't a performance hit I couldn't actually rely on it to do this completely unrelated task.


Anyway, this is just a very long-winded way of asking if there's any way I can get the reuse of RenderTextures working, because nothing I've come up with so far has really been satisfactory.  I'd be super appreciative if anyone out there has any ideas and could share them with me.
Title: AW: RenderTexture reuse
Post by: eXpl0it3r on June 22, 2015, 10:23:11 am
Question is, what do you need the render texture for each object every frame?
Title: Re: RenderTexture reuse
Post by: Kipernal on June 22, 2015, 05:54:51 pm
For a certain shader effect I need a (somewhat) high resolution rendering of the object that isn't affected by the current window's view--pulling the view out too far causes artifacts.  My basic idea was to render to a RenderTexture, then have a sprite use that texture, and then move onto the next object in line.  The main problem is that there can be a lot of these objects on the screen at once, so giving them all their own RenderTexture just isn't an option.  But that being said it also means that I don't need to actually preserve the texture's image data across frames, if that helps.
Title: Re: RenderTexture reuse
Post by: Hapax on June 23, 2015, 03:19:13 am
I don't think it's the render textures that are causing this unexpected result. I think you should make sure that your 'QuickSprite' class is doing what you think it is. You could you share 'QuickSprite' if you want opinions on it and it might help get to the root of your problem.

I inserted your exact code into a standard SFML skeleton base (the boilerplate you referred to) and implemented your QuickSprite class as simple as I could and it works fine.
(click to show/hide)
Title: Re: RenderTexture reuse
Post by: Kipernal on June 23, 2015, 03:30:16 am
Actually my QuickSprite was even lazier (I just directly inherited from sf::Sprite, though in retrospect I really should have just made a function that returned a normal sf::Sprite--no clue why I didn't...), but fundamentally they were the exact same thing.  I still did try copying and pasting your exact code, though, but it still shows two red rectangles on my screen.  Thanks for trying, though!  :)




That being said I did some more testing and I think I figured out what was stopping me from just reusing the RenderTexture and why it was drawing two red squares instead of two blue squares.  Sort of.  I don't want to say that it's a bug in SFML per se, but it seems really suspicious because the implication is that drawing using the same RenderTexture will actually always work...unless the two draw calls that use that RenderTexture's texture are not broken up by a call that uses a different/null texture.

Basically, this code, as mentioned before, does not work (at least on my machine):

window.clear(sf::Color::Black);

// Draw the first red rectangle
renderTexture.clear(red);
renderTexture.display();
window.draw(QuickSprite{ 0, 0, renderTexture.getTexture() });

// Draw the second blue rectangle
renderTexture.clear(blue);
renderTexture.display();
window.draw(QuickSprite{ 256, 256, renderTexture.getTexture() });

window.display();
 

This code, however, does:

window.clear(sf::Color::Black);

// Draw the first red rectangle
renderTexture.clear(sf::Color::Red);
renderTexture.display();
window.draw(QuickSprite{ 0, 0, renderTexture.getTexture() });

// Note this call--it seems to do nothing but without it we get two red squares
window.draw(sf::RectangleShape{});

// Draw the second blue rectangle
renderTexture.clear(sf::Color::Bed);
renderTexture.display();
window.draw(QuickSprite{ 256, 256, renderTexture.getTexture() });

window.display();
 

All it takes is a request to draw something with a null texture and suddenly I can reuse the RenderTexture to draw separate things like I wanted. I narrowed down the exact function calls that are necessary and it turns out it's the RenderWindow's applyTexture(NULL) call (and probably the call to activate(true) before that as well?).  I don't know enough about OpenGL to know why this happens, if it's just a fluke, or if it's actually an oversight in SFML.  Can anyone shed some light on this?
Title: Re: RenderTexture reuse
Post by: Hapax on June 23, 2015, 03:56:29 am
Inheriting from sf::Sprite?  :o

Your two codes have more differences that just that line. The colours theirselves are represented differently. In one code, they're variables; in the other, they're explicit SFML colours (even if one of them is "Bed"). These differences could lead on to other errors such as the variables not being set properly, or being altered by QuickSprite or something.
However, that's unlikely...

May I ask how you narrowed down the function in SFML that you think is causing your error?

Also, it would likely be helpful (to others that know more about this) if you could provide information on which version of SFML you are using, which operating system, which IDE (if you're using one), and which compiler. Whether you're running in debug or release, and whether or not you're statically linking might be of use too.
It's odd that the code I posted works differently for you so it looks like it is: in SFML somewhere, some compiler difference, or possibly a linking error. You might want to make certain that all libraries are linked correctly and you're using the latest versions of DLLs (if you're using them) etc..

EDIT: Since it makes sense to make a single sprite that lasts as long as the render texture and re-use it the same way that the render texture is re-used (rather than re-creating and destroying the sprite twice per frame), I re-wrote the code:
(click to show/hide)
Does this still give you the wrong result?
Title: Re: RenderTexture reuse
Post by: Kipernal on June 23, 2015, 04:27:35 am
Inheriting from sf::Sprite?  :o

Not something to keep around, of course, but sf::Sprite doesn't come with a constructor that takes a position and a texture and having temporaries around just cluttered the code.  Temporary insanity is why it was a class instead of a function that just returned a sf::Sprite.  :P

Your two codes have more differences that just that line. The colours theirselves are represented differently. In one code, they're variables; in the other, they're explicit SFML colours (even if one of them is "Bed"). These differences could lead on to other errors such as the variables not being set properly, or being altered by QuickSprite or something.
However, that's unlikely...

Whoops.  Those were just mistakes I made while cleaning up the code before posting it here.  I was originally doing some other color testing stuff and that's why one version has (misnamed) variables and the other just uses the sf::Color constants.  The result doesn't change though.

May I ask how you narrowed down the function in SFML that you think is causing your error?

Stepped through the debugger, skipping over certain functions to see what caused the blue rectangle to appear.  When I found what the functions were, I temporarily made all of RenderWindow's members public and called them directly (in place of the window.draw(sf::RectangleShape{}) in the above code).  With those functions in place the blue rectangle appears.

Also, it would likely be helpful (to others that know more about this) if you could provide information on which version of SFML you are using, which operating system, which IDE (if you're using one), and which compiler. Whether you're running in debug or release, and whether or not you're statically linking might be of use too.
It's odd that the code I posted works differently for you so it looks like it is: in SFML somewhere, some compiler difference, or possibly a linking error. You might want to make certain that all libraries are linked correctly and you're using the latest versions of DLLs (if you're using them) etc..

Sorry about that--since this started as a conceptual question it never crossed my mind to post that stuff.  Here's the information:

OS: Windows 8.1, 64 bit
Graphics card: AMD Radeon R7 200 Series (2048 MB memory)
SFML versions tested: Latest development snapshot
Compiler: Visual Studio 2015 RC.  Building for 32-bit.
Linkage: Static

I also tested on a super cheap laptop I have and that also gives two red squares.  Same specs as above except for the graphics card, which is probably just an integrated Intel chip.



EDIT: Since it makes sense to make a single sprite that lasts as long as the render texture and re-use it the same way that the render texture is re-used (rather than re-creating and destroying the sprite twice per frame), I re-wrote the code:

Does this still give you the wrong result?

Yep, unfortunately.   :-\
Title: Re: RenderTexture reuse
Post by: Hapax on June 23, 2015, 05:19:14 am
Here's the information:

OS: Windows 8.1, 64 bit
Graphics card: AMD Radeon R7 200 Series (2048 MB memory)
SFML versions tested: Latest development snapshot
Compiler: Visual Studio 2015 RC.  Building for 32-bit.
Linkage: Static

I also tested on a super cheap laptop I have and that also gives two red squares.  Same specs as above except for the graphics card, which is probably just an integrated Intel chip.
Just for comparison mine is:
OS: Windows 7, 64 bit
Graphics card: AMD Radeon 5450
SFML versions tested: 2.3 release
IDE: Visual Studio 2013.  Building for 32-bit.
Linkage: Tested both dynamic and static

Do you have other compilers available? If so, could you try it on those. If not, could you download a final release version of Visual Studio (earlier version) and try it on that?
Title: Re: RenderTexture reuse
Post by: Kipernal on June 23, 2015, 05:36:56 am
Alright, I just tested the exact same code you posted above (the one without the QuickSprite) using SFML 2.3 Release, Visual Studio 2013, building for 32-bit and with dynamic linkage, but unfortunately I'm still getting two red squares.  Naturally if I add window.draw(sf::RectangleShape{}) between the two draw calls I get one red and one blue, as before.

Also should probably mention just in case that my graphics drivers are up to date.  Exact version is probably meaningless but just in case it's listed as 8.01.01.1443.
Title: Re: RenderTexture reuse
Post by: Rosme on June 23, 2015, 04:24:54 pm
By curiosity, I tested it. Same result as Kipernal. Two red squares.

OS: Windows 8.1, 64 bit
Graphics card: Intel Integrated Graphics
SFML versions tested: 2.3 Release
Compiler: Visual Studio 2012. Building for 32 bit.
Linkage: Dynamic
Title: Re: RenderTexture reuse
Post by: Nexus on June 23, 2015, 06:16:07 pm
Which code have you tested? The one of Hapax without QuickSprite?

I have a setting very similar to Rosme: Windows 8.1 64 bit, Intel HD Graphics 3000, VS 2013 for 32 bit, dynamic SFML 2.3.

However I can't reproduce the problem. A blue and a red square are drawn as expected.
Title: Re: RenderTexture reuse
Post by: Jesper Juhl on June 23, 2015, 07:17:09 pm
Works for me on CentOS 7.1 (Linux) with SFML 2.3 and NVidia Quadro 2000M.
Title: Re: RenderTexture reuse
Post by: Kipernal on June 23, 2015, 07:59:03 pm
Just tested it on my laptop at work to see if there was any difference and it's working on that (showing one blue rectangle and one red rectangle) while the exact same executable shows two red rectangles on my home machine.  Environment there was Windows 7, 64-bit, with SFML static and integrated Intel graphics.

At any rate this shows that it's not just my build environment--the exact same binary is producing two different results on two different machines.
Title: Re: RenderTexture reuse
Post by: eXpl0it3r on June 23, 2015, 08:11:55 pm
(click to show/hide)

(https://i.imgur.com/2jxLP88.png)

Windows 8.1 Pro x64
AMD Radeon R9 280X
SFML 2.3 static
Title: Re: RenderTexture reuse
Post by: Hapax on June 23, 2015, 09:55:53 pm
Since it seemed to be only the people who are statically linking who are getting the wrong result, I re-tested it statically. It still worked and, in a similar direction of thought to you, Kipernal, I'm providing my built executable for you to test. Actually, I'm providing two as a check to see if it's just the render texture's clear() that's failing (or clearing with the wrong colour). The links to the executables are directly below the source code.

First one is the exact same code above ("without QuickSprite"):
(click to show/hide)

The second one draws a circle on the render texture after each clear (to see if it's clearing it and if it is, it's clearing with the wrong colour):
(click to show/hide)
Title: Re: RenderTexture reuse
Post by: Rosme on June 23, 2015, 09:57:51 pm
@Nexus: yes, Hapax one without Quicksprite.

I re-tried it, Debug and Release, x86 and x64, Static and Dynamic. Two red squares, always.

Edit: Hapax, this is what I get with your second code:

(click to show/hide)
Title: Re: RenderTexture reuse
Post by: shadowmouse on June 23, 2015, 10:02:35 pm
Just copied Hapax's first code in his latest post and got red and blue on Windows 7 with sfml 2.1 static.
Title: Re: RenderTexture reuse
Post by: Kipernal on June 23, 2015, 10:28:46 pm
Since it seemed to be only the people who are statically linking who are getting the wrong result, I re-tested it statically. It still worked and, in a similar direction of thought to you, Kipernal, I'm providing my built executable for you to test. Actually, I'm providing two as a check to see if it's just the render texture's clear() that's failing (or clearing with the wrong colour). The links to the executables are directly below the source code.

Just tried both executables, and I get the exact same results as Rosme on my home computer (AMD Radeon R7 200) and my laptop (Intel integrated).  That is, two red rectangles on the first test, and two red rectangles with two green circles inscribed in them, and blue artifacts around the second circle on the second test.

(http://i.imgur.com/56JumTO.png)

EDIT: wording
Title: Re: RenderTexture reuse
Post by: kitteh-warrior on June 24, 2015, 01:32:08 am
I tried the second sample code that Hapax posted.
To clarify, this:
The second one draws a circle on the render texture after each clear (to see if it's clearing it and if it is, it's clearing with the wrong colour):
(click to show/hide)

I tested it on my main system:
OS: Windows 8.1 Pro
GPU: AMD Radeon R4 Graphics
Linkage: Dynamic
Compiler: MinGW64 (5.0.2) [Used the same binaries for the other tests]
Results:
(click to show/hide)

I tested it on my secondary system:
OS: Windows 8.1 Home
GPU: Intel HD Graphics (this is a custom driver, to be more specific: Acer Aspire E1-510P-4402)
Linkage: Dynamic
Compiler: Used the previous binaries from main system*
Results:
(click to show/hide)

I tested it on my virtual machine (within my main system):
OS: Windows 7 Professional
GPU: VMWare's Internal
Linkage: Dynamic
Compiler: Used the previous binaries from main system*
Results:
(click to show/hide)

Upon all of the other posts, it could be Windows 8.1 that is causing a problem.
Title: Re: RenderTexture reuse
Post by: Hapax on June 24, 2015, 01:49:11 am
Well, the circle test certainly brought out some information but what that information means will be best interpreted by someone who can guess what is going on.
I'd recommend trying to remove display() or double call display() for the render texture (for the first block, the second block, or both - try them all!).

Upon all of the other posts, it could be Windows 8.1 that is causing a problem.
Windows 8.1 seems involved. Or, at least, something that is common in Windows 8.1.
It can't just be Windows 8.1 though as Nexus got the correct result. Nexus, what are you doing right?  ;D

Can someone - who is getting the error - try running the executable in compatibility mode for Windows 7?
Title: Re: RenderTexture reuse
Post by: kitteh-warrior on June 24, 2015, 02:02:32 am
Well, the circle test certainly brought out some information but what that information means will be best interpreted by someone who can guess what is going on.
I'd recommend trying to remove display() or double call display() for the render texture (for the first block, the second block, or both - try them all!).

Playing around with the code:
(click to show/hide)
This code outputs both image files to be correct. (possibly due to copying them from VRAM to RAM)

Also, removing the .display() calls did not solve the problem.
(click to show/hide)
This yields the exact same result as before.

Quote
Windows 8.1 seems involved. Or, at least, something that is common in Windows 8.1.
It can't just be Windows 8.1 though as Nexus got the correct result.
Oh, I guess I missed this post. :p

Quote
Can someone - who is getting the error - try running the executable in compatibility mode for Windows 7?
This yields the exact same result for me. I also tried running the executable as Administrator, yet no change.
Title: Re: RenderTexture reuse
Post by: Kipernal on June 24, 2015, 02:13:28 am
@Hapax Tried a few things, but all of them still drew the same artifact-y circle:


This code outputs both image files to be correct. (possibly due to copying them from VRAM to RAM)

I mentioned this before, but certain function calls result in the correct image being shown on-screen.  copyToImage being called on the RenderTexture's texture is one.  Calling applyTexture(NULL) on the RenderWindow (after making it public) is the other.

EDIT: spelling
Title: Re: RenderTexture reuse
Post by: Nexus on June 24, 2015, 12:34:52 pm
It is hardly ever the OS version that's causing the problem. And for graphical differences, it's almost never the compiler. So don't waste too much time exploring these design spaces. Much more likely are bugs or at least subtle behavior differences in graphics driver implementations. I hope you updated yours immediately before testing ;)

It looks like some OpenGL calls are cached for too long -- the glClear() seems to be only executed in certain scenarios, namely those where the buffer is prepared for download (RenderTexture::copyToImage()). Such calls usually flush the OpenGL pipeline. However, RenderTexture::display() explicitly calls glFlush() -- at least in the FBO implementation -- but that function's implementation may vary between drivers.

Those who have the problem:
Title: Re: RenderTexture reuse
Post by: Kipernal on June 24, 2015, 05:21:00 pm
Can you check which RenderTexture backend is used -- RenderTextureImplDefault or RenderTextureImplFBO?

RenderTextureImplFBO is used. If I force priv::RenderTextureImplFBO::isAvailable() to always return false, causing SFML to use RenderTextureImplDefault instead, everything works correctly, drawing a red and blue square.

Can you try if an OpenGL call glFinish() in place of/additional to RenderTexture::display() changes something?

I tried putting glFinish() before, after, and in place of both calls to renderTexture.display(), but there was no change (based on the circle test).
Title: Re: RenderTexture reuse
Post by: binary1248 on June 25, 2015, 05:16:06 am
This is definitely a driver bug. I can bet with you that multi-context tests weren't part of their OpenGL test suite, because who even makes use of that feature anyway right?

Because I (thankfully) don't have the privilege to understand how their driver "works" (or doesn't), I can only guess at this point.

After you are done drawing the first sprite, the RenderTexture's texture is left bound in the window's context. Normally this shouldn't be a problem, since drawing to the RenderTexture doesn't make use of it anyway (if it did, the results would be undefined). In fact, any normal drawing still works in this case, it's just the clear that doesn't for whatever reason.

Because the effects of OpenGL commands don't need to be complete right after they are issued, all that is done by calling all those functions is a command queue is built up. OpenGL guarantees that the effects of commands are applied in the exact order in which they were issued. Since there is only a single thread here, this also shouldn't be an issue. Commands are issued to each context serially anyway.

The problems only pop up when one tries to be smart about this system and start optimizing things that should be able to be optimized. In order to do this, I can imagine a dependency tree is internally built up that tracks which commands depend on the results of previous commands and which commands can be executed in parallel to others. The driver might be incorrectly thinking that it can't clear because the contents of the FBO attachment might still be needed somewhere. What's even stranger is that it just skips the clear command all together instead of just postponing it. Drawing a quad with the clear colour to the RenderTexture works, even though it does pretty much the same as the clear command.

Something probably just went wrong with the inter-context dependency tracking. "Normal" OpenGL users don't notice this and this bug is therefore probably not widely known because in your typical OpenGL application only 1 context is ever used anyway and if multiple are used, it's not to draw but to stream data better or balance the state validation load. There is no benefit to drawing from multiple contexts, and in our case there are even concrete drawbacks.

The thing with SFML is that it doesn't "do stuff like all the other guys do". Here are a few things that SFML does that you don't find in a typical OpenGL application:
It is a combination of these things and many others that make SFML "that special kid" that just never gets any attention. While perfectly legal according to the specification, driver developers would probably rather spend their paid time working on things that their "bigger customers" care about more. Maybe SFML might be able to get on that train one day when it starts to make use of Vulkan. ::)

There are several workarounds to solve this problem:

1. Alternate between 2 RenderTextures. This way you will implicitly force the window to rebind its texture and "break the dependency chain".
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderTexture renderTexture1;
    renderTexture1.create(256, 256);
    sf::Sprite renderSprite1(renderTexture1.getTexture());

    sf::RenderTexture renderTexture2;
    renderTexture2.create(256, 256);
    sf::Sprite renderSprite2(renderTexture2.getTexture());

    sf::RenderWindow window(sf::VideoMode(512, 512), "Re-using Render Textures Without QuickSprite", sf::Style::Default);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                window.close();
        }

        window.clear();

        renderTexture1.clear(sf::Color::Red);
        renderTexture1.display();
        renderSprite1.setPosition(0, 0);
        window.draw(renderSprite1);

        renderTexture2.clear(sf::Color::Blue);
        renderTexture2.display();
        renderSprite2.setPosition(256, 256);
        window.draw(renderSprite2);

        renderTexture1.clear(sf::Color::Green);
        renderTexture1.display();
        renderSprite1.setPosition(256, 0);
        window.draw(renderSprite1);

        renderTexture2.clear(sf::Color::Yellow);
        renderTexture2.display();
        renderSprite2.setPosition(0, 256);
        window.draw(renderSprite2);

        window.display();
    }

    return EXIT_SUCCESS;
}

2. Manually break the dependency chain by unbinding and rebinding the RenderTexture's texture yourself. It is important to rebind it after unbinding or else the window's cached texture state will go out of sync and you will need to resetGLStates() to fix it.
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderTexture renderTexture;
    renderTexture.create(256, 256);
    sf::Sprite renderSprite(renderTexture.getTexture());

    sf::RenderWindow window(sf::VideoMode(512, 512), "Re-using Render Textures Without QuickSprite", sf::Style::Default);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                window.close();
        }

        window.clear();

        renderTexture.clear(sf::Color::Red);
        renderTexture.display();
        renderSprite.setPosition(0, 0);
        window.draw(renderSprite);

        sf::Texture::bind(0);
        sf::Texture::bind(&renderTexture.getTexture());

        renderTexture.clear(sf::Color::Blue);
        renderTexture.display();
        renderSprite.setPosition(256, 256);
        window.draw(renderSprite);

        window.display();
    }

    return EXIT_SUCCESS;
}

3. Just draw a quad covering the entire RenderTexture to clear it. Draw operations seem to work even though clears do not.
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderTexture renderTexture;
    renderTexture.create(256, 256);
    sf::Sprite renderSprite(renderTexture.getTexture());

    sf::RectangleShape clearRect(sf::Vector2f(256, 256));
    clearRect.setFillColor(sf::Color::Blue);

    sf::RenderWindow window(sf::VideoMode(512, 512), "Re-using Render Textures Without QuickSprite", sf::Style::Default);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed || event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
                window.close();
        }

        window.clear();

        renderTexture.clear(sf::Color::Red);
        renderTexture.display();
        renderSprite.setPosition(0, 0);
        window.draw(renderSprite);

        renderTexture.draw(clearRect);
        renderTexture.display();
        renderSprite.setPosition(256, 256);
        window.draw(renderSprite);

        window.display();
    }

    return EXIT_SUCCESS;
}

I'd say option 2 has the lowest overhead followed by 1 then 3. Going through the whole draw process just to fill the framebuffer with a fixed value is really wasteful, and creating multiple FBO objects where unnecessary is also wasteful. If you were going to use multiple RenderTextures anyway, then option 1 isn't that bad.
Title: Re: RenderTexture reuse
Post by: Kipernal on June 25, 2015, 01:50:30 pm
Can confirm that all three of those work.

Would it be worth it adding #2 into SFML?  It is technically a driver bug but this seems like the kind of thing SFML would handle to make everything "just work," and the fix seems to be incredibly easy.  I just tried adding a flag to sf::Texture that marked it as belonging to a RenderTexture and then, at the end of RenderTarget::draw, added the following code:

if (states.texture && states.texture->m_ownedByRenderTexture)
{
    Texture::bind(0);
    m_cache.lastTextureId = 0;
}

Seemed to make everything work alright.
Title: Re: RenderTexture reuse
Post by: binary1248 on June 26, 2015, 12:48:36 am
You might not know this, but the first half of this issue was already fixed more than a year ago (as discussed here (http://en.sfml-dev.org/forums/index.php?topic=9350.0), commit (https://github.com/SFML/SFML/commit/e6b5ce1f27d22aa0150c1376550b2e3f1baec09a)). The "fix" is still present in the current RenderTarget code with the accompanying comment.

Now that it is obvious to me that it was only half of a fix, I guess your method would provide the only full solution to this problem. It isn't even as complicated as you think. sf::Texture already has a member called m_pixelsFlipped which is only set when it is an FBO attachment, so that can be checked for in the draw() method.
Title: Re: RenderTexture reuse
Post by: Kipernal on June 26, 2015, 01:36:31 pm
Went ahead and made a pull request (https://github.com/SFML/SFML/pull/915).  Thank you for the help, everyone!

It isn't even as complicated as you think. sf::Texture already has a member called m_pixelsFlipped which is only set when it is an FBO attachment, so that can be checked for in the draw() method.

I noticed that, but unfortunately m_pixelsFlipped is also set to true in Texture::update(sf::Window, ...), which looks like it would result in the texture being rebound every call to draw if it was based on the window.