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

2D: Fix CanvasTexture rendering when updating channels #101931

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2971,8 +2971,23 @@ void RendererCanvasRenderRD::_uniform_set_invalidation_callback(void *p_userdata
static_cast<RendererCanvasRenderRD *>(singleton)->rid_set_to_uniform_set.erase(*key);
}

void RendererCanvasRenderRD::_canvas_texture_invalidation_callback(bool p_deleted, void *p_userdata) {
KeyValue<RID, TightLocalVector<RID>> *kv = static_cast<KeyValue<RID, TightLocalVector<RID>> *>(p_userdata);
RD *rd = RD::get_singleton();
for (RID rid : kv->value) {
// the invalidation callback will take care of clearing rid_set_to_uniform_set cache also
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// the invalidation callback will take care of clearing rid_set_to_uniform_set cache also
// The invalidation callback will also take care of clearing rid_set_to_uniform_set cache.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoot, how'd I miss these. Ehh, we'll just get 'em in a formatting pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aye, sorry about that!

rd->free(rid);
}
kv->value.clear();
if (p_deleted) {
static_cast<RendererCanvasRenderRD *>(singleton)->canvas_texture_to_uniform_set.erase(kv->key);
}
}

void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
{
RendererRD::TextureStorage *ts = RendererRD::TextureStorage::get_singleton();

RIDSetKey key(
p_batch->tex_info->state,
state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
Expand All @@ -2992,6 +3007,19 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
const RIDCache::Pair *iter = rid_set_to_uniform_set.insert(key, rid);
uniform_set = &iter->data;
RD::get_singleton()->uniform_set_set_invalidation_callback(rid, RendererCanvasRenderRD::_uniform_set_invalidation_callback, (void *)&iter->key);

// If this is a CanvasTexture, it must be tracked so that any changes to the diffuse, normal
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If this is a CanvasTexture, it must be tracked so that any changes to the diffuse, normal
// If this is a CanvasTexture, it must be tracked so that any changes to the diffuse, normal,

// or specular channels invalidate all associated uniform sets.
if (ts->owns_canvas_texture(p_batch->tex_info->state.texture)) {
KeyValue<RID, TightLocalVector<RID>> *kv = nullptr;
if (HashMap<RID, TightLocalVector<RID>>::Iterator i = canvas_texture_to_uniform_set.find(p_batch->tex_info->state.texture); i == canvas_texture_to_uniform_set.end()) {
kv = &*canvas_texture_to_uniform_set.insert(p_batch->tex_info->state.texture, { *uniform_set });
} else {
i->value.push_back(rid);
kv = &*i;
}
ts->canvas_texture_set_invalidation_callback(p_batch->tex_info->state.texture, RendererCanvasRenderRD::_canvas_texture_invalidation_callback, kv);
}
}

if (state.current_batch_uniform_set != *uniform_set) {
Expand Down
5 changes: 5 additions & 0 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {

static void _before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid);
static void _uniform_set_invalidation_callback(void *p_userdata);
static void _canvas_texture_invalidation_callback(bool p_deleted, void *p_userdata);

typedef LRUCache<RIDSetKey, RID, HashableHasher<RIDSetKey>, HashMapComparatorDefault<RIDSetKey>, _before_evict> RIDCache;
RIDCache rid_set_to_uniform_set;
/// Maps a CanvasTexture to its associated uniform sets, which must
/// be invalidated when the CanvasTexture is updated, such as changing the
/// diffuse texture.
HashMap<RID, TightLocalVector<RID>> canvas_texture_to_uniform_set;

struct Batch {
// Position in the UBO measured in bytes
Expand Down
16 changes: 16 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ using namespace RendererRD;
void TextureStorage::CanvasTexture::clear_cache() {
info_cache[0] = CanvasTextureCache();
info_cache[1] = CanvasTextureCache();
if (invalidated_callback != nullptr) {
invalidated_callback(false, invalidated_callback_userdata);
}
}

TextureStorage::CanvasTexture::~CanvasTexture() {
if (invalidated_callback != nullptr) {
invalidated_callback(true, invalidated_callback_userdata);
}
}

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -735,6 +741,16 @@ TextureStorage::CanvasTextureInfo TextureStorage::canvas_texture_get_info(RID p_
return res;
}

void TextureStorage::canvas_texture_set_invalidation_callback(RID p_canvas_texture, InvalidationCallback p_callback, void *p_userdata) {
CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
if (!ct) {
return;
}

ct->invalidated_callback = p_callback;
ct->invalidated_callback_userdata = p_userdata;
}

/* Texture API */

RID TextureStorage::texture_allocate() {
Expand Down
6 changes: 6 additions & 0 deletions servers/rendering/renderer_rd/storage_rd/texture_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class TextureStorage : public RendererTextureStorage {
_FORCE_INLINE_ bool is_null() const { return diffuse.is_null(); }
};

typedef void (*InvalidationCallback)(bool p_deleted, void *p_userdata);

private:
friend class LightStorage;
friend class MaterialStorage;
Expand Down Expand Up @@ -118,6 +120,9 @@ class TextureStorage : public RendererTextureStorage {
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
CanvasTextureCache info_cache[2];

InvalidationCallback invalidated_callback = nullptr;
void *invalidated_callback_userdata = nullptr;

Size2i size_cache = Size2i(1, 1);
bool use_normal_cache = false;
bool use_specular_cache = false;
Expand Down Expand Up @@ -499,6 +504,7 @@ class TextureStorage : public RendererTextureStorage {
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;

CanvasTextureInfo canvas_texture_get_info(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, bool p_use_srgb, bool p_texture_is_data);
void canvas_texture_set_invalidation_callback(RID p_canvas_texture, InvalidationCallback p_callback, void *p_userdata);

/* Texture API */

Expand Down