[PATCH xserver 1/2] Revert "glamor: Remove the FBO cache."

Michel Dänzer michel at daenzer.net
Fri Mar 3 08:46:54 UTC 2017


From: Michel Dänzer <michel.daenzer at amd.com>

This reverts commit 950ffb8d6fd1480f305e38c571bda44f247f1de2 (and parts
of commit 4b5326aeba539249fcded91bf7806a708eeca651).

It halved (or worse) the performance with some x11perf tests on
radeonsi, even though radeonsi has a BO cache.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---

I suspect the reason why radeonsi's BO cache can't make up for the lack of
the glamor FBO cache is that the former can only return idle BOs. So
while the glamor FBO cache allows re-using the same FBO over and over
for a series of operations using temporary pixmaps of the same size, the
radeonsi BO cache has to keep using different BOs until a command stream
is flushed to the GPU and processed by it.

 glamor/glamor.c       |   5 +
 glamor/glamor_fbo.c   | 249 ++++++++++++++++++++++++++++++++++++++++++++++++--
 glamor/glamor_priv.h  |  27 ++++++
 glamor/glamor_utils.h |  40 ++++++++
 4 files changed, 315 insertions(+), 6 deletions(-)

diff --git a/glamor/glamor.c b/glamor/glamor.c
index c54cf3b43..feae7a21f 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -110,6 +110,7 @@ glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex)
         ErrorF("XXX fail to create fbo.\n");
         return;
     }
+    fbo->external = TRUE;
 
     glamor_pixmap_attach_fbo(pixmap, fbo);
 }
@@ -253,7 +254,9 @@ glamor_block_handler(ScreenPtr screen)
     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 
     glamor_make_current(glamor_priv);
+    glamor_priv->tick++;
     glFlush();
+    glamor_fbo_expire(glamor_priv);
 }
 
 static void
@@ -719,6 +722,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
     ps->Glyphs = glamor_composite_glyphs;
 
     glamor_init_vbo(screen);
+    glamor_init_pixmap_fbo(screen);
 
 #ifdef GLAMOR_GRADIENT_SHADER
     glamor_init_gradient_shader(screen);
@@ -748,6 +752,7 @@ glamor_release_screen_priv(ScreenPtr screen)
 
     glamor_priv = glamor_get_screen_private(screen);
     glamor_fini_vbo(screen);
+    glamor_fini_pixmap_fbo(screen);
     glamor_pixmap_fini(screen);
     free(glamor_priv);
 
diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c
index 988bb585b..a531f6052 100644
--- a/glamor/glamor_fbo.c
+++ b/glamor/glamor_fbo.c
@@ -30,9 +30,107 @@
 
 #include "glamor_priv.h"
 
