[PATCH 1/4] dix: Provide means to report exact sizes of resources.

Rami Ylimäki rami.ylimaki at vincit.fi
Thu Oct 28 03:23:41 PDT 2010


X resource extension doesn't report the size of pixmaps very
accurately. Therefore we provide a way to calculate the pixmap size in
more detail for drivers.

This requires that we abstract the resource size calculation functions
so that they can be wrapped or overridden by extensions or
drivers. For example, a driver could override pixmap size calculation
function to report more accurate sizes.

It's also useful to be able to override size calculation for any
resource. We want to also find out if clients are using pixmap bytes
indirectly. For example, a pixmap could be referenced by render,
composite and dri2 extensions. It's often easier to calculate the
indirect pixmap usage at the same time when a resource size is
calculated for types other than RT_PIXMAP. In theory, one could
implement size calculation for all resources, but currently we are
only interested in indirect usage of pixmaps from other resources.

The size calculation functions provided by this commit match what is
currently done in X resource extension. The functions will be improved
in later commits to take render pictures and composite windows into
account. DRI2 buffers aren't handled in later commits, because a video
driver can implement and override necessary functions.

Signed-off-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
---
 Xext/xres.c        |   41 +++--------
 dix/resource.c     |  199 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/resource.h |   23 ++++++
 3 files changed, 231 insertions(+), 32 deletions(-)

diff --git a/Xext/xres.c b/Xext/xres.c
index 06639a2..e2fd8a7 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -187,54 +187,33 @@ ProcXResQueryClientResources (ClientPtr client)
     return Success;
 }
 
-static unsigned long
-ResGetApproxPixmapBytes (PixmapPtr pix)
+static void
+ResFindResourcePixmaps (pointer value, XID id, RESTYPE type, pointer cdata)
 {
-   unsigned long nPixels;
-   int           bytesPerPixel; 
-
-   bytesPerPixel = pix->drawable.bitsPerPixel>>3;
-   nPixels       = pix->drawable.width * pix->drawable.height;
+    SizeType sizeFunc = GetResourceTypeSizeFunc(type);
+    ResourceSizeRec size = { 0, 0 };
+    unsigned long *bytes = cdata;
 
-   /* Divide by refcnt as pixmap could be shared between clients,  
-    * so total pixmap mem is shared between these. 
-   */
-   return ( nPixels * bytesPerPixel ) / pix->refcnt;
+    sizeFunc(value, id, &size);
+    *bytes += size.pixmapRefSize;
 }
 
 static void 
 ResFindPixmaps (pointer value, XID id, pointer cdata)
 {
-   unsigned long *bytes = (unsigned long *)cdata;
-   PixmapPtr pix = (PixmapPtr)value;
-
-   *bytes += ResGetApproxPixmapBytes(pix);
+    ResFindResourcePixmaps(value, id, RT_PIXMAP, cdata);
 }
 
 static void
 ResFindWindowPixmaps (pointer value, XID id, pointer cdata)
 {
-   unsigned long *bytes = (unsigned long *)cdata;
-   WindowPtr pWin = (WindowPtr)value;
-
-   if (pWin->backgroundState == BackgroundPixmap)
-     *bytes += ResGetApproxPixmapBytes(pWin->background.pixmap);
-
-   if (pWin->border.pixmap != NULL && !pWin->borderIsPixel)
-     *bytes += ResGetApproxPixmapBytes(pWin->border.pixmap);
+    ResFindResourcePixmaps(value, id, RT_WINDOW, cdata);
 }
 
 static void
 ResFindGCPixmaps (pointer value, XID id, pointer cdata)
 {
-   unsigned long *bytes = (unsigned long *)cdata;
-   GCPtr pGC = (GCPtr)value;
-
-   if (pGC->stipple != NULL)
-     *bytes += ResGetApproxPixmapBytes(pGC->stipple);
-
-   if (pGC->tile.pixmap != NULL && !pGC->tileIsPixel)
-     *bytes += ResGetApproxPixmapBytes(pGC->tile.pixmap);
+    ResFindResourcePixmaps(value, id, RT_GC, cdata);
 }
 
 static int
diff --git a/dix/resource.c b/dix/resource.c
index a0fe719..72c0761 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -142,6 +142,7 @@ Equipment Corporation.
 #include "xace.h"
 #include <assert.h>
 #include "registry.h"
