-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Change default Resource.fetchImage flipY to false #7701
Conversation
Thanks for the pull request @OmarShehata!
Reviewers, don't forget to make sure that:
|
@lilleyse this is good to look at. Consider if this breaking change is indeed the behavior we want over the current behavior. |
Lens flare might have them. Though your Sandcastle is more obviously correct. |
The code looks fine. Chrome and Firefox sandcastle demos look good. I think the breaking change is acceptable, it's not super common behavior to see and seems unavoidable with |
Just to be perfectly clear what the breaking change here is, consider the following psuedocode:
This flipped-but-only-in-chrome (aka when ImageBitmap is supported) issue is what I thought is strange behavior that I was trying to avoid. This happens because the default orientation for fetching an image is not the same as for uploading a texture anymore. On the bright side, here's what it does fix. Consider this psuedocode:
The pixels are going to be:
So I guess either way there's a "flipped but only when ImageBitmap is supported" issue, but this seems like the lesser of the evils. The confusion in 1.56.1 would be in our own codebase vs exposed to the user. One thing we could do make it cleaner after this is change the default flipY in |
@mramato did you want to weigh in on this behavior? It's summarized in #7701 (comment). |
Overall, we need to have consistent behavior across all browsers, otherwise it's a leaky abstraction and a bad API. If I'm understanding this PR correctly, this fixes the inconsistent behavior from an external/users point of view and makes it consistent with 1.55. If that's the case, I would not consider this a breaking change for 1.56.1 but instead it fixes a bug in 1.56.0 (the bug being inconsistent behavior across browsers)
Assuming @lilleyse is happy with everything, I guess the only question I have is: Using the official API, are there any places in the code where a user needs to be aware of texture flipping or special case handling if ImageBitmap is supported? I hope the answer is no (or at least no more than 1.55). If the answer is yes, then what are those cases and how can we fix it so the answer becomes no? |
This is what we were trying to figure out last night. Most of our codepaths that are user-facing take an image string, and fetch it (so it will flip because it knows it's about to upload as a texture). The only way this would break is if a user is fetching the image themselves using |
If we want the safest possible approach that makes no breaking change, we could add an option to choose whether to decode using ImageBitmap, make it false by default, and then enable it throughout our codebase. |
@lilleyse here's a Sandcastle to demonstrate this. This will work in Firefox but not in Chrome. This is because Material doesn't take in an ImageBitmap. We can allow Material to take an ImageBitmap, but then it will be flipped. The only way to make this not a breaking change is to have |
This sounds like the right approach, perhaps a |
We actually considered doing this when we acknowledged that this was "technically a breaking change": Looks like it slipped due to my lack of foresight here:
|
@OmarShehata don't beat yourself up too much, the important thing is we have a fix and we all learned something. @lilleyse what do you think about the proposed solution? Makes sense to me and will be relatively painless for us internally. We can always make a larger (and planned) breaking change in the future if we decide it will allow us to simplify the API. |
@mramato I think it makes perfect sense. |
@@ -268,7 +268,7 @@ define([ | |||
request : request | |||
}); | |||
var promise = resource.fetchImage({ | |||
flipY : false | |||
preferImageBitmap: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few places including here that don't pass in preferBlob: true
. Should they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Especially curious about ImageryProvider
not using preferBlob
since preferBlob
is helpful for ImageBitmap
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually not sure when in general we want to set preferBlob: true
. @mramato do you have any insight here?
In terms of using ImageBitmap, preferImageBitmap
forces it to fetch it as a blob, otherwise decoding is locked to the main thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preferBlob
is something you don't want to set unless you are working around limitations inherent in using an Image element.
Some of these include:
- Sending headers with the request, for example an Authorization header with an access token in it for secured urls, can't be accomplished with an Image element.
- Getting the size/length of the resulting data
DiscardMissingTileImagePolicy
does this.
It's possible I'm forgetting something, but I think those are the only 2. If preferImageBitmap
implies preferBlob is true, that's fine and the end result is transparent to the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if you set preferBlob: true
, it still gives you back an Image
. It just stores the blob
to it as well so you can do things like read the bytes or size etc. right?
The image.blob = blob
is not set when using ImageBitmap, so I'm surprised nothing has broken there. Also, it looks like if an ImageryProvider has a discard policy, it's going to load every tile with its blob?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this is necessary because when you first create the DiscardMissingTileImagePolicy, it does one request, to check what the missing tile looks like? And then that's why we need preferBlob: true
on every subsequent request, to check if what we got is a missing tile or a real tile, if I'm reading this right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so looks like all we need to do here is make sure when you set preferBlob: true
you can access the blob, regardless of whether it's loading using Image
or ImageBitmap
. But when you want to use preferBlob
and when you want to use preferImageBitmap
are unrelated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And part of that was my confusion because I didn't notice that ImageBitmap
was always requesting a blob regardless of the preferBlob
setting. So preferBlob
is orthogonal and its main purpose is to just attach a blob to the Image
/ImageBitmap
to be used by DiscardMissingTileImagePolicy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but also to send headers. If preferBlob is not set and there are headers with the request, we use a blob.
I pushed some doc tweaks: 22f1943 |
@lilleyse the last commit makes sure ImageBitmap keeps a reference to I also made sure to |
Code and Sandcastle demos look good. |
In 1.56 we added ImageBitmap support, which cannot be flipped during texture upload, so I exposed an option to
flipY
on fetch instead. Since textures in Cesium are flipped by default, I set the default flipY to true. This now means that anyone who usedfetchImage()
to do anything other than render it in Cesium (such as read pixels, or draw to another canvas), it was now upside down with this release.This PR changes the
flipY
default on fetchImage to false. This is still a breaking change compared to 1.55. If someone usesfetchImage
in Cesium, then passes that image to something like a material that uploads it as a texture, it'll now be upside down in 1.56.1 (this PR). If this is a less common case, then I think this breaking change is better than the breaking change in 1.56.Testing this
The general rule is, if an image is going to be uploaded as a texture, it should be flipped on fetch. If ImageBitmap is NOT supported, then the image will be flipped during upload. If ImageBitmap is supported, then it will be flipped during fetch.
Now that the default flip on fetch is false, we must flip images everywhere when we fetch if we expect to render them in the WebGL context (with the exception of 3D models which don't get flipped on upload). This means:
TextureAtlas
, which should fix the Billboards too.It's also important to test these in Firefox, where ImageBitmap is not supported.