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

Author Topic: How to reload a texture without adding a driver overhead?  (Read 4916 times)

0 Members and 1 Guest are viewing this topic.

oomek

  • Jr. Member
  • **
  • Posts: 90
    • View Profile
    • Email
How to reload a texture without adding a driver overhead?
« on: October 16, 2018, 07:26:36 pm »
I draw a set of sprites on the screen and reload textures quite often with png files which have random pixel dimensions which I cannot change. I found that calling loadFrom...() functions on the texture that is currently being drawn on the screen adds a penalty of up to 16ms delay. I found a way to eliminate that delay like in the code below, but this causes a vram leak. Is there any better way of coding it without vram leakage, or adding an additional array of textures and flipflop between them?

sf::Image img;
if ( !img.loadFromStream( s ) )
        return false;

sf::Texture *new_tex = new sf::Texture;
m_texture.swap( *new_tex );
m_texture.loadFromImage( img );
« Last Edit: October 16, 2018, 07:33:03 pm by oomek »

Antonio9227

  • Newbie
  • *
  • Posts: 25
    • View Profile
Re: How to reload a texture without adding a driver overhead?
« Reply #1 on: October 16, 2018, 09:00:43 pm »
I can think of 2 ways of dealing with this; the first one is having an array of textures and switching between them, the second one is having just 1 texture containing multiple sprites.

[Array/Dictionary]
One way is to load all the textures you need when your program starts (or when you load a specific scene), then when you need to change the texture for a specific sprite just call the setTexture method with the new texture as a parameter. In this way your program won't have to access the HDD to load stuff.

[Sprite atlas]
Another way is to construct a sprite atlas. A sprite atlas is a pretty big image file that contains all the sprites you need. Then you can call the setTetureRect method of your sprite to change what part of the image it will use when drawn. While it's much easier to do this when all your sprites are the same size, it is 100% possible to do this with sprites that have different sizes.
Alongside with your atlas.png you will need a file that tells your program the texture rect of each sprite you want to use. You can hardcode this but I recommend not to because it's easier to debug and add new stuff later on like this.

Here's a sprite atlas I randomly found on the internet. As you can see it has sprites of all sizes.
(click to show/hide)

There are also programs that input individual image files and generate an optimal atlas (and also output all texture rects)
« Last Edit: October 16, 2018, 09:04:28 pm by Antonio9227 »

oomek

  • Jr. Member
  • **
  • Posts: 90
    • View Profile
    • Email
Re: How to reload a texture without adding a driver overhead?
« Reply #2 on: October 16, 2018, 09:10:12 pm »
Thanks for tips. Those ideas would definitely help when the size of my png library wasn't 15000:) Also I have no control over what the users are trying to display.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: How to reload a texture without adding a driver overhead?
« Reply #3 on: October 16, 2018, 09:38:52 pm »
To me the most obvious solution would be to just have two textures, one that is active and one that can load a new image.

If the image sizes are the same (as I guess isn't the case from your description), you could just load the image from disk with sf::Image (which is the most time consuming operation) and the update() the texture with the pixel data.

What you shouldn't do is reallocate a new texture over and over again.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

oomek

  • Jr. Member
  • **
  • Posts: 90
    • View Profile
    • Email
Re: How to reload a texture without adding a driver overhead?
« Reply #4 on: October 16, 2018, 10:19:47 pm »
So the flipflop textures are the only way I suppose. I was hoping I could save some vram by not allocating everything twice.

Sometimes the textures are the same size, but it's completely random. I use update() in that case, but the thing I've noticed is when I call update() on the texture currently assigned to a sprite strangely there is no overhead in that case, I looked through the sfml sources, but I still can't find any reasonable explanation.
« Last Edit: October 16, 2018, 10:25:10 pm by oomek »

oomek

  • Jr. Member
  • **
  • Posts: 90
    • View Profile
    • Email
Re: How to reload a texture without adding a driver overhead?
« Reply #5 on: October 17, 2018, 01:46:31 am »
I've tried 2 textures per sprite and flip between them and the 1 frame lag is gone, but then when I uncommented generateMipMap() the performance has become worse than with a single texture.