sunxi_mali_ump_dri2.c 41.4 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
/*
 * 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>

35
36
#include <sys/types.h>
#include <sys/stat.h>
37
#include <sys/ioctl.h>
38
39
#include <fcntl.h>
#include <unistd.h>
40
41

#include "xorgVersion.h"
42
#include "xf86_OSproc.h"
43
44
45
46
47
48
49
50
#include "xf86.h"
#include "xf86drm.h"
#include "dri2.h"
#include "damage.h"
#include "fb.h"

#include "fbdev_priv.h"
#include "sunxi_disp.h"
51
#include "sunxi_disp_hwcursor.h"
52
53
54
#include "sunxi_disp_ioctl.h"
#include "sunxi_mali_ump_dri2.h"

55
56
57
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a)  (sizeof((a)) / sizeof((a)[0]))
#endif
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

/*
 * 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)
{
109
    SunxiMaliDRI2 *mali = (SunxiMaliDRI2 *)value;
110

111
    if (mali->bWalkingAboveOverlayWin) {
112
113
114
115
        if (pWin->mapped && pWin->realized && pWin->drawable.class != InputOnly) {
            BoxRec sboxrec1;
            BoxPtr sbox1 = WindowExtents(pWin, &sboxrec1);
            BoxRec sboxrec2;
116
            BoxPtr sbox2 = WindowExtents(mali->pOverlayWin, &sboxrec2);
117
            if (BOXES_OVERLAP(sbox1, sbox2)) {
118
                mali->bOverlayWinOverlapped = TRUE;
119
120
121
122
123
124
125
                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;
            }
        }
    }
126
127
    else if (pWin == mali->pOverlayWin) {
        mali->bWalkingAboveOverlayWin = TRUE;
128
129
130
131
132
    }

    return WT_WALKCHILDREN;
}

133
134
135
136
137
138
/* Migrate pixmap to UMP buffer */
static UMPBufferInfoPtr
MigratePixmapToUMP(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
139
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
140
141
142
143
    UMPBufferInfoPtr umpbuf;
    size_t pitch = ((pPixmap->devKind + 7) / 8) * 8;
    size_t size = pitch * pPixmap->drawable.height;

144
    HASH_FIND_PTR(mali->HashPixmapToUMP, &pPixmap, umpbuf);
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
188

    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;

189
    HASH_ADD_PTR(mali->HashPixmapToUMP, pPixmap, umpbuf);
190
191
192
193
194

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

195
196
static void UpdateOverlay(ScreenPtr pScreen);

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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);
    }
}

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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;
}

243
244
245
246
247
248
249
250
251
252
253
/* 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;
}

254
255
256
257
258
259
static DRI2Buffer2Ptr MaliDRI2CreateBuffer(DrawablePtr  pDraw,
                                           unsigned int attachment,
                                           unsigned int format)
{
    ScreenPtr                pScreen  = pDraw->pScreen;
    ScrnInfoPtr              pScrn    = xf86Screens[pScreen->myNum];
260
    DRI2Buffer2Ptr           buffer;
261
    UMPBufferInfoPtr         privates;
262
    ump_handle               handle;
263
    SunxiMaliDRI2           *mali = SUNXI_MALI_UMP_DRI2(pScrn);
264
265
    sunxi_disp_t            *disp = SUNXI_DISP(pScrn);
    Bool                     can_use_overlay = TRUE;
266
    PixmapPtr                pWindowPixmap;
267
    DRI2WindowStatePtr       window_state = NULL;
268
    Bool                     need_window_resize_bug_workaround = FALSE;
269

270
271
272
273
274
    if (!(buffer = calloc(1, sizeof *buffer))) {
        ErrorF("MaliDRI2CreateBuffer: calloc failed\n");
        return NULL;
    }

275
276
277
278
279
280
281
282
283
    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);
    }

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
    /* 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);
300
301
302
303
304

        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);

305
        return validate_dri2buf(buffer);
306
307
308
309
    }

    if (!(privates = calloc(1, sizeof *privates))) {
        ErrorF("MaliDRI2CreateBuffer: calloc failed\n");
310
311
312
        free(buffer);
        return NULL;
    }
313
    privates->refcount = 1;
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
    /* 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;
334
        buffer->name     = mali->ump_null_secure_id;
335
        return validate_dri2buf(buffer);
336
    }
337
338

    /* We could not allocate disp layer or get framebuffer secure id */
