summaryrefslogtreecommitdiff
path: root/display/qxldd.h
blob: 9283c433d61eb1ac9fb81f5515f4bc2818119e10 (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
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*
   Copyright (C) 2009 Red Hat, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _H_QXLDD
#define _H_QXLDD


#include "stddef.h"

#include <stdarg.h>
#include <stdlib.h>
#include "windef.h"
#include "wingdi.h"
#include "winddi.h"
#include "qxl_driver.h"
#include "mspace.h"
#if (WINVER < 0x0501)
#include "wdmhelper.h"
#endif

#define ALLOC_TAG 'dlxq'

#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))

#define DEBUG_PRINT(arg) DebugPrint arg

#ifdef DBG
#define ASSERT(pdev, x) if (!(x)) { \
    DebugPrint(pdev, 0, "ASSERT(%s) failed @ %s\n", #x, __FUNCTION__); \
    EngDebugBreak();\
}
#define ONDBG(x) x
#else
#define ASSERT(pdev, x)
#define ONDBG(x)
#endif

#define PANIC(pdev, str) {                                      \
    DebugPrint(pdev, 0, "PANIC: %s @ %s\n", str, __FUNCTION__); \
    EngDebugBreak();                                            \
}

typedef enum {
    QXL_SUCCESS,
    QXL_FAILED,
    QXL_UNSUPPORTED,
} QXLRESULT;

typedef struct Ring RingItem;
typedef struct Ring {
    RingItem *prev;
    RingItem *next;
} Ring;

#define IMAGE_HASH_SHIFT 15
#define IMAGE_HASH_SIZE (1 << IMAGE_HASH_SHIFT)
#define IMAGE_HASH_MASK (IMAGE_HASH_SIZE - 1)

#define IMAGE_POOL_SIZE (1 << 15)

#define CURSOR_CACHE_SIZE (1 << 6)
#define CURSOR_HASH_SIZE (CURSOR_CACHE_SIZE << 1)
#define CURSOR_HASH_NASKE (CURSOR_HASH_SIZE - 1)

#define PALETTE_CACHE_SIZE (1 << 6)
#define PALETTE_HASH_SIZE (PALETTE_CACHE_SIZE << 1)
#define PALETTE_HASH_NASKE (PALETTE_HASH_SIZE - 1)

//#define CALL_TEST

#ifdef CALL_TEST
enum {
    CALL_COUNTER_COPY_BITS,
    CALL_COUNTER_BIT_BLT,
    CALL_COUNTER_TEXT_OUT,
    CALL_COUNTER_STROKE_PATH,
    CALL_COUNTER_STRETCH_BLT,
    CALL_COUNTER_STRETCH_BLT_ROP,
    CALL_COUNTER_TRANSPARENT_BLT,
    CALL_COUNTER_ALPHA_BLEND,

    CALL_COUNTER_FILL_PATH,
    CALL_COUNTER_GRADIENT_FILL,
    CALL_COUNTER_LINE_TO,
    CALL_COUNTER_PLG_BLT,
    CALL_COUNTER_STROKE_AND_FILL_PATH,

    NUM_CALL_COUNTERS,
};
#endif

typedef struct QuicData QuicData;

#define IMAGE_KEY_HASH_SIZE (1 << 15)
#define IMAGE_KEY_HASH_MASK (IMAGE_KEY_HASH_SIZE - 1)

typedef struct ImageKey {
    HSURF hsurf;
    UINT64 unique;
    UINT32 key;
} ImageKey;

typedef struct CacheImage {
    struct CacheImage *next;
    RingItem lru_link;
    UINT32 key;
    UINT32 hits;
    UINT8 format;
    UINT32 width;
    UINT32 height;
    struct InternalImage *image;
} CacheImage;

#define NUM_UPDATE_TRACE_ITEMS 10
typedef struct UpdateTrace {
    RingItem link;
    UINT32 last_time;
    RECTL area;
    HSURF hsurf;
} UpdateTrace;

typedef struct PMemSlot {
    MemSlot slot;
    ADDRESS high_bits;
} PMemSlot;

typedef struct DevResDynamic {
    CacheImage cache_image_pool[IMAGE_POOL_SIZE];
    Ring cache_image_lru;
    Ring cursors_lru;
    Ring palette_lru;
} DevResDynamic;

