sunxi_mali_ump_dri2.c 46.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
 * Copyright (C) 2013 Siarhei Siamashka <siarhei.siamashka@gmail.com>
 *
 * Initially derived from "mali_dri2.c" which is a part of xf86-video-mali,
 * even though there is now hardly any original line of code remaining.
 *
 * Copyright (C) 2010 ARM Limited. All rights reserved.
 *
 * 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 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ump/ump.h>
#include <ump/ump_ref_drv.h>

#include <sys/ioctl.h>

#include "xorgVersion.h"
38
#include "xf86_OSproc.h"
39
40
41
42
43
44
45
46
#include "xf86.h"
#include "xf86drm.h"
#include "dri2.h"
#include "damage.h"
#include "fb.h"

#include "fbdev_priv.h"
#include "sunxi_disp.h"
47
#include "sunxi_disp_hwcursor.h"
48
49
50
#include "sunxi_disp_ioctl.h"
#include "sunxi_mali_ump_dri2.h"

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
static const uint32_t crc32_table[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
    0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
    0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
    0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
    0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
    0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
    0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
    0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
    0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
    0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
    0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
    0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
    0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
    0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
    0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
    0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
    0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
    0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
    0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
    0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
    0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
    0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

static inline uint32_t
crc32_byte(uint32_t crc32, uint8_t data)
{
    crc32 ^= 0xFFFFFFFF;
    crc32 = (crc32 >> 8) ^ crc32_table[(crc32 ^ data) & 0xFF];
    return crc32 ^ 0xFFFFFFFF;
}

static uint32_t calc_ump_checksum(UMPBufferInfoPtr umpbuf, uint32_t seed)
{
    int i;
    uint8_t *buf = umpbuf->addr + umpbuf->offs;
    uint32_t result = 0;
    uint32_t hi, lo;
    for (i = 0; i < RANDOM_SAMPLES_COUNT; i++) {
        /* LCG pseudorandom number generation */
        seed = seed * 1103515245 + 12345;
        hi = seed & 0xFFFF0000;
        seed = seed * 1103515245 + 12345;
        lo = seed >> 16;
        result = crc32_byte(result, buf[(hi | lo) % umpbuf->size]);
    }
    return result;
}

static void save_ump_checksum(UMPBufferInfoPtr umpbuf, uint32_t seed)
{
    umpbuf->has_checksum = TRUE;
    umpbuf->checksum_seed = seed;
    umpbuf->checksum = calc_ump_checksum(umpbuf, seed);
}

static Bool test_ump_checksum(UMPBufferInfoPtr umpbuf)
{
    return calc_ump_checksum(umpbuf, umpbuf->checksum_seed) == umpbuf->checksum;
}

134
135
136
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a)  (sizeof((a)) / sizeof((a)[0]))
#endif
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

/*
 * The code below is borrowed from "xserver/dix/window.c"
 */

#define BOXES_OVERLAP(b1, b2) \
      (!( ((b1)->x2 <= (b2)->x1)  || \
	( ((b1)->x1 >= (b2)->x2)) || \
	( ((b1)->y2 <= (b2)->y1)) || \
	( ((b1)->y1 >= (b2)->y2)) ) )

static BoxPtr
WindowExtents(WindowPtr pWin, BoxPtr pBox)
{
    pBox->x1 = pWin->drawable.x - wBorderWidth(pWin);
    pBox->y1 = pWin->drawable.y - wBorderWidth(pWin);
    pBox->x2 = pWin->drawable.x + (int) pWin->drawable.width
        + wBorderWidth(pWin);
    pBox->y2 = pWin->drawable.y + (int) pWin->drawable.height
        + wBorderWidth(pWin);
    return pBox;
}

static int
FancyTraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data)
{
    int result;
    WindowPtr pChild;

    if (!(pChild = pWin))
        return WT_NOMATCH;
    while (1) {
        result = (*func) (pChild, data);
        if (result == WT_STOPWALKING)
            return WT_STOPWALKING;
        if ((result == WT_WALKCHILDREN) && pChild->lastChild) {
            pChild = pChild->lastChild;
            continue;
        }
        while (!pChild->prevSib && (pChild != pWin))
            pChild = pChild->parent;
        if (pChild == pWin)
            break;
        pChild = pChild->prevSib;
    }
    return WT_NOMATCH;
}

static int
WindowWalker(WindowPtr pWin, pointer value)
{
188
    SunxiMaliDRI2 *mali = (SunxiMaliDRI2 *)value;
189

190
    if (mali->bWalkingAboveOverlayWin) {
191
192
193
194
        if (pWin->mapped && pWin->realized && pWin->drawable.class != InputOnly) {
            BoxRec sboxrec1;
            BoxPtr sbox1 = WindowExtents(pWin, &sboxrec1);
            BoxRec sboxrec2;
195
            BoxPtr sbox2 = WindowExtents(mali->pOverlayWin, &sboxrec2);
196
            if (BOXES_OVERLAP(sbox1, sbox2)) {
197
                mali->bOverlayWinOverlapped = TRUE;
198
199
200
201
202
203
204
                DebugMsg("overlapped by %p, x=%d, y=%d, w=%d, h=%d\n", pWin,
                         pWin->drawable.x, pWin->drawable.y,
                         pWin->drawable.width, pWin->drawable.height);
                return WT_STOPWALKING;
            }
        }
    }
205
206
    else if (pWin == mali->pOverlayWin) {
        mali->bWalkingAboveOverlayWin = TRUE;
207
208
209
210
211
    }

    return WT_WALKCHILDREN;
}

