evas/cserve2: Add font and glyphs loading implementation

to cserve2.
Big commit that implements the entire functionality. Besides loading
fonts and glyphs, and sharing the glyph bitmaps with clients, it also
adds:
- new request system, with a much better abstraction;
- new working slaves management;
- slaves can be threads or process now;
- started a debugging and statistics implementation on server.

The image caching part still uses the old request and slaves system, but
should be changed to use the new one soon and get more easily
maintainable.



SVN revision: 72699
This commit is contained in:
Rafael Antognolli 2012-06-22 20:31:17 +00:00
parent de28f1ed31
commit 64fecc2fab
12 changed files with 1953 additions and 148 deletions

View File

@ -45,7 +45,7 @@ if EVAS_CSERVE2
SUBDIRS = loaders
libexec_PROGRAMS = evas_cserve2 evas_cserve2_slave dummy_slave
bin_PROGRAMS = evas_cserve2_client
bin_PROGRAMS = evas_cserve2_client evas_cserve2_usage
AM_CPPFLAGS = \
-I. \
@ -56,7 +56,8 @@ AM_CPPFLAGS = \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \
@FREETYPE_CFLAGS@ \
@EINA_CFLAGS@
@EINA_CFLAGS@ \
@EET_CFLAGS@
evas_cserve2_SOURCES = \
evas_cserve2.h \
@ -70,14 +71,24 @@ evas_cserve2_requests.c \
evas_cserve2_fonts.c \
evas_cserve2_main_loop_linux.c
libevas_cserve2_utils_la = $(top_builddir)/src/lib/cserve2/libevas_cserve2_utils.la
evas_cserve2_LDADD = \
@FREETYPE_LIBS@ \
@EINA_LIBS@ \
@EFL_SHM_OPEN_LIBS@
@EFL_SHM_OPEN_LIBS@ \
@EET_LIBS@ \
$(libevas_cserve2_utils_la)
evas_cserve2_client_SOURCES = \
evas_cserve2_client.c
evas_cserve2_usage_SOURCES = \
evas_cserve2_usage.c
evas_cserve2_usage_LDADD = \
@EINA_LIBS@
evas_cserve2_slave_SOURCES = \
evas_cserve2_slave.c \
evas_cserve2_utils.c

View File

@ -89,8 +89,8 @@ error_send(int fd, Error_Type err)
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
void *
cserve2_shm_map(const char *name, size_t length, off_t offset)
static void *
_cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
@ -106,11 +106,13 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
return map;
}
void
cserve2_shm_unmap(void *map, size_t length)
/*
static void
_cserve2_shm_unmap(void *map, size_t length)
{
munmap(map, length);
}
*/
static Error_Type
image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Image_Opened *result)
@ -128,8 +130,8 @@ image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Im
static Error_Type
image_load(const char *shmfile, Slave_Msg_Image_Load *params)
{
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;

View File

@ -21,6 +21,8 @@
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__)
#define DEBUG_LOAD_TIME 1
extern int _evas_cserve2_bin_log_dom;
typedef struct _Slave Slave;
@ -119,11 +121,12 @@ struct _Slave_Msg_Font_Load {
void *ftdata1; // Freetype file source info comes here
void *ftdata2; // Freetype font info comes here
unsigned int rend_flags;
unsigned int hint;
unsigned int size;
unsigned int dpi;
const char *name;
const char *file;
void *data;
int datasize;
};
struct _Slave_Msg_Font_Loaded {
@ -131,11 +134,58 @@ struct _Slave_Msg_Font_Loaded {
void *ftdata2;
};
struct _Slave_Msg_Font_Glyphs_Load {
struct {
void *ftdata1;
void *ftdata2;
unsigned int rend_flags;
unsigned int hint;
} font;
struct {
unsigned int nglyphs;
unsigned int *glyphs;
} glyphs;
struct {
Shm_Handle *shm;
unsigned int usage;
unsigned int nglyphs;
} cache;
};
struct _Slave_Msg_Glyph {
unsigned int index;
unsigned int offset;
unsigned int size;
unsigned int rows;
unsigned int width;
unsigned int pitch;
unsigned int num_grays;
unsigned int pixel_mode;
};
typedef struct _Slave_Msg_Glyph Slave_Msg_Glyph;
struct _Slave_Msg_Font_Cache {
unsigned int nglyphs;
Slave_Msg_Glyph *glyphs;
Shm_Handle *shm;
unsigned int usage;
};
typedef struct _Slave_Msg_Font_Cache Slave_Msg_Font_Cache;
struct _Slave_Msg_Font_Glyphs_Loaded {
unsigned int ncaches;
Slave_Msg_Font_Cache **caches;
};
typedef struct _Slave_Msg_Font_Load Slave_Msg_Font_Load;
typedef struct _Slave_Msg_Font_Loaded Slave_Msg_Font_Loaded;
typedef struct _Slave_Msg_Font_Glyphs_Load Slave_Msg_Font_Glyphs_Load;
typedef struct _Slave_Msg_Font_Glyphs_Loaded Slave_Msg_Font_Glyphs_Loaded;
typedef void *(*Font_Request_Msg_Create)(void *data, int *size);
typedef void (*Font_Request_Msg_Free)(void *data);
typedef void (*Font_Request_Msg_Free)(void *msg, void *data);
typedef void (*Font_Request_Response)(Client *c, void *data, void *resp, unsigned int rid);
typedef void (*Font_Request_Error)(Client *c, void *data, Error_Type error, unsigned int rid);
@ -161,6 +211,8 @@ typedef enum {
CSERVE2_REQ_LAST
} Font_Request_Type;
typedef struct _Glyph_Entry Glyph_Entry;
typedef void (*Fd_Watch_Cb)(int fd, Fd_Flags flags, void *data);
typedef void (*Timeout_Cb)(void); /* void* for compat? */
typedef void (*Main_Loop_Child_Dead_Cb)(int pid, int status); /* void* for compat? */
@ -211,6 +263,9 @@ off_t cserve2_shm_map_offset_get(const Shm_Handle *shm);
off_t cserve2_shm_offset_get(const Shm_Handle *shm);
size_t cserve2_shm_map_size_get(const Shm_Handle *shm);
size_t cserve2_shm_size_get(const Shm_Handle *shm);
void *cserve2_shm_map(Shm_Handle *shm);
void cserve2_shm_unmap(Shm_Handle *shm);
size_t cserve2_shm_size_normalize(size_t size);
void cserve2_command_run(Client *client, Message_Type type);
@ -225,10 +280,16 @@ void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsi
void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid);
void cserve2_cache_image_unload(Client *client, unsigned int client_image_id);
int cserve2_cache_font_load(Client *client, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int hint, unsigned int size, unsigned int dpi, unsigned int rid);
int cserve2_cache_font_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid);
int cserve2_cache_font_unload(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid);
int cserve2_cache_font_glyphs_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int hint, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid);
int cserve2_cache_font_glyphs_used(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid);
void cserve2_cache_stats_get(Client *client, unsigned int rid);
void cserve2_cache_font_debug(Client *client, unsigned int rid);
Font_Request *cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Font_Request_Funcs *funcs, void *data);
void cserve2_request_waiter_add(Font_Request *req, unsigned int rid, Client *client);
void cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err);
void cserve2_request_cancel_all(Font_Request *req, Error_Type err);
void cserve2_requests_init(void);
@ -240,5 +301,7 @@ void cserve2_cache_requests_response(Slave_Command type, void *msg, void *data);
void cserve2_font_init(void);
void cserve2_font_shutdown(void);
void *cserve2_font_slave_cb(Slave_Thread_Data *sd, Slave_Command *cmd, const void *cmddata, void *data);
void cserve2_font_source_ft_free(void *fontsource);
void cserve2_font_ft_free(void *fontinfo);
#endif /* _EVAS_CSERVE2_H */

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@
#include "evas_cserve2.h"
static const char *SOCK_PATH = "/tmp/cserve2.socket";
static unsigned int _rid_count = 0;
static struct sockaddr_un socket_local;