+#include "gcstruct.h"
 
 #ifdef XSERVER_DTRACE
 #include <sys/types.h>
@@ -185,51 +186,213 @@ RESTYPE TypeMask;
 
 struct ResourceType {
     DeleteType deleteFunc;
+    SizeType sizeFunc;
     int errorValue;
 };
 
+/**
+ * Used by all resources that don't specify a function to calculate
+ * resource size. Currently this is used for all resources with
+ * insignificant memory usage.
+ *
+ * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc
+ *
+ * @param[in] value Pointer to resource object.
+ *
+ * @param[in] id Resource ID for the object.
+ *
+ * @param[out] size Fill all fields to zero to indicate that size of
+ *                  resource can't be determined.
+ */
+static void
+GetDefaultBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    size->resourceSize = 0;
+    size->pixmapRefSize = 0;
+}
+
+/**
+ * Calculate drawable size in bytes. Reference counting is not taken
+ * into account.
+ *
+ * @param[in] drawable Pointer to a drawable.
+ *
+ * @return Estimate of total memory usage for the drawable.
+ */
+static unsigned long
+GetDrawableBytes(DrawablePtr drawable)
+{
+    int bytes = 0;
+
+    if (drawable)
+    {
+        int bytesPerPixel = drawable->bitsPerPixel >> 3;
+        int numberOfPixels = drawable->width * drawable->height;
+        bytes = numberOfPixels * bytesPerPixel;
+    }
+
+    return bytes;
+}
+
+/**
+ * Calculate pixmap size in bytes. Reference counting is taken into
+ * account. Any extra data attached by extensions and drivers is not
+ * taken into account. The purpose of this function is to estimate
+ * memory usage that can be attributed to single reference of the
+ * pixmap.
+ *
+ * @param[in] value Pointer to a pixmap.
+ *
+ * @param[in] id Resource ID of pixmap. If the pixmap hasn't been
+ *               added as resource, just pass value->drawable.id.
+ *
+ * @param[out] size Estimate of memory usage attributed to a single
+ *                  pixmap reference.
+ */
+static void
+GetPixmapBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    PixmapPtr pixmap = value;
+
+    size->resourceSize = 0;
+    size->pixmapRefSize = 0;
+
+    if (pixmap && pixmap->refcnt)
+    {
+        DrawablePtr drawable = &pixmap->drawable;
+        size->resourceSize = GetDrawableBytes(drawable);
+        size->pixmapRefSize = size->resourceSize / pixmap->refcnt;
+    }
+}
+
+/**
+ * Calculate window size in bytes. The purpose of this function is to
+ * estimate memory usage that can be attributed to all pixmap
+ * references of the window.
+ *
+ * @param[in] value Pointer to a window.
+ *
+ * @param[in] id Resource ID of window.
+ *
+ * @param[out] size Estimate of memory usage attributed to a all
+ *                  pixmap references of a window.
+ */
+static void
+GetWindowBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+    ResourceSizeRec pixmapSize = { 0, 0 };
+    WindowPtr window = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (window->backgroundState == BackgroundPixmap)
+    {
+        PixmapPtr pixmap = window->background.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+    if (window->border.pixmap && !window->borderIsPixel)
+    {
+        PixmapPtr pixmap = window->border.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
+/**
+ * Calculate graphics context size in bytes. The purpose of this
+ * function is to estimate memory usage that can be attributed to all
+ * pixmap references of the graphics context.
+ *
+ * @param[in] value Pointer to a graphics context.
+ *
+ * @param[in] id Resource ID of graphics context.
+ *
+ * @param[out] size Estimate of memory usage attributed to a all
+ *                  pixmap references of a graphics context.
+ */
+static void
+GetGcBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+    ResourceSizeRec pixmapSize = { 0, 0 };
+    GCPtr gc = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (gc->stipple)
+    {
+        PixmapPtr pixmap = gc->stipple;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+    if (gc->tile.pixmap && !gc->tileIsPixel)
+    {
+        PixmapPtr pixmap = gc->tile.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
 static struct ResourceType *resourceTypes;
 static const struct ResourceType predefTypes[] = {
     [RT_NONE & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = (DeleteType)NoopDDA,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadValue,
     },
     [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = DeleteWindow,
+	.sizeFunc = GetWindowBytes,
 	.errorValue = BadWindow,
     },
     [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = dixDestroyPixmap,
+	.sizeFunc = GetPixmapBytes,
 	.errorValue = BadPixmap,
     },
     [RT_GC & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = FreeGC,
+	.sizeFunc = GetGcBytes,
 	.errorValue = BadGC,
     },
     [RT_FONT & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = CloseFont,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadFont,
     },
     [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = FreeCursor,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadCursor,
     },
     [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = FreeColormap,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadColor,
     },
     [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = FreeClientPixels,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadColor,
     },
     [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = OtherClientGone,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadValue,
     },
     [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
 	.deleteFunc = DeletePassiveGrab,
+	.sizeFunc = GetDefaultBytes,
 	.errorValue = BadValue,
-    },
+    }
 };
 
 CallbackListPtr ResourceStateCallback;
@@ -258,6 +421,7 @@ CreateNewResourceType(DeleteType deleteFunc, char *name)
     lastResourceType = next;
     resourceTypes = types;
     resourceTypes[next].deleteFunc = deleteFunc;
+    resourceTypes[next].sizeFunc = GetDefaultBytes;
     resourceTypes[next].errorValue = BadValue;
 
     /* Called even if name is NULL, to remove any previous entry */
@@ -266,6 +430,39 @@ CreateNewResourceType(DeleteType deleteFunc, char *name)
     return next;
 }
 
+/**
+ * Get the function used to calculate resource size. Extensions and
+ * drivers need to be able to determine the current size calculation
+ * function if they want to wrap or override it.
+ *
+ * @param[in] type     Resource type used in size calculations.
+ *
+ * @return Function to calculate the size of a single
+ *                     resource.
+ */
+SizeType
+GetResourceTypeSizeFunc(RESTYPE type)
+{
+    return resourceTypes[type & TypeMask].sizeFunc;
+}
+
+/**
+ * Override the default function that calculates resource size. For
+ * example, video driver knows better how to calculate pixmap memory
+ * usage and can therefore wrap or override size calculation for
+ * RT_PIXMAP.
+ *
+ * @param[in] type     Resource type used in size calculations.
+ *
+ * @param[in] sizeFunc Function to calculate the size of a single
+ *                     resource.
+ */
+void
+SetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc)
+{
+    resourceTypes[type & TypeMask].sizeFunc = sizeFunc;
+}
+
 void
 SetResourceTypeErrorValue(RESTYPE type, int errorValue)
 {
diff --git a/include/resource.h b/include/resource.h
index 0c5a59d..406d74a 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -134,10 +134,27 @@ typedef struct {
     pointer value;
 } ResourceStateInfoRec;
 
+/* Structure for estimating resource memory usage. Memory usage
+ * consists of space allocated for the resource itself and of
+ * references to other resources. Currently the most important use for
+ * this structure is to estimate pixmap usage of different resources
+ * more accurately. */
+typedef struct {
+    /* Size of resource itself. Zero if not implemented. */
+    unsigned long resourceSize;
+    /* Size attributed to pixmap references from the resource. */
+    unsigned long pixmapRefSize;
+} ResourceSizeRec, *ResourceSizePtr;
+
 typedef int (*DeleteType)(
     pointer /*value*/,
     XID /*id*/);
 
+typedef void (*SizeType)(
+    pointer /*value*/,
+    XID /*id*/,
+    ResourceSizePtr /*size*/);
+
 typedef void (*FindResType)(
     pointer /*value*/,
     XID /*id*/,
@@ -157,6 +174,12 @@ typedef Bool (*FindComplexResType)(
 extern _X_EXPORT RESTYPE CreateNewResourceType(
     DeleteType /*deleteFunc*/, char * /*name*/);
 
+extern _X_EXPORT SizeType GetResourceTypeSizeFunc(
+    RESTYPE /*type*/);
+
+extern _X_EXPORT void SetResourceTypeSizeFunc(
+    RESTYPE /*type*/, SizeType /*sizeFunc*/);
+
 extern _X_EXPORT void SetResourceTypeErrorValue(
     RESTYPE /*type*/, int /*errorValue*/);
 
-- 
1.6.3.3



More information about the xorg-devel mailing list