-void
-glamor_destroy_fbo(glamor_screen_private *glamor_priv,
-                   glamor_pixmap_fbo *fbo)
+#define GLAMOR_CACHE_EXPIRE_MAX 100
+
+#define GLAMOR_CACHE_DEFAULT    0
+#define GLAMOR_CACHE_EXACT_SIZE 1
+
+//#define NO_FBO_CACHE 1
+#define FBO_CACHE_THRESHOLD  (256*1024*1024)
+
+/* Loop from the tail to the head. */
+#define xorg_list_for_each_entry_reverse(pos, head, member)             \
+    for (pos = __container_of((head)->prev, pos, member);               \
+         &pos->member != (head);                                        \
+         pos = __container_of(pos->member.prev, pos, member))
+
+#define xorg_list_for_each_entry_safe_reverse(pos, tmp, head, member)   \
+    for (pos = __container_of((head)->prev, pos, member),               \
+         tmp = __container_of(pos->member.prev, pos, member);           \
+         &pos->member != (head);                                        \
+         pos = tmp, tmp = __container_of(pos->member.prev, tmp, member))
+
+inline static int
+cache_wbucket(int size)
+{
+    int order = __fls(size / 32);
+
+    if (order >= CACHE_BUCKET_WCOUNT)
+        order = CACHE_BUCKET_WCOUNT - 1;
+    return order;
+}
+
+inline static int
+cache_hbucket(int size)
+{
+    int order = __fls(size / 32);
+
+    if (order >= CACHE_BUCKET_HCOUNT)
+        order = CACHE_BUCKET_HCOUNT - 1;
+    return order;
+}
+
+static int
+cache_format(GLenum format)
+{
+    switch (format) {
+    case GL_ALPHA:
+    case GL_LUMINANCE:
+    case GL_RED:
+        return 2;
+    case GL_RGB:
+        return 1;
+    case GL_RGBA:
+        return 0;
+    default:
+        return -1;
+    }
+}
+
+static glamor_pixmap_fbo *
+glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv,
+                            int w, int h, GLenum format)
+{
+    struct xorg_list *cache;
+    glamor_pixmap_fbo *fbo_entry, *ret_fbo = NULL;
+    int n_format;
+
+#ifdef NO_FBO_CACHE
+    return NULL;
+#else
+    n_format = cache_format(format);
+    if (n_format == -1)
+        return NULL;
+    cache = &glamor_priv->fbo_cache[n_format]
+        [cache_wbucket(w)]
+        [cache_hbucket(h)];
+
+    xorg_list_for_each_entry(fbo_entry, cache, list) {
+        if (fbo_entry->width == w && fbo_entry->height == h) {
+
+            DEBUGF("Request w %d h %d format %x \n", w, h, format);
+            DEBUGF("got cache entry %p w %d h %d fbo %d tex %d format %x\n",
+                   fbo_entry, fbo_entry->width, fbo_entry->height,
+                   fbo_entry->fb, fbo_entry->tex, fbo_entry->format);
+            assert(format == fbo_entry->format);
+            xorg_list_del(&fbo_entry->list);
+            ret_fbo = fbo_entry;
+            break;
+        }
+    }
+
+    if (ret_fbo)
+        glamor_priv->fbo_cache_watermark -= ret_fbo->width * ret_fbo->height;
+
+    assert(glamor_priv->fbo_cache_watermark >= 0);
+
+    return ret_fbo;
+#endif
+}
+
+static void
+glamor_purge_fbo(glamor_screen_private *glamor_priv,
+                 glamor_pixmap_fbo *fbo)
 {
     glamor_make_current(glamor_priv);
 
@@ -44,6 +142,52 @@ glamor_destroy_fbo(glamor_screen_private *glamor_priv,
     free(fbo);
 }
 
+static void
+glamor_pixmap_fbo_cache_put(glamor_screen_private *glamor_priv,
+                            glamor_pixmap_fbo *fbo)
+{
+    struct xorg_list *cache;
+    int n_format;
+
+#ifdef NO_FBO_CACHE
+    glamor_purge_fbo(fbo);
+    return;
+#else
+    n_format = cache_format(fbo->format);
+
+    if (fbo->fb == 0 || fbo->external || n_format == -1
+        || glamor_priv->fbo_cache_watermark >= FBO_CACHE_THRESHOLD) {
+        glamor_priv->tick += GLAMOR_CACHE_EXPIRE_MAX;
+        glamor_fbo_expire(glamor_priv);
+        glamor_purge_fbo(glamor_priv, fbo);
+        return;
+    }
+
+    cache = &glamor_priv->fbo_cache[n_format]
+        [cache_wbucket(fbo->width)]
+        [cache_hbucket(fbo->height)];
+    DEBUGF
+        ("Put cache entry %p to cache %p w %d h %d format %x fbo %d tex %d \n",
+         fbo, cache, fbo->width, fbo->height, fbo->format, fbo->fb, fbo->tex);
+
+    /* Reset the texture swizzle that may have been set by
+     * glamor_picture.c.  Don't reset GL_RED -> GL_ALPHA swizzle, though
+     */
+    if (glamor_priv->has_texture_swizzle && n_format != 2) {
+        glamor_make_current(glamor_priv);
+        glBindTexture(GL_TEXTURE_2D, fbo->tex);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+    }
+
+    glamor_priv->fbo_cache_watermark += fbo->width * fbo->height;
+    xorg_list_add(&fbo->list, cache);
+    fbo->expire = glamor_priv->tick + GLAMOR_CACHE_EXPIRE_MAX;
+#endif
+}
+
 static int
 glamor_pixmap_ensure_fb(glamor_screen_private *glamor_priv,
                         glamor_pixmap_fbo *fbo)
@@ -103,14 +247,20 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
     if (fbo == NULL)
         return NULL;
 
+    xorg_list_init(&fbo->list);
+
     fbo->tex = tex;
     fbo->width = w;
     fbo->height = h;
+    fbo->external = FALSE;
     fbo->format = format;
 
+    if (flag == CREATE_PIXMAP_USAGE_SHARED)
+        fbo->external = TRUE;
+
     if (flag != GLAMOR_CREATE_FBO_NO_FBO) {
         if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) {
-            glamor_destroy_fbo(glamor_priv, fbo);
+            glamor_purge_fbo(glamor_priv, fbo);
             fbo = NULL;
         }
     }
