Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Textures aren't zeroed #194

Closed
sjaak31367 opened this issue Oct 30, 2020 · 13 comments
Closed

New Textures aren't zeroed #194

sjaak31367 opened this issue Oct 30, 2020 · 13 comments

Comments

@sjaak31367
Copy link

Hello!

I managed to stumble over a bug in a private project, and after quite a bit of digging and testing managed to conclude where it came from.
The bug was that generated images sometimes contained semi-random pixels/images, even though that shouldn't be there.
After bug-hunting I discovered that

Texture texture = new Texture(uint sizeX, uint sizeY);
Image image = Texture.CopyToImage();

Did not produce an image where all pixels were zero (or equivalent).


On one hand this makes sense, as it gets assigned a chunk of memory, and if there's still data-remnants in that chunk, well, that's now part of its data.
On the other hand, I'd expect a new Texture to be empty; to contain nothing!


TL;DR: Texture(uint sizeX, uint sizeY) does not create an empty Texture.
This can be circumvented by doing:

Image image = new Image(sizeX, sizeY, new Color(0, 0, 0, 0));
Texture texture = new Texture(image);

But I'd argue that expecting a newly created Texture to be empty, is not unreasonable.

Here's a very small thingy to demonstrate that newly created Texures aren't empty. (Or possibly that CopyToImage() grabs data that should be zeroes.)

Greetings, and kind regards!
~Sjaak

@LaurentGomila
Copy link
Member

LaurentGomila commented Oct 31, 2020

If the doc doesn't explicitly says that it should be zeroed, then it's not a bug. Moreover, as you said, this behavior makes sense.

So it's more a feature request actually 😉

But what's the point of defining the content of an uninitialized texture? Who's going to rely on that? If you want a black texture, then explicitly create one in your code. Uploading pixel data to every newly created texture would make texture creation slower, and then the 99.9% of people that don't need that would complain.

@eXpl0it3r
Copy link
Member

eXpl0it3r commented Nov 1, 2020

The mentioned constructor simply calls the other mentioned constructor with the color black.
I'll have to try and reproduce this, maybe it's just some missing initialization somewhere.

public Image(uint width, uint height) : this(width, height, Color.Black) { }
////////////////////////////////////////////////////////////
/// <summary>
/// Construct the image from a single color
/// </summary>
/// <param name="width">Image width</param>
/// <param name="height">Image height</param>
/// <param name="color">Color to fill the image with</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Image(uint width, uint height, Color color) : base(sfImage_createFromColor(width, height, color))
{
if (CPointer == IntPtr.Zero)
{
throw new LoadingFailedException("image");
}
}

@LaurentGomila
Copy link
Member

@eXpl0it3r don't confuse between Image and Texture. What leaves the content uninitialized is to call new Texture(width, height), without using an Image, and as I said it's fine like this.

@eXpl0it3r
Copy link
Member

Ah, I had the feeling I was missing something, but somehow forgot that original code was about the texture.
As for texture creation, this is as Laurent said, expect behavior within SFML itself.

I'm also not sure what exactly the goal is of creating an empty texture. If you want to update the texture frequently, you'd probably want a RenderTexture, that you then can also clear with whatever color you want. If you just want a black rectangle, you could also use a RectangleShape. Otherwise you'd load an image replacing the texture content.

So what exactly is the use case of a created "empty" texture?

@sjaak31367
Copy link
Author

"[...] and then the 99.9% of people that don't need that would complain."
That indeed is a fair and good note. For most people this wouldn't make a difference, except things would be slower and less efficient.


I will admit, I did fall into the project which lead me to find this, quite without backstory. So there might well be a way to go about this, that would be better than using Texture.

A simplified explanation of the use is a Paint-like program: A simple canvas, a pencil, brushes, a fill-option, and some other stuff.
And layers, and the canvas is divided into segments.
I believe the display is done with Sprites, which have a Texture. So that's the reason why I was quite fumbled by Textures not being zeroed, as creating a new empty layer with an unused Texture, sometimes just added garbled stuff.



TL;DR: I should look into other ways to do the rendering part. And understand and agree that an empty Texture will not be zeroed upon creation, as that would be a negative performance impact for many users.
But I would request (if possible) the addition of a Texture(uint width, uint height, Color color) constructor added to Texture, in a similar fashion that Image sports.
For those who want an empty Texture, without having to zero it themselves, and possibly/probably less efficient than it being done through C++ with an optimized algorithm.

@LaurentGomila
Copy link
Member

There's already a way to do it, as you mentioned, and it can even be a one-liner:

Texture texture = new Texture(new Image(sizeX, sizeY, new Color(0, 0, 0, 0)));

So is it worth adding a new constructor, just to avoid typing new Image in the line above?

@sjaak31367
Copy link
Author

Ah yes, that's a very logical one-liner, which I feel quite dumb for not thinking of.
For most purposes that would indeed suffice, however it'd not be the most memory/processor efficient way, I'd think. (But would suffice for most purposes.)