212
213
214
215
216
217
/* Migrate pixmap to UMP buffer */
static UMPBufferInfoPtr
MigratePixmapToUMP(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
218
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
219
220
221
222
    UMPBufferInfoPtr umpbuf;
    size_t pitch = ((pPixmap->devKind + 7) / 8) * 8;
    size_t size = pitch * pPixmap->drawable.height;

223
    HASH_FIND_PTR(mali->HashPixmapToUMP, &pPixmap, umpbuf);
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

    if (umpbuf) {
        DebugMsg("MigratePixmapToUMP %p, already exists = %p\n", pPixmap, umpbuf);
        return umpbuf;
    }

    /* create the UMP buffer */
    umpbuf = calloc(1, sizeof(UMPBufferInfoRec));
    if (!umpbuf) {
        ErrorF("MigratePixmapToUMP: calloc failed\n");
        return NULL;
    }
    umpbuf->refcount = 1;
    umpbuf->pPixmap = pPixmap;
    umpbuf->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
    if (umpbuf->handle == UMP_INVALID_MEMORY_HANDLE) {
        ErrorF("MigratePixmapToUMP: ump_ref_drv_allocate failed\n");
        free(umpbuf);
        return NULL;
    }
    umpbuf->size = size;
    umpbuf->addr = ump_mapped_pointer_get(umpbuf->handle);
    umpbuf->depth = pPixmap->drawable.depth;
    umpbuf->width = pPixmap->drawable.width;
    umpbuf->height = pPixmap->drawable.height;

    /* copy the pixel data to the new location */
    if (pitch == pPixmap->devKind) {
        memcpy(umpbuf->addr, pPixmap->devPrivate.ptr, size);
    } else {
        int y;
        for (y = 0; y < umpbuf->height; y++) {
            memcpy(umpbuf->addr + y * pitch, 
                   pPixmap->devPrivate.ptr + y * pPixmap->devKind,
                   pPixmap->devKind);
        }
    }

    umpbuf->BackupDevKind = pPixmap->devKind;
    umpbuf->BackupDevPrivatePtr = pPixmap->devPrivate.ptr;

    pPixmap->devKind = pitch;
    pPixmap->devPrivate.ptr = umpbuf->addr;

268
    HASH_ADD_PTR(mali->HashPixmapToUMP, pPixmap, umpbuf);
269
270
271
272
273

    DebugMsg("MigratePixmapToUMP %p, new buf = %p\n", pPixmap, umpbuf);
    return umpbuf;
}

274
275
static void UpdateOverlay(ScreenPtr pScreen);

276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
static void unref_ump_buffer_info(UMPBufferInfoPtr umpbuf)
{
    if (--umpbuf->refcount <= 0) {
        DebugMsg("unref_ump_buffer_info(%p) [refcount=%d, handle=%p]\n",
                 umpbuf, umpbuf->refcount, umpbuf->handle);
        if (umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
            ump_mapped_pointer_release(umpbuf->handle);
            ump_reference_release(umpbuf->handle);
        }
        free(umpbuf);
    }
    else {
        DebugMsg("Reduced ump_buffer_info %p refcount to %d\n",
                 umpbuf, umpbuf->refcount);
    }
}

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
static void umpbuf_add_to_queue(DRI2WindowStatePtr window_state,
                                UMPBufferInfoPtr umpbuf)
{
    if (window_state->ump_queue[window_state->ump_queue_head]) {
        ErrorF("Fatal error, UMP buffers queue overflow!\n");
        return;
    }

    window_state->ump_queue[window_state->ump_queue_head] = umpbuf;
    window_state->ump_queue_head = (window_state->ump_queue_head + 1) %
                                   ARRAY_SIZE(window_state->ump_queue);
}

static UMPBufferInfoPtr umpbuf_fetch_from_queue(DRI2WindowStatePtr window_state)
{
    UMPBufferInfoPtr umpbuf;

    /* Check if the queue is empty */
    if (window_state->ump_queue_tail == window_state->ump_queue_head)
        return NULL;

    umpbuf = window_state->ump_queue[window_state->ump_queue_tail];
    window_state->ump_queue[window_state->ump_queue_tail] = NULL;

    window_state->ump_queue_tail = (window_state->ump_queue_tail + 1) %
                                   ARRAY_SIZE(window_state->ump_queue);
    return umpbuf;
}

322
323
324
325
326
327
328
329
330
331
332
/* Verify and fixup the DRI2Buffer before returning it to the X server */
static DRI2Buffer2Ptr validate_dri2buf(DRI2Buffer2Ptr dri2buf)
{
    UMPBufferInfoPtr umpbuf = (UMPBufferInfoPtr)dri2buf->driverPrivate;
    umpbuf->secure_id = dri2buf->name;
    umpbuf->pitch     = dri2buf->pitch;
    umpbuf->cpp       = dri2buf->cpp;
    umpbuf->offs      = dri2buf->flags;
    return dri2buf;
}