View File

@ -2,23 +2,49 @@
# include "config.h"
#endif
#ifdef BUILD_FONT_LOADER_EET
#include <Eet.h>
#endif
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_SIZES_H
#include FT_TYPES_H
#include FT_MODULE_H
#include FT_OUTLINE_H
#include "evas_cserve2.h"
#define CACHESIZE 4 * 1024
/* The tangent of the slant angle we do on runtime. This value was
* retrieved from engines/common/evas_font.h */
#define _EVAS_FONT_SLANT_TAN 0.221694663
#define CHECK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
#define MIN_GLYPHS 50
#define MAX_CACHE_SIZE 1 * 1024 * 1024 // 1MB
#define EVAS_FONT_ROUND_26_6_TO_INT(x) \
(((x + 0x20) & -0x40) >> 6)
static FT_Library cserve2_ft_lib = 0;
static int initialised = 0;
typedef struct _Font_Info Font_Info;
typedef struct _Font_Source_Info Font_Source_Info;
struct _Font_Info
{
Font_Source_Info *fsi;
FT_Size size;
int real_size;
int real_size; // this is probably useless, not used even on client
int fsize;
int dpi;
int max_h;
unsigned int runtime_rend;
int shmsize;
};
struct _Font_Source_Info
@ -26,11 +52,11 @@ struct _Font_Source_Info
FT_Face face;
int orig_upem;
int current_size;
int current_dpi;
void *data;
int datasize;
};
typedef struct _Font_Info Font_Info;
typedef struct _Font_Source_Info Font_Source_Info;
static void *
_font_slave_error_send(Error_Type error)
{
@ -40,29 +66,80 @@ _font_slave_error_send(Error_Type error)
return e;
}
static void
_font_slave_size_use(Font_Info *fi)
{
Font_Source_Info *fsi = fi->fsi;
// if ((fsi->current_size != fi->fsize)
// || (fsi->current_dpi != fi->dpi))
{
FT_Activate_Size(fi->size);
fsi->current_size = fi->fsize;
fsi->current_dpi = fi->dpi;
}
}
static Font_Source_Info *
_font_slave_source_load(const char *file)
_font_slave_source_load(const char *file, const char *name)
{
int error;
Font_Source_Info *fsi = malloc(sizeof(*fsi));
Font_Source_Info *fsi = calloc(1, sizeof(*fsi));
error = FT_New_Face(cserve2_ft_lib, file, 0, &(fsi->face));
if (error)
if (!name)
{
free(fsi);
return NULL;
error = FT_New_Face(cserve2_ft_lib, file, 0, &(fsi->face));
if (error)
{
free(fsi);
return NULL;
}
}
#ifdef BUILD_FONT_LOADER_EET
else
{
Eet_File *ef;
void *fdata;
int fsize = 0;
ef = eet_open(file, EET_FILE_MODE_READ);
if (!ef)
{
free(fsi);
return NULL;
}
fdata = eet_read(ef, name, &fsize);
eet_close(ef);
if (!fdata)
{
free(fsi);
return NULL;
}
fsi->data = fdata;
fsi->datasize = fsize;
error = FT_New_Memory_Face(cserve2_ft_lib, fsi->data, fsi->datasize,
0, &(fsi->face));
if (error)
{
free(fsi->data);
free(fsi);
return NULL;
}
}
#endif
error = FT_Select_Charmap(fsi->face, ft_encoding_unicode);
if (error)
{
FT_Done_Face(fsi->face);
free(fsi->data);
free(fsi);
return NULL;
}
fsi->orig_upem = fsi->face->units_per_EM;
fsi->current_size = 0;
fsi->current_dpi = 0;
return fsi;
}
@ -79,46 +156,55 @@ _font_slave_int_load(const Slave_Msg_Font_Load *msg, Font_Source_Info *fsi)
if (!error)
FT_Activate_Size(fi->size);
fi->fsize = msg->size;
fi->dpi = msg->dpi;
fi->real_size = msg->size * 64;
fi->fsi = fsi;
error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, msg->dpi, msg->dpi);
if (error)
{
fi->real_size = msg->size;
error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
}
error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
if (error)
{
int i;
int i, maxd = 0x7fffffff;
int chosen_size = 0;
int chosen_width = 0;
int chosen_size2 = 0;
for (i = 0; i < fsi->face->num_fixed_sizes; i++)
{
int s;
int d, cd;
int s, cd;
s = fsi->face->available_sizes[i].height;
cd = chosen_size - msg->size;
s = fsi->face->available_sizes[i].size;
cd = chosen_size - fi->real_size;
if (cd < 0) cd = -cd;
d = s - msg->size;
if (d < 0) d = -d;
if (d < cd)
if (cd < maxd)
{
chosen_width = fsi->face->available_sizes[i].width;
maxd = cd;
chosen_size = s;
chosen_size2 = fsi->face->available_sizes[i].y_ppem;
if (maxd == 0) break;
}
if (d == 0) break;
}
fi->real_size = chosen_size;
error = FT_Set_Pixel_Sizes(fsi->face, chosen_width, fi->real_size);
error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
if (error)
{
ERR("Could not choose the font size for font: '%s'.", msg->name);
FT_Done_Size(fi->size);
free(fi);
return NULL;
error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi);
if (error)
{
/* hack around broken fonts */
fi->real_size = (chosen_size2 / 64) * 60;
error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi);
if (error)
{
ERR("Could not choose the font size for font: '%s:%s'.",
msg->file, msg->name);
FT_Done_Size(fi->size);
free(fi);
return NULL;
}
}
}
}
@ -159,11 +245,12 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
Font_Source_Info *fsi;
Font_Info *fi;
DBG("slave received FONT_LOAD: '%s'", msg->name);
fsi = msg->ftdata1;
/* Loading Font Source */
if (!fsi)
fsi = _font_slave_source_load(msg->file);
fsi = _font_slave_source_load(msg->file, msg->name);
// FIXME: Return correct error message
if (!fsi)
@ -175,8 +262,8 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
fi = _font_slave_int_load(msg, fsi);
if (!fi)
{
FT_Done_Face(fsi->face);
free(fsi);
if (!msg->ftdata1)
cserve2_font_source_ft_free(fsi);
return NULL;
}
@ -187,6 +274,241 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
return response;
}
static Shm_Handle *
_font_slave_memory_alloc(Font_Info *fi)
{
Shm_Handle *shm = cserve2_shm_request(fi->shmsize);
return shm;
}
/* This function will load the "index" glyph to the glyph slot of the font.
* In order to use or render it, one should access it from the glyph slot,
* or get the glyph using FT_Get_Glyph().
*/
static Eina_Bool
_font_slave_glyph_load(Font_Info *fi, unsigned int index, unsigned int hint)
{
Font_Source_Info *fsi = fi->fsi;
FT_Error error;
const FT_Int32 hintflags[3] =
{ FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000,
0x00000, 0x10000};
error = FT_Load_Glyph(fsi->face, index,
FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP |
hintflags[hint]);
if (error)
{
ERR("Could not load glyph %d", index);
return EINA_FALSE;
}
/* Transform the outline of Glyph according to runtime_rend. */
if (fi->runtime_rend & FONT_REND_SLANT)
FT_Outline_Transform(&fsi->face->glyph->outline, &transform);
/* Embolden the outline of Glyph according to rundtime_rend. */
if (fi->runtime_rend & FONT_REND_WEIGHT)
FT_Outline_Embolden(&fsi->face->glyph->outline,
(fsi->face->size->metrics.x_ppem * 5 * 64) /
100);
return EINA_TRUE;
}
/* This function will render the glyph currently in the glyph slot into the
* given Font Cache.
*/
static Eina_Bool
_font_slave_glyph_render(Font_Info *fi, Slave_Msg_Font_Cache *c, unsigned int index)
{
Font_Source_Info *fsi = fi->fsi;
unsigned int glyphsize;
char *cachedata = cserve2_shm_map(c->shm);
FT_Glyph glyph;
FT_BitmapGlyph bglyph;
FT_Get_Glyph(fsi->face->glyph, &glyph);
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
bglyph = (FT_BitmapGlyph)glyph;
glyphsize = bglyph->bitmap.pitch * bglyph->bitmap.rows;
if (c->usage + glyphsize > cserve2_shm_size_get(c->shm))
{
FT_Done_Glyph(glyph);
return EINA_FALSE;
}
memcpy(cachedata + c->usage, bglyph->bitmap.buffer, glyphsize);
// TODO: Check if we have problems with alignment
c->glyphs[c->nglyphs].index = index;
c->glyphs[c->nglyphs].offset = c->usage;
c->glyphs[c->nglyphs].size = glyphsize;
c->glyphs[c->nglyphs].rows = bglyph->bitmap.rows;
c->glyphs[c->nglyphs].width = bglyph->bitmap.width;
c->glyphs[c->nglyphs].pitch = bglyph->bitmap.pitch;
c->glyphs[c->nglyphs].num_grays = bglyph->bitmap.num_grays;
c->glyphs[c->nglyphs].pixel_mode = bglyph->bitmap.pixel_mode;
c->usage += glyphsize;
c->nglyphs++;
FT_Done_Glyph(glyph);
return EINA_TRUE;
}
static void
_font_slave_int_metrics_get(Font_Info *fi, unsigned int hint, unsigned int c, int *width, int *height, int *depth)
{
unsigned int idx;
Font_Source_Info *fsi = fi->fsi;
FT_BBox outbox;
FT_Glyph glyph;
idx = FT_Get_Char_Index(fsi->face, c);
if (!idx)
goto end;
if (!_font_slave_glyph_load(fi, idx, hint))
goto end;
FT_Get_Glyph(fsi->face->glyph, &glyph);
FT_Glyph_Get_CBox(glyph,
((hint == 0) ? FT_GLYPH_BBOX_UNSCALED :
FT_GLYPH_BBOX_GRIDFIT),
&outbox);
if (width) *width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin);
if (height)
*height = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax - outbox.xMin);
if (depth) *depth = 1; // FIXME: Do we need to check this?
FT_Done_Glyph(glyph);
return;
end:
if (width) *width = 0;
if (height) *height = 0;
if (depth) *depth = 0;
}
static unsigned int
_font_slave_int_shm_prev_calculate(unsigned int size, unsigned int nglyphs)
{
unsigned int average = size / nglyphs;
unsigned int newsize;
newsize = MIN_GLYPHS * average;
newsize = cserve2_shm_size_normalize(newsize);
if (newsize > MAX_CACHE_SIZE)
return MAX_CACHE_SIZE;
return newsize;
}
static unsigned int
_font_slave_int_shm_calculate(Font_Info *fi, unsigned int hint)
{
const char *c;
int i;
int size = 0;
int average;
for (c = CHECK_CHARS, i = 0; *c != '\0'; c++, i++)
{
int w, h, depth;
_font_slave_int_metrics_get(fi, hint, *c, &w, &h, &depth);
size += w * h * depth;
}
average = size / i; // average glyph size
size = MIN_GLYPHS * average;
size = cserve2_shm_size_normalize(size);
if (size > MAX_CACHE_SIZE)
return MAX_CACHE_SIZE; // Assumes no glyph will be bigger than this
return size;
}
static Slave_Msg_Font_Glyphs_Loaded *
_font_slave_glyphs_load(const void *cmddata, void *data __UNUSED__)
{
const Slave_Msg_Font_Glyphs_Load *msg = cmddata;
Slave_Msg_Font_Glyphs_Loaded *response;
Font_Info *fi;
unsigned int i;
unsigned int total_glyphs;
Eina_List *caches = NULL;
Slave_Msg_Font_Cache *c = NULL;
fi = msg->font.ftdata2;
_font_slave_size_use(fi);
if (msg->cache.shm)
{
c = malloc(sizeof(*c) + sizeof(Slave_Msg_Glyph) *
(msg->glyphs.nglyphs));
c->nglyphs = 0;
c->glyphs = (void *)(c + 1);
c->shm = msg->cache.shm;
c->usage = msg->cache.usage;
caches = eina_list_append(caches, c);
total_glyphs = msg->cache.nglyphs;
}
if (!fi->shmsize)
fi->shmsize = _font_slave_int_shm_calculate(fi, msg->font.hint);
i = 0;
while (i < msg->glyphs.nglyphs)
{
Eina_Bool r = EINA_TRUE;
if (!c)
{
Shm_Handle *shm;
shm = _font_slave_memory_alloc(fi);
c = malloc(sizeof(*c) + sizeof(Slave_Msg_Glyph) *
(msg->glyphs.nglyphs - i));
c->nglyphs = 0;
c->glyphs = (void *)(c + 1);
c->shm = shm;
c->usage = 0;
caches = eina_list_append(caches, c);
total_glyphs = 0;
}
if (_font_slave_glyph_load(fi, msg->glyphs.glyphs[i], msg->font.hint))
r = _font_slave_glyph_render(fi, c, msg->glyphs.glyphs[i]);
if (!r) // SHM is full
{
fi->shmsize = _font_slave_int_shm_prev_calculate
(c->usage, total_glyphs);
c = NULL;
continue;
}
i++;
total_glyphs++;
}
response = malloc(sizeof(*response) +
sizeof(c) * eina_list_count(caches));
response->ncaches = eina_list_count(caches);
response->caches = (void *)(response + 1);
i = 0;
EINA_LIST_FREE(caches, c)
response->caches[i++] = c;
return response;
}
void *
cserve2_font_slave_cb(Slave_Thread_Data *sd __UNUSED__, Slave_Command *cmd, const void *cmddata, void *data)
{
@ -198,7 +520,7 @@ cserve2_font_slave_cb(Slave_Thread_Data *sd __UNUSED__, Slave_Command *cmd, cons
response = _font_slave_load(cmddata, data);
break;
case FONT_GLYPHS_LOAD:
// command for FONT_GLYPHS_LOAD
response = _font_slave_glyphs_load(cmddata, data);
break;
default:
ERR("Invalid command for font slave: %d", *cmd);
@ -224,6 +546,10 @@ cserve2_font_init(void)
error = FT_Init_FreeType(&cserve2_ft_lib);
if (error) return;
#ifdef BUILD_FONT_LOADER_EET
eet_init();
#endif
}
void
@ -239,4 +565,27 @@ cserve2_font_shutdown(void)
FT_Done_FreeType(cserve2_ft_lib);
cserve2_ft_lib = 0;
#ifdef BUILD_FONT_LOADER_EET
eet_shutdown();
#endif
}
void
cserve2_font_source_ft_free(void *fontsource)
{
Font_Source_Info *fsi = fontsource;
FT_Done_Face(fsi->face);
free(fsi->data);
free(fsi);
}
void
cserve2_font_ft_free(void *fontinfo)
{
Font_Info *fi = fontinfo;
FT_Done_Size(fi->size);
free(fi);
}

