Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-cache / bitmap.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Bitmap Cache V2
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <freerdp/freerdp.h>
21 #include <freerdp/utils/stream.h>
22 #include <freerdp/utils/memory.h>
23
24 #include <freerdp/cache/bitmap.h>
25
26 void update_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
27 {
28         rdpBitmap* bitmap;
29         rdpCache* cache = context->cache;
30
31         if (memblt->cacheId == 0xFF)
32                 bitmap = offscreen_cache_get(cache->offscreen, memblt->cacheIndex);
33         else
34                 bitmap = bitmap_cache_get(cache->bitmap, (uint8) memblt->cacheId, memblt->cacheIndex);
35
36         memblt->bitmap = bitmap;
37         IFCALL(cache->bitmap->MemBlt, context, memblt);
38 }
39
40 void update_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
41 {
42         rdpBitmap* bitmap;
43         rdpCache* cache = context->cache;
44
45         if (mem3blt->cacheId == 0xFF)
46                 bitmap = offscreen_cache_get(cache->offscreen, mem3blt->cacheIndex);
47         else
48                 bitmap = bitmap_cache_get(cache->bitmap, (uint8) mem3blt->cacheId, mem3blt->cacheIndex);
49
50         mem3blt->bitmap = bitmap;
51         IFCALL(cache->bitmap->Mem3Blt, context, mem3blt);
52 }
53
54 void update_gdi_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap)
55 {
56         rdpBitmap* bitmap;
57         rdpBitmap* prevBitmap;
58         rdpCache* cache = context->cache;
59
60         bitmap = Bitmap_Alloc(context);
61
62         Bitmap_SetDimensions(context, bitmap, cache_bitmap->bitmapWidth, cache_bitmap->bitmapHeight);
63
64         bitmap->Decompress(context, bitmap,
65                         cache_bitmap->bitmapDataStream, cache_bitmap->bitmapWidth, cache_bitmap->bitmapHeight,
66                         cache_bitmap->bitmapBpp, cache_bitmap->bitmapLength, cache_bitmap->compressed);
67
68         bitmap->New(context, bitmap);
69
70         prevBitmap = bitmap_cache_get(cache->bitmap, cache_bitmap->cacheId, cache_bitmap->cacheIndex);
71
72         if (prevBitmap != NULL)
73                 Bitmap_Free(context, prevBitmap);
74
75         bitmap_cache_put(cache->bitmap, cache_bitmap->cacheId, cache_bitmap->cacheIndex, bitmap);
76 }
77
78 void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2)
79 {
80         rdpBitmap* bitmap;
81         rdpBitmap* prevBitmap;
82         rdpCache* cache = context->cache;
83
84         bitmap = Bitmap_Alloc(context);
85
86         Bitmap_SetDimensions(context, bitmap, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight);
87
88         if (cache_bitmap_v2->bitmapBpp == 0)
89         {
90                 /* Workaround for Windows 8 bug where bitmapBpp is not set */
91                 cache_bitmap_v2->bitmapBpp = context->instance->settings->color_depth;
92         }
93
94         bitmap->Decompress(context, bitmap,
95                         cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight,
96                         cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, cache_bitmap_v2->compressed);
97
98         bitmap->New(context, bitmap);
99
100         prevBitmap = bitmap_cache_get(cache->bitmap, cache_bitmap_v2->cacheId, cache_bitmap_v2->cacheIndex);
101
102         if (prevBitmap != NULL)
103                 Bitmap_Free(context, prevBitmap);
104
105         bitmap_cache_put(cache->bitmap, cache_bitmap_v2->cacheId, cache_bitmap_v2->cacheIndex, bitmap);
106 }
107
108 void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap_update)
109 {
110         int i;
111         rdpBitmap* bitmap;
112         BITMAP_DATA* bitmap_data;
113         boolean reused = true;
114         rdpCache* cache = context->cache;
115
116         if (cache->bitmap->bitmap == NULL)
117         {
118                 cache->bitmap->bitmap = Bitmap_Alloc(context);
119                 cache->bitmap->bitmap->ephemeral = true;
120                 reused = false;
121         }
122
123         bitmap = cache->bitmap->bitmap;
124
125         for (i = 0; i < (int) bitmap_update->number; i++)
126         {
127                 bitmap_data = &bitmap_update->rectangles[i];
128
129                 bitmap->bpp = bitmap_data->bitsPerPixel;
130                 bitmap->length = bitmap_data->bitmapLength;
131                 bitmap->compressed = bitmap_data->compressed;
132
133                 Bitmap_SetRectangle(context, bitmap,
134                                 bitmap_data->destLeft, bitmap_data->destTop,
135                                 bitmap_data->destRight, bitmap_data->destBottom);
136
137                 Bitmap_SetDimensions(context, bitmap, bitmap_data->width, bitmap_data->height);
138
139                 bitmap->Decompress(context, bitmap,
140                                 bitmap_data->bitmapDataStream, bitmap_data->width, bitmap_data->height,
141                                 bitmap_data->bitsPerPixel, bitmap_data->bitmapLength, bitmap_data->compressed);
142
143                 if (reused)
144                         bitmap->Free(context, bitmap);
145                 else
146                         reused = true;
147
148                 bitmap->New(context, bitmap);
149
150                 bitmap->Paint(context, bitmap);
151         }
152 }
153
154 rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmap_cache, uint32 id, uint32 index)
155 {
156         rdpBitmap* bitmap;
157
158         if (id > bitmap_cache->maxCells)
159         {
160                 printf("get invalid bitmap cell id: %d\n", id);
161                 return NULL;
162         }
163
164         if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
165                 index = bitmap_cache->cells[id].number - 1;
166
167         if (index > bitmap_cache->cells[id].number)
168         {
169                 printf("get invalid bitmap index %d in cell id: %d\n", index, id);
170                 return NULL;
171         }
172
173         bitmap = bitmap_cache->cells[id].entries[index];
174
175         return bitmap;
176 }
177
178 void bitmap_cache_put(rdpBitmapCache* bitmap_cache, uint32 id, uint32 index, rdpBitmap* bitmap)
179 {
180         if (id > bitmap_cache->maxCells)
181         {
182                 printf("put invalid bitmap cell id: %d\n", id);
183                 return;
184         }
185
186         if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
187                 index = bitmap_cache->cells[id].number - 1;
188
189         if (index > bitmap_cache->cells[id].number)
190         {
191                 printf("put invalid bitmap index %d in cell id: %d\n", index, id);
192                 return;
193         }
194
195         bitmap_cache->cells[id].entries[index] = bitmap;
196 }
197
198 void bitmap_cache_register_callbacks(rdpUpdate* update)
199 {
200         rdpCache* cache = update->context->cache;
201
202         cache->bitmap->MemBlt = update->primary->MemBlt;
203         cache->bitmap->Mem3Blt = update->primary->Mem3Blt;
204
205         update->primary->MemBlt = update_gdi_memblt;
206         update->primary->Mem3Blt = update_gdi_mem3blt;
207
208         update->secondary->CacheBitmap = update_gdi_cache_bitmap;
209         update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2;
210
211         update->BitmapUpdate = update_gdi_bitmap_update;
212 }
213
214 rdpBitmapCache* bitmap_cache_new(rdpSettings* settings)
215 {
216         int i;
217         rdpBitmapCache* bitmap_cache;
218
219         bitmap_cache = (rdpBitmapCache*) xzalloc(sizeof(rdpBitmapCache));
220
221         if (bitmap_cache != NULL)
222         {
223                 bitmap_cache->settings = settings;
224                 bitmap_cache->update = ((freerdp*) settings->instance)->update;
225                 bitmap_cache->context = bitmap_cache->update->context;
226
227                 bitmap_cache->maxCells = 5;
228
229                 settings->bitmap_cache = false;
230                 settings->bitmapCacheV2NumCells = 5;
231                 settings->bitmapCacheV2CellInfo[0].numEntries = 600;
232                 settings->bitmapCacheV2CellInfo[0].persistent = false;
233                 settings->bitmapCacheV2CellInfo[1].numEntries = 600;
234                 settings->bitmapCacheV2CellInfo[1].persistent = false;
235                 settings->bitmapCacheV2CellInfo[2].numEntries = 2048;
236                 settings->bitmapCacheV2CellInfo[2].persistent = false;
237                 settings->bitmapCacheV2CellInfo[3].numEntries = 4096;
238                 settings->bitmapCacheV2CellInfo[3].persistent = false;
239                 settings->bitmapCacheV2CellInfo[4].numEntries = 2048;
240                 settings->bitmapCacheV2CellInfo[4].persistent = false;
241
242                 bitmap_cache->cells = (BITMAP_V2_CELL*) xzalloc(sizeof(BITMAP_V2_CELL) * bitmap_cache->maxCells);
243
244                 for (i = 0; i < (int) bitmap_cache->maxCells; i++)
245                 {
246                         bitmap_cache->cells[i].number = settings->bitmapCacheV2CellInfo[i].numEntries;
247                         bitmap_cache->cells[i].entries = (rdpBitmap**) xzalloc(sizeof(rdpBitmap*) * bitmap_cache->cells[i].number);
248                 }
249         }
250
251         return bitmap_cache;
252 }
253
254 void bitmap_cache_free(rdpBitmapCache* bitmap_cache)
255 {
256         int i, j;
257         rdpBitmap* bitmap;
258
259         if (bitmap_cache != NULL)
260         {
261                 for (i = 0; i < (int) bitmap_cache->maxCells; i++)
262                 {
263                         for (j = 0; j < (int) bitmap_cache->cells[i].number; j++)
264                         {
265                                 bitmap = bitmap_cache->cells[i].entries[j];
266
267                                 if (bitmap != NULL)
268                                 {
269                                         Bitmap_Free(bitmap_cache->context, bitmap);
270                                 }
271                         }
272
273                         xfree(bitmap_cache->cells[i].entries);
274                 }
275
276                 if (bitmap_cache->bitmap != NULL)
277                         Bitmap_Free(bitmap_cache->context, bitmap_cache->bitmap);
278
279                 xfree(bitmap_cache->cells);
280                 xfree(bitmap_cache);
281         }
282 }