From 18bb668a2ec4207828a52928760c7e8445740a96 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sat, 16 Jul 2022 13:27:48 +0100 Subject: [PATCH] Fix skeleton 2D stale bounding rect Adds special logic for handling skeleton bounding rect updates. Previously these were never being updated because the canvas item is never set to "rect_dirty". --- drivers/dummy/rasterizer_dummy.h | 1 + drivers/gles2/rasterizer_storage_gles2.cpp | 7 ++++ drivers/gles2/rasterizer_storage_gles2.h | 3 ++ drivers/gles3/rasterizer_storage_gles3.cpp | 8 ++++ drivers/gles3/rasterizer_storage_gles3.h | 3 ++ servers/visual/rasterizer.h | 43 ++++++++++++++++------ 6 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 0373bbcc0ef..72d5050143f 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -483,6 +483,7 @@ public: Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { return Transform(); } void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {} Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { return Transform2D(); } + uint32_t skeleton_get_revision(RID p_skeleton) const { return 0; } /* Light API */ diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 13777ea38e4..d52595c12dd 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -3731,6 +3731,7 @@ void RasterizerStorageGLES2::skeleton_bone_set_transform_2d(RID p_skeleton, int if (!skeleton->update_list.in_list()) { skeleton_update_list.add(&skeleton->update_list); } + skeleton->revision++; } Transform2D RasterizerStorageGLES2::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { @@ -3763,6 +3764,12 @@ void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, cons skeleton->base_transform_2d = p_base_transform; } +uint32_t RasterizerStorageGLES2::skeleton_get_revision(RID p_skeleton) const { + const Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND_V(!skeleton, 0); + return skeleton->revision; +} + void RasterizerStorageGLES2::update_dirty_blend_shapes() { while (blend_shapes_update_list.first()) { Mesh *mesh = blend_shapes_update_list.first()->self(); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 14bd9db4e78..bc10cb81d40 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -890,6 +890,7 @@ public: bool use_2d; int size; + uint32_t revision; // TODO use float textures for storage @@ -905,6 +906,7 @@ public: Skeleton() : use_2d(false), size(0), + revision(1), tex_id(0), update_list(this) { } @@ -924,6 +926,7 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); + virtual uint32_t skeleton_get_revision(RID p_skeleton) const; void _update_skeleton_transform_buffer(const PoolVector &p_data, size_t p_size); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 485945103be..a98f6275719 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5277,6 +5277,8 @@ void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int if (!skeleton->update_list.in_list()) { skeleton_update_list.add(&skeleton->update_list); } + + skeleton->revision++; } Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); @@ -5310,6 +5312,12 @@ void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, cons skeleton->base_transform_2d = p_base_transform; } +uint32_t RasterizerStorageGLES3::skeleton_get_revision(RID p_skeleton) const { + const Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND_V(!skeleton, 0); + return skeleton->revision; +} + void RasterizerStorageGLES3::update_dirty_skeletons() { glActiveTexture(GL_TEXTURE0); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index a40285b5586..ccb20508319 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -920,6 +920,7 @@ public: struct Skeleton : RID_Data { bool use_2d; int size; + uint32_t revision; Vector skel_texture; GLuint texture; SelfList update_list; @@ -929,6 +930,7 @@ public: Skeleton() : use_2d(false), size(0), + revision(1), texture(0), update_list(this) { } @@ -948,6 +950,7 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); + virtual uint32_t skeleton_get_revision(RID p_skeleton) const; /* Light API */ diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 71ff30ad6d3..ce71698a77b 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -448,6 +448,7 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; + virtual uint32_t skeleton_get_revision(RID p_skeleton) const = 0; /* Light API */ @@ -947,19 +948,24 @@ public: }; Transform2D xform; - bool clip; - bool visible; - bool behind; - bool update_when_visible; - //VS::MaterialBlendMode blend_mode; - int light_mask; + bool clip : 1; + bool visible : 1; + bool behind : 1; + bool update_when_visible : 1; + bool distance_field : 1; + bool light_masked : 1; + mutable bool custom_rect : 1; + mutable bool rect_dirty : 1; + Vector commands; - mutable bool custom_rect; - mutable bool rect_dirty; mutable Rect2 rect; RID material; RID skeleton; + //VS::MaterialBlendMode blend_mode; + int32_t light_mask; + mutable uint32_t skeleton_revision; + Item *next; struct CopyBackBuffer { @@ -975,15 +981,29 @@ public: Item *final_clip_owner; Item *material_owner; ViewportRender *vp_render; - bool distance_field; - bool light_masked; Rect2 global_rect_cache; const Rect2 &get_rect() const { - if (custom_rect || (!rect_dirty && !update_when_visible)) { + if (custom_rect) { return rect; } + if (!rect_dirty && !update_when_visible) { + if (skeleton == RID()) { + return rect; + } else { + // special case for skeletons + uint32_t rev = RasterizerStorage::base_singleton->skeleton_get_revision(skeleton); + if (rev == skeleton_revision) { + // no change to the skeleton since we last calculated the bounding rect + return rect; + } else { + // We need to recalculate. + // Mark as done for next time. + skeleton_revision = rev; + } + } + } //must update rect int s = commands.size(); @@ -1171,6 +1191,7 @@ public: } Item() { light_mask = 1; + skeleton_revision = 0; vp_render = nullptr; next = nullptr; final_clip_owner = nullptr;