20#include <freerdp/config.h>
25#include <winpr/assert.h>
26#include <winpr/cast.h>
28#include <freerdp/freerdp.h>
29#include <freerdp/constants.h>
30#include <winpr/stream.h>
32#include <freerdp/log.h>
33#include <freerdp/gdi/bitmap.h>
35#include "../gdi/gdi.h"
36#include "../core/graphics.h"
41#define TAG FREERDP_TAG("cache.bitmap")
43static rdpBitmap* bitmap_cache_get(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index);
44static BOOL bitmap_cache_put(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index,
47static BOOL update_gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
49 rdpBitmap* bitmap =
nullptr;
50 rdpCache* cache =
nullptr;
52 cache = context->cache;
54 if (memblt->cacheId == 0xFF)
55 bitmap = offscreen_cache_get(cache->offscreen, memblt->cacheIndex);
57 bitmap = bitmap_cache_get(cache->bitmap, (BYTE)memblt->cacheId, memblt->cacheIndex);
60 if (bitmap ==
nullptr)
63 memblt->bitmap = bitmap;
64 return IFCALLRESULT(TRUE, cache->bitmap->MemBlt, context, memblt);
67static BOOL update_gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
69 rdpBitmap* bitmap =
nullptr;
70 rdpCache* cache = context->cache;
71 rdpBrush* brush = &mem3blt->brush;
74 if (mem3blt->cacheId == 0xFF)
75 bitmap = offscreen_cache_get(cache->offscreen, mem3blt->cacheIndex);
77 bitmap = bitmap_cache_get(cache->bitmap, (BYTE)mem3blt->cacheId, mem3blt->cacheIndex);
83 const BYTE style = WINPR_ASSERTING_INT_CAST(UINT8, brush->style);
84 BYTE* data = brush->data;
86 if (brush->style & CACHED_BRUSH)
88 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
96 mem3blt->bitmap = bitmap;
97 IFCALLRET(cache->bitmap->Mem3Blt, ret, context, mem3blt);
103static BOOL update_gdi_cache_bitmap(rdpContext* context,
const CACHE_BITMAP_ORDER* cacheBitmap)
105 rdpBitmap* bitmap =
nullptr;
106 rdpBitmap* prevBitmap =
nullptr;
107 rdpCache* cache = context->cache;
108 bitmap = Bitmap_Alloc(context);
113 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapWidth),
114 WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapHeight)))
117 if (!bitmap->Decompress(context, bitmap, cacheBitmap->bitmapDataStream,
118 cacheBitmap->bitmapWidth, cacheBitmap->bitmapHeight,
119 cacheBitmap->bitmapBpp, cacheBitmap->bitmapLength,
120 cacheBitmap->compressed, RDP_CODEC_ID_NONE))
123 if (!bitmap->New(context, bitmap))
126 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex);
127 Bitmap_Free(context, prevBitmap);
128 if (!bitmap_cache_put(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex, bitmap))
133 Bitmap_Free(context, bitmap);
140 rdpBitmap* prevBitmap =
nullptr;
141 rdpCache* cache = context->cache;
142 rdpSettings* settings = context->settings;
143 rdpBitmap* bitmap = Bitmap_Alloc(context);
149 bitmap->key64 = ((UINT64)cacheBitmapV2->key1 | (((UINT64)cacheBitmapV2->key2) << 32));
151 if (!cacheBitmapV2->bitmapBpp)
152 cacheBitmapV2->bitmapBpp = ColorDepth;
154 if ((ColorDepth == 15) && (cacheBitmapV2->bitmapBpp == 16))
155 cacheBitmapV2->bitmapBpp = ColorDepth;
157 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapWidth),
158 WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapHeight)))
161 if (!bitmap->Decompress(context, bitmap, cacheBitmapV2->bitmapDataStream,
162 cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight,
163 cacheBitmapV2->bitmapBpp, cacheBitmapV2->bitmapLength,
164 cacheBitmapV2->compressed, RDP_CODEC_ID_NONE))
167 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex);
169 if (!bitmap->New(context, bitmap))
172 Bitmap_Free(context, prevBitmap);
173 if (!bitmap_cache_put(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex, bitmap))
178 Bitmap_Free(context, bitmap);
184 rdpBitmap* bitmap =
nullptr;
185 rdpBitmap* prevBitmap =
nullptr;
186 BOOL compressed = TRUE;
187 rdpCache* cache = context->cache;
188 rdpSettings* settings = context->settings;
190 bitmap = Bitmap_Alloc(context);
196 bitmap->key64 = ((UINT64)cacheBitmapV3->key1 | (((UINT64)cacheBitmapV3->key2) << 32));
198 if (!cacheBitmapV3->bpp)
199 cacheBitmapV3->bpp = ColorDepth;
201 compressed = (bitmapData->codecID != RDP_CODEC_ID_NONE);
203 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->width),
204 WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->height)))
207 if (!bitmap->Decompress(context, bitmap, bitmapData->data, bitmapData->width,
208 bitmapData->height, bitmapData->bpp, bitmapData->length, compressed,
209 bitmapData->codecID))
212 if (!bitmap->New(context, bitmap))
215 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex);
216 Bitmap_Free(context, prevBitmap);
217 if (!bitmap_cache_put(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex, bitmap))
222 Bitmap_Free(context, bitmap);
226rdpBitmap* bitmap_cache_get(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index)
228 rdpBitmap* bitmap =
nullptr;
230 if (
id >= bitmapCache->maxCells)
232 WLog_ERR(TAG,
"get invalid bitmap cell id: %" PRIu32
"",
id);
236 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
238 index = bitmapCache->cells[id].number;
240 else if (index > bitmapCache->cells[
id].number)
242 WLog_ERR(TAG,
"get invalid bitmap index %" PRIu32
" in cell id: %" PRIu32
"", index,
id);
246 bitmap = bitmapCache->cells[id].entries[index];
250BOOL bitmap_cache_put(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index, rdpBitmap* bitmap)
252 WINPR_ASSERT(bitmapCache);
253 if (
id > bitmapCache->maxCells)
255 WLog_ERR(TAG,
"put invalid bitmap cell id: %" PRIu32
"",
id);
259 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
261 index = bitmapCache->cells[id].number;
263 else if (index > bitmapCache->cells[
id].number)
265 WLog_ERR(TAG,
"put invalid bitmap index %" PRIu32
" in cell id: %" PRIu32
"", index,
id);
269 bitmapCache->cells[id].entries[index] = bitmap;
273void bitmap_cache_register_callbacks(rdpUpdate* update)
275 rdpCache* cache =
nullptr;
277 WINPR_ASSERT(update);
278 WINPR_ASSERT(update->context);
279 WINPR_ASSERT(update->context->cache);
281 cache = update->context->cache;
286 cache->bitmap->MemBlt = update->primary->MemBlt;
287 cache->bitmap->Mem3Blt = update->primary->Mem3Blt;
288 update->primary->MemBlt = update_gdi_memblt;
289 update->primary->Mem3Blt = update_gdi_mem3blt;
290 update->secondary->CacheBitmap = update_gdi_cache_bitmap;
291 update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2;
292 update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3;
293 update->BitmapUpdate = gdi_bitmap_update;
297static int bitmap_cache_save_persistent(
rdpBitmapCache* bitmapCache)
299 WINPR_ASSERT(bitmapCache);
301 rdpContext* context = bitmapCache->context;
302 rdpSettings* settings = context->settings;
312 const char* BitmapCachePersistFile =
314 if (!BitmapCachePersistFile)
317 rdpPersistentCache* persistent = persistent_cache_new();
322 int status = persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, version);
327 if (bitmapCache->cells)
329 for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
332 for (UINT32 j = 0; j < cell->number + 1 && cell->entries; j++)
335 rdpBitmap* bitmap = cell->entries[j];
337 if (!bitmap || !bitmap->key64)
340 cacheEntry.key64 = bitmap->key64;
342 cacheEntry.width = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width);
343 cacheEntry.height = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height);
344 const UINT64 size = 4ULL * bitmap->width * bitmap->height;
345 if (size > UINT32_MAX)
347 cacheEntry.size = (UINT32)size;
348 cacheEntry.flags = 0;
349 cacheEntry.data = bitmap->data;
351 if (persistent_cache_write_entry(persistent, &cacheEntry) < 1)
363 persistent_cache_free(persistent);
369 WINPR_ASSERT(bitmapCache);
370 if (!bitmapCache->cells)
374 for (UINT32 i = 0; i <= bitmapCache->maxCells; i++)
382 for (j = 0; j < cell->number + 1; j++)
384 rdpBitmap* bitmap = cell->entries[j];
385 Bitmap_Free(bitmapCache->context, bitmap);
388 free((
void*)cell->entries);
391 free(bitmapCache->cells);
393 bitmapCache->cells =
nullptr;
401 rdpContext* context = bitmapCache->context;
402 WINPR_ASSERT(context);
404 rdpSettings* settings = context->settings;
405 WINPR_ASSERT(settings);
407 const UINT32 BitmapCacheV2NumCells =
410 if (BitmapCacheV2NumCells == bitmapCache->maxCells)
413 bitmap_cache_cell_free(bitmapCache);
419 if (!bitmapCache->cells)
421 bitmapCache->maxCells = BitmapCacheV2NumCells;
423 for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
426 freerdp_settings_get_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, i);
431 UINT32 nr = info->numEntries;
433 cell->entries = (rdpBitmap**)calloc((nr + 1),
sizeof(rdpBitmap*));
444 BITMAP_V2_CELL* extra = &bitmapCache->cells[bitmapCache->maxCells];
446 extra->entries = (rdpBitmap**)calloc(1,
sizeof(rdpBitmap*));
458 WINPR_ASSERT(context);
465 bitmapCache->context = context;
467 if (!bitmap_cache_resize(bitmapCache))
472 WINPR_PRAGMA_DIAG_PUSH
473 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
474 bitmap_cache_free(bitmapCache);
475 WINPR_PRAGMA_DIAG_POP
484 bitmap_cache_save_persistent(bitmapCache);
486 bitmap_cache_cell_free(bitmapCache);
488 persistent_cache_free(bitmapCache->persistent);
493static void free_bitmap_data(
BITMAP_DATA* data,
size_t count)
498 for (
size_t x = 0; x < count; x++)
499 free(data[x].bitmapDataStream);
511 for (
size_t x = 0; x < count; x++)
515 if (data[x].bitmapLength > 0)
517 dst[x].bitmapDataStream = malloc(data[x].bitmapLength);
519 if (!dst[x].bitmapDataStream)
522 memcpy(dst[x].bitmapDataStream, data[x].bitmapDataStream, data[x].bitmapLength);
528 free_bitmap_data(dst, count);
532void free_bitmap_update(WINPR_ATTR_UNUSED rdpContext* context,
538 free_bitmap_data(pointer->rectangles, pointer->number);
546 if (!dst || !pointer)
550 dst->rectangles = copy_bitmap_data(pointer->rectangles, pointer->number);
552 if (!dst->rectangles)
557 WINPR_PRAGMA_DIAG_PUSH
558 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
559 free_bitmap_update(context, dst);
560 WINPR_PRAGMA_DIAG_POP
573 if (order->bitmapLength > 0)
575 dst->bitmapDataStream = malloc(order->bitmapLength);
577 if (!dst->bitmapDataStream)
580 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
585 WINPR_PRAGMA_DIAG_PUSH
586 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
587 free_cache_bitmap_order(context, dst);
588 WINPR_PRAGMA_DIAG_POP
592void free_cache_bitmap_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_BITMAP_ORDER* order)
595 free(order->bitmapDataStream);
610 if (order->bitmapLength > 0)
612 dst->bitmapDataStream = malloc(order->bitmapLength);
614 if (!dst->bitmapDataStream)
617 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
622 WINPR_PRAGMA_DIAG_PUSH
623 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
624 free_cache_bitmap_v2_order(context, dst);
625 WINPR_PRAGMA_DIAG_POP
629void free_cache_bitmap_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
633 free(order->bitmapDataStream);
648 if (order->bitmapData.length > 0)
650 dst->bitmapData.data = malloc(order->bitmapData.length);
652 if (!dst->bitmapData.data)
655 memcpy(dst->bitmapData.data, order->bitmapData.data, order->bitmapData.length);
660 WINPR_PRAGMA_DIAG_PUSH
661 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
662 free_cache_bitmap_v3_order(context, dst);
663 WINPR_PRAGMA_DIAG_POP
670 free(order->bitmapData.data);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.