333
334
335
336
337
338
static DRI2Buffer2Ptr MaliDRI2CreateBuffer(DrawablePtr  pDraw,
                                           unsigned int attachment,
                                           unsigned int format)
{
    ScreenPtr                pScreen  = pDraw->pScreen;
    ScrnInfoPtr              pScrn    = xf86Screens[pScreen->myNum];
339
    DRI2Buffer2Ptr           buffer;
340
    UMPBufferInfoPtr         privates;
341
    ump_handle               handle;
342
    SunxiMaliDRI2           *mali = SUNXI_MALI_UMP_DRI2(pScrn);
343
344
    sunxi_disp_t            *disp = SUNXI_DISP(pScrn);
    Bool                     can_use_overlay = TRUE;
345
    PixmapPtr                pWindowPixmap;
346
    DRI2WindowStatePtr       window_state = NULL;
347
    Bool                     need_window_resize_bug_workaround = FALSE;
348

349
350
351
352
353
    if (!(buffer = calloc(1, sizeof *buffer))) {
        ErrorF("MaliDRI2CreateBuffer: calloc failed\n");
        return NULL;
    }

354
355
356
357
358
359
360
361
362
    if (pDraw->type == DRAWABLE_WINDOW &&
        (pWindowPixmap = pScreen->GetWindowPixmap((WindowPtr)pDraw)))
    {
        DebugMsg("win=%p (w=%d, h=%d, x=%d, y=%d) has backing pix=%p (w=%d, h=%d, screen_x=%d, screen_y=%d)\n",
                 pDraw, pDraw->width, pDraw->height, pDraw->x, pDraw->y,
                 pWindowPixmap, pWindowPixmap->drawable.width, pWindowPixmap->drawable.height,
                 pWindowPixmap->screen_x, pWindowPixmap->screen_y);
    }

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    /* If it is a pixmap, just migrate this pixmap to UMP buffer */
    if (pDraw->type == DRAWABLE_PIXMAP)
    {
        if (!(privates = MigratePixmapToUMP((PixmapPtr)pDraw))) {
            ErrorF("MaliDRI2CreateBuffer: MigratePixmapToUMP failed\n");
            free(buffer);
            return NULL;
        }
        privates->refcount++;
        buffer->attachment    = attachment;
        buffer->driverPrivate = privates;
        buffer->format        = format;
        buffer->flags         = 0;
        buffer->cpp           = pDraw->bitsPerPixel / 8;
        buffer->pitch         = ((PixmapPtr)pDraw)->devKind;
        buffer->name = ump_secure_id_get(privates->handle);
379
380
381
382
383

        DebugMsg("DRI2CreateBuffer pix=%p, buf=%p:%p, att=%d, ump=%d:%d, w=%d, h=%d, cpp=%d, depth=%d\n",
                 pDraw, buffer, privates, attachment, buffer->name, buffer->flags,
                 privates->width, privates->height, buffer->cpp, privates->depth);

384
        return validate_dri2buf(buffer);
385
386
387
388
    }

    if (!(privates = calloc(1, sizeof *privates))) {
        ErrorF("MaliDRI2CreateBuffer: calloc failed\n");
389
390
391
        free(buffer);
        return NULL;
    }
392
    privates->refcount = 1;
393

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
    /* The default common values */
    buffer->attachment    = attachment;
    buffer->driverPrivate = privates;
    buffer->format        = format + 1; /* hack to suppress DRI2 buffers reuse */
    buffer->flags         = 0;
    buffer->cpp           = pDraw->bitsPerPixel / 8;
    /* Stride must be 8 bytes aligned for Mali400 */
    buffer->pitch         = ((buffer->cpp * pDraw->width + 7) / 8) * 8;

    privates->size     = pDraw->height * buffer->pitch;
    privates->width    = pDraw->width;
    privates->height   = pDraw->height;
    privates->depth    = pDraw->depth;

    /* We are not interested in anything other than back buffer requests ... */
    if (attachment != DRI2BufferBackLeft || pDraw->type != DRAWABLE_WINDOW) {
        /* ... and just return some dummy UMP buffer */
        privates->handle = UMP_INVALID_MEMORY_HANDLE;
        privates->addr   = NULL;
413
        buffer->name     = mali->ump_null_secure_id;
414
        return validate_dri2buf(buffer);
415
    }
416
417

    /* We could not allocate disp layer or get framebuffer secure id */
418
    if (!disp || mali->ump_fb_secure_id == UMP_INVALID_SECURE_ID)
419
420
421
        can_use_overlay = FALSE;

    /* Overlay is already used by a different window */
422
    if (mali->pOverlayWin && mali->pOverlayWin != (void *)pDraw)
423
424
        can_use_overlay = FALSE;

425
426
427
428
    /* Don't waste overlay on some strange 1x1 window created by gnome-shell */
    if (pDraw->width == 1 && pDraw->height == 1)
        can_use_overlay = FALSE;

429
    /* TODO: try to support other color depths later */
430
    if (pDraw->bitsPerPixel != 32 && pDraw->bitsPerPixel != 16)
431
432
        can_use_overlay = FALSE;

433
    if (disp && disp->framebuffer_size - disp->gfx_layer_size < privates->size * 2) {
434
435
436
437
438
        DebugMsg("Not enough space in the offscreen framebuffer (wanted %d for DRI2)\n",
                 privates->size);
        can_use_overlay = FALSE;
    }

439
    /* Allocate the DRI2-related window bookkeeping information */
440
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
441
442
443
    if (!window_state) {
        window_state = calloc(1, sizeof(*window_state));
        window_state->pDraw = pDraw;
444
        HASH_ADD_PTR(mali->HashWindowState, pDraw, window_state);
445
        DebugMsg("Allocate DRI2 bookkeeping for window %p\n", pDraw);
446
447
448
449
450
        if (disp && can_use_overlay) {
            /* erase the offscreen part of the framebuffer */
            memset(disp->framebuffer_addr + disp->gfx_layer_size, 0,
                   disp->framebuffer_size - disp->gfx_layer_size);
        }
451
    }
452
    window_state->buf_request_cnt++;
453
454

    /* For odd buffer requests save the window size */
455
    if (window_state->buf_request_cnt & 1) {
456
457
458
459
460
461
        /* remember window size for one buffer */
        window_state->width = pDraw->width;
        window_state->height = pDraw->height;
    }

    /* For even buffer requests check if the window size is still the same */
462
463
    need_window_resize_bug_workaround =
                          !(window_state->buf_request_cnt & 1) &&
464
                          (pDraw->width != window_state->width ||
465
                           pDraw->height != window_state->height) &&
466
                          mali->ump_null_secure_id <= 2;
467

468
    if (can_use_overlay) {
469
470
471
472
473
        /* Release unneeded buffers */
        if (window_state->ump_mem_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_mem_buffer_ptr);
        window_state->ump_mem_buffer_ptr = NULL;

474
475
476
477
        /* Use offscreen part of the framebuffer as an overlay */
        privates->handle = UMP_INVALID_MEMORY_HANDLE;
        privates->addr = disp->framebuffer_addr;

478
        buffer->name = mali->ump_fb_secure_id;
479

480
        if (window_state->buf_request_cnt & 1) {
481
            buffer->flags = disp->gfx_layer_size;
482
483
484
            privates->extra_flags |= UMPBUF_MUST_BE_ODD_FRAME;
        }
        else {
485
            buffer->flags = disp->gfx_layer_size + privates->size;
486
487
            privates->extra_flags |= UMPBUF_MUST_BE_EVEN_FRAME;
        }
488
489
490

        umpbuf_add_to_queue(window_state, privates);
        privates->refcount++;
491

492
        mali->pOverlayWin = (WindowPtr)pDraw;
493

494
495
        if (need_window_resize_bug_workaround) {
            DebugMsg("DRI2 buffers size mismatch detected, trying to recover\n");
496
            buffer->name = mali->ump_alternative_fb_secure_id;
497
498
499
        }
    }
    else {
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
        /* Release unneeded buffers */
        if (window_state->ump_back_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_back_buffer_ptr);
        window_state->ump_back_buffer_ptr = NULL;
        if (window_state->ump_front_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_front_buffer_ptr);
        window_state->ump_front_buffer_ptr = NULL;

        if (need_window_resize_bug_workaround) {
            DebugMsg("DRI2 buffers size mismatch detected, trying to recover\n");

            if (window_state->ump_mem_buffer_ptr)
                unref_ump_buffer_info(window_state->ump_mem_buffer_ptr);
            window_state->ump_mem_buffer_ptr = NULL;

            privates->handle = UMP_INVALID_MEMORY_HANDLE;
            privates->addr   = NULL;
517
            buffer->name     = mali->ump_null_secure_id;
518
519
520
            return validate_dri2buf(buffer);
        }

521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
        /* Reuse the existing UMP buffer if we can */
        if (window_state->ump_mem_buffer_ptr &&
            window_state->ump_mem_buffer_ptr->size == privates->size &&
            window_state->ump_mem_buffer_ptr->depth == privates->depth &&
            window_state->ump_mem_buffer_ptr->width == privates->width &&
            window_state->ump_mem_buffer_ptr->height == privates->height) {

            free(privates);

            privates = window_state->ump_mem_buffer_ptr;
            privates->refcount++;
            buffer->driverPrivate = privates;
            buffer->name = ump_secure_id_get(privates->handle);

            DebugMsg("Reuse the already allocated UMP buffer %p, ump=%d\n",
                     privates, buffer->name);
537
            return validate_dri2buf(buffer);
538
539
        }

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
        /* Allocate UMP memory buffer */
#ifdef HAVE_LIBUMP_CACHE_CONTROL
        privates->handle = ump_ref_drv_allocate(privates->size,
                                    UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR |
                                    UMP_REF_DRV_CONSTRAINT_USE_CACHE);
        ump_cache_operations_control(UMP_CACHE_OP_START);
        ump_switch_hw_usage_secure_id(ump_secure_id_get(privates->handle),
                                      UMP_USED_BY_MALI);
        ump_cache_operations_control(UMP_CACHE_OP_FINISH);
#else
        privates->handle = ump_ref_drv_allocate(privates->size,
                                    UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
#endif
        if (privates->handle == UMP_INVALID_MEMORY_HANDLE) {
            ErrorF("Failed to allocate UMP buffer (size=%d)\n",
                   (int)privates->size);
        }
        privates->addr = ump_mapped_pointer_get(privates->handle);
        buffer->name = ump_secure_id_get(privates->handle);
        buffer->flags = 0;
560
561
562
563
564
565
566

        /* Replace the old UMP buffer with the newly allocated one */
        if (window_state->ump_mem_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_mem_buffer_ptr);

        window_state->ump_mem_buffer_ptr = privates;
        privates->refcount++;
567
568
    }

569
570
571
    DebugMsg("DRI2CreateBuffer win=%p, buf=%p:%p, att=%d, ump=%d:%d, w=%d, h=%d, cpp=%d, depth=%d\n",
             pDraw, buffer, privates, attachment, buffer->name, buffer->flags,
             privates->width, privates->height, buffer->cpp, privates->depth);
572

573
    return validate_dri2buf(buffer);
574
575
576
577
}

static void MaliDRI2DestroyBuffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
{
578
    UMPBufferInfoPtr privates;
579
580
    ScreenPtr pScreen = pDraw->pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
581
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
582

583
584
    if (mali->pOverlayDirtyUMP == buffer->driverPrivate)
        mali->pOverlayDirtyUMP = NULL;
585

586
587
588
    DebugMsg("DRI2DestroyBuffer %s=%p, buf=%p:%p, att=%d\n",
             pDraw->type == DRAWABLE_WINDOW ? "win" : "pix",
             pDraw, buffer, buffer->driverPrivate, buffer->attachment);
589
590

    if (buffer != NULL) {
591
        privates = (UMPBufferInfoPtr)buffer->driverPrivate;
592
        unref_ump_buffer_info(privates);
593
594
595
596
597
        free(buffer);
    }
}

/* Do ordinary copy */
598
599
600
static void MaliDRI2CopyRegion_copy(DrawablePtr      pDraw,
                                    RegionPtr        pRegion,
                                    UMPBufferInfoPtr umpbuf)
601
602
603
604
{
    GCPtr pGC;
    RegionPtr copyRegion;
    ScreenPtr pScreen = pDraw->pScreen;
605
    UMPBufferInfoPtr privates;
606
607
608
    PixmapPtr pScratchPixmap;

#ifdef HAVE_LIBUMP_CACHE_CONTROL
609
    if (umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
610
611
        /* That's a normal UMP allocation, not a wrapped framebuffer */
        ump_cache_operations_control(UMP_CACHE_OP_START);
612
        ump_switch_hw_usage_secure_id(umpbuf->secure_id, UMP_USED_BY_CPU);
613
614
615
616
617
618
        ump_cache_operations_control(UMP_CACHE_OP_FINISH);
    }
#endif

    pGC = GetScratchGC(pDraw->depth, pScreen);
    pScratchPixmap = GetScratchPixmapHeader(pScreen,
619
620
621
622
                                            umpbuf->width, umpbuf->height,
                                            umpbuf->depth, umpbuf->cpp * 8,
                                            umpbuf->pitch,
                                            umpbuf->addr + umpbuf->offs);
623
624
625
626
627
628
629
630
631
632
    copyRegion = REGION_CREATE(pScreen, NULL, 0);
    REGION_COPY(pScreen, copyRegion, pRegion);
    (*pGC->funcs->ChangeClip)(pGC, CT_REGION, copyRegion, 0);
    ValidateGC(pDraw, pGC);
    (*pGC->ops->CopyArea)((DrawablePtr)pScratchPixmap, pDraw, pGC, 0, 0,
                          pDraw->width, pDraw->height, 0, 0);
    FreeScratchPixmapHeader(pScratchPixmap);
    FreeScratchGC(pGC);

#ifdef HAVE_LIBUMP_CACHE_CONTROL
633
    if (umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
634
635
        /* That's a normal UMP allocation, not a wrapped framebuffer */
        ump_cache_operations_control(UMP_CACHE_OP_START);
636
        ump_switch_hw_usage_secure_id(umpbuf->secure_id, UMP_USED_BY_MALI);
637
638
639
640
641
642
643
644
        ump_cache_operations_control(UMP_CACHE_OP_FINISH);
    }
#endif
}

static void FlushOverlay(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
645
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
646

647
    if (mali->pOverlayWin && mali->pOverlayDirtyUMP) {
648
        DebugMsg("Flushing overlay content from DRI2 buffer to window\n");
649
        MaliDRI2CopyRegion_copy((DrawablePtr)mali->pOverlayWin,
650
                                &pScreen->root->winSize,
651
652
                                mali->pOverlayDirtyUMP);
        mali->pOverlayDirtyUMP = NULL;
653
654
655
    }
}

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
#ifdef DEBUG_WITH_RGB_PATTERN
static void check_rgb_pattern(DRI2WindowStatePtr window_state,
                              UMPBufferInfoPtr umpbuf)
{
    switch (*(uint32_t *)(umpbuf->addr + umpbuf->offs)) {
    case 0xFFFF0000:
        if (window_state->rgb_pattern_state == 0) {
            ErrorF("starting RGB pattern with [Red]\n");
        }
        else if (window_state->rgb_pattern_state != 'B') {
            ErrorF("warning - transition to [Red] not from [Blue]\n");
        }
        window_state->rgb_pattern_state = 'R';
        break;
    case 0xFF00FF00:
        if (window_state->rgb_pattern_state == 0) {
            ErrorF("starting RGB pattern with [Green]\n");
        }
        else if (window_state->rgb_pattern_state != 'R') {
            ErrorF("warning - transition to [Green] not from [Red]\n");
        }
        window_state->rgb_pattern_state = 'G';
        break;
    case 0xFF0000FF:
        if (window_state->rgb_pattern_state == 0) {
            ErrorF("starting RGB pattern with [Blue]\n");
        }
        else if (window_state->rgb_pattern_state != 'G') {
            ErrorF("warning - transition to [Blue] not from [Green]\n");
        }
        window_state->rgb_pattern_state = 'B';
        break;
    default:
        if (window_state->rgb_pattern_state != 0) {
            ErrorF("stopping RGB pattern\n");
        }
        window_state->rgb_pattern_state = 0;
    }
}
#endif

697
698
699
700
701
702
703
static void MaliDRI2CopyRegion(DrawablePtr   pDraw,
                               RegionPtr     pRegion,
                               DRI2BufferPtr pDstBuffer,
                               DRI2BufferPtr pSrcBuffer)
{
    ScreenPtr pScreen = pDraw->pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
704
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
705
    UMPBufferInfoPtr umpbuf;
706
    sunxi_disp_t *disp = SUNXI_DISP(xf86Screens[pScreen->myNum]);
707
    DRI2WindowStatePtr window_state = NULL;
708
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
709
710
711
712
713
714
715
716
717
718
719
720

    if (pDraw->type == DRAWABLE_PIXMAP) {
        DebugMsg("MaliDRI2CopyRegion has been called for pixmap %p\n", pDraw);
        return;
    }

    if (!window_state) {
        DebugMsg("MaliDRI2CopyRegion: can't find window %p in the hash\n", pDraw);
        return;
    }

    /* Try to fetch a new UMP buffer from the queue */
721
722
    umpbuf = umpbuf_fetch_from_queue(window_state);

723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
    /*
     * In the case if the queue of incoming buffers is already empty and
     * we are just swapping two allocated DRI2 buffers, we can do an extra
     * sanity check. The normal behaviour is that the back buffer may change,
     * and the front buffer may not. But if this is not the case, we need to
     * take some corrective actions here.
     */
    if (!umpbuf && window_state->ump_front_buffer_ptr &&
                   window_state->ump_front_buffer_ptr->addr &&
                   window_state->ump_back_buffer_ptr &&
                   window_state->ump_back_buffer_ptr->addr &&
                   window_state->ump_front_buffer_ptr != window_state->ump_back_buffer_ptr) {

        UMPBufferInfoPtr ump_front = window_state->ump_front_buffer_ptr;
        UMPBufferInfoPtr ump_back = window_state->ump_back_buffer_ptr;

        Bool front_modified = ump_front->has_checksum && !test_ump_checksum(ump_front);
        Bool back_modified = ump_back->has_checksum && !test_ump_checksum(ump_back);

        ump_front->has_checksum = FALSE;
        ump_back->has_checksum = FALSE;

        if (back_modified && !front_modified) {
            /* That's normal, we have successfully passed this check */
            ump_back->extra_flags |= UMPBUF_PASSED_ORDER_CHECK;
            ump_front->extra_flags |= UMPBUF_PASSED_ORDER_CHECK;
        }
        else if (front_modified) {
            /* That's bad, the order of buffers is messed up, but we can exchange them */
            UMPBufferInfoPtr tmp               = window_state->ump_back_buffer_ptr;
            window_state->ump_back_buffer_ptr  = window_state->ump_front_buffer_ptr;
            window_state->ump_front_buffer_ptr = tmp;
            DebugMsg("Unexpected modification of the front buffer detected.\n");
        }
        else {
            /* Not enough information to make a decision yet */
        }
    }

762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
    /*
     * Swap back and front buffers. But also ensure that the buffer
     * flags UMPBUF_MUST_BE_ODD_FRAME and UMPBUF_MUST_BE_EVEN_FRAME
     * are respected. In the case if swapping the buffers would result
     * in fetching the UMP buffer from the queue in the wrong order,
     * just skip the swap. This is a hack, which causes some temporary
     * glitch when resizing windows, but prevents a bigger problem.
     */
    if (!umpbuf || (!((umpbuf->extra_flags & UMPBUF_MUST_BE_ODD_FRAME) &&
                     (window_state->buf_swap_cnt & 1)) &&
                    !((umpbuf->extra_flags & UMPBUF_MUST_BE_EVEN_FRAME) &&
                     !(window_state->buf_swap_cnt & 1)))) {
        UMPBufferInfoPtr tmp               = window_state->ump_back_buffer_ptr;
        window_state->ump_back_buffer_ptr  = window_state->ump_front_buffer_ptr;
        window_state->ump_front_buffer_ptr = tmp;
        window_state->buf_swap_cnt++;
778
779
    }

780
781
782
783
784
785
786
787
788
    /* Try to replace the front buffer with a new UMP buffer from the queue */
    if (umpbuf) {
        if (window_state->ump_front_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_front_buffer_ptr);
        window_state->ump_front_buffer_ptr = umpbuf;
    }
    else {
        umpbuf = window_state->ump_front_buffer_ptr;
    }
789
790
791

    if (!umpbuf)
        umpbuf = window_state->ump_mem_buffer_ptr;
792

793
    if (!umpbuf || !umpbuf->addr)
794
795
        return;

796
797
798
799
#ifdef DEBUG_WITH_RGB_PATTERN
    check_rgb_pattern(window_state, umpbuf);
#endif

800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
    /*
     * Here we can calculate checksums over randomly sampled bytes from UMP
     * buffers in order to check later whether they had been modified. This
     * is skipped if the buffers have UMPBUF_PASSED_ORDER_CHECK flag set.
     */
    if (window_state->ump_front_buffer_ptr && window_state->ump_front_buffer_ptr->addr &&
        window_state->ump_back_buffer_ptr && window_state->ump_back_buffer_ptr->addr &&
        window_state->ump_front_buffer_ptr != window_state->ump_back_buffer_ptr) {

        UMPBufferInfoPtr ump_front = window_state->ump_front_buffer_ptr;
        UMPBufferInfoPtr ump_back = window_state->ump_back_buffer_ptr;

        if (!(ump_front->extra_flags & UMPBUF_PASSED_ORDER_CHECK))
            save_ump_checksum(ump_front, window_state->buf_swap_cnt);
        if (!(ump_back->extra_flags & UMPBUF_PASSED_ORDER_CHECK))
            save_ump_checksum(ump_back, window_state->buf_swap_cnt);
    }

818
819
    UpdateOverlay(pScreen);

820
    if (!mali->bOverlayWinEnabled || umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
821
        MaliDRI2CopyRegion_copy(pDraw, pRegion, umpbuf);
822
        mali->pOverlayDirtyUMP = NULL;
823
824
825
        return;
    }

826
    /* Mark the overlay as "dirty" and remember the last up to date UMP buffer */
827
    mali->pOverlayDirtyUMP = umpbuf;
828
829
830

    /* Activate the overlay */
    sunxi_layer_set_output_window(disp, pDraw->x, pDraw->y, pDraw->width, pDraw->height);
831
832
    sunxi_layer_set_rgb_input_buffer(disp, umpbuf->cpp * 8, umpbuf->offs,
                                     umpbuf->width, umpbuf->height, umpbuf->pitch / 4);
833
    sunxi_layer_show(disp);
834

835
    if (mali->bSwapbuffersWait) {
836
837
838
        /* FIXME: blocking here for up to 1/60 second is not nice */
        sunxi_wait_for_vsync(disp);
    }
839
840
841
842
843
844
845
}

/************************************************************************/

static void UpdateOverlay(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
846
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
847
848
    sunxi_disp_t *disp = SUNXI_DISP(pScrn);

849
    if (!mali->pOverlayWin || !disp)
850
851
        return;

852
    /* Disable overlays if the hardware cursor is not in use */
853
854
    if (!mali->bHardwareCursorIsInUse) {
        if (mali->bOverlayWinEnabled) {
855
856
            DebugMsg("Disabling overlay (no hardware cursor)\n");
            sunxi_layer_hide(disp);
857
            mali->bOverlayWinEnabled = FALSE;
858
859
860
861
        }
        return;
    }

862
    /* If the window is not mapped, make sure that the overlay is disabled */
863
    if (!mali->pOverlayWin->mapped)
864
    {
865
        if (mali->bOverlayWinEnabled) {
866
867
            DebugMsg("Disabling overlay (window is not mapped)\n");
            sunxi_layer_hide(disp);
868
            mali->bOverlayWinEnabled = FALSE;
869
870
871
872
873
874
875
876
877
878
        }
        return;
    }

    /*
     * Walk the windows tree to get the obscured/unobscured status of
     * the window (because we can't rely on self->pOverlayWin->visibility
     * for redirected windows).
     */

879
880
881
    mali->bWalkingAboveOverlayWin = FALSE;
    mali->bOverlayWinOverlapped = FALSE;
    FancyTraverseTree(pScreen->root, WindowWalker, mali);
882
883

    /* If the window got overlapped -> disable overlay */
884
    if (mali->bOverlayWinOverlapped && mali->bOverlayWinEnabled) {
885
886
        DebugMsg("Disabling overlay (window is obscured)\n");
        FlushOverlay(pScreen);
887
        mali->bOverlayWinEnabled = FALSE;
888
889
890
891
892
        sunxi_layer_hide(disp);
        return;
    }

    /* If the window got moved -> update overlay position */
893
894
895
    if (!mali->bOverlayWinOverlapped &&
        (mali->overlay_x != mali->pOverlayWin->drawable.x ||
         mali->overlay_y != mali->pOverlayWin->drawable.y))
896
    {
897
898
899
900
901
902
903
904
        mali->overlay_x = mali->pOverlayWin->drawable.x;
        mali->overlay_y = mali->pOverlayWin->drawable.y;

        sunxi_layer_set_output_window(disp, mali->pOverlayWin->drawable.x,
                                      mali->pOverlayWin->drawable.y,
                                      mali->pOverlayWin->drawable.width,
                                      mali->pOverlayWin->drawable.height);
        DebugMsg("Move overlay to (%d, %d)\n", mali->overlay_x, mali->overlay_y);
905
906
907
    }

    /* If the window got unobscured -> enable overlay */
908
    if (!mali->bOverlayWinOverlapped && !mali->bOverlayWinEnabled) {
909
        DebugMsg("Enabling overlay (window is fully unobscured)\n");
910
        mali->bOverlayWinEnabled = TRUE;
911
912
913
914
915
916
917
918
919
        sunxi_layer_show(disp);
    }
}

static Bool
DestroyWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
920
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
921
    Bool ret;
922
923
    DrawablePtr pDraw = &pWin->drawable;
    DRI2WindowStatePtr window_state = NULL;
924
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
925
926
    if (window_state) {
        DebugMsg("Free DRI2 bookkeeping for window %p\n", pWin);
927
        HASH_DEL(mali->HashWindowState, window_state);
928
929
        if (window_state->ump_mem_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_mem_buffer_ptr);
930
931
932
933
        if (window_state->ump_back_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_back_buffer_ptr);
        if (window_state->ump_front_buffer_ptr)
            unref_ump_buffer_info(window_state->ump_front_buffer_ptr);
934
935
        free(window_state);
    }
936

937
    if (pWin == mali->pOverlayWin) {
938
939
        sunxi_disp_t *disp = SUNXI_DISP(pScrn);
        sunxi_layer_hide(disp);
940
        mali->pOverlayWin = NULL;
941
942
943
        DebugMsg("DestroyWindow %p\n", pWin);
    }

944
    pScreen->DestroyWindow = mali->DestroyWindow;
945
    ret = (*pScreen->DestroyWindow) (pWin);
946
    mali->DestroyWindow = pScreen->DestroyWindow;
947
948
949
950
951
952
953
954
955
956
    pScreen->DestroyWindow = DestroyWindow;

    return ret;
}

