summaryrefslogtreecommitdiffstats
path: root/libfreerdp/cache/offscreen.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/cache/offscreen.c')
-rw-r--r--libfreerdp/cache/offscreen.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/libfreerdp/cache/offscreen.c b/libfreerdp/cache/offscreen.c
new file mode 100644
index 0000000..3b8b43e
--- /dev/null
+++ b/libfreerdp/cache/offscreen.c
@@ -0,0 +1,243 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Offscreen Bitmap Cache
+ *
+ * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <freerdp/config.h>
+
+#include <stdio.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/stream.h>
+
+#include <freerdp/log.h>
+
+#include "../core/graphics.h"
+
+#include "offscreen.h"
+#include "cache.h"
+
+#define TAG FREERDP_TAG("cache.offscreen")
+
+struct rdp_offscreen_cache
+{
+ UINT32 maxSize; /* 0 */
+ UINT32 maxEntries; /* 1 */
+ rdpBitmap** entries; /* 2 */
+ UINT32 currentSurface; /* 3 */
+
+ rdpContext* context;
+};
+
+static void offscreen_cache_put(rdpOffscreenCache* offscreen_cache, UINT32 index,
+ rdpBitmap* bitmap);
+static void offscreen_cache_delete(rdpOffscreenCache* offscreen, UINT32 index);
+
+static BOOL
+update_gdi_create_offscreen_bitmap(rdpContext* context,
+ const CREATE_OFFSCREEN_BITMAP_ORDER* createOffscreenBitmap)
+{
+ UINT16 index = 0;
+ rdpBitmap* bitmap = NULL;
+ rdpCache* cache = NULL;
+
+ if (!context || !createOffscreenBitmap || !context->cache)
+ return FALSE;
+
+ cache = context->cache;
+ bitmap = Bitmap_Alloc(context);
+
+ if (!bitmap)
+ return FALSE;
+
+ Bitmap_SetDimensions(bitmap, createOffscreenBitmap->cx, createOffscreenBitmap->cy);
+
+ if (!bitmap->New(context, bitmap))
+ {
+ Bitmap_Free(context, bitmap);
+ return FALSE;
+ }
+
+ offscreen_cache_delete(cache->offscreen, createOffscreenBitmap->id);
+ offscreen_cache_put(cache->offscreen, createOffscreenBitmap->id, bitmap);
+
+ if (cache->offscreen->currentSurface == createOffscreenBitmap->id)
+ bitmap->SetSurface(context, bitmap, FALSE);
+
+ for (UINT32 i = 0; i < createOffscreenBitmap->deleteList.cIndices; i++)
+ {
+ index = createOffscreenBitmap->deleteList.indices[i];
+ offscreen_cache_delete(cache->offscreen, index);
+ }
+
+ return TRUE;
+}
+
+static BOOL update_gdi_switch_surface(rdpContext* context,
+ const SWITCH_SURFACE_ORDER* switchSurface)
+{
+ rdpCache* cache = NULL;
+ rdpBitmap* bitmap = NULL;
+
+ if (!context || !context->cache || !switchSurface || !context->graphics)
+ return FALSE;
+
+ cache = context->cache;
+ bitmap = context->graphics->Bitmap_Prototype;
+ if (!bitmap)
+ return FALSE;
+
+ if (switchSurface->bitmapId == SCREEN_BITMAP_SURFACE)
+ {
+ bitmap->SetSurface(context, NULL, TRUE);
+ }
+ else
+ {
+ rdpBitmap* bmp = NULL;
+ bmp = offscreen_cache_get(cache->offscreen, switchSurface->bitmapId);
+ if (bmp == NULL)
+ return FALSE;
+
+ bitmap->SetSurface(context, bmp, FALSE);
+ }
+
+ cache->offscreen->currentSurface = switchSurface->bitmapId;
+ return TRUE;
+}
+
+rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index)
+{
+ rdpBitmap* bitmap = NULL;
+
+ WINPR_ASSERT(offscreenCache);
+
+ if (index >= offscreenCache->maxEntries)
+ {
+ WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
+ return NULL;
+ }
+
+ bitmap = offscreenCache->entries[index];
+
+ if (!bitmap)
+ {
+ WLog_ERR(TAG, "invalid offscreen bitmap at index: 0x%08" PRIX32 "", index);
+ return NULL;
+ }
+
+ return bitmap;
+}
+
+void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBitmap* bitmap)
+{
+ WINPR_ASSERT(offscreenCache);
+
+ if (index >= offscreenCache->maxEntries)
+ {
+ WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
+ return;
+ }
+
+ offscreen_cache_delete(offscreenCache, index);
+ offscreenCache->entries[index] = bitmap;
+}
+
+void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index)
+{
+ rdpBitmap* prevBitmap = NULL;
+
+ WINPR_ASSERT(offscreenCache);
+
+ if (index >= offscreenCache->maxEntries)
+ {
+ WLog_ERR(TAG, "invalid offscreen bitmap index (delete): 0x%08" PRIX32 "", index);
+ return;
+ }
+
+ prevBitmap = offscreenCache->entries[index];
+
+ if (prevBitmap != NULL)
+ Bitmap_Free(offscreenCache->context, prevBitmap);
+
+ offscreenCache->entries[index] = NULL;
+}
+
+void offscreen_cache_register_callbacks(rdpUpdate* update)
+{
+ WINPR_ASSERT(update);
+ WINPR_ASSERT(update->altsec);
+
+ update->altsec->CreateOffscreenBitmap = update_gdi_create_offscreen_bitmap;
+ update->altsec->SwitchSurface = update_gdi_switch_surface;
+}
+
+rdpOffscreenCache* offscreen_cache_new(rdpContext* context)
+{
+ rdpOffscreenCache* offscreenCache = NULL;
+ rdpSettings* settings = NULL;
+
+ WINPR_ASSERT(context);
+
+ settings = context->settings;
+ WINPR_ASSERT(settings);
+
+ offscreenCache = (rdpOffscreenCache*)calloc(1, sizeof(rdpOffscreenCache));
+
+ if (!offscreenCache)
+ return NULL;
+
+ offscreenCache->context = context;
+ offscreenCache->currentSurface = SCREEN_BITMAP_SURFACE;
+ offscreenCache->maxSize = 7680;
+ offscreenCache->maxEntries = 2000;
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheSize, offscreenCache->maxSize))
+ goto fail;
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheEntries,
+ offscreenCache->maxEntries))
+ goto fail;
+ offscreenCache->entries = (rdpBitmap**)calloc(offscreenCache->maxEntries, sizeof(rdpBitmap*));
+
+ if (!offscreenCache->entries)
+ goto fail;
+
+ return offscreenCache;
+fail:
+ WINPR_PRAGMA_DIAG_PUSH
+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
+ offscreen_cache_free(offscreenCache);
+ WINPR_PRAGMA_DIAG_POP
+ return NULL;
+}
+
+void offscreen_cache_free(rdpOffscreenCache* offscreenCache)
+{
+ if (offscreenCache)
+ {
+ if (offscreenCache->entries)
+ {
+ for (size_t i = 0; i < offscreenCache->maxEntries; i++)
+ {
+ rdpBitmap* bitmap = offscreenCache->entries[i];
+ Bitmap_Free(offscreenCache->context, bitmap);
+ }
+ }
+
+ free(offscreenCache->entries);
+ free(offscreenCache);
+ }
+}