20 #include <freerdp/config.h>
24 #include <winpr/crt.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")
43 static rdpBitmap* bitmap_cache_get(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index);
44 static BOOL bitmap_cache_put(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index,
47 static BOOL update_gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
49 rdpBitmap* bitmap = NULL;
50 rdpCache* cache = NULL;
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);
63 memblt->bitmap = bitmap;
64 return IFCALLRESULT(TRUE, cache->bitmap->MemBlt, context, memblt);
67 static BOOL update_gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
69 rdpBitmap* bitmap = NULL;
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);
85 if (brush->style & CACHED_BRUSH)
87 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
95 mem3blt->bitmap = bitmap;
96 IFCALLRET(cache->bitmap->Mem3Blt, ret, context, mem3blt);
101 static BOOL update_gdi_cache_bitmap(rdpContext* context,
const CACHE_BITMAP_ORDER* cacheBitmap)
103 rdpBitmap* bitmap = NULL;
104 rdpBitmap* prevBitmap = NULL;
105 rdpCache* cache = context->cache;
106 bitmap = Bitmap_Alloc(context);
111 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapWidth),
112 WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapHeight)))
115 if (!bitmap->Decompress(context, bitmap, cacheBitmap->bitmapDataStream,
116 cacheBitmap->bitmapWidth, cacheBitmap->bitmapHeight,
117 cacheBitmap->bitmapBpp, cacheBitmap->bitmapLength,
118 cacheBitmap->compressed, RDP_CODEC_ID_NONE))
121 if (!bitmap->New(context, bitmap))
124 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex);
125 Bitmap_Free(context, prevBitmap);
126 return bitmap_cache_put(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex, bitmap);
129 Bitmap_Free(context, bitmap);
136 rdpBitmap* prevBitmap = NULL;
137 rdpCache* cache = context->cache;
138 rdpSettings* settings = context->settings;
139 rdpBitmap* bitmap = Bitmap_Alloc(context);
145 bitmap->key64 = ((UINT64)cacheBitmapV2->key1 | (((UINT64)cacheBitmapV2->key2) << 32));
147 if (!cacheBitmapV2->bitmapBpp)
148 cacheBitmapV2->bitmapBpp = ColorDepth;
150 if ((ColorDepth == 15) && (cacheBitmapV2->bitmapBpp == 16))
151 cacheBitmapV2->bitmapBpp = ColorDepth;
153 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapWidth),
154 WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapHeight)))
157 if (!bitmap->Decompress(context, bitmap, cacheBitmapV2->bitmapDataStream,
158 cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight,
159 cacheBitmapV2->bitmapBpp, cacheBitmapV2->bitmapLength,
160 cacheBitmapV2->compressed, RDP_CODEC_ID_NONE))
163 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex);
165 if (!bitmap->New(context, bitmap))
168 Bitmap_Free(context, prevBitmap);
169 return bitmap_cache_put(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex,
173 Bitmap_Free(context, bitmap);
179 rdpBitmap* bitmap = NULL;
180 rdpBitmap* prevBitmap = NULL;
181 BOOL compressed = TRUE;
182 rdpCache* cache = context->cache;
183 rdpSettings* settings = context->settings;
185 bitmap = Bitmap_Alloc(context);
191 bitmap->key64 = ((UINT64)cacheBitmapV3->key1 | (((UINT64)cacheBitmapV3->key2) << 32));
193 if (!cacheBitmapV3->bpp)
194 cacheBitmapV3->bpp = ColorDepth;
196 compressed = (bitmapData->codecID != RDP_CODEC_ID_NONE);
198 if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->width),
199 WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->height)))
202 if (!bitmap->Decompress(context, bitmap, bitmapData->data, bitmapData->width,
203 bitmapData->height, bitmapData->bpp, bitmapData->length, compressed,
204 bitmapData->codecID))
207 if (!bitmap->New(context, bitmap))
210 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex);
211 Bitmap_Free(context, prevBitmap);
212 return bitmap_cache_put(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex,
216 Bitmap_Free(context, bitmap);
220 rdpBitmap* bitmap_cache_get(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index)
222 rdpBitmap* bitmap = NULL;
224 if (
id >= bitmapCache->maxCells)
226 WLog_ERR(TAG,
"get invalid bitmap cell id: %" PRIu32
"",
id);
230 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
232 index = bitmapCache->cells[id].number;
234 else if (index > bitmapCache->cells[
id].number)
236 WLog_ERR(TAG,
"get invalid bitmap index %" PRIu32
" in cell id: %" PRIu32
"", index,
id);
240 bitmap = bitmapCache->cells[id].entries[index];
244 BOOL bitmap_cache_put(
rdpBitmapCache* bitmapCache, UINT32
id, UINT32 index, rdpBitmap* bitmap)
246 if (
id > bitmapCache->maxCells)
248 WLog_ERR(TAG,
"put invalid bitmap cell id: %" PRIu32
"",
id);
252 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
254 index = bitmapCache->cells[id].number;
256 else if (index > bitmapCache->cells[
id].number)
258 WLog_ERR(TAG,
"put invalid bitmap index %" PRIu32
" in cell id: %" PRIu32
"", index,
id);
262 bitmapCache->cells[id].entries[index] = bitmap;
266 void bitmap_cache_register_callbacks(rdpUpdate* update)
268 rdpCache* cache = NULL;
270 WINPR_ASSERT(update);
271 WINPR_ASSERT(update->context);
272 WINPR_ASSERT(update->context->cache);
274 cache = update->context->cache;
279 cache->bitmap->MemBlt = update->primary->MemBlt;
280 cache->bitmap->Mem3Blt = update->primary->Mem3Blt;
281 update->primary->MemBlt = update_gdi_memblt;
282 update->primary->Mem3Blt = update_gdi_mem3blt;
283 update->secondary->CacheBitmap = update_gdi_cache_bitmap;
284 update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2;
285 update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3;
286 update->BitmapUpdate = gdi_bitmap_update;
290 static int bitmap_cache_save_persistent(
rdpBitmapCache* bitmapCache)
292 rdpContext* context = bitmapCache->context;
293 rdpSettings* settings = context->settings;
303 const char* BitmapCachePersistFile =
305 if (!BitmapCachePersistFile)
308 rdpPersistentCache* persistent = persistent_cache_new();
313 int status = persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, version);
318 if (bitmapCache->cells)
320 for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
323 for (UINT32 j = 0; j < cell->number + 1 && cell->entries; j++)
326 rdpBitmap* bitmap = cell->entries[j];
328 if (!bitmap || !bitmap->key64)
331 cacheEntry.key64 = bitmap->key64;
333 cacheEntry.width = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width);
334 cacheEntry.height = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height);
335 const UINT64 size = 4ULL * bitmap->width * bitmap->height;
336 if (size > UINT32_MAX)
338 cacheEntry.size = (UINT32)size;
339 cacheEntry.flags = 0;
340 cacheEntry.data = bitmap->data;
342 if (persistent_cache_write_entry(persistent, &cacheEntry) < 1)
354 persistent_cache_free(persistent);
360 rdpSettings* settings = NULL;
363 WINPR_ASSERT(context);
365 settings = context->settings;
366 WINPR_ASSERT(settings);
373 const UINT32 BitmapCacheV2NumCells =
375 bitmapCache->context = context;
378 if (!bitmapCache->cells)
380 bitmapCache->maxCells = BitmapCacheV2NumCells;
382 for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
385 freerdp_settings_get_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, i);
387 UINT32 nr = info->numEntries;
389 cell->entries = (rdpBitmap**)calloc((nr + 1),
sizeof(rdpBitmap*));
398 WINPR_PRAGMA_DIAG_PUSH
399 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
400 bitmap_cache_free(bitmapCache);
401 WINPR_PRAGMA_DIAG_POP
410 bitmap_cache_save_persistent(bitmapCache);
412 if (bitmapCache->cells)
414 for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
422 for (j = 0; j < cell->number + 1; j++)
424 rdpBitmap* bitmap = cell->entries[j];
425 Bitmap_Free(bitmapCache->context, bitmap);
428 free((
void*)cell->entries);
431 free(bitmapCache->cells);
434 persistent_cache_free(bitmapCache->persistent);
439 static void free_bitmap_data(
BITMAP_DATA* data,
size_t count)
444 for (
size_t x = 0; x < count; x++)
445 free(data[x].bitmapDataStream);
457 for (
size_t x = 0; x < count; x++)
461 if (data[x].bitmapLength > 0)
463 dst[x].bitmapDataStream = malloc(data[x].bitmapLength);
465 if (!dst[x].bitmapDataStream)
468 memcpy(dst[x].bitmapDataStream, data[x].bitmapDataStream, data[x].bitmapLength);
474 free_bitmap_data(dst, count);
478 void free_bitmap_update(rdpContext* context,
BITMAP_UPDATE* pointer)
483 free_bitmap_data(pointer->rectangles, pointer->number);
491 if (!dst || !pointer)
495 dst->rectangles = copy_bitmap_data(pointer->rectangles, pointer->number);
497 if (!dst->rectangles)
502 WINPR_PRAGMA_DIAG_PUSH
503 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
504 free_bitmap_update(context, dst);
505 WINPR_PRAGMA_DIAG_POP
518 if (order->bitmapLength > 0)
520 dst->bitmapDataStream = malloc(order->bitmapLength);
522 if (!dst->bitmapDataStream)
525 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
530 WINPR_PRAGMA_DIAG_PUSH
531 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
532 free_cache_bitmap_order(context, dst);
533 WINPR_PRAGMA_DIAG_POP
540 free(order->bitmapDataStream);
555 if (order->bitmapLength > 0)
557 dst->bitmapDataStream = malloc(order->bitmapLength);
559 if (!dst->bitmapDataStream)
562 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
567 WINPR_PRAGMA_DIAG_PUSH
568 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
569 free_cache_bitmap_v2_order(context, dst);
570 WINPR_PRAGMA_DIAG_POP
577 free(order->bitmapDataStream);
592 if (order->bitmapData.length > 0)
594 dst->bitmapData.data = malloc(order->bitmapData.length);
596 if (!dst->bitmapData.data)
599 memcpy(dst->bitmapData.data, order->bitmapData.data, order->bitmapData.length);
604 WINPR_PRAGMA_DIAG_PUSH
605 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
606 free_cache_bitmap_v3_order(context, dst);
607 WINPR_PRAGMA_DIAG_POP
614 free(order->bitmapData.data);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.