static void
PostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind)
{
    ScreenPtr pScreen = pWin ? pWin->drawable.pScreen : pLayerWin->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
957
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
958

959
960
    if (mali->PostValidateTree) {
        pScreen->PostValidateTree = mali->PostValidateTree;
961
        (*pScreen->PostValidateTree) (pWin, pLayerWin, kind);
962
        mali->PostValidateTree = pScreen->PostValidateTree;
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
        pScreen->PostValidateTree = PostValidateTree;
    }

    UpdateOverlay(pScreen);
}

/*
 * If somebody is trying to make a screenshot, we want to have DRI2 buffer
 * flushed.
 */
static void
GetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
         unsigned int format, unsigned long planeMask, char *d)
{
    ScreenPtr pScreen = pDrawable->pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
979
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
980
981

    /* FIXME: more precise check */
982
    if (mali->pOverlayDirtyUMP)
983
984
        FlushOverlay(pScreen);

985
986
    if (mali->GetImage) {
        pScreen->GetImage = mali->GetImage;
987
        (*pScreen->GetImage) (pDrawable, x, y, w, h, format, planeMask, d);
988
        mali->GetImage = pScreen->GetImage;
989
990
991
992
        pScreen->GetImage = GetImage;
    }
}

993
994
995
996
997
static Bool
DestroyPixmap(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
998
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
999
1000
    Bool result;
    UMPBufferInfoPtr umpbuf;
1001
    HASH_FIND_PTR(mali->HashPixmapToUMP, &pPixmap, umpbuf);
1002
1003
1004
1005
1006
1007
1008

    if (umpbuf) {
        DebugMsg("DestroyPixmap %p for migrated UMP pixmap (UMP buffer=%p)\n", pPixmap, umpbuf);

        pPixmap->devKind = umpbuf->BackupDevKind;
        pPixmap->devPrivate.ptr = umpbuf->BackupDevPrivatePtr;

1009
        HASH_DEL(mali->HashPixmapToUMP, umpbuf);
1010
1011
        umpbuf->pPixmap = NULL;
        unref_ump_buffer_info(umpbuf);
1012
1013
    }

1014
    pScreen->DestroyPixmap = mali->DestroyPixmap;
1015
    result = (*pScreen->DestroyPixmap) (pPixmap);
1016
    mali->DestroyPixmap = pScreen->DestroyPixmap;
1017
1018
1019
1020
1021
1022
    pScreen->DestroyPixmap = DestroyPixmap;


    return result;
}