typedef struct DevRes {
    mspace _mspace;
    UINT8 *mspace_start;
    UINT8 *mspace_end;
    BOOL need_init;
    UINT64 free_outputs;
    UINT32 update_id;

    DevResDynamic *dynamic;

    ImageKey image_key_lookup[IMAGE_KEY_HASH_SIZE];
    struct CacheImage *image_cache[IMAGE_HASH_SIZE];
    struct InternalCursor *cursor_cache[CURSOR_HASH_SIZE];
    UINT32 num_cursors;
    UINT32 last_cursor_id;
    struct InternalPalette *palette_cache[PALETTE_HASH_SIZE];
    UINT32 num_palettes;

#ifdef DBG
    int num_free_pages;
    int num_outputs;
    int num_path_pages;
    int num_rects_pages;
    int num_bits_pages;
    int num_buf_pages;
    int num_glyphs_pages;
    int num_cursor_pages;
#endif

#ifdef CALL_TEST
    BOOL count_calls;
    UINT32 total_calls;
    UINT32 call_counters[NUM_CALL_COUNTERS];
#endif
} DevRes;

typedef struct PDev {
    HANDLE driver;
    HDEV eng;
    HPALETTE palette;
    HSURF surf;
    UINT8 surf_enable;
    DWORD video_mode_index;
    SIZEL resolution;
    UINT32 max_bitmap_size;
    ULONG bitmap_format;
    ULONG fb_size;
    BYTE* fb;
    ULONG stride;
    FLONG red_mask;
    FLONG green_mask;
    FLONG blue_mask;
    ULONG fp_state_size;

    PHYSICAL surf_phys;
    UINT8 *surf_base;

    QuicData *quic_data;

    QXLCommandRing *cmd_ring;
    QXLCursorRing *cursor_ring;
    QXLReleaseRing *release_ring;
    UINT32 notify_cmd_port;
    UINT32 notify_cursor_port;
    UINT32 notify_oom_port;
    PEVENT display_event;
    PEVENT cursor_event;
    PEVENT sleep_event;

    HSURF draw_bitmap;
    SURFOBJ *draw_surf;

    UINT32 log_port;
    UINT8 *log_buf;
    UINT32 *log_level;

    HSEMAPHORE malloc_sem;
    HSEMAPHORE print_sem;

    PMemSlot *mem_slots;
    UINT8 num_mem_slot;
    UINT8 main_mem_slot;
    UINT8 slot_id_bits;
    UINT8 slot_gen_bits;
    ADDRESS va_slot_mask;

    UINT32 num_io_pages;
    UINT8 *io_pages_virt;
    UINT64 io_pages_phys;

    UINT32 *dev_update_id;

    UINT32 update_area_port;
    Rect *update_area;

    UINT32 *mm_clock;

    UINT32 *compression_level;

    FLONG cursor_trail;

#if (WINVER < 0x0501)
    PQXLWaitForEvent WaitForEvent;
#endif

    UINT32 create_primary_port;
    UINT32 destroy_primary_port;
    UINT32 destroy_surface_wait_port;

    UINT8* primary_memory_start;
    UINT32 primary_memory_size;

    QXLSurfaceCreate *primary_surface_create;

    UINT32 dev_id;

    DevRes Res;

    Ring update_trace;
    UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
} PDev;


void DebugPrintV(PDev *pdev, const char *message, va_list ap);
void DebugPrint(PDev *pdev, int level, const char *message, ...);

void InitGlobalRes();
void CleanGlobalRes();
void InitResources(PDev *pdev);
void SyncResources(PDev *pdev);

#ifdef CALL_TEST
void CountCall(PDev *pdev, int counter);
#else
#define CountCall(a, b)
#endif

char *BitmapFormatToStr(int format);
char *BitmapTypeToStr(int type);

static _inline void RingInit(Ring *ring)
{
    ring->next = ring->prev = ring;
}

static _inline void RingItemInit(RingItem *item)
{
    item->next = item->prev = NULL;
}

static _inline BOOL RingItemIsLinked(RingItem *item)
{
    return !!item->next;
}

static _inline BOOL RingIsEmpty(PDev *pdev, Ring *ring)
{
    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
    return ring == ring->next;
}

static _inline void RingAdd(PDev *pdev, Ring *ring, RingItem *item)
{
    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
    ASSERT(pdev, item->next == NULL && item->prev == NULL);

    item->next = ring->next;
    item->prev = ring;
    ring->next = item->next->prev = item;
}

static _inline void RingRemove(PDev *pdev, RingItem *item)
{
    ASSERT(pdev, item->next != NULL && item->prev != NULL);
    ASSERT(pdev, item->next != item);

    item->next->prev = item->prev;
    item->prev->next = item->next;
    item->prev = item->next = 0;
}

static _inline RingItem *RingGetTail(PDev *pdev, Ring *ring)
{
    RingItem *ret;

    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);

    if (RingIsEmpty(pdev, ring)) {
        return NULL;
    }
    ret = ring->prev;
    return ret;
}

#endif