xf86-video-intel: 4 commits - src/sna/kgem.c src/sna/kgem.h src/sna/sna_accel.c src/sna/sna_glyphs.c
Chris Wilson
ickle at kemper.freedesktop.org
Sat Jul 14 12:19:19 PDT 2012
src/sna/kgem.c | 6 +
src/sna/kgem.h | 2
src/sna/sna_accel.c | 252 ++++++++++++++++++++++++++++++---------------------
src/sna/sna_glyphs.c | 2
4 files changed, 157 insertions(+), 105 deletions(-)
New commits:
commit f17037275c05198c3c3f456964fd42032f9085b6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Jul 14 20:11:17 2012 +0100
sna: Reorder overlapping boxes for CopyArea/Window
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 4257e07..d3787c1 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -3692,6 +3692,54 @@ move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
}
}
+static BoxPtr
+reorder_boxes(BoxPtr box, int n, int dx, int dy)
+{
+ BoxPtr new, base, next, tmp;
+
+ DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
+
+ if (dy < 0) {
+ new = malloc(sizeof(BoxRec) * n);
+ if (new == NULL)
+ return NULL;
+
+ base = next = box + n - 1;
+ while (base >= box) {
+ while (next >= box && base->y1 == next->y1)
+ next--;
+ tmp = next + 1;
+ while (tmp <= base)
+ *new++ = *tmp++;
+ base = next;
+ }
+ new -= n;
+ box = new;
+ }
+
+ if (dx < 0) {
+ new = malloc(sizeof(BoxRec) * n);
+ if (!new) {
+ if (dy < 0)
+ free(box);
+ return NULL;
+ }
+ base = next = box;
+ while (base < box + n) {
+ while (next < box + n && next->y1 == base->y1)
+ next++;
+ tmp = next;
+ while (tmp != base)
+ *new++ = *--tmp;
+ base = next;
+ }
+ new -= n;
+ box = new;
+ }
+
+ return box;
+}
+
static void
sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
RegionPtr region,int dx, int dy,
@@ -3700,6 +3748,8 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
PixmapPtr pixmap = get_drawable_pixmap(src);
struct sna *sna = to_sna_from_pixmap(pixmap);
struct sna_pixmap *priv = sna_pixmap(pixmap);
+ BoxPtr box = RegionRects(region);
+ int n = RegionNumRects(region);
int alu = gc ? gc->alu : GXcopy;
int16_t tx, ty;
@@ -3707,8 +3757,14 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (((dx | dy) == 0 && alu == GXcopy))
return;
+ if (n > 1 && (dx | dy) < 0) {
+ box = reorder_boxes(box, n, dx, dy);
+ if (box == NULL)
+ return;
+ }
+
DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
- __FUNCTION__, RegionNumRects(region),
+ __FUNCTION__, n,
region->extents.x1, region->extents.y1,
region->extents.x2, region->extents.y2,
dx, dy, alu,
@@ -3725,7 +3781,7 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (priv->gpu_bo) {
if (alu == GXcopy && priv->clear)
- return;
+ goto out;
assert(priv->gpu_bo->proxy == NULL);
if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ)) {
@@ -3737,9 +3793,7 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (!sna->render.copy_boxes(sna, alu,
pixmap, priv->gpu_bo, dx, dy,
pixmap, priv->gpu_bo, tx, ty,
- RegionRects(region),
- RegionNumRects(region),
- 0)) {
+ box, n, 0)) {
DBG(("%s: fallback - accelerated copy boxes failed\n",
__FUNCTION__));
goto fallback;
@@ -3754,11 +3808,9 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
fallback:
DBG(("%s: fallback", __FUNCTION__));
if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
- return;
+ goto out;
if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
- BoxPtr box = RegionRects(region);
- int n = RegionNumRects(region);
FbBits *dst_bits, *src_bits;
int stride = pixmap->devKind;
int bpp = pixmap->drawable.bitsPerPixel;
@@ -3778,7 +3830,7 @@ fallback:
} while (--n);
} else {
if (gc && !sna_gc_move_to_cpu(gc, dst, region))
- return;
+ goto out;
get_drawable_deltas(src, pixmap, &tx, &ty);
miCopyRegion(src, dst, gc,
@@ -3789,6 +3841,10 @@ fallback:
sna_gc_move_to_gpu(gc);
}
}
+
+out:
+ if (box != RegionRects(region))
+ free(box);
}
static int
commit 86e09d14bd00344d378b86a19ebb44f7d946926c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Jul 14 17:51:31 2012 +0100
sna: Tidy sna_copy_boxes
So there appears to be a bug hidden here. But only when we scroll
upwards in a GTK+ application. Hmm.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 5880c78..f85b5af 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -800,7 +800,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
kgem->half_cpu_cache_pages = cpu_cache_size() >> 13;
DBG(("%s: half cpu cache %d pages\n", __FUNCTION__,
- kgem->half_cpu_cace_pages));
+ kgem->half_cpu_cache_pages));
list_init(&kgem->batch_partials);
list_init(&kgem->active_partials);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 9627a06..4257e07 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -69,6 +69,7 @@
#define ACCEL_PUT_IMAGE 1
#define ACCEL_COPY_AREA 1
#define ACCEL_COPY_PLANE 1
+#define ACCEL_COPY_WINDOW 1
#define ACCEL_POLY_POINT 1
#define ACCEL_POLY_LINE 1
#define ACCEL_POLY_SEGMENT 1
@@ -3723,6 +3724,9 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
goto fallback;
if (priv->gpu_bo) {
+ if (alu == GXcopy && priv->clear)
+ return;
+
assert(priv->gpu_bo->proxy == NULL);
if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ)) {
DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
@@ -3773,7 +3777,7 @@ fallback:
box++;
} while (--n);
} else {
- if (!sna_gc_move_to_cpu(gc, dst, region))
+ if (gc && !sna_gc_move_to_cpu(gc, dst, region))
return;
get_drawable_deltas(src, pixmap, &tx, &ty);
@@ -3781,7 +3785,8 @@ fallback:
region, dx - tx, dy - ty,
fbCopyNtoN, 0, NULL);
- sna_gc_move_to_gpu(gc);
+ if (gc)
+ sna_gc_move_to_gpu(gc);
}
}
}
@@ -3821,17 +3826,17 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
struct sna *sna = to_sna_from_pixmap(src_pixmap);
struct sna_damage **damage;
struct kgem_bo *bo;
- int alu = gc ? gc->alu : GXcopy;
int16_t src_dx, src_dy;
int16_t dst_dx, dst_dy;
BoxPtr box = RegionRects(region);
int n = RegionNumRects(region);
+ int alu = gc->alu;
int stride, bpp;
char *bits;
bool replaces;
- if (n == 0)
- return;
+ assert(RegionNumRects(region));
+ assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
if (src_pixmap == dst_pixmap)
return sna_self_copy_boxes(src, dst, gc,
@@ -3851,13 +3856,10 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
bpp = dst_pixmap->drawable.bitsPerPixel;
get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy);
- get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
- src_dx += dx;
- src_dy += dy;
-
RegionTranslate(region, dst_dx, dst_dy);
- src_dx -= dst_dx;
- src_dy -= dst_dy;
+ get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
+ src_dx += dx - dst_dx;
+ src_dy += dy - dst_dy;
replaces = n == 1 &&
box->x1 <= 0 &&
@@ -3897,8 +3899,6 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (src_priv && src_priv->clear) {
DBG(("%s: applying src clear[%08x] to dst\n",
__FUNCTION__, src_priv->clear_color));
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
if (n == 1) {
if (!sna->render.fill_one(sna,
dst_pixmap, bo,
@@ -3927,7 +3927,6 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (damage)
sna_damage_add(damage, region);
-
return;
}
@@ -3945,11 +3944,8 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
goto fallback;
}
- if (damage) {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
+ if (damage)
sna_damage_add(damage, region);
- }
return;
}
@@ -3980,11 +3976,8 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
goto fallback;
}
- if (damage) {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
+ if (damage)
sna_damage_add(damage, region);
- }
return;
}
@@ -4016,11 +4009,8 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
goto fallback;
}
- if (damage) {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
+ if (damage)
sna_damage_add(damage, region);
- }
return;
}
@@ -4028,7 +4018,7 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
PixmapPtr tmp;
int i;
- assert (src_pixmap->drawable.depth != 1);
+ assert(src_pixmap->drawable.depth != 1);
DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
__FUNCTION__, alu));
@@ -4078,11 +4068,8 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
}
tmp->drawable.pScreen->DestroyPixmap(tmp);
- if (damage) {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
+ if (damage)
sna_damage_add(damage, region);
- }
return;
} else {
DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
@@ -4132,12 +4119,9 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
dst_pixmap->drawable.height);
list_del(&dst_priv->list);
dst_priv->undamaged = false;
- } else {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
+ } else
sna_damage_add(&dst_priv->gpu_damage,
region);
- }
assert_pixmap_damage(dst_pixmap);
}
}
@@ -4151,9 +4135,6 @@ fallback:
__FUNCTION__, src_priv->clear_color));
if (dst_priv) {
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
-
if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
region,
MOVE_WRITE | MOVE_INPLACE_HINT))
@@ -4198,9 +4179,6 @@ fallback:
if (dst_priv) {
unsigned mode;
- assert_pixmap_contains_box(dst_pixmap,
- RegionExtents(region));
-
if (alu_overwrites(alu))
mode = MOVE_WRITE | MOVE_INPLACE_HINT;
else
@@ -4267,6 +4245,21 @@ typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
RegionPtr region, int dx, int dy,
Pixel bitPlane, void *closure);
+inline static bool
+box_intersect(BoxPtr a, const BoxRec *b)
+{
+ if (a->x1 < b->x1)
+ a->x1 = b->x1;
+ if (a->x2 > b->x2)
+ a->x2 = b->x2;
+ if (a->y1 < b->y1)
+ a->y1 = b->y1;
+ if (a->y2 > b->y2)
+ a->y2 = b->y2;
+
+ return a->x1 < a->x2 && a->y1 < a->y2;
+}
+
static RegionPtr
sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
int sx, int sy,
@@ -4274,13 +4267,18 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
int dx, int dy,
sna_copy_func copy, Pixel bitPlane, void *closure)
{
- RegionPtr clip = NULL, free_clip = NULL;
+ RegionPtr clip, free_clip = NULL;
RegionRec region;
- bool expose = false;
+ bool expose;
+
+ DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
+ __FUNCTION__, sx, sy, dx, dy, width, height));
/* Short cut for unmapped windows */
- if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized)
+ if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
+ DBG(("%s: unmapped\n", __FUNCTION__));
return NULL;
+ }
if (src->pScreen->SourceValidate)
src->pScreen->SourceValidate(src, sx, sy,
@@ -4293,25 +4291,23 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
dx += dst->x;
dy += dst->y;
+ DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
+ __FUNCTION__, sx, sy, dx, dy, width, height));
+
region.extents.x1 = dx;
region.extents.y1 = dy;
region.extents.x2 = dx + width;
region.extents.y2 = dy + height;
region.data = NULL;
- {
- BoxPtr box = &gc->pCompositeClip->extents;
- if (region.extents.x1 < box->x1)
- region.extents.x1 = box->x1;
- if (region.extents.x2 > box->x2)
- region.extents.x2 = box->x2;
- if (region.extents.y1 < box->y1)
- region.extents.y1 = box->y1;
- if (region.extents.y2 > box->y2)
- region.extents.y2 = box->y2;
- }
- if (box_empty(®ion.extents))
+ DBG(("%s: dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
+ region.extents.x1, region.extents.y1,
+ region.extents.x2, region.extents.y2));
+
+ if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) {
+ DBG(("%s: dst clipped out\n", __FUNCTION__));
return NULL;
+ }
region.extents.x1 += sx - dx;
region.extents.x2 += sx - dx;
@@ -4319,31 +4315,28 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
region.extents.y2 += sy - dy;
/* Compute source clip region */
- if (src->type == DRAWABLE_PIXMAP) {
- if (src == dst && gc->clientClipType == CT_NONE)
- clip = gc->pCompositeClip;
+ clip = NULL;
+ if (src == dst && gc->clientClipType == CT_NONE) {
+ DBG(("%s: using gc clip for src\n", __FUNCTION__));
+ clip = gc->pCompositeClip;
+ } else if (src->type == DRAWABLE_PIXMAP) {
+ DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
+ } else if (gc->subWindowMode == IncludeInferiors) {
+ /*
+ * XFree86 DDX empties the border clip when the
+ * VT is inactive, make sure the region isn't empty
+ */
+ if (((WindowPtr)src)->parent ||
+ !RegionNotEmpty(&((WindowPtr)src)->borderClip)) {
+ DBG(("%s: include inferiors\n", __FUNCTION__));
+ free_clip = clip = NotClippedByChildren((WindowPtr)src);
+ }
} else {
- if (gc->subWindowMode == IncludeInferiors) {
- /*
- * XFree86 DDX empties the border clip when the
- * VT is inactive, make sure the region isn't empty
- */
- if (!((WindowPtr) src)->parent &&
- RegionNotEmpty(&((WindowPtr) src)->borderClip)) {
- /*
- * special case bitblt from root window in
- * IncludeInferiors mode; just like from a pixmap
- */
- } else if (src == dst && gc->clientClipType == CT_NONE) {
- clip = gc->pCompositeClip;
- } else {
- free_clip = clip =
- NotClippedByChildren((WindowPtr) src);
- }
- } else
- clip = &((WindowPtr)src)->clipList;
+ DBG(("%s: window clip\n", __FUNCTION__));
+ clip = &((WindowPtr)src)->clipList;
}
if (clip == NULL) {
+ DBG(("%s: fast source clip against extents\n", __FUNCTION__));
expose = true;
if (region.extents.x1 < src->x) {
region.extents.x1 = src->x;
@@ -4364,13 +4357,22 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
if (box_empty(®ion.extents))
return NULL;
} else {
+ expose = false;
RegionIntersect(®ion, ®ion, clip);
if (free_clip)
RegionDestroy(free_clip);
}
+ DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
+ region.extents.x1, region.extents.y1,
+ region.extents.x2, region.extents.y2,
+ RegionNumRects(®ion)));
RegionTranslate(®ion, dx-sx, dy-sy);
if (gc->pCompositeClip->data)
RegionIntersect(®ion, ®ion, gc->pCompositeClip);
+ DBG(("%s: copy region (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
+ region.extents.x1, region.extents.y1,
+ region.extents.x2, region.extents.y2,
+ RegionNumRects(®ion)));
if (RegionNotEmpty(®ion))
copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure);
@@ -4485,21 +4487,6 @@ out:
0, NULL);
}
-inline static bool
-box_intersect(BoxPtr a, const BoxRec *b)
-{
- if (a->x1 < b->x1)
- a->x1 = b->x1;
- if (a->x2 > b->x2)
- a->x2 = b->x2;
- if (a->y1 < b->y1)
- a->y1 = b->y1;
- if (a->y2 > b->y2)
- a->y2 = b->y2;
-
- return a->x1 < a->x2 && a->y1 < a->y2;
-}
-
static const BoxRec *
find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
{
@@ -12231,7 +12218,7 @@ sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
#endif
- if (wedged(sna)) {
+ if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
DBG(("%s: fallback -- wedged\n", __FUNCTION__));
if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
return;
commit 924f596463555db27214fd8227218c2e21ecddc8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Jul 14 19:03:08 2012 +0100
sna: Avoid BLT to snoopable bo on older gen
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index b44c734..5880c78 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -768,6 +768,10 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
DBG(("%s: semaphores enabled? %d\n", __FUNCTION__,
kgem->has_semaphores));
+ kgem->can_blt_cpu = gen == 0 || gen >= 30;
+ DBG(("%s: can blt to cpu? %d\n", __FUNCTION__,
+ kgem->can_blt_cpu));
+
if (!is_hw_supported(kgem, dev)) {
xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
"Detected unsupported/dysfunctional hardware, disabling acceleration.\n");
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index e5db6fd..c354547 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -160,6 +160,8 @@ struct kgem {
uint32_t has_cache_level :1;
uint32_t has_llc :1;
+ uint32_t can_blt_cpu :1;
+
uint16_t fence_max;
uint16_t half_cpu_cache_pages;
uint32_t aperture_total, aperture_high, aperture_low, aperture_mappable;
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 406cbfa..9627a06 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1070,7 +1070,7 @@ sna_pixmap_create_mappable_gpu(PixmapPtr pixmap)
static inline bool use_cpu_bo_for_write(struct sna *sna,
struct sna_pixmap *priv)
{
- return priv->cpu_bo != NULL && sna->kgem.gen >= 30;
+ return priv->cpu_bo != NULL && sna->kgem.can_blt_cpu;
}
static inline bool use_cpu_bo_for_read(struct sna_pixmap *priv)
@@ -2455,6 +2455,9 @@ use_cpu_bo:
if (priv->cpu_bo == NULL)
return NULL;
+ if (!to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu)
+ return NULL;
+
if (flags == 0 && !kgem_bo_is_busy(priv->cpu_bo))
return NULL;
commit 44e226b1d9fca8cb95b0864adf8708b03ee8472c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Jul 14 18:36:29 2012 +0100
sna/glyphs: A repeat of the earlier typo for pixman glyphs
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
index fa5e45b..80c0b74 100644
--- a/src/sna/sna_glyphs.c
+++ b/src/sna/sna_glyphs.c
@@ -1346,7 +1346,7 @@ glyphs_fallback(CARD8 op,
pixman_image_t *glyph_image;
glyph_image = sna_glyph_get_image(g, screen);
- if (glyph_image)
+ if (glyph_image == NULL)
goto next;
ptr = pixman_glyph_cache_insert(cache, g, NULL,
More information about the xorg-commit
mailing list