-
-
Notifications
You must be signed in to change notification settings - Fork 18.7k
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
Multirect - Fix refining regions in derived Textures #76775
Conversation
593e01f
to
4ed637d
Compare
Note this doesn't link to my GH account, use
I like mutable/inout args (performance-wise they make more sense). They seem less readable on the caller side though. Note in #76703 I made args separated based on the Other thing is I'm not sure about the naming convention for such params. Like what
If the original values need to be preserved then copies could be passed in in the first place. So that's not an issue. Also it's even better to copy explicitely only when needed instead of always, possibly for no reason (and hoping compiler will optimize it out).
Haven't gave it much thought, I guess it could be
Makes sense to me, can't think of a situation when such logic would break something (although regression reports can be enlightening 😄). |
scene/resources/texture.h
Outdated
@@ -77,6 +83,7 @@ class Texture : public Resource { | |||
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; | |||
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; | |||
virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; | |||
virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return ((get_width() | get_height()) == 0) ? REFINE_RECT_RESULT_NO_DRAW : REFINE_RECT_RESULT_DRAW; } |
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.
Since r_dst_rect
, r_src_rect
are as well inputs in here, it might make sense to return "no draw" also in case any of these rects has zero size.
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.
Although this seems to make sense for r_dst_rect
(zero size should presumably not draw), maybe zero size src_rect
is valid? The UVs would be the same but it can still draw something. This is similar to the question of whether to not draw in the case of Texture
derived classes like GradientTexture
. 🤔
Makes me again wonder if we should just mirror the old behaviour for safety.
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.
Although this seems to make sense for
r_dst_rect
(zero size should presumably not draw), maybe zero sizesrc_rect
is valid? The UVs would be the same but it can still draw something. This is similar to the question of whether to not draw in the case ofTexture
derived classes likeGradientTexture
. thinking
Hmm, in theory someone could want to transform vertices in the vertex shader so I guess even in case of a zero-sized r_dst_rect
not drawing it could be argued against. 🤔 Not sure whether doing so makes sense / why someone would do it.
But I agree, zero-sized r_src_rect
makes more sense. Like someone might want to draw a single color rect by sampling the texture at specific UV (again not sure if doing so makes sense).
So might be safest to not add rect related conditions here.
Makes me again wonder if we should just mirror the old behaviour for safety.
Regarding width/height checks it might be fine to remove them. I'd assume trying to draw kinda invalid (zero-sized) textures is rather not a common case, so not preventing it right here shouldn't affect performance much anyway. And given it's against 3.x it might be better to prioritize avoiding potential regressions here indeed.
Ah yes, will change this, wasn't sure how the noreply emails worked. 👍
Possibly, but might be better in a separate PR. There's already a couple of things in here that aren't central to the PR (the modulate change and the
Afaik Godot just uses
Yes, this was my thoughts as to eliminating this step.
It seems worth a try, rather than complicating the code with adding extra overrides unnecessarily (if there is no need, less code is better). UPDATE: Changed mind on this and it now mirrors the old behaviour. |
4ed637d
to
deb9b95
Compare
Based on the discussion for the |
This comment was marked as outdated.
This comment was marked as outdated.
deb9b95
to
8356f6b
Compare
Rect2 temp_rect = r_dst_rect; | ||
Rect2 temp_src_rect = r_src_rect; | ||
|
||
if (get_rect_region(temp_rect, temp_src_rect, r_dst_rect, r_src_rect)) { | ||
return atlas->refine_rect_region(r_dst_rect, r_src_rect); | ||
} |
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.
If we want to avoid copying then this should be fine too (under assumption both get_rect_region
and refine_rect_region
are assigning the results at the end of their execution):
Rect2 temp_rect = r_dst_rect; | |
Rect2 temp_src_rect = r_src_rect; | |
if (get_rect_region(temp_rect, temp_src_rect, r_dst_rect, r_src_rect)) { | |
return atlas->refine_rect_region(r_dst_rect, r_src_rect); | |
} | |
if (get_rect_region(r_dst_rect, r_src_rect, r_dst_rect, r_src_rect)) { | |
return atlas->refine_rect_region(r_dst_rect, r_src_rect); | |
} |
I've done it like that originally (pre opening my PR) but changed it for clarity. So if changing like suggested then probably adding some comment would be a good idea.
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 used the temps because imo it is dodgy territory using the same variable for both const ref and referenced return argument to the same function, because of aliasing. The function may assume that the const argument is unchanging (either the programmer of the function, or the compiler).
(It may well be UB in fact, I'm having a play in godbolt to see if I can coax this. 🙂 You can immediately see how difficult it would be to optimize around this kind of aliasing.
Ah it looks like the compiler should operate under the assumption that aliasing can occur, which disables some optimizations, unless you use the restrict
keyword. So compiler wise this may be ok, but there still is the danger that the function reader / writer / modifier may assume that there is no aliasing, so it's still seems dodgy:
Using the temp enforces the const nature and prevents aliasing, and may well be compiled out if unneeded in this case (as get_rect_region()
is known at compile time, even though virtual).
So imo changing this should be left to a future PR that changes the get_rect_region()
function.
8356f6b
to
94f9dd1
Compare
Fixes allowing all derived texture types to modify region prior to rendering.
94f9dd1
to
43b6205
Compare
Rebased (and removed coauthor as now that is already merged). |
@lawnjelly BTW
It was already done like that in #68960, not sure if you want to fix it in here or in some subsequent PR (this method is unused anyway; but I do see its existence kinda makes sense API-wise). |
Ah I'll take a look at the flipping arg, it's a while since I wrote it, it may be historical or for expansion. 👍 EDIT: It's probably there for expansion for efficiency, but not fully implemented in the function yet. The efficient API is when you have a bunch of rects to add as efficiently as possible. If the client code knows there are no flips in advance, there's no need to check for flips. But at the moment it checks in all cases. |
Thanks! |
Fixes allowing all derived texture types to modify region prior to rendering.
Fixes similar bug to #76686 for
LargeTexture
andMeshTexture
.Notes
LargeTexture
andMeshTexture
, by returning an enum instead of a simple true / false, allowing fallback to the olddraw_rect_region()
function for complex texture types.rect
andr
in the calling code, although they don't appear to be used after the call to draw.get_combined_rect_region
made sense.