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

[TextServer / Font] Do not duplicate images to prevent unnecessary embedding. #87971

Merged
merged 1 commit into from
Feb 15, 2024
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
12 changes: 12 additions & 0 deletions core/io/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3300,6 +3300,18 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
_set_color_at_ofs(data.ptrw(), ofs, p_color);
}

const uint8_t *Image::ptr() const {
return data.ptr();
}

uint8_t *Image::ptrw() {
return data.ptrw();
}

int64_t Image::data_size() const {
return data.size();
}

void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats.");

Expand Down
4 changes: 4 additions & 0 deletions core/io/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,10 @@ class Image : public Resource {
void set_pixelv(const Point2i &p_point, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);

const uint8_t *ptr() const;
uint8_t *ptrw();
int64_t data_size() const;

void adjust_bcs(float p_brightness, float p_contrast, float p_saturation);

void set_as_black();
Expand Down
55 changes: 30 additions & 25 deletions modules/text_server_adv/text_server_adv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_

ShelfPackTexture *ct = p_data->textures.ptrw();
for (int32_t i = 0; i < p_data->textures.size(); i++) {
if (p_image_format != ct[i].format) {
if (ct[i].image.is_null()) {
continue;
}
if (p_image_format != ct[i].image->get_format()) {
continue;
}
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
Expand Down Expand Up @@ -838,12 +841,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
}

ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
tex.format = p_image_format;
tex.imgdata.resize(texsize * texsize * p_color_size);
tex.image = Image::create_empty(texsize, texsize, false, p_image_format);
{
// Zero texture.
uint8_t *w = tex.imgdata.ptrw();
ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
uint8_t *w = tex.image->ptrw();
ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->data_size(), ret);
// Initialize the texture to all-white pixels to prevent artifacts when the
// font is displayed at a non-default scale with filtering enabled.
if (p_color_size == 2) {
Expand Down Expand Up @@ -1020,12 +1022,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);

{
uint8_t *wr = tex.imgdata.ptrw();
uint8_t *wr = tex.image->ptrw();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
Expand Down Expand Up @@ -1086,12 +1088,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];

{
uint8_t *wr = tex.imgdata.ptrw();
uint8_t *wr = tex.image->ptrw();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
Expand Down Expand Up @@ -2751,16 +2753,15 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve

ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];

tex.imgdata = p_image->get_data();
tex.image = p_image;
tex.texture_w = p_image->get_width();
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();

Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = p_image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = p_image->duplicate();
img->generate_mipmaps();
}

tex.texture = ImageTexture::create_from_image(img);
tex.dirty = false;
}
Expand All @@ -2775,7 +2776,7 @@ Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());

const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return tex.image;
}

void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
Expand Down Expand Up @@ -3144,8 +3145,9 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -3190,8 +3192,9 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -3583,15 +3586,16 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -3693,15 +3697,16 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down
3 changes: 1 addition & 2 deletions modules/text_server_adv/text_server_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,7 @@ class TextServerAdvanced : public TextServerExtension {
int32_t texture_w = 1024;
int32_t texture_h = 1024;

Image::Format format;
PackedByteArray imgdata;
Ref<Image> image;
Ref<ImageTexture> texture;
bool dirty = true;

Expand Down
55 changes: 30 additions & 25 deletions modules/text_server_fb/text_server_fb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_

ShelfPackTexture *ct = p_data->textures.ptrw();
for (int32_t i = 0; i < p_data->textures.size(); i++) {
if (p_image_format != ct[i].format) {
if (ct[i].image.is_null()) {
continue;
}
if (p_image_format != ct[i].image->get_format()) {
continue;
}
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
Expand Down Expand Up @@ -274,12 +277,11 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
}

ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
tex.format = p_image_format;
tex.imgdata.resize(texsize * texsize * p_color_size);
tex.image = Image::create_empty(texsize, texsize, false, p_image_format);
{
// Zero texture.
uint8_t *w = tex.imgdata.ptrw();
ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
uint8_t *w = tex.image->ptrw();
ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->data_size(), ret);
// Initialize the texture to all-white pixels to prevent artifacts when the
// font is displayed at a non-default scale with filtering enabled.
if (p_color_size == 2) {
Expand Down Expand Up @@ -456,12 +458,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);

{
uint8_t *wr = tex.imgdata.ptrw();
uint8_t *wr = tex.image->ptrw();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
Expand Down Expand Up @@ -521,12 +523,12 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];

{
uint8_t *wr = tex.imgdata.ptrw();
uint8_t *wr = tex.image->ptrw();

for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
ERR_FAIL_COND_V(ofs >= tex.image->data_size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
Expand Down Expand Up @@ -1745,16 +1747,15 @@ void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Ve

ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];

tex.imgdata = p_image->get_data();
tex.image = p_image;
tex.texture_w = p_image->get_width();
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();

Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = p_image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = p_image->duplicate();
img->generate_mipmaps();
}

tex.texture = ImageTexture::create_from_image(img);
tex.dirty = false;
}
Expand All @@ -1769,7 +1770,7 @@ Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, co
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());

const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return tex.image;
}

void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
Expand Down Expand Up @@ -2124,8 +2125,9 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -2170,8 +2172,9 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -2518,15 +2521,16 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down Expand Up @@ -2628,15 +2632,16 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
if (fd->cache[size]->face && fd->cache[size]->textures[gl.texture_idx].image.is_valid() && (fd->cache[size]->textures[gl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
Ref<Image> img = tex.image;
if (fd->mipmaps && !img->has_mipmaps()) {
img = tex.image->duplicate();
img->generate_mipmaps();
}
if (tex.texture.is_null()) {
Expand Down
3 changes: 1 addition & 2 deletions modules/text_server_fb/text_server_fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ class TextServerFallback : public TextServerExtension {
int32_t texture_w = 1024;
int32_t texture_h = 1024;

Image::Format format;
PackedByteArray imgdata;
Ref<Image> image;
Ref<ImageTexture> texture;
bool dirty = true;

Expand Down
2 changes: 1 addition & 1 deletion scene/resources/font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
int tx_cnt = get_texture_count(i, sz);
for (int k = 0; k < tx_cnt; k++) {
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE));
}
PackedInt32Array glyphs = get_glyph_list(i, sz);
for (int k = 0; k < glyphs.size(); k++) {
Expand Down
Loading