diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 2c36f53e9f05..3f7321c2dbeb 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1489,6 +1489,11 @@ void TextureStorage::texture_drawable_blit_rect(const TypedArray &p_texture glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + i = 0; + while (i < p_textures.size()) { + texture_atlas_update_texture(p_textures[i]); + i += 1; + } // Reset to system FBO glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } @@ -2315,6 +2320,30 @@ void TextureStorage::texture_atlas_remove_texture(RID p_texture) { } } +void TextureStorage::texture_atlas_update_texture(RID p_texture) { + if (texture_atlas.textures.has(p_texture)) { + CopyEffects *copy_effects = CopyEffects::get_singleton(); + ERR_FAIL_NULL(copy_effects); + ERR_FAIL_COND(texture_atlas.texture == 0); + + if (texture_atlas.dirty) { + return; //Don't mess with it while it's dirty anyway + } + + glBindFramebuffer(GL_FRAMEBUFFER, texture_atlas.framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_atlas.texture, 0); + glViewport(0, 0, texture_atlas.size.width, texture_atlas.size.height); + glDisable(GL_BLEND); + + TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture); + Texture *src_tex = get_texture(p_texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src_tex->tex_id); + copy_effects->copy_to_rect(t->uv_rect); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + } +} + GLuint TextureStorage::texture_atlas_get_texture() const { return texture_atlas.texture; } diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 2f153c92976e..91713ce82c5a 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -629,6 +629,7 @@ class TextureStorage : public RendererTextureStorage { void texture_remove_from_texture_atlas(RID p_texture); void texture_atlas_mark_dirty_on_texture(RID p_texture); void texture_atlas_remove_texture(RID p_texture); + void texture_atlas_update_texture(RID p_texture); /* DECAL API */ diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index a60815a690d5..68e56e45e2d2 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1796,9 +1796,15 @@ void TextureStorage::texture_drawable_blit_rect(const TypedArray &p_texture // DRAW!! RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 6u); + // Detect if any target is in Decal Atlas and also draw to Decal Atlas? RD::get_singleton()->draw_list_end(); RD::get_singleton()->draw_command_end_label(); + i = 0; + while (i < p_textures.size()) { + decal_atlas_mark_draw_on_texture(p_textures[i]); + i += 1; + } } //these two APIs can be used together or in combination with the others. @@ -3366,6 +3372,20 @@ void TextureStorage::decal_atlas_mark_dirty_on_texture(RID p_texture) { } } +void TextureStorage::decal_atlas_mark_draw_on_texture(RID p_texture) { + if (decal_atlas.dirty) { + return; //Don't mess with it while it's dirty anyway + } + + if (decal_atlas.textures.has(p_texture)) { + //belongs to decal_atlas + DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); + t->drawn = true; + + decal_atlas.draw_dirty = true; + } +} + void TextureStorage::decal_atlas_remove_texture(RID p_texture) { if (decal_atlas.textures.has(p_texture)) { decal_atlas.textures.erase(p_texture); @@ -3373,6 +3393,48 @@ void TextureStorage::decal_atlas_remove_texture(RID p_texture) { } } +void TextureStorage::decal_atlas_redraw_textures() { + if (decal_atlas.dirty) { + return; //Don't mess with it while it's dirty anyway + } + + if (!decal_atlas.draw_dirty) { + return; //Nothing to do + } + + decal_atlas.draw_dirty = false; + + CopyEffects *copy_effects = CopyEffects::get_singleton(); + ERR_FAIL_NULL(copy_effects); + ERR_FAIL_COND(!decal_atlas.texture.is_valid()); + + RID prev_texture; + for (int i = 0; i < decal_atlas.texture_mipmaps.size(); i++) { + const DecalAtlas::MipMap &mm = decal_atlas.texture_mipmaps[i]; + + if (decal_atlas.textures.size()) { + if (i == 0) { + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb); + for (const KeyValue &E : decal_atlas.textures) { + DecalAtlas::Texture *t = decal_atlas.textures.getptr(E.key); + if (t->drawn) { + Texture *src_tex = get_texture(E.key); + copy_effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); + t->drawn = false; + } + } + + RD::get_singleton()->draw_list_end(); + + prev_texture = mm.texture; + } else { + copy_effects->copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size)); + prev_texture = mm.texture; + } + } + } +} + AABB TextureStorage::decal_get_aabb(RID p_decal) const { Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_NULL_V(decal, AABB()); @@ -3403,6 +3465,7 @@ void TextureStorage::update_decal_atlas() { } decal_atlas.dirty = false; + decal_atlas.draw_dirty = false; if (decal_atlas.texture.is_valid()) { RD::get_singleton()->free_rid(decal_atlas.texture); @@ -3573,6 +3636,7 @@ void TextureStorage::update_decal_atlas() { DecalAtlas::Texture *t = decal_atlas.textures.getptr(E.key); Texture *src_tex = get_texture(E.key); copy_effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); + t->drawn = false; } RD::get_singleton()->draw_list_end(); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 2f6cf38806e3..5aca64b7c9c6 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -257,6 +257,7 @@ class TextureStorage : public RendererTextureStorage { int panorama_to_dp_users; int users; Rect2 uv_rect; + bool drawn = false; }; struct SortItem { @@ -277,6 +278,7 @@ class TextureStorage : public RendererTextureStorage { HashMap textures; bool dirty = true; + bool draw_dirty = false; int mipmaps = 5; RID texture; @@ -665,7 +667,9 @@ class TextureStorage : public RendererTextureStorage { virtual void decal_set_normal_fade(RID p_decal, float p_fade) override; void decal_atlas_mark_dirty_on_texture(RID p_texture); + void decal_atlas_mark_draw_on_texture(RID p_texture); void decal_atlas_remove_texture(RID p_texture); + void decal_atlas_redraw_textures(); virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override; virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override; diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp index 374eeb695ef2..a05bf9c6886a 100644 --- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp +++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp @@ -253,6 +253,7 @@ void Utilities::update_dirty_resources() { MaterialStorage::get_singleton()->_update_queued_materials(); MeshStorage::get_singleton()->_update_dirty_multimeshes(); MeshStorage::get_singleton()->_update_dirty_skeletons(); + TextureStorage::get_singleton()->decal_atlas_redraw_textures(); TextureStorage::get_singleton()->update_decal_atlas(); }