1023
1024
static void EnableHWCursor(ScrnInfoPtr pScrn)
{
1025
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
1026
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1027

1028
    if (!mali->bHardwareCursorIsInUse) {
1029
        DebugMsg("EnableHWCursor\n");
1030
        mali->bHardwareCursorIsInUse = TRUE;
1031
1032
    }

1033
1034
    UpdateOverlay(screenInfo.screens[pScrn->scrnIndex]);

1035
1036
    if (mali->EnableHWCursor) {
        hwc->EnableHWCursor = mali->EnableHWCursor;
1037
        (*hwc->EnableHWCursor) (pScrn);
1038
        mali->EnableHWCursor = hwc->EnableHWCursor;
1039
1040
1041
1042
1043
1044
        hwc->EnableHWCursor = EnableHWCursor;
    }
}

static void DisableHWCursor(ScrnInfoPtr pScrn)
{
1045
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
1046
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1047

1048
1049
    if (mali->bHardwareCursorIsInUse) {
        mali->bHardwareCursorIsInUse = FALSE;
1050
1051
1052
        DebugMsg("DisableHWCursor\n");
    }

1053
1054
    UpdateOverlay(screenInfo.screens[pScrn->scrnIndex]);

1055
1056
    if (mali->DisableHWCursor) {
        hwc->DisableHWCursor = mali->DisableHWCursor;
1057
        (*hwc->DisableHWCursor) (pScrn);
1058
        mali->DisableHWCursor = hwc->DisableHWCursor;
1059
1060
1061
1062
        hwc->DisableHWCursor = DisableHWCursor;
    }
}

