summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sna/sna_display.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 664d42c7..a9558d22 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -3093,12 +3093,18 @@ static struct sna_cursor *__sna_create_cursor(struct sna *sna)
return NULL;
}
- c->image = gem_mmap(sna->kgem.fd, c->handle, c->alloc);
- if (c->image == NULL) {
- gem_close(sna->kgem.fd, c->handle);
- free(c);
- return NULL;
- }
+ /* Old hardware uses physical addresses, which the kernel
+ * implements in an incoherent fashion requiring a pwrite.
+ */
+ if (sna->kgem.gen >= 033) {
+ c->image = gem_mmap(sna->kgem.fd, c->handle, c->alloc);
+ if (c->image == NULL) {
+ gem_close(sna->kgem.fd, c->handle);
+ free(c);
+ return NULL;
+ }
+ } else
+ c->image = NULL;
__DBG(("%s: handle=%d, allocated %d\n", __FUNCTION__, c->handle, size));
@@ -3114,7 +3120,7 @@ static struct sna_cursor *__sna_create_cursor(struct sna *sna)
static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
{
struct sna_cursor *cursor;
- uint32_t *src;
+ uint32_t *src, *image;
int width, height, size, x, y;
Rotation rotation;
@@ -3198,10 +3204,21 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
}
}
+ image = cursor->image;
+ if (image == NULL) {
+ image = malloc(4*size*size);
+ if (image == NULL) {
+ if (src != (uint32_t *)sna->cursor.ref->bits->argb)
+ free(src);
+ return NULL;
+ }
+
+ cursor->last_width = cursor->last_height = size;
+ }
if (width < cursor->last_width || height < cursor->last_height)
- memset(cursor->image, 0, 4*size*size);
+ memset(image, 0, 4*size*size);
if (rotation == RR_Rotate_0) {
- memcpy_blt(src, cursor->image, 32,
+ memcpy_blt(src, image, 32,
width * 4, size * 4,
0, 0,
0, 0,
@@ -3217,10 +3234,23 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
pixel = src[yin * width + xin];
else
pixel = 0;
- cursor->image[y * size + x] = pixel;
+ image[y * size + x] = pixel;
}
}
+ if (image != cursor->image) {
+ struct drm_i915_gem_pwrite pwrite;
+
+ VG_CLEAR(pwrite);
+ pwrite.handle = cursor->handle;
+ pwrite.offset = 0;
+ pwrite.size = 4*size*size;
+ pwrite.data_ptr = (uintptr_t)image;
+ (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite);
+
+ free(image);
+ }
+
if (src != (uint32_t *)sna->cursor.ref->bits->argb)
free(src);
@@ -3365,7 +3395,8 @@ sna_hide_cursors(ScrnInfoPtr scrn)
while (sna->cursor.cursors) {
struct sna_cursor *cursor = sna->cursor.cursors;
sna->cursor.cursors = cursor->next;
- munmap(cursor->image, cursor->alloc);
+ if (cursor->image)
+ munmap(cursor->image, cursor->alloc);
gem_close(sna->kgem.fd, cursor->handle);
free(cursor);
}