summaryrefslogtreecommitdiff
path: root/src/dfps.c
diff options
context:
space:
mode:
authorJeremy White <jwhite@codeweavers.com>2012-09-11 12:56:19 -0500
committerJeremy White <jwhite@codeweavers.com>2013-01-11 08:52:27 -0600
commit531a844ab9136d657f90a30bb049068e92629c65 (patch)
tree719a9d372ac475de905d3fbd2db1c87d180566fd /src/dfps.c
parent4301bff52bfec982b16896e395d9b4785c359a73 (diff)
Add a deferred frames mode.
This renders all operations to a frame buffer, and sends updates periodically.
Diffstat (limited to 'src/dfps.c')
-rw-r--r--src/dfps.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/dfps.c b/src/dfps.c
new file mode 100644
index 0000000..fca51ff
--- /dev/null
+++ b/src/dfps.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2012 CodeWeavers, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Jeremy White <jwhite@codeweavers.com>
+ */
+
+/*----------------------------------------------------------------------------
+ Deferred Frames Per Second (dfps) Support File
+
+ By default, The xorg-video-qxl driver transmits all of the video
+ operation across the wire. While this has the greatest fidelity, and
+ lends itself well to a variety of optimizations and behavior tuning,
+ it does not always use bandwidth efficiently.
+
+ This file implements a 'deferred frames' mode which instead renders
+ everything to a frame buffer, and then periodically sends only updated
+ portions of the screen.
+
+ For some use cases, this proves to be far more efficient with network
+ resources.
+----------------------------------------------------------------------------*/
+
+#include <xorg-server.h>
+#include "qxl.h"
+#include "dfps.h"
+
+struct dfps_info_t
+{
+ RegionRec updated_region;
+
+ PixmapPtr copy_src;
+ Pixel solid_pixel;
+};
+
+void dfps_ticker(void *opaque)
+{
+ qxl_screen_t *qxl = (qxl_screen_t *) opaque;
+ dfps_info_t *info = NULL;
+ PixmapPtr pixmap;
+
+ pixmap = qxl->pScrn->pScreen->GetScreenPixmap(qxl->pScrn->pScreen);
+ if (pixmap)
+ info = dfps_get_info(pixmap);
+ if (info)
+ {
+ qxl_surface_upload_primary_regions(qxl, pixmap, &info->updated_region);
+ RegionUninit(&info->updated_region);
+ RegionInit(&info->updated_region, NULL, 0);
+ }
+ qxl->core->timer_start(qxl->frames_timer, 1000 / qxl->deferred_fps);
+}
+
+
+static Bool unaccel (void)
+{
+ return FALSE;
+}
+
+static Bool dfps_prepare_solid (PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
+{
+ dfps_info_t *info;
+
+ if (!(info = dfps_get_info (pixmap)))
+ return FALSE;
+
+ info->solid_pixel = fg;
+
+ return TRUE;
+}
+
+static void dfps_solid (PixmapPtr pixmap, int x_1, int y_1, int x_2, int y_2)
+{
+ FbBits *bits;
+ int stride;
+ int bpp;
+ int xoff, yoff;
+ struct pixman_box16 box;
+ RegionPtr region;
+ Bool throwaway_bool;
+ dfps_info_t *info;
+
+ if (!(info = dfps_get_info (pixmap)))
+ return;
+
+ /* Draw to the frame buffer */
+ fbGetDrawable((DrawablePtr)pixmap, bits, stride, bpp, xoff, yoff);
+ pixman_fill((uint32_t *) bits, stride, bpp, x_1 + xoff, y_1 + yoff, x_2 - x_1, y_2 - y_1, info->solid_pixel);
+ fbValidateDrawable(pixmap);
+ fbFinishAccess(pixmap);
+
+ /* Track the updated region */
+ box.x1 = x_1; box.x2 = x_2; box.y1 = y_1; box.y2 = y_2;
+ region = RegionCreate(&box, 1);
+ RegionAppend(&info->updated_region, region);
+ RegionValidate(&info->updated_region, &throwaway_bool);
+ RegionUninit(region);
+ return;
+}
+
+static void dfps_done_solid (PixmapPtr pixmap)
+{
+}
+
+static Bool dfps_prepare_copy (PixmapPtr source, PixmapPtr dest,
+ int xdir, int ydir, int alu,
+ Pixel planemask)
+{
+ dfps_info_t *info;
+
+ if (!(info = dfps_get_info (dest)))
+ return FALSE;
+
+ info->copy_src = source;
+ return TRUE;
+}
+
+static void dfps_copy (PixmapPtr dest,
+ int src_x1, int src_y1,
+ int dest_x1, int dest_y1,
+ int width, int height)
+{
+ struct pixman_box16 box;
+ RegionPtr region;
+ Bool throwaway_bool;
+ GCPtr pgc;
+
+ dfps_info_t *info;
+
+ if (!(info = dfps_get_info (dest)))
+ return;
+
+ /* Render into to the frame buffer */
+ pgc = GetScratchGC(dest->drawable.depth, dest->drawable.pScreen);
+ ValidateGC(&dest->drawable, pgc);
+ fbCopyArea(&info->copy_src->drawable, &dest->drawable, pgc, src_x1, src_y1, width, height, dest_x1, dest_y1);
+ FreeScratchGC(pgc);
+
+ /* Update the tracking region */
+ box.x1 = dest_x1; box.x2 = dest_x1 + width; box.y1 = dest_y1; box.y2 = dest_y1 + height;
+ region = RegionCreate(&box, 1);
+ RegionAppend(&info->updated_region, region);
+ RegionValidate(&info->updated_region, &throwaway_bool);
+ RegionUninit(region);
+}
+
+static void dfps_done_copy (PixmapPtr dest)
+{
+}
+
+static Bool dfps_put_image (PixmapPtr dest, int x, int y, int w, int h,
+ char *src, int src_pitch)
+{
+ struct pixman_box16 box;
+ RegionPtr region;
+ Bool throwaway_bool;
+ dfps_info_t *info;
+
+ if (!(info = dfps_get_info (dest)))
+ return FALSE;
+
+ box.x1 = x; box.x2 = x + w; box.y1 = y; box.y2 = y + h;
+ region = RegionCreate(&box, 1);
+ RegionAppend(&info->updated_region, region);
+ RegionValidate(&info->updated_region, &throwaway_bool);
+ RegionUninit(region);
+
+ /* We can avoid doing the put image ourselves, as the uxa driver
+ will fall back and do it for us if we return false */
+ return FALSE;
+}
+
+
+static Bool dfps_prepare_access (PixmapPtr pixmap, RegionPtr region, uxa_access_t requested_access)
+{
+ fbPrepareAccess(pixmap);
+ if (requested_access == UXA_ACCESS_RW)
+ {
+ dfps_info_t *info;
+ Bool throwaway_bool;
+
+ if (!(info = dfps_get_info (pixmap)))
+ return FALSE;
+ RegionAppend(&info->updated_region, region);
+ RegionValidate(&info->updated_region, &throwaway_bool);
+ }
+ return TRUE;
+}
+
+static void dfps_finish_access (PixmapPtr pixmap)
+{
+ fbFinishAccess(pixmap);
+}
+
+static Bool dfps_pixmap_is_offscreen (PixmapPtr pixmap)
+{
+ return !!dfps_get_info(pixmap);
+}
+
+static void dfps_set_screen_pixmap (PixmapPtr pixmap)
+{
+ pixmap->drawable.pScreen->devPrivate = pixmap;
+}
+
+static PixmapPtr dfps_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage)
+{
+ PixmapPtr pixmap;
+ dfps_info_t *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info)
+ return FALSE;
+
+ pixmap = fbCreatePixmap (screen, w, h, depth, usage);
+ if (pixmap)
+ dfps_set_info(pixmap, info);
+ else
+ free(info);
+
+ return pixmap;
+}
+
+static Bool dfps_destroy_pixmap (PixmapPtr pixmap)
+{
+ if (pixmap->refcnt == 1)
+ {
+ dfps_info_t *info = dfps_get_info (pixmap);
+ if (info)
+ free(info);
+ dfps_set_info(pixmap, NULL);
+ }
+
+ return fbDestroyPixmap (pixmap);
+}
+
+void dfps_set_uxa_functions(qxl_screen_t *qxl, ScreenPtr screen)
+{
+ /* Solid fill */
+ //qxl->uxa->check_solid = dfps_check_solid;
+ qxl->uxa->prepare_solid = dfps_prepare_solid;
+ qxl->uxa->solid = dfps_solid;
+ qxl->uxa->done_solid = dfps_done_solid;
+
+ /* Copy */
+ //qxl->uxa->check_copy = qxl_check_copy;
+ qxl->uxa->prepare_copy = dfps_prepare_copy;
+ qxl->uxa->copy = dfps_copy;
+ qxl->uxa->done_copy = dfps_done_copy;
+
+ /* Composite */
+ qxl->uxa->check_composite = (typeof(qxl->uxa->check_composite))unaccel;
+ qxl->uxa->check_composite_target = (typeof(qxl->uxa->check_composite_target))unaccel;
+ qxl->uxa->check_composite_texture = (typeof(qxl->uxa->check_composite_texture))unaccel;
+ qxl->uxa->prepare_composite = (typeof(qxl->uxa->prepare_composite))unaccel;
+ qxl->uxa->composite = (typeof(qxl->uxa->composite))unaccel;
+ qxl->uxa->done_composite = (typeof(qxl->uxa->done_composite))unaccel;
+
+ /* PutImage */
+ qxl->uxa->put_image = dfps_put_image;
+
+ /* Prepare access */
+ qxl->uxa->prepare_access = dfps_prepare_access;
+ qxl->uxa->finish_access = dfps_finish_access;
+
+ /* General screen information */
+ qxl->uxa->pixmap_is_offscreen = dfps_pixmap_is_offscreen;
+
+ screen->SetScreenPixmap = dfps_set_screen_pixmap;
+ screen->CreatePixmap = dfps_create_pixmap;
+ screen->DestroyPixmap = dfps_destroy_pixmap;
+}