1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
static unsigned long ump_get_size_from_secure_id(ump_secure_id secure_id)
{
    unsigned long size;
    ump_handle handle;
    if (secure_id == UMP_INVALID_SECURE_ID)
        return 0;
    handle = ump_handle_create_from_secure_id(secure_id);
    if (handle == UMP_INVALID_MEMORY_HANDLE)
        return 0;
    size = ump_size_get(handle);
    ump_reference_release(handle);
    return size;
}

1077
1078
1079
SunxiMaliDRI2 *SunxiMaliDRI2_Init(ScreenPtr pScreen,
                                  Bool      bUseOverlay,
                                  Bool      bSwapbuffersWait)
1080
1081
1082
{
    int drm_fd;
    DRI2InfoRec info;
1083
    SunxiMaliDRI2 *mali;
1084
1085
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    sunxi_disp_t *disp = SUNXI_DISP(pScrn);
1086

1087
1088
1089
1090
1091
    if (!xf86LoadKernelModule("mali"))
        xf86DrvMsg(pScreen->myNum, X_INFO, "can't load 'mali' kernel module\n");
    if (!xf86LoadKernelModule("mali_drm"))
        xf86DrvMsg(pScreen->myNum, X_INFO, "can't load 'mali_drm' kernel module\n");

1092
    if (!xf86LoadSubModule(xf86Screens[pScreen->myNum], "dri2"))
1093
        return NULL;
1094
1095
1096

    if ((drm_fd = drmOpen("mali_drm", NULL)) < 0) {
        ErrorF("SunxiMaliDRI2_Init: drmOpen failed!\n");
1097
        return NULL;
1098
1099
1100
1101
1102
    }

    if (ump_open() != UMP_OK) {
        drmClose(drm_fd);
        ErrorF("SunxiMaliDRI2_Init: ump_open() != UMP_OK\n");
1103
        return NULL;
1104
1105
    }

1106
    if (!(mali = calloc(1, sizeof(SunxiMaliDRI2)))) {
1107
1108
1109
1110
        ErrorF("SunxiMaliDRI2_Init: calloc failed\n");
        return NULL;
    }

1111
1112
    mali->ump_alternative_fb_secure_id = UMP_INVALID_SECURE_ID;

1113
1114
    if (disp && bUseOverlay) {
        /* Try to get UMP framebuffer wrapper with secure id 1 */
1115
        ioctl(disp->fd_fb, GET_UMP_SECURE_ID_BUF1, &mali->ump_alternative_fb_secure_id);
1116
        /* Try to allocate a small dummy UMP buffer to secure id 2 */
1117
1118
1119
1120
        mali->ump_null_handle1 = ump_ref_drv_allocate(4096, UMP_REF_DRV_CONSTRAINT_NONE);
        if (mali->ump_null_handle1 != UMP_INVALID_MEMORY_HANDLE)
            mali->ump_null_secure_id = ump_secure_id_get(mali->ump_null_handle1);
        mali->ump_null_handle2 = UMP_INVALID_MEMORY_HANDLE;
1121
        /* Try to get UMP framebuffer for the secure id other than 1 and 2 */
1122
1123
        if (ioctl(disp->fd_fb, GET_UMP_SECURE_ID_SUNXI_FB, &mali->ump_fb_secure_id) ||
                                   mali->ump_fb_secure_id == UMP_INVALID_SECURE_ID) {
1124
1125
            xf86DrvMsg(pScreen->myNum, X_INFO,
                  "GET_UMP_SECURE_ID_SUNXI_FB ioctl failed, overlays can't be used\n");
1126
            mali->ump_fb_secure_id = UMP_INVALID_SECURE_ID;
1127
        }
1128
1129
1130
1131
1132
1133
1134
1135
        if (mali->ump_alternative_fb_secure_id == UMP_INVALID_SECURE_ID ||
            ump_get_size_from_secure_id(mali->ump_alternative_fb_secure_id) !=
                                          disp->framebuffer_size) {
            xf86DrvMsg(pScreen->myNum, X_INFO,
                  "UMP does not wrap the whole framebuffer, overlays can't be used\n");
            mali->ump_fb_secure_id = UMP_INVALID_SECURE_ID;
            mali->ump_alternative_fb_secure_id = UMP_INVALID_SECURE_ID;
        }
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
        if (disp->framebuffer_size - disp->gfx_layer_size <
                                                 disp->xres * disp->yres * 4 * 2) {
            int needed_fb_num = (disp->xres * disp->yres * 4 * 2 +
                                 disp->gfx_layer_size - 1) / disp->gfx_layer_size + 1;
            xf86DrvMsg(pScreen->myNum, X_INFO,
                "tear-free zero-copy double buffering needs more video memory\n");
            xf86DrvMsg(pScreen->myNum, X_INFO,
                "please set fb0_framebuffer_num >= %d in the fex file\n", needed_fb_num);
            xf86DrvMsg(pScreen->myNum, X_INFO,
                "and sunxi_fb_mem_reserve >= %d in the kernel cmdline\n",
                (needed_fb_num * disp->gfx_layer_size + 1024 * 1024 - 1) / (1024 * 1024));
        }
1148
1149
1150
    }
    else {
        /* Try to allocate small dummy UMP buffers to secure id 1 and 2 */
1151
1152
1153
1154
        mali->ump_null_handle1 = ump_ref_drv_allocate(4096, UMP_REF_DRV_CONSTRAINT_NONE);
        if (mali->ump_null_handle1 != UMP_INVALID_MEMORY_HANDLE)
            mali->ump_null_secure_id = ump_secure_id_get(mali->ump_null_handle1);
        mali->ump_null_handle2 = ump_ref_drv_allocate(4096, UMP_REF_DRV_CONSTRAINT_NONE);
1155
1156
        /* No UMP wrappers for the framebuffer are available */
        mali->ump_fb_secure_id = UMP_INVALID_SECURE_ID;
1157
1158
    }

1159
    if (mali->ump_null_secure_id > 2) {
1160
1161
1162
1163
        xf86DrvMsg(pScreen->myNum, X_INFO,
                   "warning, can't workaround Mali r3p0 window resize bug\n");
    }

1164
    if (disp && mali->ump_fb_secure_id != UMP_INVALID_SECURE_ID)
1165
1166
1167
1168
1169
1170
1171
1172
1173
        xf86DrvMsg(pScreen->myNum, X_INFO,
              "enabled display controller hardware overlays for DRI2\n");
    else if (bUseOverlay)
        xf86DrvMsg(pScreen->myNum, X_INFO,
              "display controller hardware overlays can't be used for DRI2\n");
    else
        xf86DrvMsg(pScreen->myNum, X_INFO,
              "display controller hardware overlays are not used for DRI2\n");

1174
1175
1176
    xf86DrvMsg(pScreen->myNum, X_INFO, "Wait on SwapBuffers? %s\n",
               bSwapbuffersWait ? "enabled" : "disabled");

1177
1178
    info.version = 3;

1179
    info.driverName = "lima";
1180
    info.deviceName = drmGetDeviceNameFromFd(drm_fd);
1181
1182
1183
1184
1185
1186
1187
1188
    info.fd = drm_fd;

    info.CreateBuffer = MaliDRI2CreateBuffer;
    info.DestroyBuffer = MaliDRI2DestroyBuffer;
    info.CopyRegion = MaliDRI2CopyRegion;

    if (!DRI2ScreenInit(pScreen, &info)) {
        drmClose(drm_fd);
1189
        free(mali);
1190
1191
1192
        return NULL;
    }
    else {
1193
        SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1194
1195

        /* Wrap the current DestroyWindow function */
1196
        mali->DestroyWindow = pScreen->DestroyWindow;
1197
1198
        pScreen->DestroyWindow = DestroyWindow;
        /* Wrap the current PostValidateTree function */
1199
        mali->PostValidateTree = pScreen->PostValidateTree;
1200
1201
        pScreen->PostValidateTree = PostValidateTree;
        /* Wrap the current GetImage function */
1202
        mali->GetImage = pScreen->GetImage;
1203
        pScreen->GetImage = GetImage;
1204
        /* Wrap the current DestroyPixmap function */
1205
        mali->DestroyPixmap = pScreen->DestroyPixmap;
1206
        pScreen->DestroyPixmap = DestroyPixmap;
1207

1208
1209
        /* Wrap hardware cursor callback functions */
        if (hwc) {
1210
            mali->EnableHWCursor = hwc->EnableHWCursor;
1211
            hwc->EnableHWCursor = EnableHWCursor;
1212
            mali->DisableHWCursor = hwc->DisableHWCursor;
1213
1214
1215
            hwc->DisableHWCursor = DisableHWCursor;
        }

1216
1217
1218
        mali->drm_fd = drm_fd;
        mali->bSwapbuffersWait = bSwapbuffersWait;
        return mali;
1219
1220
1221
1222
1223
1224
    }
}

void SunxiMaliDRI2_Close(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1225
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
1226
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1227
1228

    /* Unwrap functions */
1229
1230
1231
1232
    pScreen->DestroyWindow    = mali->DestroyWindow;
    pScreen->PostValidateTree = mali->PostValidateTree;
    pScreen->GetImage         = mali->GetImage;
    pScreen->DestroyPixmap    = mali->DestroyPixmap;
1233

1234
    if (hwc) {
1235
1236
        hwc->EnableHWCursor  = mali->EnableHWCursor;
        hwc->DisableHWCursor = mali->DisableHWCursor;
1237
1238
    }

1239
1240
1241
1242
    if (mali->ump_null_handle1 != UMP_INVALID_MEMORY_HANDLE)
        ump_reference_release(mali->ump_null_handle1);
    if (mali->ump_null_handle2 != UMP_INVALID_MEMORY_HANDLE)
        ump_reference_release(mali->ump_null_handle2);
1243

1244
    drmClose(mali->drm_fd);
1245
1246
    DRI2CloseScreen(pScreen);
}