FreeRDP
offscreen.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdio.h>
23 
24 #include <winpr/crt.h>
25 #include <winpr/assert.h>
26 #include <winpr/stream.h>
27 
28 #include <freerdp/log.h>
29 
30 #include "../core/graphics.h"
31 
32 #include "offscreen.h"
33 #include "cache.h"
34 
35 #define TAG FREERDP_TAG("cache.offscreen")
36 
37 struct rdp_offscreen_cache
38 {
39  UINT32 maxSize; /* 0 */
40  UINT32 maxEntries; /* 1 */
41  rdpBitmap** entries; /* 2 */
42  UINT32 currentSurface; /* 3 */
43 
44  rdpContext* context;
45 };
46 
47 static void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBitmap* bitmap);
48 static void offscreen_cache_delete(rdpOffscreenCache* offscreen, UINT32 index);
49 
50 static BOOL
51 update_gdi_create_offscreen_bitmap(rdpContext* context,
52  const CREATE_OFFSCREEN_BITMAP_ORDER* createOffscreenBitmap)
53 {
54  UINT16 index = 0;
55  rdpBitmap* bitmap = NULL;
56  rdpCache* cache = NULL;
57 
58  if (!context || !createOffscreenBitmap || !context->cache)
59  return FALSE;
60 
61  cache = context->cache;
62  bitmap = Bitmap_Alloc(context);
63 
64  if (!bitmap)
65  return FALSE;
66 
67  Bitmap_SetDimensions(bitmap, createOffscreenBitmap->cx, createOffscreenBitmap->cy);
68 
69  if (!bitmap->New(context, bitmap))
70  {
71  Bitmap_Free(context, bitmap);
72  return FALSE;
73  }
74 
75  offscreen_cache_delete(cache->offscreen, createOffscreenBitmap->id);
76  offscreen_cache_put(cache->offscreen, createOffscreenBitmap->id, bitmap);
77 
78  if (cache->offscreen->currentSurface == createOffscreenBitmap->id)
79  bitmap->SetSurface(context, bitmap, FALSE);
80 
81  for (UINT32 i = 0; i < createOffscreenBitmap->deleteList.cIndices; i++)
82  {
83  index = createOffscreenBitmap->deleteList.indices[i];
84  offscreen_cache_delete(cache->offscreen, index);
85  }
86 
87  return TRUE;
88 }
89 
90 static BOOL update_gdi_switch_surface(rdpContext* context,
91  const SWITCH_SURFACE_ORDER* switchSurface)
92 {
93  rdpCache* cache = NULL;
94  rdpBitmap* bitmap = NULL;
95 
96  if (!context || !context->cache || !switchSurface || !context->graphics)
97  return FALSE;
98 
99  cache = context->cache;
100  bitmap = context->graphics->Bitmap_Prototype;
101  if (!bitmap)
102  return FALSE;
103 
104  if (switchSurface->bitmapId == SCREEN_BITMAP_SURFACE)
105  {
106  bitmap->SetSurface(context, NULL, TRUE);
107  }
108  else
109  {
110  rdpBitmap* bmp = NULL;
111  bmp = offscreen_cache_get(cache->offscreen, switchSurface->bitmapId);
112  if (bmp == NULL)
113  return FALSE;
114 
115  bitmap->SetSurface(context, bmp, FALSE);
116  }
117 
118  cache->offscreen->currentSurface = switchSurface->bitmapId;
119  return TRUE;
120 }
121 
122 rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index)
123 {
124  rdpBitmap* bitmap = NULL;
125 
126  WINPR_ASSERT(offscreenCache);
127 
128  if (index >= offscreenCache->maxEntries)
129  {
130  WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
131  return NULL;
132  }
133 
134  bitmap = offscreenCache->entries[index];
135 
136  if (!bitmap)
137  {
138  WLog_ERR(TAG, "invalid offscreen bitmap at index: 0x%08" PRIX32 "", index);
139  return NULL;
140  }
141 
142  return bitmap;
143 }
144 
145 void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBitmap* bitmap)
146 {
147  WINPR_ASSERT(offscreenCache);
148 
149  if (index >= offscreenCache->maxEntries)
150  {
151  WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
152  return;
153  }
154 
155  offscreen_cache_delete(offscreenCache, index);
156  offscreenCache->entries[index] = bitmap;
157 }
158 
159 void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index)
160 {
161  rdpBitmap* prevBitmap = NULL;
162 
163  WINPR_ASSERT(offscreenCache);
164 
165  if (index >= offscreenCache->maxEntries)
166  {
167  WLog_ERR(TAG, "invalid offscreen bitmap index (delete): 0x%08" PRIX32 "", index);
168  return;
169  }
170 
171  prevBitmap = offscreenCache->entries[index];
172 
173  if (prevBitmap != NULL)
174  Bitmap_Free(offscreenCache->context, prevBitmap);
175 
176  offscreenCache->entries[index] = NULL;
177 }
178 
179 void offscreen_cache_register_callbacks(rdpUpdate* update)
180 {
181  WINPR_ASSERT(update);
182  WINPR_ASSERT(update->altsec);
183 
184  update->altsec->CreateOffscreenBitmap = update_gdi_create_offscreen_bitmap;
185  update->altsec->SwitchSurface = update_gdi_switch_surface;
186 }
187 
188 rdpOffscreenCache* offscreen_cache_new(rdpContext* context)
189 {
190  rdpOffscreenCache* offscreenCache = NULL;
191  rdpSettings* settings = NULL;
192 
193  WINPR_ASSERT(context);
194 
195  settings = context->settings;
196  WINPR_ASSERT(settings);
197 
198  offscreenCache = (rdpOffscreenCache*)calloc(1, sizeof(rdpOffscreenCache));
199 
200  if (!offscreenCache)
201  return NULL;
202 
203  offscreenCache->context = context;
204  offscreenCache->currentSurface = SCREEN_BITMAP_SURFACE;
205  offscreenCache->maxSize = 7680;
206  offscreenCache->maxEntries = 2000;
207  if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheSize, offscreenCache->maxSize))
208  goto fail;
209  if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheEntries,
210  offscreenCache->maxEntries))
211  goto fail;
212  offscreenCache->entries = (rdpBitmap**)calloc(offscreenCache->maxEntries, sizeof(rdpBitmap*));
213 
214  if (!offscreenCache->entries)
215  goto fail;
216 
217  return offscreenCache;
218 fail:
219  WINPR_PRAGMA_DIAG_PUSH
220  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
221  offscreen_cache_free(offscreenCache);
222  WINPR_PRAGMA_DIAG_POP
223  return NULL;
224 }
225 
226 void offscreen_cache_free(rdpOffscreenCache* offscreenCache)
227 {
228  if (offscreenCache)
229  {
230  if (offscreenCache->entries)
231  {
232  for (size_t i = 0; i < offscreenCache->maxEntries; i++)
233  {
234  rdpBitmap* bitmap = offscreenCache->entries[i];
235  Bitmap_Free(offscreenCache->context, bitmap);
236  }
237  }
238 
239  free(offscreenCache->entries);
240  free(offscreenCache);
241  }
242 }
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.