@@ -118,6 +268,79 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
     return fbo;
 }
 
+void
+glamor_fbo_expire(glamor_screen_private *glamor_priv)
+{
+    struct xorg_list *cache;
+    glamor_pixmap_fbo *fbo_entry, *tmp;
+    int i, j, k;
+
+    for (i = 0; i < CACHE_FORMAT_COUNT; i++)
+        for (j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+            for (k = 0; k < CACHE_BUCKET_HCOUNT; k++) {
+                cache = &glamor_priv->fbo_cache[i][j][k];
+                xorg_list_for_each_entry_safe_reverse(fbo_entry, tmp, cache,
+                                                      list) {
+                    if (GLAMOR_TICK_AFTER(fbo_entry->expire, glamor_priv->tick)) {
+                        break;
+                    }
+
+                    glamor_priv->fbo_cache_watermark -=
+                        fbo_entry->width * fbo_entry->height;
+                    xorg_list_del(&fbo_entry->list);
+                    DEBUGF("cache %p fbo %p expired %d current %d \n", cache,
+                           fbo_entry, fbo_entry->expire, glamor_priv->tick);
+                    glamor_purge_fbo(glamor_priv, fbo_entry);
+                }
+            }
+
+}
+
+void
+glamor_init_pixmap_fbo(ScreenPtr screen)
+{
+    glamor_screen_private *glamor_priv;
+    int i, j, k;
+
+    glamor_priv = glamor_get_screen_private(screen);
+    for (i = 0; i < CACHE_FORMAT_COUNT; i++)
+        for (j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+            for (k = 0; k < CACHE_BUCKET_HCOUNT; k++) {
+                xorg_list_init(&glamor_priv->fbo_cache[i][j][k]);
+            }
+    glamor_priv->fbo_cache_watermark = 0;
+}
+
+void
+glamor_fini_pixmap_fbo(ScreenPtr screen)
+{
+    struct xorg_list *cache;
+    glamor_screen_private *glamor_priv;
+    glamor_pixmap_fbo *fbo_entry, *tmp;
+    int i, j, k;
+
+    glamor_priv = glamor_get_screen_private(screen);
+    for (i = 0; i < CACHE_FORMAT_COUNT; i++)
+        for (j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+            for (k = 0; k < CACHE_BUCKET_HCOUNT; k++) {
+                cache = &glamor_priv->fbo_cache[i][j][k];
+                xorg_list_for_each_entry_safe_reverse(fbo_entry, tmp, cache,
+                                                      list) {
+                    xorg_list_del(&fbo_entry->list);
+                    glamor_purge_fbo(glamor_priv, fbo_entry);
+                }
+            }
+}
+
+void
+glamor_destroy_fbo(glamor_screen_private *glamor_priv,
+                   glamor_pixmap_fbo *fbo)
+{
+    xorg_list_del(&fbo->list);
+    glamor_pixmap_fbo_cache_put(glamor_priv, fbo);
+
+}
+
 static int
 _glamor_create_tex(glamor_screen_private *glamor_priv,
                    int w, int h, GLenum format)
@@ -155,8 +378,22 @@ glamor_pixmap_fbo *
 glamor_create_fbo(glamor_screen_private *glamor_priv,
                   int w, int h, GLenum format, int flag)
 {
-    GLint tex = _glamor_create_tex(glamor_priv, w, h, format);
-    return glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag);
+    glamor_pixmap_fbo *fbo;
+    GLint tex = 0;
+
+    if (flag == GLAMOR_CREATE_FBO_NO_FBO || flag == CREATE_PIXMAP_USAGE_SHARED)
+        goto new_fbo;
+
+    fbo = glamor_pixmap_fbo_cache_get(glamor_priv, w, h, format);
+    if (fbo)
+        return fbo;
+ new_fbo:
+    tex = _glamor_create_tex(glamor_priv, w, h, format);
+    if (!tex)
+        return NULL;
+    fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag);
+
+    return fbo;
 }
 
 /**
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index 27f95521d..a9377ace1 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -184,7 +184,16 @@ struct glamor_saved_procs {
     ScreenBlockHandlerProcPtr block_handler;
 };
 
+#define CACHE_FORMAT_COUNT 3
+
+#define CACHE_BUCKET_WCOUNT 4
+#define CACHE_BUCKET_HCOUNT 4
+
+#define GLAMOR_TICK_AFTER(t0, t1) 	\
+	(((int)(t1) - (int)(t0)) < 0)
+
 typedef struct glamor_screen_private {
+    unsigned int tick;
     enum glamor_gl_flavor gl_flavor;
     int glsl_version;
     Bool has_pack_invert;
@@ -206,6 +215,10 @@ typedef struct glamor_screen_private {
 
     GLuint one_channel_format;
 
+    struct xorg_list
+        fbo_cache[CACHE_FORMAT_COUNT][CACHE_BUCKET_WCOUNT][CACHE_BUCKET_HCOUNT];
+    unsigned long fbo_cache_watermark;
+
     /* glamor point shader */
     glamor_program point_prog;
 
@@ -314,10 +327,21 @@ enum glamor_fbo_state {
 };
 
 typedef struct glamor_pixmap_fbo {
+    struct xorg_list list; /**< linked list pointers when in the fbo cache */
+    /** glamor_priv->tick number when this FBO will be expired from the cache. */
+    unsigned int expire;
     GLuint tex; /**< GL texture name */
     GLuint fb; /**< GL FBO name */
     int width; /**< width in pixels */
     int height; /**< height in pixels */
+    /**
+     * Flag for when texture contents might be shared with a
+     * non-glamor user.
+     *
+     * This is used to avoid putting textures used by other clients
+     * into the FBO cache.
+     */
+    Bool external;
     GLenum format; /**< GL format used to create the texture. */
     GLenum type; /**< GL type used to create the texture. */
 } glamor_pixmap_fbo;
@@ -545,7 +569,10 @@ glamor_pixmap_fbo *glamor_create_fbo(glamor_screen_private *glamor_priv, int w,
 void glamor_destroy_fbo(glamor_screen_private *glamor_priv,
                         glamor_pixmap_fbo *fbo);
 void glamor_pixmap_destroy_fbo(PixmapPtr pixmap);
+void glamor_init_pixmap_fbo(ScreenPtr screen);
+void glamor_fini_pixmap_fbo(ScreenPtr screen);
 Bool glamor_pixmap_fbo_fixup(ScreenPtr screen, PixmapPtr pixmap);
+void glamor_fbo_expire(glamor_screen_private *glamor_priv);
 
 /* Return whether 'picture' is alpha-only */
 static inline Bool glamor_picture_is_alpha(PicturePtr picture)
diff --git a/glamor/glamor_utils.h b/glamor/glamor_utils.h
index 6b88527e6..03e8fe534 100644
--- a/glamor/glamor_utils.h
+++ b/glamor/glamor_utils.h
@@ -720,6 +720,46 @@ glamor_is_large_pixmap(PixmapPtr pixmap)
     return (glamor_pixmap_priv_is_large(priv));
 }
 
+#ifdef __i386__
+static inline unsigned long
+__fls(unsigned long x)
+{
+ asm("bsr %1,%0":"=r"(x)
+ :     "rm"(x));
+    return x;
+}
+#else
+static inline unsigned long
+__fls(unsigned long x)
+{
+    int n;
+
+    if (x == 0)
+        return (0);
+    n = 0;
+    if (x <= 0x0000FFFF) {
+        n = n + 16;
+        x = x << 16;
+    }
+    if (x <= 0x00FFFFFF) {
+        n = n + 8;
+        x = x << 8;
+    }
+    if (x <= 0x0FFFFFFF) {
+        n = n + 4;
+        x = x << 4;
+    }
+    if (x <= 0x3FFFFFFF) {
+        n = n + 2;
+        x = x << 2;
+    }
+    if (x <= 0x7FFFFFFF) {
+        n = n + 1;
+    }
+    return 31 - n;
+}
+#endif
+
 static inline void
 glamor_make_current(glamor_screen_private *glamor_priv)
 {
-- 
2.11.0



More information about the xorg-devel mailing list