View File

@ -33,13 +33,6 @@ static Eina_Hash *client_list = NULL;
static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL;
struct _Glyph_Request {
unsigned int index;
unsigned int offset;
};
typedef struct _Glyph_Request Glyph_Request;
void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{
@ -270,52 +263,83 @@ static void
_cserve2_client_font_load(Client *client)
{
Msg_Font_Load *msg = (Msg_Font_Load *)client->msg.buf;
char name[PATH_MAX];
char name[PATH_MAX], source[PATH_MAX], *buf;
memcpy(name, msg + 1, msg->pathlen);
buf = ((char *)msg) + sizeof(*msg);
memcpy(source, buf, msg->sourcelen);
buf += msg->sourcelen;
memcpy(name, buf, msg->pathlen);
INF("Received %s command: RID=%d",
(msg->base.type == CSERVE2_FONT_LOAD) ? "FONT_LOAD" : "FONT_UNLOAD",
msg->base.rid);
INF("Font: %s, rend_flags: %d, hint: %d, size: %d, dpi: %d",
name, msg->rend_flags, msg->hint, msg->size, msg->dpi);
INF("Font: %s, rend_flags: %d, size: %d, dpi: %d",
name, msg->rend_flags, msg->size, msg->dpi);
cserve2_cache_font_load(client, name, msg->pathlen, msg->rend_flags,
msg->hint, msg->size, msg->dpi, msg->base.rid);
if (msg->base.type == CSERVE2_FONT_LOAD)
cserve2_cache_font_load(client, source, msg->sourcelen, name,
msg->pathlen, msg->rend_flags, msg->size,
msg->dpi, msg->base.rid);
else
cserve2_cache_font_unload(client, source, msg->sourcelen, name,
msg->pathlen, msg->rend_flags, msg->size,
msg->dpi, msg->base.rid);
}
static void
_cserve2_client_font_glyphs_request(Client *client)
{
Msg_Font_Glyphs_Request *msg = (Msg_Font_Glyphs_Request *)client->msg.buf;
char fontpath[PATH_MAX];
Glyph_Request *glyphs;
unsigned int i;
const char *bufpos = client->msg.buf;
char source[PATH_MAX], fontpath[PATH_MAX], *buf;
unsigned int *glyphs;
memcpy(fontpath, msg + 1, msg->pathlen);
buf = ((char *)msg) + sizeof(*msg);
memcpy(source, buf, msg->sourcelen);
buf += msg->sourcelen;
memcpy(fontpath, buf, msg->pathlen);
buf += msg->pathlen;
bufpos = bufpos + sizeof(msg) + msg->pathlen;
glyphs = malloc(sizeof(*glyphs) * msg->nglyphs);
for (i = 0; i < msg->nglyphs; i++)
{
memcpy(&glyphs[i], bufpos, sizeof(*glyphs));
bufpos += sizeof(*glyphs);
}
memcpy(glyphs, buf, sizeof(*glyphs) * msg->nglyphs);
if (msg->base.type == CSERVE2_FONT_GLYPHS_LOAD)
{
INF("Received CSERVE2_FONT_GLYPHS_LOAD command: RID=%d",
msg->base.rid);
cserve2_cache_font_glyphs_load(client, source, msg->sourcelen,
fontpath, msg->pathlen,
msg->hint, msg->rend_flags, msg->size,
msg->dpi, glyphs, msg->nglyphs,
msg->base.rid);
}
else
{
INF("Received CSERVE2_FONT_GLYPHS_USED command: RID=%d",
msg->base.rid);
/*
cserve2_cache_font_glyphs_used(client, source, msg->sourcelen,
fontpath, msg->pathlen,
msg->hint, msg->rend_flags, msg->size,
msg->dpi, glyphs, msg->nglyphs,
msg->base.rid);
*/
}
}
static void
_cserve2_client_stats_request(Client *client)
{
Msg_Base *msg = (Msg_Base *)client->msg.buf;
cserve2_cache_stats_get(client, msg->rid);
}
static void
_cserve2_client_font_debug_request(Client *client)
{
Msg_Base *msg = (Msg_Base *)client->msg.buf;
cserve2_cache_font_debug(client, msg->rid);
}
void
cserve2_command_run(Client *client, Message_Type type)
{
@ -347,6 +371,12 @@ cserve2_command_run(Client *client, Message_Type type)
case CSERVE2_FONT_GLYPHS_USED:
_cserve2_client_font_glyphs_request(client);
break;
case CSERVE2_STATS:
_cserve2_client_stats_request(client);
break;
case CSERVE2_FONT_DEBUG:
_cserve2_client_font_debug_request(client);
break;
default:
WRN("Unhandled message");
}

View File

@ -81,7 +81,7 @@ typedef struct _Waiter Waiter;
struct _Request_Queue
{
Eina_Inlist *waiting;
Eina_Inlist *processing;
Eina_Inlist *processing; // TODO: Check if is there any use for this list.
};
typedef struct _Request_Queue Request_Queue;
@ -89,6 +89,8 @@ typedef struct _Request_Queue Request_Queue;
static Request_Queue *requests = NULL;
// static Eina_List *processing = NULL;
static void _cserve2_requests_process(void);
static void
_request_waiter_add(Font_Request *req, Client *client, unsigned int rid)
{
@ -109,15 +111,17 @@ cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Fo
req = NULL;
/* Check if this request was already being processed. */
EINA_INLIST_FOREACH(requests[type].processing, r)
{
if (r->data == data)
if (r->data != data)
continue;
req = r;
break;
}
/* Check if this request was already waiting to be processed. */
if (!req)
{
EINA_INLIST_FOREACH(requests[type].waiting, r)
@ -130,22 +134,33 @@ cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Fo
}
}
/* create new request */
if (!req)
{
DBG("Add request for rid: %d", rid);
req = malloc(sizeof(*req));
req->type = type;
req->data = data;
req->waiters = NULL;
req->processing = EINA_FALSE;
req->funcs = funcs;
requests[type].waiting = eina_inlist_append(requests[type].waiting,
EINA_INLIST_GET(req));
}
_request_waiter_add(req, client, rid);
_cserve2_requests_process();
return req;
}
void
cserve2_request_waiter_add(Font_Request *req, unsigned int rid, Client *client)
{
_request_waiter_add(req, client, rid);
}
void
cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
{
@ -167,13 +182,13 @@ cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
// TODO: When we have speculative preload, there may be no waiters,
// so we need a flag or something else to make things still load.
if (!req->waiters)
if ((!req->waiters) && (!req->processing))
{
Eina_Inlist **reqlist = &requests[req->type].waiting;
*reqlist = eina_inlist_remove(*reqlist, EINA_INLIST_GET(req));
// TODO: If the request is being processed, it can't be deleted. Must
// be marked as delete_me instead.
req->funcs->msg_free(req->msg);
req->funcs->msg_free(req->msg, req->data);
free(req);
}
@ -195,9 +210,12 @@ cserve2_request_cancel_all(Font_Request *req, Error_Type err)
free(w);
}
if (req->processing)
return;
requests[req->type].waiting = eina_inlist_remove(
requests[req->type].waiting, EINA_INLIST_GET(req));
req->funcs->msg_free(req->msg);
req->funcs->msg_free(req->msg, req->data);
free(req);
}
@ -226,7 +244,7 @@ _cserve2_request_failed(Font_Request *req, Error_Type type)
free(w);
}
req->funcs->msg_free(req->msg);
req->funcs->msg_free(req->msg, req->data);
requests[req->type].processing = eina_inlist_remove(
requests[req->type].processing, EINA_INLIST_GET(req));
free(req);
@ -252,7 +270,7 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
free(w);
}
req->funcs->msg_free(req->msg);
req->funcs->msg_free(req->msg, req->data);
// FIXME: We shouldn't free this message directly, it must be freed by a
// callback.
free(msg);
@ -265,6 +283,8 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
idle = &_workers[sw->type].idle;
*working = eina_list_remove(*working, sw);
*idle = eina_list_append(*idle, sw);
_cserve2_requests_process();
}
static void
@ -338,6 +358,8 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
int size;
char *slave_msg = req->funcs->msg_create(req->data, &size);
DBG("dispatching message of type %d to slave.", req->type);
if (!slave_msg)
{
ERR("Could not create slave message for request type %d.", req->type);
@ -352,8 +374,8 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
return EINA_TRUE;
}
void
cserve2_requests_process(void)
static void
_cserve2_requests_process(void)
{
int rtype, j;
@ -366,7 +388,7 @@ cserve2_requests_process(void)
for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++)
{
if (_request_match[j].rtype == (unsigned int)j)
if (_request_match[j].rtype == rtype)
{
type = _request_match[j].stype;
ctype = _request_match[j].ctype;
@ -387,7 +409,7 @@ cserve2_requests_process(void)
idle = &_workers[type].idle;
working = &_workers[type].working;
while (requests[j].waiting &&
while (requests[rtype].waiting &&
(eina_list_count(*working) < max_workers))
{
Slave_Worker *sw;

View File

@ -27,10 +27,30 @@ struct _Shm_Handle
off_t image_offset;
size_t map_size;
size_t image_size;
int refcount;
void *data;
};
static int id = 0;
size_t
cserve2_shm_size_normalize(size_t size)
{
long pagesize;
size_t normalized;
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 1)
{
ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
pagesize = 4096;
}
normalized = ((size + pagesize - 1) / pagesize) * pagesize;
return normalized;
}
Shm_Handle *
cserve2_shm_request(size_t size)
{
@ -38,7 +58,6 @@ cserve2_shm_request(size_t size)
Shm_Handle *shm;
char shmname[NAME_MAX];
size_t map_size;
long pagesize;
int fd;
map = calloc(1, sizeof(Shm_Mapping));
@ -59,14 +78,7 @@ cserve2_shm_request(size_t size)
}
} while (fd == -1);
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 1)
{
ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
pagesize = 4096;
}
map_size = ((size + pagesize - 1) / pagesize) * pagesize;
map_size = cserve2_shm_size_normalize(size);
if (ftruncate(fd, map_size) == -1)
{
@ -106,6 +118,9 @@ cserve2_shm_unref(Shm_Handle *shm)
Shm_Mapping *map = shm->mapping;
map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm));
if (shm->data)
munmap(shm->data, shm->image_size);
free(shm);
if (map->segments)
@ -145,3 +160,36 @@ cserve2_shm_size_get(const Shm_Handle *shm)
{
return shm->image_size;
}
void *
cserve2_shm_map(Shm_Handle *shm)
{
int fd;
const char *name;
if (shm->refcount++)
return shm->data;
name = cserve2_shm_name_get(shm);
fd = shm_open(name, O_RDWR, S_IWUSR);
if (fd == -1)
return MAP_FAILED;
shm->data = mmap(NULL, shm->image_size, PROT_WRITE, MAP_SHARED,
fd, shm->image_offset);
close(fd);
return shm->data;
}
void
cserve2_shm_unmap(Shm_Handle *shm)
{
if (--shm->refcount)
return;
munmap(shm->data, shm->image_size);
shm->data = NULL;
}

