1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
26 #include "image_cache.h"
30 gp_storage
*meta_data
;
35 /* number of elevated get calls */
36 unsigned int elevated
;
38 /* this identifies an image */
43 unsigned int max_size
;
44 unsigned int cur_size
;
50 size_t image_cache_get_ram_size(void)
55 f
= fopen("/proc/meminfo", "r");
58 GP_WARN("Failed to read /proc/meminfo");
62 if (fscanf(f
, "MemTotal: %zu", &ret
) != 1) {
64 GP_WARN("Failed to read /proc/meminfo");
74 * Reports correct image record size.
76 static size_t image_size2(gp_pixmap
*pixmap
, gp_storage
*meta_data
,
79 size_t meta_data_size
= 0;
80 size_t pixmap_size
= pixmap
->bytes_per_row
* pixmap
->h
+ sizeof(gp_pixmap
);
82 //TODO! 4096 is a size of single block, data storage may have more blocks
84 meta_data_size
= 4096;
86 return meta_data_size
+ pixmap_size
+
87 sizeof(struct image
) + strlen(path
) + 1;
90 static size_t image_size(struct image
*img
)
92 return image_size2(img
->pixmap
, NULL
, img
->path
);
95 struct image_cache
*image_cache_create(unsigned int max_size_kbytes
)
97 struct image_cache
*self
;
99 self
= malloc(sizeof(struct image_cache
));
104 self
->max_size
= max_size_kbytes
* 1024;
105 self
->cur_size
= sizeof(struct image_cache
);
110 GP_DEBUG(1, "Created image cache max size %ukB", max_size_kbytes
);
115 static void remove_img(struct image_cache
*self
, struct image
*img
, size_t size
)
117 if (img
== self
->end
)
118 self
->end
= img
->prev
;
121 img
->prev
->next
= img
->next
;
124 img
->next
->prev
= img
->prev
;
126 if (img
== self
->root
)
127 self
->root
= img
->next
;
129 self
->cur_size
-= size
;
132 static void remove_img_free(struct image_cache
*self
,
133 struct image
*img
, size_t size
)
135 GP_DEBUG(2, "Freeing image '%s' size %zu", img
->path
, size
);
137 remove_img(self
, img
, size
);
138 gp_pixmap_free(img
->pixmap
);
139 gp_storage_destroy(img
->meta_data
);
144 * Adds image to the start of the double linked list
146 static void add_img(struct image_cache
*self
, struct image
*img
, size_t size
)
148 img
->next
= self
->root
;
151 img
->next
->prev
= img
;
156 self
->cur_size
+= size
;
158 if (self
->end
== NULL
)
162 int image_cache_get(struct image_cache
*self
, gp_pixmap
**img
,
163 gp_storage
**meta_data
, int elevate
, const char *key
)
170 GP_DEBUG(2, "Looking for image '%s'", key
);
172 for (i
= self
->root
; i
!= NULL
; i
= i
->next
)
173 if (!strcmp(key
, i
->path
))
179 /* Push the image to the root of the list */
181 size_t size
= image_size(i
);
183 GP_DEBUG(2, "Refreshing image '%s'", key
);
185 remove_img(self
, i
, size
);
186 add_img(self
, i
, size
);
195 *meta_data
= i
->meta_data
;
200 gp_pixmap
*image_cache_get2(struct image_cache
*self
, int elevate
,
201 const char *fmt
, ...)
213 len
= vsnprintf(buf
, sizeof(buf
), fmt
, va
);
216 if (len
>= sizeof(buf
)) {
217 key
= malloc(len
+ 1);
219 GP_WARN("Malloc failed :(");
224 vsprintf(key
, fmt
, va
);
228 GP_DEBUG(2, "Looking for image '%s'", key
);
230 for (i
= self
->root
; i
!= NULL
; i
= i
->next
)
231 if (!strcmp(key
, i
->path
))
234 /* Push the image to the root of the list */
236 size_t size
= image_size(i
);
238 GP_DEBUG(2, "Refreshing image '%s'", key
);
240 remove_img(self
, i
, size
);
241 add_img(self
, i
, size
);
246 if (len
>= sizeof(buf
))
249 return i
? i
->pixmap
: NULL
;
252 void image_cache_print(struct image_cache
*self
)
257 printf("Image cache disabled\n");
261 printf("Image cache size %u used %u\n", self
->max_size
, self
->cur_size
);
263 for (i
= self
->root
; i
!= NULL
; i
= i
->next
)
264 printf(" size=%10zu elevated=%u key='%s'\n",
265 image_size(i
), i
->elevated
, i
->path
);
268 static int assert_size(struct image_cache
*self
, size_t size
)
270 if (self
->cur_size
+ size
< self
->max_size
)
273 while (self
->cur_size
+ size
> self
->max_size
) {
275 if (self
->end
== NULL
) {
276 GP_WARN("Cache too small for image size %zu", size
);
280 remove_img_free(self
, self
->end
, image_size(self
->end
));
286 int image_cache_put(struct image_cache
*self
, gp_pixmap
*pixmap
,
287 gp_storage
*meta_data
, const char *key
)
294 size
= image_size2(pixmap
, meta_data
, key
);
297 * We try to create room for the image. If this fails we add the image
298 * anyway because we need to store it while we are showing it (and it
299 * will be removed from cache by next image for sure).
301 assert_size(self
, size
);
303 struct image
*img
= malloc(sizeof(struct image
) + strlen(key
) + 1);
306 GP_WARN("Malloc failed :(");
310 img
->pixmap
= pixmap
;
311 img
->meta_data
= meta_data
;
313 strcpy(img
->path
, key
);
315 GP_DEBUG(2, "Adding image '%s' size %zu", img
->path
, size
);
317 add_img(self
, img
, size
);
322 int image_cache_put2(struct image_cache
*self
, gp_pixmap
*pixmap
,
323 gp_storage
*meta_data
, const char *fmt
, ...)
332 len
= vsnprintf(NULL
, 0, fmt
, va
);
336 size
= image_size2(pixmap
, meta_data
, "") + len
+ 1;
339 * We try to create room for the image. If this fails we add the image
340 * anyway because we need to store it while we are showing it (and it
341 * will be removed from cache by next image for sure).
343 assert_size(self
, size
);
345 struct image
*img
= malloc(sizeof(struct image
) + len
+ 1);
348 GP_WARN("Malloc failed :(");
352 img
->pixmap
= pixmap
;
353 img
->meta_data
= meta_data
;
357 vsprintf(img
->path
, fmt
, va
);
360 GP_DEBUG(2, "Adding image '%s' size %zu",
363 add_img(self
, img
, size
);
368 void image_cache_drop(struct image_cache
*self
)
373 GP_DEBUG(1, "Dropping images in cache");
375 while (self
->end
!= NULL
)
376 remove_img_free(self
, self
->end
, 0);
378 self
->cur_size
= sizeof(struct image_cache
);
381 void image_cache_destroy(struct image_cache
*self
)
386 GP_DEBUG(1, "Destroying image cache");
388 while (self
->end
!= NULL
)
389 remove_img_free(self
, self
->end
, 0);