1 /* 2 Copyright (C) 2009-2010 Samsung Electronics 3 Copyright (C) 2009-2010 ProFUSION embedded systems 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public License 16 along with this library; see the file COPYING.LIB. If not, write to 17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 #include "ewk_tiled_matrix.h" 23 24 #define _GNU_SOURCE 25 #include "ewk_tiled_backing_store.h" 26 #include "ewk_tiled_private.h" 27 #include <Eina.h> 28 #include <errno.h> 29 #include <inttypes.h> 30 #include <math.h> 31 #include <stdio.h> // XXX remove me later 32 #include <stdlib.h> 33 #include <string.h> 34 35 static const Evas_Coord TILE_MATRIX_BASE_TILE_SIZE = 256; 36 37 struct _Ewk_Tile_Matrix { 38 Eina_Matrixsparse *matrix; 39 Ewk_Tile_Unused_Cache *tuc; 40 Evas_Colorspace cspace; 41 struct { 42 void (*cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *update); 43 void *data; 44 } render; 45 unsigned int frozen; 46 Eina_List *updates; 47 #ifdef DEBUG_MEM_LEAKS 48 struct { 49 struct { 50 uint64_t allocated, freed; 51 } tiles, bytes; 52 } stats; 53 #endif 54 }; 55 56 #ifdef DEBUG_MEM_LEAKS 57 static uint64_t tiles_leaked = 0; 58 static uint64_t bytes_leaked = 0; 59 #endif 60 61 /* called when matrixsparse is resized or freed */ 62 static void _ewk_tile_matrix_cell_free(void *user_data, void *cell_data) 63 { 64 Ewk_Tile_Matrix *tm = user_data; 65 Eina_Inlist *l = cell_data; 66 67 if (!l) 68 return; 69 70 ewk_tile_unused_cache_freeze(tm->tuc); 71 72 while (l) { 73 Ewk_Tile *t = (Ewk_Tile *)l; 74 l = l->next; 75 76 if (t->updates || t->stats.full_update) 77 tm->updates = eina_list_remove(tm->updates, t); 78 79 if (t->visible) 80 ERR("freeing cell that is visible, leaking tile %p", t); 81 else { 82 if (!ewk_tile_unused_cache_tile_get(tm->tuc, t)) 83 ERR("tile %p was not in cache %p? leaking...", t, tm->tuc); 84 else { 85 DBG("tile cell does not exist anymore, free it %p", t); 86 87 #ifdef DEBUG_MEM_LEAKS 88 tm->stats.bytes.freed += t->bytes; 89 tm->stats.tiles.freed++; 90 #endif 91 92 ewk_tile_free(t); 93 } 94 } 95 } 96 97 ewk_tile_unused_cache_thaw(tm->tuc); 98 } 99 100 /* called when cache of unused tile is flushed */ 101 static void _ewk_tile_matrix_tile_free(void *data, Ewk_Tile *t) 102 { 103 Ewk_Tile_Matrix *tm = data; 104 Eina_Matrixsparse_Cell *cell; 105 Eina_Inlist *l, *old; 106 107 if (!eina_matrixsparse_cell_idx_get(tm->matrix, t->row, t->col, &cell)) { 108 ERR("removing tile %p that was not in the matrix? Leaking...", t); 109 return; 110 } 111 112 if (t->updates || t->stats.full_update) 113 tm->updates = eina_list_remove(tm->updates, t); 114 115 old = eina_matrixsparse_cell_data_get(cell); 116 l = eina_inlist_remove(old, EINA_INLIST_GET(t)); 117 if (!l) { 118 /* set to null to avoid double free */ 119 eina_matrixsparse_cell_data_replace(cell, NULL, NULL); 120 eina_matrixsparse_cell_clear(cell); 121 } else if (old != l) 122 eina_matrixsparse_cell_data_replace(cell, l, NULL); 123 124 if (EINA_UNLIKELY(!!t->visible)) { 125 ERR("cache of unused tiles requesting deletion of used tile %p? " 126 "Leaking...", t); 127 return; 128 } 129 130 #ifdef DEBUG_MEM_LEAKS 131 tm->stats.bytes.freed += t->bytes; 132 tm->stats.tiles.freed++; 133 #endif 134 135 ewk_tile_free(t); 136 } 137 138 /** 139 * Creates a new matrix of tiles. 140 * 141 * The tile matrix is responsible for keeping tiles around and 142 * providing fast access to them. One can use it to retrieve new or 143 * existing tiles and give them back, allowing them to be 144 * freed/replaced by the cache. 145 * 146 * @param tuc cache of unused tiles or @c NULL to create one 147 * automatically. 148 * @param cols number of columns in the matrix. 149 * @param rows number of rows in the matrix. 150 * @param cspace the color space used to create tiles in this matrix. 151 * @param render_cb function used to render given tile update. 152 * @param data context to give back to @a render_cb. 153 * 154 * @return newly allocated instance on success, @c NULL on failure. 155 */ 156 Ewk_Tile_Matrix *ewk_tile_matrix_new(Ewk_Tile_Unused_Cache *tuc, unsigned long cols, unsigned long rows, Evas_Colorspace cspace, void (*render_cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *update), const void *data) 157 { 158 Ewk_Tile_Matrix *tm; 159 160 CALLOC_OR_OOM_RET(tm, sizeof(Ewk_Tile_Matrix), NULL); 161 162 tm->matrix = eina_matrixsparse_new(rows, cols, _ewk_tile_matrix_cell_free, tm); 163 if (!tm->matrix) { 164 ERR("could not create sparse matrix."); 165 free(tm); 166 return NULL; 167 } 168 169 if (tuc) 170 tm->tuc = ewk_tile_unused_cache_ref(tuc); 171 else { 172 tm->tuc = ewk_tile_unused_cache_new(40960000); 173 if (!tm->tuc) { 174 ERR("no cache of unused tile!"); 175 eina_matrixsparse_free(tm->matrix); 176 free(tm); 177 return NULL; 178 } 179 } 180 181 tm->cspace = cspace; 182 tm->render.cb = render_cb; 183 tm->render.data = (void *)data; 184 185 return tm; 186 } 187 188 /** 189 * Destroys tiles matrix, releasing its resources. 190 * 191 * The cache instance is unreferenced, possibly freeing it. 192 */ 193 void ewk_tile_matrix_free(Ewk_Tile_Matrix *tm) 194 { 195 #ifdef DEBUG_MEM_LEAKS 196 uint64_t tiles, bytes; 197 #endif 198 199 EINA_SAFETY_ON_NULL_RETURN(tm); 200 ewk_tile_unused_cache_freeze(tm->tuc); 201 202 eina_matrixsparse_free(tm->matrix); 203 204 ewk_tile_unused_cache_thaw(tm->tuc); 205 ewk_tile_unused_cache_unref(tm->tuc); 206 207 #ifdef DEBUG_MEM_LEAKS 208 tiles = tm->stats.tiles.allocated - tm->stats.tiles.freed; 209 bytes = tm->stats.bytes.allocated - tm->stats.bytes.freed; 210 211 tiles_leaked += tiles; 212 bytes_leaked += bytes; 213 214 if (tiles || bytes) 215 ERR("tiled matrix leaked: tiles[+%"PRIu64",-%"PRIu64":%"PRIu64"] " 216 "bytes[+%"PRIu64",-%"PRIu64":%"PRIu64"]", 217 tm->stats.tiles.allocated, tm->stats.tiles.freed, tiles, 218 tm->stats.bytes.allocated, tm->stats.bytes.freed, bytes); 219 else if (tiles_leaked || bytes_leaked) 220 WRN("tiled matrix had no leaks: tiles[+%"PRIu64",-%"PRIu64"] " 221 "bytes[+%"PRIu64",-%"PRIu64"], but some other leaked " 222 "%"PRIu64" tiles (%"PRIu64" bytes)", 223 tm->stats.tiles.allocated, tm->stats.tiles.freed, 224 tm->stats.bytes.allocated, tm->stats.bytes.freed, 225 tiles_leaked, bytes_leaked); 226 else 227 INF("tiled matrix had no leaks: tiles[+%"PRIu64",-%"PRIu64"] " 228 "bytes[+%"PRIu64",-%"PRIu64"]", 229 tm->stats.tiles.allocated, tm->stats.tiles.freed, 230 tm->stats.bytes.allocated, tm->stats.bytes.freed); 231 #endif 232 233 free(tm); 234 } 235 236 /** 237 * Resize matrix to given number of rows and columns. 238 */ 239 void ewk_tile_matrix_resize(Ewk_Tile_Matrix *tm, unsigned long cols, unsigned long rows) 240 { 241 EINA_SAFETY_ON_NULL_RETURN(tm); 242 eina_matrixsparse_size_set(tm->matrix, rows, cols); 243 } 244 245 /** 246 * Get the cache of unused tiles in use by given matrix. 247 * 248 * No reference is taken to the cache. 249 */ 250 Ewk_Tile_Unused_Cache *ewk_tile_matrix_unused_cache_get(const Ewk_Tile_Matrix *tm) 251 { 252 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL); 253 return tm->tuc; 254 } 255 256 /** 257 * Get the exact tile for the given position and zoom. 258 * 259 * If the tile was unused then it's removed from the cache. 260 * 261 * After usage, please give it back using 262 * ewk_tile_matrix_tile_put(). If you just want to check if it exists, 263 * then use ewk_tile_matrix_tile_exact_exists(). 264 * 265 * @param tm the tile matrix to get tile from. 266 * @param col the column number. 267 * @param row the row number. 268 * @param zoom the exact zoom to use. 269 * 270 * @return The tile instance or @c NULL if none is found. If the tile 271 * was in the unused cache it will be @b removed (thus 272 * considered used) and one should give it back with 273 * ewk_tile_matrix_tile_put() afterwards. 274 * 275 * @see ewk_tile_matrix_tile_nearest_get() 276 * @see ewk_tile_matrix_tile_exact_get() 277 */ 278 Ewk_Tile *ewk_tile_matrix_tile_exact_get(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom) 279 { 280 Ewk_Tile *t, *item, *item_found = NULL; 281 Eina_Inlist *inl; 282 283 t = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 284 if (!t) 285 return NULL; 286 287 if (t->zoom == zoom) 288 goto end; 289 290 EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) { 291 if (item->zoom != zoom) 292 continue; 293 item_found = item; 294 break; 295 } 296 297 if (!item_found) 298 return NULL; 299 300 inl = eina_inlist_promote(EINA_INLIST_GET(t), EINA_INLIST_GET(item_found)); 301 eina_matrixsparse_data_idx_replace(tm->matrix, row, col, inl, NULL); 302 303 end: 304 if (!t->visible) { 305 if (!ewk_tile_unused_cache_tile_get(tm->tuc, t)) 306 WRN("Ewk_Tile was unused but not in cache? bug!"); 307 } 308 309 return t; 310 } 311 312 /** 313 * Checks if tile of given zoom exists in matrix. 314 * 315 * @param tm the tile matrix to check tile existence. 316 * @param col the column number. 317 * @param row the row number. 318 * @param zoom the exact zoom to query. 319 * 320 * @return @c EINA_TRUE if found, @c EINA_FALSE otherwise. 321 * 322 * @see ewk_tile_matrix_tile_exact_get() 323 */ 324 Eina_Bool ewk_tile_matrix_tile_exact_exists(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom) 325 { 326 Ewk_Tile *t, *item; 327 328 t = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 329 if (!t) 330 return EINA_FALSE; 331 332 EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) { 333 if (item->zoom == zoom) 334 return EINA_TRUE; 335 } 336 337 return EINA_FALSE; 338 } 339 340 /** 341 * Get the nearest tile for given position and zoom. 342 * 343 * The nearest tile is the one at the given position but with the 344 * closest zoom, this being the division of the tile zoom by the 345 * desired zoom, the closest to 1.0 gets it. 346 * 347 * If the tile was unused then it's removed from the cache. 348 * 349 * After usage, please give it back using ewk_tile_matrix_tile_put(). 350 * 351 * @param tm the tile matrix to get tile from. 352 * @param col the column number. 353 * @param row the row number. 354 * @param zoom the exact zoom to use. 355 * 356 * @return The tile instance or @c NULL if none is found. If the tile 357 * was in the unused cache it will be @b removed (thus 358 * considered used) and one should give it back with 359 * ewk_tile_matrix_tile_put() afterwards. 360 */ 361 Ewk_Tile *ewk_tile_matrix_tile_nearest_get(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom) 362 { 363 Ewk_Tile *t, *item, *item_found = NULL; 364 Eina_Inlist *inl; 365 float zoom_found = 0; 366 367 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL); 368 EINA_SAFETY_ON_FALSE_RETURN_VAL(zoom > 0.0, NULL); 369 370 t = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 371 if (!t) 372 return NULL; 373 374 if (t->zoom == zoom) { 375 item_found = t; 376 goto end; 377 } 378 379 EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) { 380 float cur_zoom = item->zoom; 381 382 if (cur_zoom == zoom) { 383 item_found = item; 384 break; 385 } 386 387 if (cur_zoom > zoom) 388 cur_zoom = zoom / cur_zoom; 389 else 390 cur_zoom = cur_zoom / zoom; 391 392 if (cur_zoom > zoom_found) { 393 item_found = item; 394 zoom_found = cur_zoom; 395 } 396 } 397 398 if (!item_found) 399 return NULL; 400 401 inl = eina_inlist_promote(EINA_INLIST_GET(t), EINA_INLIST_GET(item_found)); 402 eina_matrixsparse_data_idx_replace(tm->matrix, row, col, inl, NULL); 403 404 end: 405 if (!item_found->visible) { 406 if (!ewk_tile_unused_cache_tile_get(tm->tuc, item_found)) 407 WRN("Ewk_Tile was unused but not in cache? bug!"); 408 } 409 410 return item_found; 411 } 412 413 /** 414 * Create a new tile at given position and zoom level in the matrix. 415 * 416 * The newly created tile is considered in use and not put into cache 417 * of unused tiles. After it is used one should call 418 * ewk_tile_matrix_tile_put() to give it back to matrix. 419 * 420 * @param tm the tile matrix to create tile on. 421 * @param col the column number. 422 * @param row the row number. 423 * @param zoom the level to create tile, used to determine tile size. 424 */ 425 Ewk_Tile *ewk_tile_matrix_tile_new(Ewk_Tile_Matrix *tm, Evas *evas, unsigned long col, unsigned int row, float zoom) 426 { 427 Evas_Coord s; 428 Eina_Inlist *old; 429 Ewk_Tile *t; 430 431 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL); 432 EINA_SAFETY_ON_FALSE_RETURN_VAL(zoom > 0.0, NULL); 433 434 s = TILE_SIZE_AT_ZOOM(TILE_MATRIX_BASE_TILE_SIZE, zoom); 435 zoom = (float)s / (float)TILE_MATRIX_BASE_TILE_SIZE; 436 437 t = ewk_tile_new(evas, s, s, zoom, tm->cspace); 438 if (!t) { 439 ERR("could not create tile %dx%d at %f, cspace=%d", 440 s, s, (double)zoom, tm->cspace); 441 return NULL; 442 } 443 444 old = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 445 old = eina_inlist_prepend(old, EINA_INLIST_GET(t)); 446 if (!eina_matrixsparse_data_idx_replace(tm->matrix, row, col, t, NULL)) { 447 ERR("could not set matrix cell, row/col outside matrix dimensions!"); 448 ewk_tile_free(t); 449 return NULL; 450 } 451 452 t->col = col; 453 t->row = row; 454 t->x = col * s; 455 t->y = row * s; 456 457 cairo_translate(t->cairo, -t->x, -t->y); 458 459 t->stats.full_update = EINA_TRUE; 460 tm->updates = eina_list_append(tm->updates, t); 461 462 #ifdef DEBUG_MEM_LEAKS 463 tm->stats.bytes.allocated += t->bytes; 464 tm->stats.tiles.allocated++; 465 #endif 466 467 return t; 468 } 469 470 /** 471 * Gives back the tile to the tile matrix. 472 * 473 * This will report the tile is no longer in use by the one that got 474 * it with ewk_tile_matrix_tile_nearest_get() or 475 * ewk_tile_matrix_tile_exact_get(). 476 * 477 * Any previous reference to tile should be released 478 * (ewk_tile_hide()) before calling this function, so it will 479 * be known if it is not visibile anymore and thus can be put into the 480 * unused cache. 481 * 482 * @param tm the tile matrix to return tile to. 483 * @param t the tile instance to return, must @b not be @c NULL. 484 * @param last_used time in which tile was last used. 485 * 486 * @return #EINA_TRUE on success or #EINA_FALSE on failure. 487 */ 488 Eina_Bool ewk_tile_matrix_tile_put(Ewk_Tile_Matrix *tm, Ewk_Tile *t, double last_used) 489 { 490 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE); 491 EINA_SAFETY_ON_NULL_RETURN_VAL(t, EINA_FALSE); 492 493 if (t->visible) 494 return EINA_TRUE; 495 496 t->stats.last_used = last_used; 497 return ewk_tile_unused_cache_tile_put(tm->tuc, t, _ewk_tile_matrix_tile_free, tm); 498 } 499 500 Eina_Bool ewk_tile_matrix_tile_update(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, const Eina_Rectangle *update) 501 { 502 Ewk_Tile *l, *t; 503 Eina_Rectangle new_update; 504 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE); 505 EINA_SAFETY_ON_NULL_RETURN_VAL(update, EINA_FALSE); 506 507 memcpy(&new_update, update, sizeof(new_update)); 508 // check update is valid, otherwise return EINA_FALSE 509 if (update->x < 0 || update->y < 0 || update->w <= 0 || update->h <= 0) { 510 ERR("invalid update region."); 511 return EINA_FALSE; 512 } 513 514 if (update->x + update->w - 1 >= TILE_MATRIX_BASE_TILE_SIZE) 515 new_update.w = TILE_MATRIX_BASE_TILE_SIZE - update->x; 516 if (update->y + update->h - 1 >= TILE_MATRIX_BASE_TILE_SIZE) 517 new_update.h = TILE_MATRIX_BASE_TILE_SIZE - update->y; 518 519 l = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 520 521 if (!l) 522 return EINA_TRUE; 523 524 EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) { 525 if (!t->updates && !t->stats.full_update) 526 tm->updates = eina_list_append(tm->updates, t); 527 new_update.x = roundf(t->zoom * new_update.x); 528 new_update.y = roundf(t->zoom * new_update.y); 529 new_update.w = roundf(t->zoom * new_update.w); 530 new_update.h = roundf(t->zoom * new_update.h); 531 ewk_tile_update_area(t, &new_update); 532 } 533 534 return EINA_TRUE; 535 } 536 537 Eina_Bool ewk_tile_matrix_tile_update_full(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row) 538 { 539 Ewk_Tile *l, *t; 540 Eina_Matrixsparse_Cell *cell; 541 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE); 542 543 if (!eina_matrixsparse_cell_idx_get(tm->matrix, row, col, &cell)) 544 return EINA_FALSE; 545 546 if (!cell) 547 return EINA_TRUE; 548 549 l = eina_matrixsparse_cell_data_get(cell); 550 if (!l) { 551 CRITICAL("matrix cell with no tile!"); 552 return EINA_TRUE; 553 } 554 555 EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) { 556 if (!t->updates && !t->stats.full_update) 557 tm->updates = eina_list_append(tm->updates, t); 558 ewk_tile_update_full(t); 559 } 560 561 return EINA_TRUE; 562 } 563 564 void ewk_tile_matrix_tile_updates_clear(Ewk_Tile_Matrix *tm, Ewk_Tile *t) 565 { 566 EINA_SAFETY_ON_NULL_RETURN(tm); 567 if (!t->updates && !t->stats.full_update) 568 return; 569 ewk_tile_updates_clear(t); 570 tm->updates = eina_list_remove(tm->updates, t); 571 } 572 573 static Eina_Bool _ewk_tile_matrix_slicer_setup(Ewk_Tile_Matrix *tm, const Eina_Rectangle *area, float zoom, Eina_Tile_Grid_Slicer *slicer) 574 { 575 unsigned long rows, cols; 576 Evas_Coord x, y, w, h, tw, th; 577 578 if (area->w <= 0 || area->h <= 0) { 579 WRN("invalid area region: %d,%d+%dx%d.", 580 area->x, area->y, area->w, area->h); 581 return EINA_FALSE; 582 } 583 584 x = area->x; 585 y = area->y; 586 w = area->w; 587 h = area->h; 588 589 tw = TILE_SIZE_AT_ZOOM(TILE_W, zoom); 590 th = TILE_SIZE_AT_ZOOM(TILE_H, zoom); 591 592 // cropping area region to fit matrix 593 eina_matrixsparse_size_get(tm->matrix, &rows, &cols); 594 if (x < 0) { 595 w += x; 596 x = 0; 597 } 598 if (y < 0) { 599 h += y; 600 y = 0; 601 } 602 603 if (y + h - 1 > (long)(rows * th)) 604 h = rows * th - y; 605 if (x + w - 1 > (long)(cols * tw)) 606 w = cols * tw - x; 607 608 return eina_tile_grid_slicer_setup(slicer, x, y, w, h, tw, th); 609 } 610 611 612 Eina_Bool ewk_tile_matrix_update(Ewk_Tile_Matrix *tm, const Eina_Rectangle *update, float zoom) 613 { 614 const Eina_Tile_Grid_Info *info; 615 Eina_Tile_Grid_Slicer slicer; 616 EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE); 617 EINA_SAFETY_ON_NULL_RETURN_VAL(update, EINA_FALSE); 618 619 if (update->w < 1 || update->h < 1) { 620 DBG("Why we get updates with empty areas? %d,%d+%dx%d at zoom %f", 621 update->x, update->y, update->w, update->h, zoom); 622 return EINA_TRUE; 623 } 624 625 if (!_ewk_tile_matrix_slicer_setup(tm, update, zoom, &slicer)) { 626 ERR("Could not setup slicer for update %d,%d+%dx%d at zoom %f", 627 update->x, update->y, update->w, update->h, zoom); 628 return EINA_FALSE; 629 } 630 631 while (eina_tile_grid_slicer_next(&slicer, &info)) { 632 unsigned long col, row; 633 Ewk_Tile *l, *t; 634 col = info->col; 635 row = info->row; 636 637 l = eina_matrixsparse_data_idx_get(tm->matrix, row, col); 638 if (!l) 639 continue; 640 641 EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) { 642 if (!t->updates && !t->stats.full_update) 643 tm->updates = eina_list_append(tm->updates, t); 644 if (info->full) 645 ewk_tile_update_full(t); 646 else { 647 if (t->zoom != zoom) 648 ewk_tile_update_full(t); 649 else 650 ewk_tile_update_area(t, &info->rect); 651 } 652 } 653 } 654 655 656 return EINA_TRUE; 657 } 658 659 void ewk_tile_matrix_updates_process(Ewk_Tile_Matrix *tm) 660 { 661 Eina_List *l, *l_next; 662 Ewk_Tile *t; 663 EINA_SAFETY_ON_NULL_RETURN(tm); 664 665 // process updates, unflag tiles 666 EINA_LIST_FOREACH_SAFE(tm->updates, l, l_next, t) { 667 ewk_tile_updates_process(t, tm->render.cb, tm->render.data); 668 if (t->visible) { 669 ewk_tile_updates_clear(t); 670 tm->updates = eina_list_remove_list(tm->updates, l); 671 } 672 } 673 } 674 675 void ewk_tile_matrix_updates_clear(Ewk_Tile_Matrix *tm) 676 { 677 Ewk_Tile *t; 678 EINA_SAFETY_ON_NULL_RETURN(tm); 679 680 EINA_LIST_FREE(tm->updates, t) 681 ewk_tile_updates_clear(t); 682 tm->updates = NULL; 683 } 684 685 // remove me later! 686 void ewk_tile_matrix_dbg(const Ewk_Tile_Matrix *tm) 687 { 688 Eina_Iterator *it = eina_matrixsparse_iterator_complete_new(tm->matrix); 689 Eina_Matrixsparse_Cell *cell; 690 Eina_Bool last_empty = EINA_FALSE; 691 692 #ifdef DEBUG_MEM_LEAKS 693 printf("Ewk_Tile Matrix: tiles[+%"PRIu64",-%"PRIu64":%"PRIu64"] " 694 "bytes[+%"PRIu64",-%"PRIu64":%"PRIu64"]\n", 695 tm->stats.tiles.allocated, tm->stats.tiles.freed, 696 tm->stats.tiles.allocated - tm->stats.tiles.freed, 697 tm->stats.bytes.allocated, tm->stats.bytes.freed, 698 tm->stats.bytes.allocated - tm->stats.bytes.freed); 699 #else 700 printf("Ewk_Tile Matrix:\n"); 701 #endif 702 703 EINA_ITERATOR_FOREACH(it, cell) { 704 unsigned long row, col; 705 Eina_Inlist *l; 706 eina_matrixsparse_cell_position_get(cell, &row, &col); 707 l = eina_matrixsparse_cell_data_get(cell); 708 709 if (!l) { 710 if (!last_empty) { 711 last_empty = EINA_TRUE; 712 printf("Empty:"); 713 } 714 printf(" [%lu,%lu]", col, row); 715 } else { 716 if (last_empty) { 717 last_empty = EINA_FALSE; 718 printf("\n"); 719 } 720 Ewk_Tile *t; 721 722 printf("%3lu,%3lu %10p:", col, row, l); 723 EINA_INLIST_FOREACH(l, t) 724 printf(" [%3lu,%3lu + %dx%d @ %0.3f]%c", 725 t->col, t->row, t->w, t->h, t->zoom, 726 t->visible ? '*': ' '); 727 printf("\n"); 728 } 729 } 730 if (last_empty) 731 printf("\n"); 732 eina_iterator_free(it); 733 734 ewk_tile_unused_cache_dbg(tm->tuc); 735 } 736 737 /** 738 * Freeze matrix to not do maintenance tasks. 739 * 740 * Maintenance tasks optimize usage, but maybe we know we should hold 741 * on them until we do the last operation, in this case we freeze 742 * while operating and then thaw when we're done. 743 * 744 * @see ewk_tile_matrix_thaw() 745 */ 746 void ewk_tile_matrix_freeze(Ewk_Tile_Matrix *tm) 747 { 748 EINA_SAFETY_ON_NULL_RETURN(tm); 749 if (!tm->frozen) 750 ewk_tile_unused_cache_freeze(tm->tuc); 751 tm->frozen++; 752 } 753 754 /** 755 * Unfreezes maintenance tasks. 756 * 757 * If this is the last counterpart of freeze, then maintenance tasks 758 * will run immediately. 759 */ 760 void ewk_tile_matrix_thaw(Ewk_Tile_Matrix *tm) 761 { 762 EINA_SAFETY_ON_NULL_RETURN(tm); 763 if (!tm->frozen) { 764 ERR("thawing more than freezing!"); 765 return; 766 } 767 768 tm->frozen--; 769 if (!tm->frozen) 770 ewk_tile_unused_cache_thaw(tm->tuc); 771 } 772