339
    if (!disp || mali->ump_fb_odd_secure_id == UMP_INVALID_SECURE_ID)
340
341
342
        can_use_overlay = FALSE;

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

346
347
348
349
    /* Don't waste overlay on some strange 1x1 window created by gnome-shell */
    if (pDraw->width == 1 && pDraw->height == 1)
        can_use_overlay = FALSE;

350
    /* TODO: try to support other color depths later */
351
    if (pDraw->bitsPerPixel != 32 && pDraw->bitsPerPixel != 16)
352
353
        can_use_overlay = FALSE;

354
    if (disp && disp->framebuffer_size - disp->gfx_layer_size < privates->size * 2) {
355
356
357
358
359
        DebugMsg("Not enough space in the offscreen framebuffer (wanted %d for DRI2)\n",
                 privates->size);
        can_use_overlay = FALSE;
    }

360
    /* Allocate the DRI2-related window bookkeeping information */
361
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
362
363
364
    if (!window_state) {
        window_state = calloc(1, sizeof(*window_state));
        window_state->pDraw = pDraw;
365
        HASH_ADD_PTR(mali->HashWindowState, pDraw, window_state);
366
        DebugMsg("Allocate DRI2 bookkeeping for window %p\n", pDraw);
367
368
369
370
371
        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);
        }
372
    }
373
    window_state->buf_request_cnt++;
374
375

    /* For odd buffer requests save the window size */
376
    if (window_state->buf_request_cnt & 1) {
377
378
379
380
381
382
        /* 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 */
383
384
    need_window_resize_bug_workaround =
                          !(window_state->buf_request_cnt & 1) &&
385
                          (pDraw->width != window_state->width ||
386
                           pDraw->height != window_state->height) &&
387
                          mali->has_window_resize_bug;
388

389
390
391
392
393
    if (can_use_overlay) {
        /* Use offscreen part of the framebuffer as an overlay */
        privates->handle = UMP_INVALID_MEMORY_HANDLE;
        privates->addr = disp->framebuffer_addr;

394
        if (window_state->buf_request_cnt & 1) {
395
            buffer->flags = disp->gfx_layer_size;
396
            privates->extra_flags |= UMPBUF_MUST_BE_ODD_FRAME;
397
            buffer->name = mali->ump_fb_odd_secure_id;
398
399
        }
        else {
400
            buffer->flags = disp->gfx_layer_size + privates->size;
401
            privates->extra_flags |= UMPBUF_MUST_BE_EVEN_FRAME;
402
            buffer->name = mali->ump_fb_even_secure_id;
403
        }
404
405
406

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

408
        mali->pOverlayWin = (WindowPtr)pDraw;
409

410
411
        if (need_window_resize_bug_workaround) {
            DebugMsg("DRI2 buffers size mismatch detected, trying to recover\n");
412
            buffer->name = mali->ump_fb_r3p0_workaround_secure_id;
413
414
415
        }
    }
    else {
416
/* FIXME
417
418
419
420
421
        if (need_window_resize_bug_workaround) {
            DebugMsg("DRI2 buffers size mismatch detected, trying to recover\n");

            privates->handle = UMP_INVALID_MEMORY_HANDLE;
            privates->addr   = NULL;
422
            buffer->name     = mali->ump_null_secure_id;
423
424
            return validate_dri2buf(buffer);
        }
425
*/
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
        /* 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;
446
447
        privates->extra_flags = (window_state->buf_request_cnt & 1) ?
                                UMPBUF_MUST_BE_ODD_FRAME : UMPBUF_MUST_BE_EVEN_FRAME;
448

449
        umpbuf_add_to_queue(window_state, privates);
450
        privates->refcount++;
451
452
    }

453
454
455
    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);
456

457
    return validate_dri2buf(buffer);
458
459
460
461
}

static void MaliDRI2DestroyBuffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
{
462
    UMPBufferInfoPtr privates;
463
464
    ScreenPtr pScreen = pDraw->pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
465
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
466

467
468
    if (mali->pOverlayDirtyUMP == buffer->driverPrivate)
        mali->pOverlayDirtyUMP = NULL;
469

470
471
472
    DebugMsg("DRI2DestroyBuffer %s=%p, buf=%p:%p, att=%d\n",
             pDraw->type == DRAWABLE_WINDOW ? "win" : "pix",
             pDraw, buffer, buffer->driverPrivate, buffer->attachment);
473
474

    if (buffer != NULL) {
475
        privates = (UMPBufferInfoPtr)buffer->driverPrivate;
476
        unref_ump_buffer_info(privates);
477
478
479
480
481
        free(buffer);
    }
}

/* Do ordinary copy */
482
483
484
static void MaliDRI2CopyRegion_copy(DrawablePtr      pDraw,
                                    RegionPtr        pRegion,
                                    UMPBufferInfoPtr umpbuf)
485
486
487
488
{
    GCPtr pGC;
    RegionPtr copyRegion;
    ScreenPtr pScreen = pDraw->pScreen;
489
    UMPBufferInfoPtr privates;
490
491
492
    PixmapPtr pScratchPixmap;

#ifdef HAVE_LIBUMP_CACHE_CONTROL
493
    if (umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
494
495
        /* That's a normal UMP allocation, not a wrapped framebuffer */
        ump_cache_operations_control(UMP_CACHE_OP_START);
496
        ump_switch_hw_usage_secure_id(umpbuf->secure_id, UMP_USED_BY_CPU);
497
498
499
500
501
502
        ump_cache_operations_control(UMP_CACHE_OP_FINISH);
    }
#endif

    pGC = GetScratchGC(pDraw->depth, pScreen);
    pScratchPixmap = GetScratchPixmapHeader(pScreen,
503
504
505
506
                                            umpbuf->width, umpbuf->height,
                                            umpbuf->depth, umpbuf->cpp * 8,
                                            umpbuf->pitch,
                                            umpbuf->addr + umpbuf->offs);
507
508
509
510
511
512
513
514
515
516
    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
517
    if (umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
518
519
        /* That's a normal UMP allocation, not a wrapped framebuffer */
        ump_cache_operations_control(UMP_CACHE_OP_START);
520
        ump_switch_hw_usage_secure_id(umpbuf->secure_id, UMP_USED_BY_MALI);
521
522
523
524
525
526
527
528
        ump_cache_operations_control(UMP_CACHE_OP_FINISH);
    }
#endif
}

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

531
    if (mali->pOverlayWin && mali->pOverlayDirtyUMP) {
532
        DebugMsg("Flushing overlay content from DRI2 buffer to window\n");
533
        MaliDRI2CopyRegion_copy((DrawablePtr)mali->pOverlayWin,
534
                                &pScreen->root->winSize,
535
536
                                mali->pOverlayDirtyUMP);
        mali->pOverlayDirtyUMP = NULL;
537
538
539
    }
}

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
#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

581
582
583
584
585
586
587
static void MaliDRI2CopyRegion(DrawablePtr   pDraw,
                               RegionPtr     pRegion,
                               DRI2BufferPtr pDstBuffer,
                               DRI2BufferPtr pSrcBuffer)
{
    ScreenPtr pScreen = pDraw->pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
588
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
589
    UMPBufferInfoPtr umpbuf;
590
    sunxi_disp_t *disp = SUNXI_DISP(xf86Screens[pScreen->myNum]);
591
    DRI2WindowStatePtr window_state = NULL;
592
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
593
594
595
596
597
598
599
600
601
602
603
604

    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 */
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
    umpbuf = umpbuf_fetch_from_queue(window_state);

    /*
     * 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++;
623
624
    }

625
626
627
628
629
630
631
632
633
    /* 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;
    }
634
635

    if (!umpbuf || !umpbuf->addr)
636
637
        return;

638
639
640
641
#ifdef DEBUG_WITH_RGB_PATTERN
    check_rgb_pattern(window_state, umpbuf);
#endif

642
643
    UpdateOverlay(pScreen);

644
    if (!mali->bOverlayWinEnabled || umpbuf->handle != UMP_INVALID_MEMORY_HANDLE) {
645
        MaliDRI2CopyRegion_copy(pDraw, pRegion, umpbuf);
646
        mali->pOverlayDirtyUMP = NULL;
647
648
649
        return;
    }

650
    /* Mark the overlay as "dirty" and remember the last up to date UMP buffer */
651
    mali->pOverlayDirtyUMP = umpbuf;
652
653
654

    /* Activate the overlay */
    sunxi_layer_set_output_window(disp, pDraw->x, pDraw->y, pDraw->width, pDraw->height);
655
656
    sunxi_layer_set_rgb_input_buffer(disp, umpbuf->cpp * 8, umpbuf->offs,
                                     umpbuf->width, umpbuf->height, umpbuf->pitch / 4);
657
    sunxi_layer_show(disp);
658

659
    if (mali->bSwapbuffersWait) {
660
661
662
        /* FIXME: blocking here for up to 1/60 second is not nice */
        sunxi_wait_for_vsync(disp);
    }
663
664
665
666
667
668
669
}

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

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

673
    if (!mali->pOverlayWin || !disp)
674
675
        return;

676
    /* Disable overlays if the hardware cursor is not in use */
677
678
    if (!mali->bHardwareCursorIsInUse) {
        if (mali->bOverlayWinEnabled) {
679
680
            DebugMsg("Disabling overlay (no hardware cursor)\n");
            sunxi_layer_hide(disp);
681
            mali->bOverlayWinEnabled = FALSE;
682
683
684
685
        }
        return;
    }

686
    /* If the window is not mapped, make sure that the overlay is disabled */
687
    if (!mali->pOverlayWin->mapped)
688
    {
689
        if (mali->bOverlayWinEnabled) {
690
691
            DebugMsg("Disabling overlay (window is not mapped)\n");
            sunxi_layer_hide(disp);
692
            mali->bOverlayWinEnabled = FALSE;
693
694
695
696
697
698
699
700
701
702
        }
        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).
     */

703
704
705
    mali->bWalkingAboveOverlayWin = FALSE;
    mali->bOverlayWinOverlapped = FALSE;
    FancyTraverseTree(pScreen->root, WindowWalker, mali);
706
707

    /* If the window got overlapped -> disable overlay */
708
    if (mali->bOverlayWinOverlapped && mali->bOverlayWinEnabled) {
709
710
        DebugMsg("Disabling overlay (window is obscured)\n");
        FlushOverlay(pScreen);
711
        mali->bOverlayWinEnabled = FALSE;
712
713
714
715
716
        sunxi_layer_hide(disp);
        return;
    }

    /* If the window got moved -> update overlay position */
717
718
719
    if (!mali->bOverlayWinOverlapped &&
        (mali->overlay_x != mali->pOverlayWin->drawable.x ||
         mali->overlay_y != mali->pOverlayWin->drawable.y))
720
    {
721
722
723
724
725
726
727
728
        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);
729
730
731
    }

    /* If the window got unobscured -> enable overlay */
732
    if (!mali->bOverlayWinOverlapped && !mali->bOverlayWinEnabled) {
733
        DebugMsg("Enabling overlay (window is fully unobscured)\n");
734
        mali->bOverlayWinEnabled = TRUE;
735
736
737
738
739
740
741
742
743
        sunxi_layer_show(disp);
    }
}

static Bool
DestroyWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
744
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
745
    Bool ret;
746
747
    DrawablePtr pDraw = &pWin->drawable;
    DRI2WindowStatePtr window_state = NULL;
748
    HASH_FIND_PTR(mali->HashWindowState, &pDraw, window_state);
749
750
    if (window_state) {
        DebugMsg("Free DRI2 bookkeeping for window %p\n", pWin);
751
        HASH_DEL(mali->HashWindowState, window_state);
752
        /* Empty queue? */
753
754
755
756
        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);
757
758
        free(window_state);
    }
759

760
    if (pWin == mali->pOverlayWin) {
761
762
        sunxi_disp_t *disp = SUNXI_DISP(pScrn);
        sunxi_layer_hide(disp);
763
        mali->pOverlayWin = NULL;
764
765
766
        DebugMsg("DestroyWindow %p\n", pWin);
    }

767
    pScreen->DestroyWindow = mali->DestroyWindow;
768
    ret = (*pScreen->DestroyWindow) (pWin);
769
    mali->DestroyWindow = pScreen->DestroyWindow;
770
771
772
773
774
775
776
777
778
779
    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];
780
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
781

782
783
    if (mali->PostValidateTree) {
        pScreen->PostValidateTree = mali->PostValidateTree;
784
        (*pScreen->PostValidateTree) (pWin, pLayerWin, kind);
785
        mali->PostValidateTree = pScreen->PostValidateTree;
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
        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];
802
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
803
804

    /* FIXME: more precise check */
805
    if (mali->pOverlayDirtyUMP)
806
807
        FlushOverlay(pScreen);

808
809
    if (mali->GetImage) {
        pScreen->GetImage = mali->GetImage;
810
        (*pScreen->GetImage) (pDrawable, x, y, w, h, format, planeMask, d);
811
        mali->GetImage = pScreen->GetImage;
812
813
814
815
        pScreen->GetImage = GetImage;
    }
}

816
817
818
819
820
static Bool
DestroyPixmap(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
821
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
822
823
    Bool result;
    UMPBufferInfoPtr umpbuf;
824
    HASH_FIND_PTR(mali->HashPixmapToUMP, &pPixmap, umpbuf);
825
826
827
828
829
830
831

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

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

832
        HASH_DEL(mali->HashPixmapToUMP, umpbuf);
833
834
        umpbuf->pPixmap = NULL;
        unref_ump_buffer_info(umpbuf);
835
836
    }

837
    pScreen->DestroyPixmap = mali->DestroyPixmap;
838
    result = (*pScreen->DestroyPixmap) (pPixmap);
839
    mali->DestroyPixmap = pScreen->DestroyPixmap;
840
841
842
843
844
845
    pScreen->DestroyPixmap = DestroyPixmap;


    return result;
}

846
847
static void EnableHWCursor(ScrnInfoPtr pScrn)
{
848
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
849
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
850

851
    if (!mali->bHardwareCursorIsInUse) {
852
        DebugMsg("EnableHWCursor\n");
853
        mali->bHardwareCursorIsInUse = TRUE;
854
855
    }

856
857
    UpdateOverlay(screenInfo.screens[pScrn->scrnIndex]);

858
859
    if (mali->EnableHWCursor) {
        hwc->EnableHWCursor = mali->EnableHWCursor;
860
        (*hwc->EnableHWCursor) (pScrn);
861
        mali->EnableHWCursor = hwc->EnableHWCursor;
862
863
864
865
866
867
        hwc->EnableHWCursor = EnableHWCursor;
    }
}

static void DisableHWCursor(ScrnInfoPtr pScrn)
{
868
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
869
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
870

871
872
    if (mali->bHardwareCursorIsInUse) {
        mali->bHardwareCursorIsInUse = FALSE;
873
874
875
        DebugMsg("DisableHWCursor\n");
    }

876
877
    UpdateOverlay(screenInfo.screens[pScrn->scrnIndex]);

878
879
    if (mali->DisableHWCursor) {
        hwc->DisableHWCursor = mali->DisableHWCursor;
880
        (*hwc->DisableHWCursor) (pScrn);
881
        mali->DisableHWCursor = hwc->DisableHWCursor;
882
883
884
885
        hwc->DisableHWCursor = DisableHWCursor;
    }
}

886
887
888
889
890
891
892
893
894
895
896
897
898
899
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;
}

900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
/*
 * Mali400 kernel module version detection code, borrowed from
 *        https://github.com/linux-sunxi/sunxi-mali
 */

#define MALI_KERNEL_VERSION_R3P2 19

#define MALI_GET_API_VERSION      _IOWR(0x82, 5, struct mali_get_api_version *)
#define MALI_GET_API_VERSION_R3P1 _IOWR(0x82, 3, struct mali_get_api_version *)

struct mali_api_version {
    unsigned int empty;
    unsigned int version;
    int compatible;
};

static int get_mali_kernel_version(void)
{
    int fd;
    struct mali_api_version api_version;
    if ((fd = open("/dev/mali", O_RDONLY)) == -1)
        return 0;

    if (ioctl(fd, MALI_GET_API_VERSION, &api_version))
        if (ioctl(fd, MALI_GET_API_VERSION_R3P1, &api_version))
            return api_version.version = 0;

    close(fd);
    return api_version.version;
}

931
932
933
SunxiMaliDRI2 *SunxiMaliDRI2_Init(ScreenPtr pScreen,
                                  Bool      bUseOverlay,
                                  Bool      bSwapbuffersWait)
934
935
936
{
    int drm_fd;
    DRI2InfoRec info;
937
    int mali_kernel_version;
938
    SunxiMaliDRI2 *mali;
939
940
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    sunxi_disp_t *disp = SUNXI_DISP(pScrn);
941

942
943
944
945
946
    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");

947
    if (!xf86LoadSubModule(xf86Screens[pScreen->myNum], "dri2"))
948
        return NULL;
949
950
951

    if ((drm_fd = drmOpen("mali_drm", NULL)) < 0) {
        ErrorF("SunxiMaliDRI2_Init: drmOpen failed!\n");
952
        return NULL;
953
954
955
956
957
    }

    if (ump_open() != UMP_OK) {
        drmClose(drm_fd);
        ErrorF("SunxiMaliDRI2_Init: ump_open() != UMP_OK\n");
958
        return NULL;
959
960
    }

961
    if (!(mali = calloc(1, sizeof(SunxiMaliDRI2)))) {
962
963
964
965
        ErrorF("SunxiMaliDRI2_Init: calloc failed\n");
        return NULL;
    }

966
967
968
969
970
971
972
973
974
975
976
977
    /* Get the mali kernel module version */
    mali_kernel_version = get_mali_kernel_version();

    /* Check if the r3p0 window resize bug workaround is necessary */
    mali->has_window_resize_bug = mali_kernel_version < MALI_KERNEL_VERSION_R3P2;

    mali->ump_fb_odd_secure_id = UMP_INVALID_SECURE_ID;
    mali->ump_fb_even_secure_id = UMP_INVALID_SECURE_ID;
    mali->ump_fb_r3p0_workaround_secure_id = UMP_INVALID_SECURE_ID;
    mali->ump_null_secure_id = UMP_INVALID_SECURE_ID;
    mali->ump_null_handle1 = UMP_INVALID_MEMORY_HANDLE;
    mali->ump_null_handle2 = UMP_INVALID_MEMORY_HANDLE;
978

979
    if (disp && bUseOverlay) {
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
        int err = 0;

        if (mali_kernel_version < MALI_KERNEL_VERSION_R3P2)
        {
            /* For r3p0 mali blob:
             *    secure id 1 - wraps the whole framebuffer
             *    secure id 2 - a small dummy buffer (kind of /dev/null)
             *    secure id 3 - wraps the whole framebuffer
             *
             *  ump_fb_odd_secure_id = ump_fb_even_secure_id = secure id 3
             *  ump_null_secure_id = secure id 2
             *  ump_fb_r3p0_workaround_secure_id = secure id 1
             */
            err |= ioctl(disp->fd_fb, GET_UMP_SECURE_ID_BUF1, &mali->ump_fb_r3p0_workaround_secure_id);
            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);
            err |= ioctl(disp->fd_fb, GET_UMP_SECURE_ID_SUNXI_FB, &mali->ump_fb_odd_secure_id);
            mali->ump_fb_even_secure_id = mali->ump_fb_odd_secure_id;
        }
        else {
            /* For r3p2 mali blob:
             *    secure id 1 - wraps the whole framebuffer
             *    secure id 2 - wraps the whole framebuffer
             *    secure id 3 - wraps the whole framebuffer
             *
             *  ump_fb_odd_secure_id  = secure id 1
             *  ump_fb_even_secure_id = secure id 2
             */
            err |= ioctl(disp->fd_fb, GET_UMP_SECURE_ID_BUF1, &mali->ump_fb_odd_secure_id);
            err |= ioctl(disp->fd_fb, GET_UMP_SECURE_ID_BUF2, &mali->ump_fb_even_secure_id);
            err |= ioctl(disp->fd_fb, GET_UMP_SECURE_ID_SUNXI_FB, &mali->ump_fb_r3p0_workaround_secure_id);
            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);
        }

        if (err || mali->ump_null_secure_id == UMP_INVALID_SECURE_ID ||
            mali->ump_fb_r3p0_workaround_secure_id == UMP_INVALID_SECURE_ID ||
            mali->ump_fb_even_secure_id == UMP_INVALID_SECURE_ID ||
            mali->ump_fb_odd_secure_id == UMP_INVALID_SECURE_ID) {

            xf86DrvMsg(pScreen->myNum, X_INFO,
                  "One of the GET_UMP_SECURE_ID_* ioctls failed\n");
1024
            xf86DrvMsg(pScreen->myNum, X_INFO,
1025
                  "This usually indicates a problem in the linux kernel or its configuration\n");
1026
        }
1027
1028
1029
1030
1031
        else if (ump_get_size_from_secure_id(mali->ump_fb_odd_secure_id) != disp->framebuffer_size ||
                 ump_get_size_from_secure_id(mali->ump_fb_even_secure_id) != disp->framebuffer_size) {

            xf86DrvMsg(pScreen->myNum, X_INFO,
                  "UMP does not wrap the whole framebuffer\n");
1032
            xf86DrvMsg(pScreen->myNum, X_INFO,
1033
                  "This usually indicates a problem in the linux kernel or its configuration\n");
1034
        }
1035
1036

        /* Just a hint for the user if the framebuffer size is too small */
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
        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));
        }
1049
1050
1051
    }
    else {
        /* Try to allocate small dummy UMP buffers to secure id 1 and 2 */
1052
1053
1054
1055
        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);
1056
1057
    }

1058
1059
    if (mali->ump_null_secure_id > 2 && mali->has_window_resize_bug) {
        /* Could not allocate a magic secure id number 1 or 2 */
1060
1061
        xf86DrvMsg(pScreen->myNum, X_INFO,
                   "warning, can't workaround Mali r3p0 window resize bug\n");
1062
1063
        /* So there is no point even trying to workaround this bug */
        mali->has_window_resize_bug = FALSE;
1064
1065
    }

1066
    if (disp && mali->ump_fb_odd_secure_id != UMP_INVALID_SECURE_ID)
1067
1068
1069
1070
1071
1072
1073
1074
1075
        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");

1076
1077
1078
    xf86DrvMsg(pScreen->myNum, X_INFO, "Wait on SwapBuffers? %s\n",
               bSwapbuffersWait ? "enabled" : "disabled");

1079
1080
    info.version = 3;

1081
    info.driverName = "lima";
1082
1083
1084
1085
1086
1087
1088
1089
1090
    info.deviceName = "/dev/dri/card0";
    info.fd = drm_fd;

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

    if (!DRI2ScreenInit(pScreen, &info)) {
        drmClose(drm_fd);
1091
        free(mali);
1092
1093
1094
        return NULL;
    }
    else {
1095
        SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1096
1097

        /* Wrap the current DestroyWindow function */
1098
        mali->DestroyWindow = pScreen->DestroyWindow;
1099
1100
        pScreen->DestroyWindow = DestroyWindow;
        /* Wrap the current PostValidateTree function */
1101
        mali->PostValidateTree = pScreen->PostValidateTree;
1102
1103
        pScreen->PostValidateTree = PostValidateTree;
        /* Wrap the current GetImage function */
1104
        mali->GetImage = pScreen->GetImage;
1105
        pScreen->GetImage = GetImage;
1106
        /* Wrap the current DestroyPixmap function */
1107
        mali->DestroyPixmap = pScreen->DestroyPixmap;
1108
        pScreen->DestroyPixmap = DestroyPixmap;
1109

1110
1111
        /* Wrap hardware cursor callback functions */
        if (hwc) {
1112
            mali->EnableHWCursor = hwc->EnableHWCursor;
1113
            hwc->EnableHWCursor = EnableHWCursor;
1114
            mali->DisableHWCursor = hwc->DisableHWCursor;
1115
1116
1117
            hwc->DisableHWCursor = DisableHWCursor;
        }

1118
1119
1120
        mali->drm_fd = drm_fd;
        mali->bSwapbuffersWait = bSwapbuffersWait;
        return mali;
1121
1122
1123
1124
1125
1126
    }
}

void SunxiMaliDRI2_Close(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1127
    SunxiMaliDRI2 *mali = SUNXI_MALI_UMP_DRI2(pScrn);
1128
    SunxiDispHardwareCursor *hwc = SUNXI_DISP_HWC(pScrn);
1129
1130

    /* Unwrap functions */
1131
1132
1133
1134
    pScreen->DestroyWindow    = mali->DestroyWindow;
    pScreen->PostValidateTree = mali->PostValidateTree;
    pScreen->GetImage         = mali->GetImage;
    pScreen->DestroyPixmap    = mali->DestroyPixmap;
1135

1136
    if (hwc) {
1137
1138
        hwc->EnableHWCursor  = mali->EnableHWCursor;
        hwc->DisableHWCursor = mali->DisableHWCursor;
1139
1140
    }

1141
1142
1143
1144
    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);
1145

1146
    drmClose(mali->drm_fd);
1147
1148
    DRI2CloseScreen(pScreen);
}