View File

@ -187,8 +187,8 @@ error_send(int fd, Error_Type err)
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
void *
cserve2_shm_map(const char *name, size_t length, off_t offset)
static void *
_cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
@ -204,8 +204,8 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
return map;
}
void
cserve2_shm_unmap(void *map, size_t length)
static void
_cserve2_shm_unmap(void *map, size_t length)
{
munmap(map, length);
}
@ -316,8 +316,8 @@ image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Ima
Evas_Loader_Module_Api *api;
int err;
Error_Type ret = CSERVE2_NONE;
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;
@ -352,7 +352,7 @@ image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Ima
result->alpha_sparse = ilp.alpha_sparse;
done:
cserve2_shm_unmap(map, params->shm.mmap_size);
_cserve2_shm_unmap(map, params->shm.mmap_size);
return ret;
}

View File

@ -0,0 +1,230 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <Eina.h>
#include "evas_cs2.h"
static int socketfd = -1;
static unsigned int _rid_count = 1;
static int _evas_cserve2_usage_log_dom = -1;
static struct sockaddr_un socksize;
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(socksize.sun_path)
#endif
#ifdef ERR
#undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_usage_log_dom, __VA_ARGS__)
#ifdef DBG
#undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_usage_log_dom, __VA_ARGS__)
#ifdef WRN
#undef WRN
#endif
#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_usage_log_dom, __VA_ARGS__)
#ifdef INF
#undef INF
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_usage_log_dom, __VA_ARGS__)
static void
_socket_path_set(char *path)
{
char *env;
char buf[UNIX_PATH_MAX];
env = getenv("EVAS_CSERVE2_SOCKET");
if (env && env[0])
{
strncpy(path, env, UNIX_PATH_MAX - 1);
return;
}
snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)getuid());
/* FIXME: check we can actually create this socket */
strcpy(path, buf);
}
static Eina_Bool
_server_connect(void)
{
int s, len;
struct sockaddr_un remote;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
ERR("socket");
return EINA_FALSE;
}
remote.sun_family = AF_UNIX;
_socket_path_set(remote.sun_path);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1)
{
ERR("connect");
return EINA_FALSE;
}
fcntl(s, F_SETFL, O_NONBLOCK);
socketfd = s;
DBG("connected to cserve2 server.");
return EINA_TRUE;
}
static void
_server_disconnect(void)
{
close(socketfd);
socketfd = -1;
}
static Eina_Bool
_server_send(const void *data, int size)
{
int sent = 0;
ssize_t ret;
const char *msg = data;
while (sent < size)
{
ret = send(socketfd, msg + sent, size - sent, MSG_NOSIGNAL);
if (ret < 0)
{
if ((errno == EAGAIN) || (errno == EINTR))
continue;
return EINA_FALSE;
}
sent += ret;
}
return EINA_TRUE;
}
static int sr_size = 0;
static int sr_got = 0;
static char *sr_buf = NULL;
static void *
_server_read(int *size)
{
int n;
void *ret;
if (sr_size)
goto get_data;
n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
if (n < 0)
return NULL;
sr_buf = malloc(sr_size);
get_data:
n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
if (n < 0)
return NULL;
sr_got += n;
if (sr_got < sr_size)
return NULL;
*size = sr_size;
sr_size = 0;
sr_got = 0;
ret = sr_buf;
sr_buf = NULL;
return ret;
}
static void
_usage_msg_send(void)
{
Msg_Base msg;
int size;
memset(&msg, 0, sizeof(msg));
msg.type = CSERVE2_STATS;
msg.rid = _rid_count++;
size = sizeof(msg);
if (!_server_send(&size, sizeof(size)))
{
ERR("Could not send usage msg size to server.");
return;
}
if (!_server_send(&msg, size))
{
ERR("Could not send usage msg body to server.");
return;
}
}
static void
_usage_msg_read(void)
{
Msg_Stats *msg = NULL;
int size;
printf("Requesting server statistics.\n\n");
while (!msg)
msg = _server_read(&size);
if (msg->base.type != CSERVE2_STATS)
{
ERR("Invalid message received from server."
"Something went badly wrong.");
return;
}
printf("Printing server usage.\n");
printf("======================\n\n");
printf("Font Usage Statistics:\n");
printf("Requested usage: %d bytes\n", msg->fonts.requested_usage);
printf("Real usage: %d bytes\n", msg->fonts.real_usage);
printf("Fonts load time: %dus\n", msg->fonts.fonts_load);
printf("Fonts used load time: %dus\n", msg->fonts.fonts_used_load);
printf("Glyphs load time: %dus\n", msg->fonts.glyphs_load);
printf("\n");
}
int
main(void)
{
eina_init();
_evas_cserve2_usage_log_dom = eina_log_domain_register
("evas_cserve2_usage", EINA_COLOR_BLUE);
if (!_server_connect())
{
ERR("Could not connect to server.");
return -1;
}
_usage_msg_send();
_usage_msg_read();
_server_disconnect();
eina_shutdown();
}

View File

@ -22,6 +22,8 @@ typedef enum {
CSERVE2_FONT_GLYPHS_LOAD,
CSERVE2_FONT_GLYPHS_LOADED,
CSERVE2_FONT_GLYPHS_USED,
CSERVE2_STATS,
CSERVE2_FONT_DEBUG,
CSERVE2_ERROR
} Message_Type;
@ -127,9 +129,9 @@ struct _Msg_Close {
*/
struct _Msg_Font_Load {
Msg_Base base;
unsigned int sourcelen; // font id
unsigned int pathlen; // font id
unsigned int rend_flags; // font id
unsigned int hint; // font id
unsigned int size; // font id
unsigned int dpi; // font id
};
@ -146,18 +148,19 @@ struct _Msg_Font_Loaded {
/**
* @struct _Msg_Font_Glyphs_Request
*
* Message from client to request load of glyphs, of inform usage of them.
* Message from client to request load of glyphs, or inform usage of them.
*
* The path strings follow the struct inside the message, as well as
* the list of glyphs to be loaded.
*/
struct _Msg_Font_Glyphs_Request {
Msg_Base base;
unsigned int sourcelen; // font id
unsigned int pathlen; // font id
unsigned int rend_flags; // font id
unsigned int hint; // font id
unsigned int size; // font id
unsigned int dpi; // font id
unsigned int hint;
unsigned int nglyphs;
};
@ -180,6 +183,12 @@ struct _Msg_Font_Glyphs_Request {
* - struct {
* unsigned int index;
* unsigned int offset;
* unsigned int size;
* unsigned int rows;
* unsigned int width;
* unsigned int pitch;
* unsigned int num_grays;
* unsigned int pixel_mode;
* } glarray[];
*/
struct _Msg_Font_Glyphs_Loaded {
@ -187,6 +196,56 @@ struct _Msg_Font_Glyphs_Loaded {
unsigned int ncaches;
};
struct _Msg_Stats {
Msg_Base base;
struct {
unsigned int requested_usage;
unsigned int real_usage;
int fonts_load; // total time spent loading fonts
int fonts_used_load; // total time spent loading fonts that are
// really used
int glyphs_load; // total time spent loading glyphs
} fonts;
};
/*
* @struct _Msg_Font_Debug
*
* Message from server containing all font cache info.
*
* Content of the message follows:
*
* * number of font entries;
* * each font entry:
* - unsigned int filelen
* - const char file
* - unsigned int namelen
* - const char name
* - unsigned int rend_flags;
* - unsigned int size;
* - unsigned int dpi;
* - unsigned int unused;
* - ncaches:
* - each cache:
* * usigned int shmnamelen;
* * const char shmname;
* * unsigned int size;
* * unsigned int usage;
* * unsigned int nglyphs;
* * each glyph:
* - unsigned int index;
* - unsigned int offset;
* - unsigned int size;
* - unsigned int rows;
* - unsigned int width;
* - unsigned int pitch;
* - unsigned int num_grays;
* - unsigned int pixel_mode;
*/
struct _Msg_Font_Debug {
Msg_Base base;
};
struct _Msg_Error {
Msg_Base base;
int error;
@ -206,6 +265,8 @@ typedef struct _Msg_Font_Load Msg_Font_Load;
typedef struct _Msg_Font_Loaded Msg_Font_Loaded;
typedef struct _Msg_Font_Glyphs_Request Msg_Font_Glyphs_Request;
typedef struct _Msg_Font_Glyphs_Loaded Msg_Font_Glyphs_Loaded;
typedef struct _Msg_Stats Msg_Stats;
typedef struct _Msg_Font_Debug Msg_Font_Debug;
typedef struct _Msg_Error Msg_Error;
#endif