Imagine you're in the unfortunate position of having to create, say, a 10'000 by 10'000 empty Texture for whatever reason.
Creating an empty 10'000 by 10'000 empty Image (new Image(10000, 10000, new Color(0, 0, 0, 0))) only to convert it over to a Texture and then dispose of it, would be a lot slower (I presume) than directly creating an empty Texture (new Texture(10000, 10000, new Color(0, 0, 0, 0)))


TL;DR: Good one-liner, thanks! It'd would probably suffice, but possibly an additional constructor might be more memory/processor efficient. (But it might also be such an edge case that it's negligible.)
(note: I am not handling Textures anywhere near that size, but a theoretical future-proofing for others.)


If this extra memory/processor-use is deemed negligible, feel free to close this issue.
If the addition of a Texture(uint width, uint height, Color color) constructor is deemed not "useless", feel free to rename the issue to something like "[ Feature request ] Texture(uint width, uint height, Color color) constructor".

Kind regards, and many thanks for your time!
~Sjaak

@LaurentGomila
Copy link
Member

would be a lot slower (I presume) than directly creating an empty Texture

I don't know any low-level way of "creating an empty texture" directly. As far as I know, creating a buffer in RAM and then uploading it to the GPU to initialize the texture, is the only way to do it. Even if the texture is full of the same color.

@sjaak31367
Copy link
Author

Preface: I've never (knowingly) worked with code doing stuff with, on, or near the GPU.

I always thought of the GPU as a tiny PC of its own, it has RAM, it has a processing unit. It's just clocked lower, but more parallel-capable. (And a different instruction-set) (If this idea is wildly incorrect, please do correct me.)

If this idea is semi-correct, you might be able to tell it (the GPU) to grab an N-sized chunk of memory, and write a specific value (color) to each address in that chunk, possibly in parallel, to speed it along.
However I can see how telling the CPU to do that with normal RAM, and then pushing the result to the GPU and VRAM is less work, and nicer to GPU-use.


Not having a Texture(uint width, uint height, Color color) constructor, and having to use Texture(new Image(uint width, uint height, Color color)), I am alright with.
I would however request a possible note in the docs near Texture.Texture(uint width, uint height), noting/warning/pointing out the fact that they are not zeroed/empty textures.
Them being zeroed is a logical assumption, but them being not zeroed, also makes sense.



TL;DR:

Texture texture = new Texture(new Image(sizeX, sizeY, new Color(0, 0, 0, 0)));

I am very much willing to settle for. But possibly to avoid future people walking into the "Why isn't this new Texture empty?"-thing, a note in the docs might be useful.

@LaurentGomila
Copy link
Member

Sure, an improvement to the documentation would not hurt 👍

However, you should never rely on implicit initialization states. Always make it explicit in your code. Especially when those are undocumented assumptions 😉

@sjaak31367
Copy link
Author

you should never rely on implicit initialization states. Always make it explicit in your code.

That is very sound advice, which I will be taking with me into the future, thank you.

@eXpl0it3r eXpl0it3r changed the title [ BUG ] New Textures aren't zeroed New Textures aren't zeroed Jun 15, 2023
@eXpl0it3r
Copy link
Member

Anyone interested in providing an update to the documentation?

DemoXinMC added a commit to DemoXinMC/SFML.Net that referenced this issue Jan 3, 2024
* Addresses requests in SFML#194 and SFML#195
* Updated all [Obsolete] attributes to be less repetitive
* Added a large number of quick reference links to existing summaries
* Corrected various typos and unparsable markup(\a and \p)
* Added additional formatting to numerous summaries, resulting in more readable tooltips
* Added a suggestion to use TimeSpan over SFML's Time while working within a managed environment
DemoXinMC added a commit to DemoXinMC/SFML.Net that referenced this issue Jan 4, 2024
* Addresses requests in SFML#194 and SFML#195
* Updated all [Obsolete] attributes to be less repetitive
* Added a large number of quick reference links to existing summaries
* Corrected various typos and unparsable markup(\a and \p)
* Added additional formatting to numerous summaries, resulting in more readable tooltips
* Added a suggestion to use TimeSpan over SFML's Time while working within a managed environment
* Added a warning to `VertexBuffer.NativeHandle`'s getter informing the end-user that most people shouldn't need that property and to be cautious
DemoXinMC added a commit to DemoXinMC/SFML.Net that referenced this issue Feb 17, 2024
* Addresses requests in SFML#194 and SFML#195
* Updated all [Obsolete] attributes to be less repetitive
* Added a large number of quick reference links to existing summaries
* Corrected various typos and unparsable markup(\a and \p)
* Added additional formatting to numerous summaries, resulting in more readable tooltips
* Added a suggestion to use TimeSpan over SFML's Time while working within a managed environment
eXpl0it3r pushed a commit that referenced this issue Feb 17, 2024
* Addresses requests in #194 and #195
* Updated all [Obsolete] attributes to be less repetitive
* Added a large number of quick reference links to existing summaries
* Corrected various typos and unparsable markup(\a and \p)
* Added additional formatting to numerous summaries, resulting in more readable tooltips
* Added a suggestion to use TimeSpan over SFML's Time while working within a managed environment
@eXpl0it3r
Copy link
Member

Fixed in SFML.Net with #239

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants