summaryrefslogtreecommitdiff
path: root/src/offscreen_manager.c
blob: 10e2e59b4acb30c95461fe4c90542e5b527e0edd (plain)
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
38
39
40
41
42
43
44
45
46
47
48
49
50
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
134
135
136
/* **********************************************************
 * Copyright (C) 1998-2002 VMware, Inc.
 * All Rights Reserved
 * **********************************************************/
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/vmware/offscreen_manager.c,v 1.1 2002/12/10 04:17:19 dawes Exp $ */

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

#include "vmware.h"

struct _Heap {
    CARD8* ptr;
    CARD32 size;
    CARD32 maxSlots;
    CARD32 startOffset;
    SVGASurface* frontBuffer;
    SVGASurface* slotsStart;
    Bool clear;
};

static SVGASurface* FillInSurface(Heap* heap, SVGASurface* surface,
                                  CARD32 width, CARD32 height,
                                  CARD32 bpp, CARD32 pitch, CARD32 size,
                                  CARD32 sizeUsed);

Heap*
vmwareHeap_Create(CARD8* ptr, CARD32 size, CARD32 maxSlots, CARD32 startOffset,
            CARD32 sWidth, CARD32 sHeight, CARD32 sBPP, CARD32 sPitch,
            CARD32 sFbOffset)
{
    Heap* newHeap = malloc(sizeof (Heap));

    newHeap->ptr = ptr;
    newHeap->size = size - sizeof(SVGASurface); /* leave room for frontbuffer */
    newHeap->maxSlots = maxSlots;
    newHeap->startOffset = startOffset;

    newHeap->frontBuffer = FillInSurface(newHeap,
                                         (SVGASurface*)(ptr + newHeap->size),
                                         sWidth, sHeight, sBPP, sPitch,
                                         sHeight * sPitch, 0);
    newHeap->frontBuffer->dataOffset = sFbOffset;
    newHeap->frontBuffer->numQueued = newHeap->frontBuffer->numDequeued = 0;

    newHeap->slotsStart = (SVGASurface*)(newHeap->ptr + newHeap->size) - 
                                          newHeap->maxSlots;
    newHeap->clear = FALSE;
    vmwareHeap_Clear(newHeap);

    return newHeap;
}

void
vmwareHeap_Destroy(Heap* heap)
{
    free(heap);
}

void
vmwareHeap_Clear(Heap* heap)
{
    if (!heap->clear) {
        memset(heap->slotsStart, 0, heap->maxSlots * sizeof (SVGASurface));
        heap->clear = TRUE;
    }
}

static SVGASurface*
FillInSurface(Heap* heap, SVGASurface* surface, CARD32 width, CARD32 height,
              CARD32 bpp, CARD32 pitch, CARD32 size, CARD32 offset)
{
    surface->size = sizeof (SVGASurface);
    surface->version = SVGA_SURFACE_VERSION_1;
    surface->bpp = bpp;
    surface->width = width;
    surface->height = height;
    surface->pitch = pitch;
    if (surface->userData == 0) {
        /*
         * We allocate exactly what we need the first time we use a slot, so
         * all reuses of this slot will be equal or smaller.
         */
        surface->userData = size;
    }
    surface->dataOffset = offset + heap->startOffset;

    return surface;
}

SVGASurface*
vmwareHeap_GetFrontBuffer(Heap* heap)
{
   return heap->frontBuffer;
}

SVGASurface*
vmwareHeap_AllocSurface(Heap* heap, CARD32 width, CARD32 height,
                  CARD32 pitch, CARD32 bpp)
{
    CARD32 size = pitch * height;
    CARD32 sizeUsed = 0;
    SVGASurface* surface = heap->slotsStart;
    int i;

    /*
     * NOTE: we use SVGASurface::userData to store the largest this slot's
     * size has ever been, since we don't ever compact anything.
     */

    /* find a free slot that's big enough */
    for (i = 0; i < heap->maxSlots; i++) {
        if (surface[i].userData == 0) { /* this surface has never been used */
            if ((CARD8*)heap->slotsStart - heap->ptr - sizeUsed < size) {
                /* no room left for data*/
                return NULL;
            }

            heap->clear = FALSE;
            return FillInSurface(heap, surface + i, width, height, bpp,
                                 pitch, size, sizeUsed);
        }

        if (surface[i].numQueued == surface[i].numDequeued &&
            surface[i].userData >= size) { /* free and big enough, sweet! */
            heap->clear = FALSE;
            return FillInSurface(heap, surface + i, width, height, bpp,
                                 pitch, size, sizeUsed);
        }

        sizeUsed += surface[i].userData;
    }

    return NULL;   
}