OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [framebuf/] [synth/] [current/] [host/] [framebuf.c] - Blame information for rev 791

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//============================================================================
2
//
3
//     framebuf.c
4
//
5
//     A utility program to perform low-level ethernet operations
6
//
7
//============================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2008 Free Software Foundation, Inc.                        
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//============================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
//  Author(s):   bartv
43
//  Contact(s):  bartv
44
//  Date:        2005/10/28
45
//  Version:     0.01
46
//  Description:
47
//      Implementation of a framebuffer device. This script should only ever
48
//      be run from inside the ecosynth auxiliary.
49
//
50
// This program is fork'ed by the framebuf.tcl script running inside
51
// the synthetic target auxiliary. It is responsible for performing the
52
// low-level framebuffer accesses.
53
//
54
//####DESCRIPTIONEND####
55
//============================================================================
56
 
57
// We want to instantiate multiple conversion routines for the different
58
// graphics formats, with extensive use of macros for efficiences. Multiple
59
// C #include's are used for this.
60
#ifndef RENDERFN
61
# include <stdio.h>
62
# include <stdarg.h>
63
# include <stdlib.h>
64
# include <string.h>
65
# include <time.h>
66
# include <signal.h>
67
# include <limits.h>
68
# include <unistd.h>
69
# include <fcntl.h>
70
# include <errno.h>
71
# include <sys/param.h>
72
# include <sys/types.h>
73
# include <sys/stat.h>
74
# include <sys/socket.h>
75
# include <sys/ioctl.h>
76
# include <sys/mman.h>
77
# include <X11/Xlib.h>
78
 
79
// The protocol between host and target is defined by a private
80
// target-side header.
81
# include "../src/protocol.h"
82
 
83
// ----------------------------------------------------------------------------
84
// Globals
85
// First the variables needed for X operations. The window is created by
86
// Tcl/Tk code and its id is supplied as an argument.
87
static Display*         host_display;
88
static Window           host_win    = 0;
89
static GC               host_gc;
90
static XImage*          host_image;
91
 
92
// R, G & B shifts for the host-side. Used for palette conversion.
93
static int              host_r_shift;
94
static int              host_g_shift;
95
static int              host_b_shift;
96
 
97
// The image data. Only 32bpp is supported.
98
// NOTE: this is not 64-bit clean.
99
static unsigned int*    img_fb;
100
 
101
// This is used for display depths up to and including 16bpp -
102
// 256K of static data is irrelevant for a Linux host-side app.
103
// 32bpp will have to be handled differently.
104
static unsigned int     host_palette[65536];
105
 
106
// The current function for rendering target-side data
107
static void             (*render_fn)(int, int, int, int);
108
 
109
// And palette init and update functions.
110
static void             (*palette_init_fn)(void);
111
static void             (*palette_update_fn)(void);
112
 
113
// Positions. With target-side viewports, magnification, and the
114
// possibility of windows being resized, this can
115
// get very messy.
116
//
117
// The target-side framebuffer consists of n pages, each of
118
// width*height pixels, plus possibly padding at the end of each
119
// scanline.
120
//
121
// img_fb consists of viewport_width*viewport_height pixels.
122
// At magnification 1 each pixel is a 32-bit unsigned int, but
123
// at higher magnification each pixel takes up mag^2 unsigned
124
// ints.
125
//
126
// win_width and win_height determine the current window dimensions in
127
// target pixel units, i.e. ignoring magnification. x_win_width
128
// and x_win_height are the same dimensions in X pixels, so
129
// mag*win_width. These dimensions are provided by X configure events.
130
// They may be smaller, the same size, or larger than the viewport.
131
//
132
// A coordinate (target_x,target_y) within the current page
133
// corresponds to (target_x - viewport_x, target_y - viewport_y).
134
// within host_image and within the window.
135
//
136
// For an X expose event we get X windows coordinates.
137
 
138
// The actually visible window dimensions. If the Tk window gets
139
// resized then only part of the image data may be visible. These
140
// variables change in response to X configure events.
141
static int              win_width;
142
static int              win_height;
143
static int              x_win_width;
144
static int              x_win_height;
145
 
146
// Target-side framebuffer.
147
//
148
// The synth_fb_data structure at the start of the shared memory region.
149
static synth_fb_data*   shared_fb_data;
150
 
151
// The target-side framebuffer starts at shared_fb_data->framebuf[0].
152
// However that is not necessarily where the visible data starts
153
// because of page flipping and viewport support. This always points
154
// at the top-left corner of visible data.
155
static void*            target_fb;
156
 
157
// Parameters supplied by the target.
158
static int              target_id;
159
static int              target_depth;
160
static int              target_le;
161
static int              target_width;
162
static int              target_height;
163
static int              target_viewport_width;
164
static int              target_viewport_height;
165
static int              target_stride;
166
static int              target_number_pages;
167
static char*            target_format;
168
 
169
// Parameters supplied by a host-side configuration file
170
static int              config_magnification;
171
 
172
// Communication between host and target happens partially through the
173
// shared memory region and partially through a fifo, the latter
174
// allowing for select(). shared_fb_data already points at the shared
175
// memory region.
176
static char             shm_name[L_tmpnam];
177
static int              shm_created;
178
static int              shm_fd;
179
static char             fifo_t2h_name[L_tmpnam];
180
static int              fifo_t2h_created;
181
static int              fifo_t2h_fd;
182
static char             fifo_h2t_name[L_tmpnam];
183
static int              fifo_h2t_created;
184
static int              fifo_h2t_fd;
185
 
186
// An atexit() handler for cleaning up the fifos and shared memory.
187
static void
188
atexit_handler(void)
189
{
190
    if (shm_created) {
191
        unlink(shm_name);
192
    }
193
    if (fifo_t2h_created) {
194
        unlink(fifo_t2h_name);
195
    }
196
    if (fifo_h2t_created) {
197
        unlink(fifo_h2t_name);
198
    }
199
}
200
 
201
// ----------------------------------------------------------------------------
202
// Diagnostics. Warnings and errors are sent up to the I/O auxiliary for
203
// display there. Debug output goes straight to stderr
204
 
205
// Set the DEBUG_LEVEL to 0 for no debugging, 3 for maximum debugging.
206
#define DEBUG_LEVEL 0
207
#define DEBUG(_level_, _str_, ...)                                  \
208
    if (_level_ <= DEBUG_LEVEL) {                                   \
209
        fprintf(stderr, "%d: " _str_, target_id, ## __VA_ARGS__);   \
210
    }
211
 
212
#if 0
213
static void
214
warn(char* fmt, ...)
215
{
216
    char        buf[512];
217
    va_list     args;
218
    va_start(args, fmt);
219
 
220
    sprintf(buf, "Warning (fb%d) : ", target_id);
221
    vsnprintf(buf + strlen(buf), 512 - strlen(buf), fmt, args);
222
    buf[511] = '\0';
223
 
224
    (void) write(1, buf, strlen(buf));
225
}
226
#endif
227
 
228
static void
229
error(char* fmt, ...)
230
{
231
    char        buf[512];
232
    va_list     args;
233
    va_start(args, fmt);
234
 
235
    sprintf(buf, "Error (fb%d) : ", target_id);
236
    vsnprintf(buf + strlen(buf), 512 - strlen(buf), fmt, args);
237
    buf[511] = '\0';
238
 
239
    (void) write(1, buf, strlen(buf));
240
    exit(1);
241
}
242
 
243
// ----------------------------------------------------------------------------
244
// Host-side.
245
//
246
// The main redraw routines. schedule_redraw() can get called as a result of:
247
//
248
// 1) an X expose event.
249
// 2) a message from the Tk code affecting the on/off setting of
250
//    the framebuffer.
251
// 3) a message from the target-side code indicating some of the
252
//    target-side data has changed, or some other event such as
253
//    viewport repositioning or page flipping.
254
//
255
// It just maintains a bounding box. do_redraw() does the real work and
256
// is called from inside the main loop.
257
 
258
static int  redraw_pending = 0;
259
static int  x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height;
260
 
261
static void
262
do_redraw(void)
263
{
264
    while (redraw_pending) {
265
        redraw_pending = 0;
266
        DEBUG(3, "do_redraw: win_x %d, win_y %d, width %d, height %d\n", x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height);
267
        XPutImage(host_display, host_win, host_gc, host_image, x_redraw_x, x_redraw_y, x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height);
268
        XFlush(host_display);
269
    }
270
}
271
 
272
static void
273
schedule_redraw(int x_new_x, int x_new_y, int x_new_width, int x_new_height)
274
{
275
    if (! redraw_pending) {
276
        redraw_pending  = 1;
277
        x_redraw_x        = x_new_x;
278
        x_redraw_y        = x_new_y;
279
        x_redraw_width    = x_new_width;
280
        x_redraw_height   = x_new_height;
281
    } else {
282
        if (x_redraw_x > x_new_x) {
283
            x_redraw_x = x_new_x;
284
        } else {
285
            x_new_width += (x_new_x - x_redraw_x);
286
        }
287
        if (x_redraw_y > x_new_y) {
288
            x_redraw_y = x_new_y;
289
        } else {
290
            x_new_height += (x_new_y - x_redraw_y);
291
        }
292
        if (x_new_width > x_redraw_width) {
293
            x_redraw_width = x_new_width;
294
        }
295
        if (x_new_height > x_redraw_height) {
296
            x_redraw_height = x_new_height;
297
        }
298
    }
299
}
300
 
301
// ----------------------------------------------------------------------------
302
// Utility for blanking the screen
303
static void
304
blackout(void)
305
{
306
    memset(img_fb, 0, target_viewport_width * target_viewport_height * sizeof(int) * config_magnification * config_magnification);
307
    if (0 != host_win) {
308
        schedule_redraw(0, 0, x_win_width, x_win_height);
309
    }
310
}
311
 
312
// ----------------------------------------------------------------------------
313
// This function gets called when the main select() indicates the
314
// X server is trying to send some data.
315
static void
316
handle_X_event(void)
317
{
318
    XEvent      event;
319
 
320
    XNextEvent(host_display, &event);
321
    switch(event.type) {
322
      case Expose:
323
        {
324
            // In theory this code should be able to do partial redraws for every
325
            // expose event, but that does not seem to work reliably. Instead do a
326
            // full redraw, but only for the final event in a sequence.
327
            if (0 == event.xexpose.count) {
328
                DEBUG(3, "X expose event, x %d, y %d, width %d, height %d\n",
329
                      event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height);
330
                schedule_redraw(0, 0, x_win_width, x_win_height);
331
            }
332
            break;
333
        }
334
 
335
      case ConfigureNotify:
336
        {
337
            DEBUG(2, "X configure notify event, width %d, height %d\n", event.xconfigure.width, event.xconfigure.height);
338
            x_win_width     = event.xconfigure.width;
339
            x_win_height    = event.xconfigure.height;
340
            win_width       = (x_win_width  + config_magnification - 1) / config_magnification;
341
            win_height      = (x_win_height + config_magnification - 1) / config_magnification;
342
 
343
            if (shared_fb_data->display_on && shared_fb_data->blank_on) {
344
                (*render_fn)(0 + shared_fb_data->viewport_x, 0 + shared_fb_data->viewport_y, win_width, win_height);
345
            } else {
346
                blackout();
347
            }
348
            break;
349
        }
350
    }
351
}
352
 
353
// ----------------------------------------------------------------------------
354
// Conversion routines
355
 
356
// This dummy function is installed to handle draw requests before the
357
// window is mapped - until that time the exact render function is unknown.
358
static void
359
dummy_render_fn(int target_x, int target_y, int width, int height)
360
{
361
    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
362
    DEBUG(2, "         : window has not been mapped on to the display yet\n");
363
}
364
#else  // RENDERFN
365
 
366
// These functions get instantiated N times for the N different
367
// graphics formats. We need to take the target-side region defined by
368
// x/y/width/height, render it into the image data, and then redraw
369
// the relevant part of the image data. There is no point rendering more
370
// data than is visible.
371
 
372
static void
373
RENDERFN(1, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
374
{
375
    int             x, y;
376
    int             win_x, win_y;
377
    unsigned int*   img_data;
378
    unsigned int    colour;
379
    TARGET_DATA;
380
 
381
    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
382
    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
383
        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
384
        return;
385
    }
386
    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
387
 
388
    win_x   = target_x - shared_fb_data->viewport_x;
389
    win_y   = target_y - shared_fb_data->viewport_y;
390
    if (win_x < 0) {
391
        width       += win_x;
392
        win_x        = 0;
393
    }
394
    if (win_y < 0) {
395
        height      += win_y;
396
        win_y        = 0;
397
    }
398
    if ((win_x + width) > win_width) {
399
        width = win_width - win_x;
400
    }
401
    if ((win_y + height) > win_height) {
402
        height = win_height - win_y;
403
    }
404
    DEBUG(2, "         : after clipping, win_x %d, win_y %d, width %d, height %d\n", win_x, win_y, width, height);
405
    if ((width < 0) || (height < 0)) {
406
        return;
407
    }
408
 
409
    img_data    = img_fb    + (win_y * target_viewport_width) + win_x;
410
    for (y = 0; y < height; y++) {
411
        for (x = 0; x < width; x++) {
412
            colour  = TARGET_NEXT_COLOUR();
413
            *img_data++  = colour;
414
        }
415
        img_data += (target_viewport_width - width);
416
        TARGET_NEXT_LINE();
417
    }
418
    schedule_redraw(win_x, win_y, width, height);
419
}
420
 
421
static void
422
RENDERFN(2, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
423
{
424
    int             x, y;
425
    int             win_x, win_y;
426
    unsigned int*   img_data0;
427
    unsigned int*   img_data1;
428
    unsigned int    colour;
429
    TARGET_DATA;
430
 
431
    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
432
    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
433
        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
434
        return;
435
    }
436
    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
437
    win_x   = target_x - shared_fb_data->viewport_x;
438
    win_y   = target_y - shared_fb_data->viewport_y;
439
    if (win_x < 0) {
440
        width       += win_x;
441
        win_x        = 0;
442
    }
443
    if (win_y < 0) {
444
        height      += win_y;
445
        win_y        = 0;
446
    }
447
    if ((win_x + width) > win_width) {
448
        width = win_width - win_x;
449
    }
450
    if ((win_y + height) > win_height) {
451
        height = win_height - win_y;
452
    }
453
    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
454
    if ((width < 0) || (height < 0)) {
455
        return;
456
    }
457
 
458
 
459
    for (y = 0; y < height; y++) {
460
        img_data0       = img_fb + (2 * (win_y + y) * (2 * target_viewport_width)) + (2 * win_x);
461
        img_data1       = img_data0 + (2 * target_viewport_width);
462
        for (x = 0; x < width; x++) {
463
            colour  = TARGET_NEXT_COLOUR();
464
            *img_data0++  = colour;
465
            *img_data0++  = colour;
466
            *img_data1++  = colour;
467
            *img_data1++  = colour;
468
        }
469
        TARGET_NEXT_LINE();
470
    }
471
    schedule_redraw(2 * win_x, 2 * win_y, 2 * width, 2 * height);
472
}
473
 
474
static void
475
RENDERFN(3, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
476
{
477
    int             x, y;
478
    int             win_x, win_y;
479
    unsigned int*   img_data0;
480
    unsigned int*   img_data1;
481
    unsigned int*   img_data2;
482
    unsigned int    colour;
483
    TARGET_DATA;
484
 
485
    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
486
    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
487
        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
488
        return;
489
    }
490
    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
491
    win_x   = target_x - shared_fb_data->viewport_x;
492
    win_y   = target_y - shared_fb_data->viewport_y;
493
    if (win_x < 0) {
494
        width       += win_x;
495
        win_x        = 0;
496
    }
497
    if (win_y < 0) {
498
        height      += win_y;
499
        win_y        = 0;
500
    }
501
    if ((win_x + width) > win_width) {
502
        width = win_width - win_x;
503
    }
504
    if ((win_y + height) > win_height) {
505
        height = win_height - win_y;
506
    }
507
    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
508
    if ((width < 0) || (height < 0)) {
509
        return;
510
    }
511
 
512
    for (y = 0; y < height; y++) {
513
        img_data0       = img_fb + (3 * (win_y + y) * (3 * target_viewport_width)) + (3 * win_x);
514
        img_data1       = img_data0 + (3 * target_viewport_width);
515
        img_data2       = img_data1 + (3 * target_viewport_width);
516
 
517
        for (x = 0; x < width; x++) {
518
            colour  = TARGET_NEXT_COLOUR();
519
            *img_data0++  = colour;
520
            *img_data0++  = colour;
521
            *img_data0++  = colour;
522
            *img_data1++  = colour;
523
            *img_data1++  = colour;
524
            *img_data1++  = colour;
525
            *img_data2++  = colour;
526
            *img_data2++  = colour;
527
            *img_data2++  = colour;
528
        }
529
        TARGET_NEXT_LINE();
530
    }
531
    schedule_redraw(3 * win_x, 3 * win_y, 3 * width, 3 * height);
532
}
533
 
534
static void
535
RENDERFN(4, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
536
{
537
    int             x, y;
538
    int             win_x, win_y;
539
    unsigned int*   img_data0;
540
    unsigned int*   img_data1;
541
    unsigned int*   img_data2;
542
    unsigned int*   img_data3;
543
    unsigned int    colour;
544
    TARGET_DATA;
545
 
546
    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
547
    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
548
        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
549
        return;
550
    }
551
    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
552
    win_x   = target_x - shared_fb_data->viewport_x;
553
    win_y   = target_y - shared_fb_data->viewport_y;
554
    if (win_x < 0) {
555
        width       += win_x;
556
        win_x        = 0;
557
    }
558
    if (win_y < 0) {
559
        height      += win_y;
560
        win_y        = 0;
561
    }
562
    if ((win_x + width) > win_width) {
563
        width = win_width - win_x;
564
    }
565
    if ((win_y + height) > win_height) {
566
        height = win_height - win_y;
567
    }
568
    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
569
    if ((width < 0) || (height < 0)) {
570
        return;
571
    }
572
 
573
    for (y = 0; y < height; y++) {
574
        img_data0       = img_fb + (4 * (win_y + y) * (4 * target_viewport_width)) + (4 * win_x);
575
        img_data1       = img_data0 + (4 * target_viewport_width);
576
        img_data2       = img_data1 + (4 * target_viewport_width);
577
        img_data3       = img_data2 + (4 * target_viewport_width);
578
 
579
        for (x = 0; x < width; x++) {
580
            colour  = TARGET_NEXT_COLOUR();
581
            *img_data0++  = colour;
582
            *img_data0++  = colour;
583
            *img_data0++  = colour;
584
            *img_data0++  = colour;
585
            *img_data1++  = colour;
586
            *img_data1++  = colour;
587
            *img_data1++  = colour;
588
            *img_data1++  = colour;
589
            *img_data2++  = colour;
590
            *img_data2++  = colour;
591
            *img_data2++  = colour;
592
            *img_data2++  = colour;
593
            *img_data3++  = colour;
594
            *img_data3++  = colour;
595
            *img_data3++  = colour;
596
            *img_data3++  = colour;
597
        }
598
        TARGET_NEXT_LINE();
599
    }
600
    schedule_redraw(4 * win_x, 4 * win_y, 4 * width, 4 * height);
601
}
602
 
603
#endif
604
#ifndef RENDERFN
605
 
606
# define RENDERFN_AUX(_magnification_, _format_) render_ ## _magnification_ ## _ ## _format_
607
# define RENDERFN(_magnification_, _format_)     RENDERFN_AUX(_magnification_, _format_)
608
 
609
// ----------------------------------------------------------------------------
610
// 1bpp, BE. It is convenient to always render in byte-multiples
611
# define TARGET_FORMAT   1BPP_BE
612
 
613
# define TARGET_DATA                                                \
614
    unsigned char*  target_fb_current;                              \
615
    unsigned int    mask;                                           \
616
    width       += target_x & 0x07;                                 \
617
    target_x    &= ~0x07;                                           \
618
    width        = (width + 7) & ~0x07;                             \
619
    target_fb_current   = ((unsigned char*)target_fb) +             \
620
        (target_y * target_stride) + (target_x >> 3);               \
621
    mask         = 0x0080
622
 
623
# define TARGET_NEXT_COLOUR()                                       \
624
    ({                                                              \
625
        unsigned int next_colour;                                   \
626
        next_colour = host_palette[*target_fb_current & mask];      \
627
        mask >>= 1;                                                 \
628
        if (0 == mask) {                                            \
629
            target_fb_current += 1;                                 \
630
            mask               = 0x0080;                            \
631
        }                                                           \
632
        next_colour;                                                \
633
    })
634
 
635
# define TARGET_NEXT_LINE()                                         \
636
    target_fb_current += target_stride - (width >> 3)
637
 
638
# include "framebuf.c"
639
# undef TARGET_FORMAT
640
# undef TARGET_DATA
641
# undef TARGET_NEXT_COLOUR
642
# undef TARGET_NEXT_LINE
643
 
644
// ----------------------------------------------------------------------------
645
// 1bpp, LE
646
# define TARGET_FORMAT   1BPP_LE
647
 
648
# define TARGET_DATA                                                \
649
    unsigned char*  target_fb_current;                              \
650
    unsigned int    mask;                                           \
651
    width       += target_x & 0x07;                                 \
652
    target_x    &= ~0x07;                                           \
653
    width        = (width + 7) & ~0x07;                             \
654
    target_fb_current   = ((unsigned char*)target_fb) +             \
655
        (target_y * target_stride) + (target_x >> 3);               \
656
    mask         = 0x0001
657
 
658
# define TARGET_NEXT_COLOUR()                                       \
659
    ({                                                              \
660
        unsigned int next_colour;                                   \
661
        next_colour = host_palette[*target_fb_current & mask];      \
662
        mask <<= 1;                                                 \
663
        if (0x0100 == mask) {                                       \
664
            target_fb_current += 1;                                 \
665
            mask               = 0x0001;                            \
666
        }                                                           \
667
        next_colour;                                                \
668
    })
669
 
670
# define TARGET_NEXT_LINE()                                         \
671
    target_fb_current += target_stride - (width >> 3)
672
 
673
# include "framebuf.c"
674
# undef TARGET_FORMAT
675
# undef TARGET_DATA
676
# undef TARGET_NEXT_COLOUR
677
# undef TARGET_NEXT_LINE
678
 
679
// ----------------------------------------------------------------------------
680
// 2bpp, BE
681
# define TARGET_FORMAT   2BPP_BE
682
 
683
# define TARGET_DATA                                                \
684
    unsigned char*  target_fb_current;                              \
685
    unsigned int    mask;                                           \
686
    width       += target_x & 0x03;                                 \
687
    target_x    &= ~0x03;                                           \
688
    width        = (width + 3) & ~0x03;                             \
689
    target_fb_current   = ((unsigned char*)target_fb) +             \
690
        (target_y * target_stride) + (target_x >> 2);               \
691
    mask         = 0x00C0
692
 
693
# define TARGET_NEXT_COLOUR()                                       \
694
    ({                                                              \
695
        unsigned int next_colour;                                   \
696
        next_colour = host_palette[*target_fb_current & mask];      \
697
        mask >>= 2;                                                 \
698
        if (0x00 == mask) {                                         \
699
            target_fb_current += 1;                                 \
700
            mask               = 0x00C0;                            \
701
        }                                                           \
702
        next_colour;                                                \
703
    })
704
 
705
# define TARGET_NEXT_LINE()                                         \
706
    target_fb_current += target_stride - (width >> 2)
707
 
708
# include "framebuf.c"
709
# undef TARGET_FORMAT
710
# undef TARGET_DATA
711
# undef TARGET_NEXT_COLOUR
712
# undef TARGET_NEXT_LINE
713
 
714
// ----------------------------------------------------------------------------
715
// 2bpp, LE
716
# define TARGET_FORMAT   2BPP_LE
717
 
718
# define TARGET_DATA                                                \
719
    unsigned char*  target_fb_current;                              \
720
    unsigned int    mask;                                           \
721
    width       += target_x & 0x03;                                 \
722
    target_x    &= ~0x03;                                           \
723
    width        = (width + 3) & ~0x03;                             \
724
    target_fb_current   = ((unsigned char*)target_fb) +             \
725
        (target_y * target_stride) + (target_x >> 2);               \
726
    mask         = 0x0003
727
 
728
# define TARGET_NEXT_COLOUR()                                       \
729
    ({                                                              \
730
        unsigned int next_colour;                                   \
731
        next_colour = host_palette[*target_fb_current & mask];      \
732
        mask <<= 2;                                                 \
733
        if (0x0300 == mask) {                                       \
734
            target_fb_current += 1;                                 \
735
            mask               = 0x0003;                            \
736
        }                                                           \
737
        next_colour;                                                \
738
    })
739
 
740
# define TARGET_NEXT_LINE()                                         \
741
    target_fb_current += target_stride - (width >> 2)
742
 
743
# include "framebuf.c"
744
# undef TARGET_FORMAT
745
# undef TARGET_DATA
746
# undef TARGET_NEXT_COLOUR
747
# undef TARGET_NEXT_LINE
748
 
749
// ----------------------------------------------------------------------------
750
// 4bpp, BE
751
# define TARGET_FORMAT   4BPP_BE
752
 
753
# define TARGET_DATA                                                \
754
    unsigned char*  target_fb_current;                              \
755
    unsigned int    mask;                                           \
756
    width       += target_x & 0x01;                                 \
757
    target_x    &= ~0x01;                                           \
758
    width        = (width + 1) & ~0x01;                             \
759
    target_fb_current   = ((unsigned char*)target_fb) +             \
760
        (target_y * target_stride) + (target_x >> 1);               \
761
    mask         = 0x00F0
762
 
763
# define TARGET_NEXT_COLOUR()                                       \
764
    ({                                                              \
765
        unsigned int next_colour;                                   \
766
        next_colour = host_palette[*target_fb_current & mask];      \
767
        mask >>= 4;                                                 \
768
        if (0 == mask) {                                            \
769
            target_fb_current += 1;                                 \
770
            mask               = 0x00F0;                            \
771
        }                                                           \
772
        next_colour;                                                \
773
    })
774
 
775
# define TARGET_NEXT_LINE()                                         \
776
    target_fb_current += target_stride - (width >> 1)
777
 
778
# include "framebuf.c"
779
# undef TARGET_FORMAT
780
# undef TARGET_DATA
781
# undef TARGET_NEXT_COLOUR
782
# undef TARGET_NEXT_LINE
783
 
784
// ----------------------------------------------------------------------------
785
// 4bpp, LE
786
# define TARGET_FORMAT   4BPP_LE
787
 
788
# define TARGET_DATA                                                \
789
    unsigned char*  target_fb_current;                              \
790
    unsigned int    mask;                                           \
791
    width       += target_x & 0x01;                                 \
792
    target_x    &= ~0x01;                                           \
793
    width        = (width + 1) & ~0x01;                             \
794
    target_fb_current   = ((unsigned char*)target_fb) +             \
795
        (target_y * target_stride) + (target_x >> 1);               \
796
    mask         = 0x000F
797
 
798
# define TARGET_NEXT_COLOUR()                                       \
799
    ({                                                              \
800
        unsigned int next_colour;                                   \
801
        next_colour = host_palette[*target_fb_current & mask];      \
802
        mask <<= 4;                                                 \
803
        if (0x0F00 == mask) {                                       \
804
            target_fb_current += 1;                                 \
805
            mask               = 0x000F;                            \
806
        }                                                           \
807
        next_colour;                                                \
808
    })
809
 
810
# define TARGET_NEXT_LINE()                                         \
811
    target_fb_current += target_stride - (width >> 2)
812
 
813
# include "framebuf.c"
814
# undef TARGET_FORMAT
815
# undef TARGET_DATA
816
# undef TARGET_NEXT_COLOUR
817
# undef TARGET_NEXT_LINE
818
 
819
// ----------------------------------------------------------------------------
820
// 8bpp, paletted or true colour. In the case of a true colour display the
821
// host_palette array will have been filled in appropriately for 332 so
822
// conversion to 32-bit true colour again just involves indirecting through
823
// the palette, rather than the more expensive bit masking and shifting.
824
# define TARGET_FORMAT   8BPP
825
 
826
# define TARGET_DATA                                                \
827
    unsigned char*  target_fb_current;                              \
828
    target_fb_current   = ((unsigned char*)target_fb) +             \
829
        (target_y * target_stride) + target_x
830
 
831
# define TARGET_NEXT_COLOUR() host_palette[*target_fb_current++]
832
 
833
# define TARGET_NEXT_LINE()                                         \
834
    target_fb_current += (target_stride - width)
835
 
836
# include "framebuf.c"
837
# undef TARGET_FORMAT
838
# undef TARGET_DATA
839
# undef TARGET_NEXT_COLOUR
840
# undef TARGET_NEXT_LINE
841
 
842
// ----------------------------------------------------------------------------
843
// 16bpp. Again this is handled via the host_palette array, suitably
844
// initialized for either 555 or 565
845
# define TARGET_FORMAT   16BPP
846
 
847
# define TARGET_DATA                                                \
848
    unsigned short*  target_fb_current;                             \
849
    target_fb_current   = ((unsigned short*)target_fb) +            \
850
        (target_y * (target_stride >> 1)) + target_x
851
 
852
# define TARGET_NEXT_COLOUR()   host_palette[*target_fb_current++]
853
 
854
# define TARGET_NEXT_LINE()                                         \
855
    target_fb_current += ((target_stride >> 1) - width)
856
 
857
# include "framebuf.c"
858
# undef TARGET_FORMAT
859
# undef TARGET_DATA
860
# undef TARGET_NEXT_COLOUR
861
# undef TARGET_NEXT_LINE
862
 
863
// ----------------------------------------------------------------------------
864
// 32bpp, 0888, no swapping
865
 
866
# define TARGET_FORMAT   32BPP
867
 
868
# define TARGET_DATA                                                \
869
    unsigned int*  target_fb_current;                               \
870
    target_fb_current   = ((unsigned int*)target_fb) +              \
871
        (target_y * (target_stride >> 2)) + target_x
872
 
873
# define TARGET_NEXT_COLOUR() *target_fb_current++ & 0x00FFFFFF
874
 
875
# define TARGET_NEXT_LINE()                                         \
876
    target_fb_current += ((target_stride >> 2) - width)
877
 
878
# include "framebuf.c"
879
# undef TARGET_FORMAT
880
# undef TARGET_DATA
881
# undef TARGET_NEXT_COLOUR
882
# undef TARGET_NEXT_LINE
883
 
884
// ----------------------------------------------------------------------------
885
// 32bpp, 0888, but the host uses 8880.
886
# define TARGET_FORMAT   32BPP_SWAPPED
887
 
888
# define TARGET_DATA                                                \
889
    unsigned int*  target_fb_current;                               \
890
    target_fb_current   = ((unsigned int*)target_fb) +              \
891
        (target_y * (target_stride >> 2)) + target_x
892
 
893
# define TARGET_NEXT_COLOUR()                                       \
894
    ({                                                              \
895
        unsigned int _colour_ = *target_fb_current++;               \
896
        _colour_ =                                                  \
897
            ((_colour_ & 0x000000FF) << 24) |                       \
898
            ((_colour_ & 0x0000FF00) << 16) |                       \
899
            ((_colour_ & 0x00FF0000) <<  8);                        \
900
        _colour_;                                                   \
901
    })
902
 
903
# define TARGET_NEXT_LINE()                                         \
904
    target_fb_current += ((target_stride >> 2) - width)
905
 
906
# include "framebuf.c"
907
# undef TARGET_FORMAT
908
# undef TARGET_DATA
909
# undef TARGET_NEXT_COLOUR
910
# undef TARGET_NEXT_LINE
911
 
912
// ----------------------------------------------------------------------------
913
// Palette management. 8bpp and 16bpp true colour can be initialized
914
// statically. 32bpp does not involve the host_palette array at all.
915
// Other formats involve dynamic palette updating.
916
 
917
static void
918
palette_initialize_8bpp_332(void)
919
{
920
    static const unsigned char expand2[4]  = { 0x00, 0x55, 0xAA, 0xFF };
921
    static const unsigned char expand3[8]  = { 0x00, 0x20 + 4, 0x40 + 9, 0x60 + 13, 0x80 + 18, 0xA0 + 22, 0xC0 + 27, 0xE0 + 31 };
922
    int i;
923
    for (i = 0; i < 256; i++) {
924
        int r   = (i & 0x00E0) >> 5;
925
        int g   = (i & 0x001C) >> 2;
926
        int b   = (i & 0x0003) >> 0;
927
        host_palette[i] = (expand3[r] << host_r_shift) | (expand3[g] << host_g_shift) | (expand2[b] << host_b_shift);
928
    }
929
}
930
 
931
static void
932
palette_initialize_16bpp_555(void)
933
{
934
    static const unsigned char expand5[32] = {
935
        0x00 + 0, 0x08 + 0, 0x10 + 0, 0x18 + 0, 0x20 + 1, 0x28 + 1, 0x30 + 1, 0x38 + 1,
936
        0x40 + 2, 0x48 + 2, 0x50 + 2, 0x58 + 2, 0x60 + 3, 0x68 + 3, 0x70 + 3, 0x78 + 3,
937
        0x80 + 4, 0x88 + 4, 0x90 + 4, 0x98 + 4, 0xA0 + 5, 0xA8 + 5, 0xB0 + 5, 0xB8 + 5,
938
        0xC0 + 6, 0xC8 + 6, 0xD0 + 6, 0xD8 + 6, 0xE0 + 7, 0xE8 + 7, 0xF0 + 7, 0xF8 + 7,
939
    };
940
    int i;
941
    for (i = 0; i < 65536; i++) {
942
        int r = (i & 0x00007C00) >> 10;
943
        int g = (i & 0x000003E0) >> 5;
944
        int b = (i & 0x0000001F) >> 0;
945
        host_palette[i] = (expand5[r] << host_r_shift) | (expand5[g] << host_g_shift) | (expand5[b] << host_b_shift);
946
    }
947
}
948
 
949
static void
950
palette_initialize_16bpp_565(void)
951
{
952
    static const unsigned char expand5[32] = {
953
        0x00 + 0, 0x08 + 0, 0x10 + 0, 0x18 + 0, 0x20 + 1, 0x28 + 1, 0x30 + 1, 0x38 + 1,
954
        0x40 + 2, 0x48 + 2, 0x50 + 2, 0x58 + 2, 0x60 + 3, 0x68 + 3, 0x70 + 3, 0x78 + 3,
955
        0x80 + 4, 0x88 + 4, 0x90 + 4, 0x98 + 4, 0xA0 + 5, 0xA8 + 5, 0xB0 + 5, 0xB8 + 5,
956
        0xC0 + 6, 0xC8 + 6, 0xD0 + 6, 0xD8 + 6, 0xE0 + 7, 0xE8 + 7, 0xF0 + 7, 0xF8 + 7,
957
    };
958
    static const unsigned char expand6[64] = {
959
        0x00 + 0, 0x04 + 0, 0x08 + 0, 0x0C + 0, 0x10 + 0, 0x14 + 0, 0x18 + 0, 0x1C + 0,
960
        0x20 + 0, 0x24 + 0, 0x28 + 0, 0x2C + 0, 0x30 + 0, 0x34 + 0, 0x38 + 0, 0x3C + 0,
961
        0x40 + 1, 0x44 + 1, 0x48 + 1, 0x4C + 1, 0x50 + 1, 0x54 + 1, 0x58 + 1, 0x5C + 1,
962
        0x60 + 1, 0x64 + 1, 0x68 + 1, 0x6C + 1, 0x70 + 1, 0x74 + 1, 0x78 + 1, 0x7C + 1,
963
        0x80 + 2, 0x84 + 2, 0x88 + 2, 0x8C + 2, 0x90 + 2, 0x94 + 2, 0x98 + 2, 0x9C + 2,
964
        0xA0 + 2, 0xA4 + 2, 0xA8 + 2, 0xAC + 2, 0xB0 + 2, 0xB4 + 2, 0xB8 + 2, 0xBC + 2,
965
        0xC0 + 3, 0xC4 + 3, 0xC8 + 3, 0xCC + 3, 0xD0 + 3, 0xD4 + 3, 0xD8 + 3, 0xDC + 3,
966
        0xE0 + 3, 0xE4 + 3, 0xE8 + 3, 0xEC + 3, 0xF0 + 3, 0xF4 + 3, 0xF8 + 3, 0xFC + 3,
967
    };
968
    int i;
969
    for (i = 0; i < 65536; i++) {
970
        int r = (i & 0x0000F800) >> 11;
971
        int g = (i & 0x000007E0) >> 5;
972
        int b = (i & 0x0000001F) >> 0;
973
        host_palette[i] = (expand5[r] << host_r_shift) | (expand6[g] << host_g_shift) | (expand5[b] << host_b_shift);
974
    }
975
}
976
 
977
static void
978
palette_update(void)
979
{
980
    int             i, j;
981
    unsigned char*  target_palette;
982
    int             r, g, b;
983
 
984
    target_palette  = shared_fb_data->palette;
985
    for (i = 0; i < (0x01 << target_depth); i++) {
986
        r = *target_palette++;
987
        g = *target_palette++;
988
        b = *target_palette++;
989
        host_palette[i] = (r << host_r_shift) | (g << host_g_shift) | (b << host_b_shift);
990
    }
991
 
992
    // Make sure the palette is replicated throughout the first 256
993
    // entries. That way when rendering <8bpp data we can just mask
994
    // the target-side bytes without having to shift.
995
    for (j = 0; i < 256; i++, j++) {
996
        host_palette[i] = host_palette[j];
997
    }
998
}
999
 
1000
// ----------------------------------------------------------------------------
1001
// This array is used to map the various display formats etc. on to
1002
// render functions.
1003
static struct _render_details {
1004
    char*           rd_format;
1005
    unsigned int    rd_endianness_matters;
1006
    unsigned int    rd_le;
1007
    void            (*rd_palette_init)(void);
1008
    void            (*rd_palette_update)(void);
1009
    void            (*rd_render_fns[4])(int, int, int, int);
1010
} render_array[] = {
1011
    // 32BPP must come first
1012
    { "32BPP_TRUE_0888", 0, 0, NULL, NULL,
1013
      { &render_1_32BPP, &render_2_32BPP, &render_3_32BPP, &render_4_32BPP }
1014
    },
1015
    { "16BPP_TRUE_555",  0, 0, &palette_initialize_16bpp_555, NULL,
1016
      { &render_1_16BPP, &render_2_16BPP, &render_3_16BPP, &render_4_16BPP }
1017
    },
1018
    { "16BPP_TRUE_565",  0, 0, &palette_initialize_16bpp_565, NULL,
1019
      { &render_1_16BPP, &render_2_16BPP, &render_3_16BPP, &render_4_16BPP }
1020
    },
1021
    { "8BPP_TRUE_332",   0, 0, &palette_initialize_8bpp_332, NULL,
1022
      { &render_1_8BPP, &render_2_8BPP, &render_3_8BPP, &render_4_8BPP }
1023
    },
1024
    { "8BPP_PAL888",     0, 0, NULL, &palette_update,
1025
      { &render_1_8BPP, &render_2_8BPP, &render_3_8BPP, &render_4_8BPP }
1026
    },
1027
    { "4BPP_PAL888",     1, 1, NULL, &palette_update,
1028
      { &render_1_4BPP_LE, &render_2_4BPP_LE, &render_3_4BPP_LE, &render_4_4BPP_LE }
1029
    },
1030
    { "4BPP_PAL888",     1, 0, NULL, &palette_update,
1031
      { &render_1_4BPP_BE, &render_2_4BPP_BE, &render_3_4BPP_BE, &render_4_4BPP_BE }
1032
    },
1033
    { "2BPP_PAL888",     1, 1, NULL, &palette_update,
1034
      { &render_1_2BPP_LE, &render_2_2BPP_LE, &render_3_2BPP_LE, &render_4_2BPP_LE }
1035
    },
1036
    { "2BPP_PAL888",     1, 0, NULL, &palette_update,
1037
      { &render_1_2BPP_BE, &render_2_2BPP_BE, &render_3_2BPP_BE, &render_4_2BPP_BE }
1038
    },
1039
    { "1BPP_PAL888",     1, 1, NULL, &palette_update,
1040
      { &render_1_1BPP_LE, &render_2_1BPP_LE, &render_3_1BPP_LE, &render_4_1BPP_LE }
1041
    },
1042
    { "1BPP_PAL888",     1, 0, NULL, &palette_update,
1043
      { &render_1_1BPP_BE, &render_2_1BPP_BE, &render_3_1BPP_BE, &render_4_1BPP_BE }
1044
    },
1045
    { NULL }
1046
};
1047
 
1048
 
1049
// ----------------------------------------------------------------------------
1050
// Communication between host and target
1051
//
1052
// When the target wants to wake up the host it sends a single byte down
1053
// a fifo, typically after having filled in appropriate fields in the
1054
// shared memory region.
1055
static void
1056
handle_target_request(void)
1057
{
1058
    unsigned char   buf[1];
1059
    int             result;
1060
 
1061
    result  = read(fifo_t2h_fd, buf, 1);
1062
    if (-1 == result) {
1063
        if (EINTR == errno) {
1064
            return;
1065
        }
1066
        error("unexpected error %d (%s) reading fifo command from target-side code", errno, strerror(errno));
1067
    }
1068
    if (0 == result) {
1069
        // The target-side must have exited. Do not follow suit yet. Instead
1070
        // exit only when the I/O auxiliary exits.
1071
        DEBUG(1, "eCos application has exited\n");
1072
        close(fifo_t2h_fd);
1073
        fifo_t2h_fd = -1;
1074
        return;
1075
    }
1076
 
1077
    switch(buf[0]) {
1078
      case SYNTH_FB_OK:
1079
        {
1080
            // The target has finished initializing. This may have
1081
            // involved filling in the palette
1082
            DEBUG(1, "target request SYNTH_FB_OK, eCos application has connected.\n");
1083
            if (palette_update_fn) {
1084
                (*palette_update_fn)();
1085
            }
1086
            break;
1087
        }
1088
 
1089
      case SYNTH_FB_SYNC:
1090
        {
1091
            // The target has updated part of the display.
1092
            DEBUG(2, "target request SYNC, x0 %d, y0 %d, x1 %d, y1 %d\n",
1093
                  shared_fb_data->sync_x0, shared_fb_data->sync_y0, shared_fb_data->sync_x1, shared_fb_data->sync_y1);
1094
            (*render_fn)(shared_fb_data->sync_x0, shared_fb_data->sync_y0,
1095
                         (shared_fb_data->sync_x1 - shared_fb_data->sync_x0),
1096
                         (shared_fb_data->sync_y1 - shared_fb_data->sync_y0));
1097
            break;
1098
        }
1099
 
1100
      case SYNTH_FB_WRITE_PALETTE:
1101
        {
1102
            // The target-side palette has been updated. Adjust the
1103
            // host-side palette and then render the whole window with
1104
            // the curent colours (unless blanked).
1105
            DEBUG(1, "target request WRITE_PALETTE\n");
1106
            if (palette_update_fn) {
1107
                (*palette_update_fn)();
1108
            }
1109
            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1110
        }
1111
 
1112
      case SYNTH_FB_BLANK:
1113
        {
1114
            DEBUG(1, "target request blank, display should be %s\n", shared_fb_data->blank_on ? "on" : "off");
1115
            if (shared_fb_data->blank_on) {
1116
                (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1117
            } else {
1118
                blackout();
1119
            }
1120
            break;
1121
        }
1122
 
1123
      case SYNTH_FB_VIEWPORT:
1124
        {
1125
            // Just rerender the whole display as per the new viewport position.
1126
            DEBUG(1, "target request move viewport to x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
1127
            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1128
            break;
1129
        }
1130
 
1131
      case SYNTH_FB_PAGE_FLIP:
1132
        {
1133
            int page_size   = target_height * target_stride;
1134
            DEBUG(1, "target request page flip to page %d\n", shared_fb_data->page_visible);
1135
            target_fb       = (void*)(((char*)&(shared_fb_data->framebuf[0])) + (page_size * shared_fb_data->page_visible));
1136
            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1137
            break;
1138
        }
1139
    }
1140
 
1141
    // Send a single-byte response back to the target
1142
    DEBUG(2, "target request handled\n");
1143
    buf[0] = SYNTH_FB_OK;
1144
    do {
1145
        result = write(fifo_h2t_fd, buf, 1);
1146
    } while ((result < 0) && (errno == EINTR));
1147
    if (result < 0) {
1148
        error("unexpected error %d (%s) writing fifo status to target-side code", errno, strerror(errno));
1149
    }
1150
}
1151
 
1152
// ----------------------------------------------------------------------------
1153
// Communication from the Tcl/Tk script
1154
static void
1155
handle_mapped(int winid)
1156
{
1157
    Status              result;
1158
    XWindowAttributes   attr;
1159
    XGCValues           gc_values;
1160
    Visual*             visual;
1161
    int                 i;
1162
 
1163
    DEBUG(1, "X window %d has been mapped\n", winid);
1164
    if (0 != (int)host_win) {
1165
        error("  window has already been mapped.\n");
1166
    }
1167
 
1168
    host_win    = (Window)winid;
1169
    result      = XGetWindowAttributes(host_display, host_win, &attr);
1170
    if (0 == result) {
1171
        error("failed to get window attributes.");
1172
    }
1173
    gc_values.graphics_exposures    = False;
1174
    host_gc = XCreateGC(host_display, host_win, GCGraphicsExposures, &gc_values);
1175
    result = XSelectInput(host_display, host_win, ExposureMask | StructureNotifyMask);
1176
 
1177
    // The Tcl script has already checked that we are on a 24/32 bit display.
1178
    // We need to know the colour shifts and possibly adjust the render array.
1179
    visual  = attr.visual;
1180
    DEBUG(1, "  red_mask 0x%08lx, green_mask 0x%08lx, blue_mask 0x%08lx\n", visual->red_mask, visual->green_mask, visual->blue_mask);
1181
    if ((0x00FF0000 == visual->red_mask) && (0x0000FF00 == visual->green_mask) && (0x000000FF == visual->blue_mask)) {
1182
        // 0888, nothing special needed
1183
        host_r_shift    = 16;
1184
        host_g_shift    =  8;
1185
        host_b_shift    =  0;
1186
    } else if ((0x0000FF00 == visual->red_mask) && (0x00FF0000 == visual->green_mask) && (0xFF000000 == visual->blue_mask)) {
1187
        // 8880
1188
        host_r_shift    =  8;
1189
        host_g_shift    = 16;
1190
        host_b_shift    = 24;
1191
        render_array[0].rd_render_fns[0]    = &render_1_32BPP_SWAPPED;
1192
        render_array[0].rd_render_fns[1]    = &render_2_32BPP_SWAPPED;
1193
        render_array[0].rd_render_fns[2]    = &render_3_32BPP_SWAPPED;
1194
        render_array[0].rd_render_fns[3]    = &render_4_32BPP_SWAPPED;
1195
    }
1196
 
1197
    // Time to figure out which render function etc. to use.
1198
    render_fn = (void (*)(int, int, int, int)) NULL;
1199
    for (i = 0; render_array[i].rd_format; i++) {
1200
        if ((0 == strcmp(render_array[i].rd_format, target_format)) &&
1201
            (!render_array[i].rd_endianness_matters || (render_array[i].rd_le == target_le))) {
1202
 
1203
            render_fn           = render_array[i].rd_render_fns[config_magnification - 1];
1204
            palette_init_fn     = render_array[i].rd_palette_init;
1205
            palette_update_fn   = render_array[i].rd_palette_update;
1206
            break;
1207
        }
1208
    }
1209
    if (NULL == render_fn) {
1210
        error("Target format not supported.");
1211
    }
1212
 
1213
    // Now it is possible to create the XImage structure, the fifos,
1214
    // and the shared memory region for interaction with the target.
1215
    // The XImage needs to be large enough for the viewport. That may
1216
    // be larger than the actually visible window, but the window may
1217
    // get resized.
1218
    host_image  = XCreateImage(host_display, visual,
1219
                               24,          // image depth. 24 bits of colour info.
1220
                               ZPixmap,
1221
                               0,           // offset
1222
                               NULL,        // data, filled in later
1223
                               target_viewport_width  * config_magnification,
1224
                               target_viewport_height * config_magnification,
1225
                               32,          // bitmap_pad
1226
 
1227
        );
1228
    if (NULL == host_image) {
1229
        error("Failed to allocate XImage structure.");
1230
    }
1231
    host_image->data    = (void*)img_fb;
1232
 
1233
    x_win_width     = attr.width;
1234
    x_win_height    = attr.height;
1235
    win_width       = (x_win_width  + config_magnification - 1) / config_magnification;
1236
    win_height      = (x_win_height + config_magnification - 1) / config_magnification;
1237
    DEBUG(1, "  mapped window, X width %d, X height %d, win width %d, win height %d, blank on %d, display on %d\n",
1238
          x_win_width, x_win_height, win_width, win_height, shared_fb_data->blank_on, shared_fb_data->display_on);
1239
 
1240
    // The palette may get initialized locally or by the target, depending
1241
    // on the mode.
1242
    if (palette_init_fn) {
1243
        (*palette_init_fn)();
1244
    }
1245
    if (palette_update_fn) {
1246
        (*palette_update_fn)();
1247
    }
1248
    if (shared_fb_data->display_on && shared_fb_data->blank_on) {
1249
        (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1250
    } else {
1251
        // Just draw the initial blank screen.
1252
        blackout();
1253
    }
1254
}
1255
 
1256
static void
1257
handle_auxiliary_request(void)
1258
{
1259
    synth_fb_auxiliary_request  req;
1260
    int                         result;
1261
 
1262
    result = read(0, &req, sizeof(synth_fb_auxiliary_request));
1263
    if (result <= 0) {
1264
        // The I/O auxiliary has terminated, so assume the window has gone as well.
1265
        exit(0);
1266
    }
1267
    DEBUG(2, "handle_auxiliary request %d\n", req.command);
1268
    switch (req.command) {
1269
      case SYNTH_FB_AUX_MAPPED:
1270
        {
1271
            handle_mapped(req.arg1);
1272
            break;
1273
        }
1274
      case SYNTH_FB_AUX_ON:
1275
        {
1276
            // This is used when the target-side switches the display
1277
            // off and back on, rather than just blanking it. Treat it
1278
            // the same as blanking.
1279
            DEBUG(1, "Target has switched the display on\n");
1280
            shared_fb_data->display_on  = 1;
1281
            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
1282
            break;
1283
        }
1284
      case SYNTH_FB_AUX_OFF:
1285
        {
1286
            DEBUG(1, "Target has switched the display off\n");
1287
            shared_fb_data->display_on  = 0;
1288
            blackout();
1289
            break;
1290
        }
1291
      case SYNTH_FB_AUX_REDRAW:
1292
        {
1293
            DEBUG(1, "Auxiliary has requested a redraw\n");
1294
            schedule_redraw(0, 0, x_win_width, x_win_height);
1295
        }
1296
    }
1297
    DEBUG(2, "handle_auxiliary request done\n");
1298
}
1299
 
1300
// Report an error to ecosynth during initialization. This means a
1301
// single byte 0, followed by a string.
1302
static void
1303
report_init_error(char* msg)
1304
{
1305
    write(1, "0", 1);
1306
    write(1, msg, strlen(msg));
1307
    close(1);
1308
    exit(0);
1309
}
1310
 
1311
// ----------------------------------------------------------------------------
1312
int
1313
main(int argc, char** argv)
1314
{
1315
    int                 size;
1316
    fd_set              read_fds;
1317
    int                 max_fd;
1318
 
1319
    atexit(&atexit_handler);
1320
    signal(SIGPIPE, SIG_IGN);
1321
 
1322
    if (12 != argc) {
1323
        report_init_error("Incorrect number of arguments.");
1324
    }
1325
    target_id               = (int) strtoul(argv[1], NULL, 0);
1326
    target_depth            = (int) strtoul(argv[2], NULL, 0);
1327
    target_le               = (int) strtoul(argv[3], NULL, 0);
1328
    target_width            = (int) strtoul(argv[4], NULL, 0);
1329
    target_height           = (int) strtoul(argv[5], NULL, 0);
1330
    target_viewport_width   = (int) strtoul(argv[6], NULL, 0);
1331
    target_viewport_height  = (int) strtoul(argv[7], NULL, 0);
1332
    target_stride           = (int) strtoul(argv[8], NULL, 0);
1333
    target_number_pages     = (int) strtoul(argv[9], NULL, 0);
1334
    target_format           = argv[10];
1335
    config_magnification    = (int) strtoul(argv[11], NULL, 0);
1336
 
1337
    if ((target_depth != 1) && (target_depth != 2) && (target_depth != 4) && (target_depth != 8) && (target_depth != 16) && (target_depth != 32)) {
1338
        report_init_error("Invalid target depth.");
1339
    }
1340
    if ((target_width < 16) || (target_width > 4096)) {
1341
        report_init_error("Invalid target width.");
1342
    }
1343
    if ((target_height < 16) || (target_height > 4096)) {
1344
        report_init_error("Invalid target height.");
1345
    }
1346
    if ((target_viewport_width < 16) || (target_viewport_width > target_width)) {
1347
        report_init_error("Invalid target viewport width.");
1348
    }
1349
    if ((target_viewport_height < 16) || (target_viewport_height > target_height)) {
1350
        report_init_error("Invalid target viewport height.");
1351
    }
1352
    if ((target_number_pages < 1) || (target_number_pages > 4)) {
1353
        report_init_error("Invalid target number of pages.");
1354
    }
1355
    if ((config_magnification < 1) || (config_magnification > 4)) {
1356
        report_init_error("Invalid config magnification.");
1357
    }
1358
 
1359
    host_display    = XOpenDisplay(NULL);
1360
    if (NULL == host_display) {
1361
        report_init_error("Failed to open X display.");
1362
    }
1363
    img_fb = (unsigned int*) malloc(target_viewport_width * target_viewport_height * sizeof(int) * config_magnification * config_magnification);
1364
    if (NULL == img_fb) {
1365
        report_init_error("Failed to allocate XImage data.");
1366
    }
1367
    blackout();
1368
 
1369
    // Use of tmpnam() is generally discouraged and generates a linker
1370
    // warning, but only three temporary file names are needed and
1371
    // there are no root privileges involved so security is not a big
1372
    // issue. mkstemp() cannot easily be used with fifos.
1373
    if (NULL == tmpnam(fifo_t2h_name)) {
1374
        report_init_error("Failed to create unique file name for target->host fifo.");
1375
    }
1376
    if (0 != mkfifo(fifo_t2h_name, S_IRUSR | S_IWUSR)) {
1377
        report_init_error("Failed to create target->host fifo.");
1378
    }
1379
    // Opening O_RDONLY or O_WRONLY will result in blocking until the
1380
    // other end is open as well, which is not what is wanted here.
1381
    // Instead we use the Linux feature of opening with O_RDWR which
1382
    // gives non-blocking behaviour.
1383
    fifo_t2h_created    = 1;
1384
    fifo_t2h_fd         = open(fifo_t2h_name, O_RDWR);
1385
    if (-1 == fifo_t2h_fd) {
1386
        report_init_error("Failed to open target->host fifo.");
1387
    }
1388
    if (NULL == tmpnam(fifo_h2t_name)) {
1389
        report_init_error("Failed to create unique file name for host->target fifo.");
1390
    }
1391
    if (0 != mkfifo(fifo_h2t_name, S_IRUSR | S_IWUSR)) {
1392
        report_init_error("Failed to create host->target fifo.");
1393
    }
1394
    fifo_h2t_created    = 1;
1395
    fifo_h2t_fd         = open(fifo_h2t_name, O_RDWR);
1396
    if (-1 == fifo_h2t_fd) {
1397
        report_init_error("Failed to open target->host fifo.");
1398
    }
1399
 
1400
    size    = sizeof(synth_fb_data) + (target_height * target_stride * target_number_pages);
1401
    if (NULL == tmpnam(shm_name)) {
1402
        report_init_error("Failed to create unique file name for shared memory.");
1403
    }
1404
    shm_fd  = open(shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
1405
    if (shm_fd < 0) {
1406
        report_init_error("Failed to open file for shared memory region.");
1407
    }
1408
    shm_created = 1;
1409
    if (ftruncate(shm_fd, size) < 0) {
1410
        report_init_error("Failed to set shared memory file size.");
1411
    }
1412
 
1413
    shared_fb_data = (synth_fb_data*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
1414
    if (shared_fb_data == (synth_fb_data*)MAP_FAILED) {
1415
        report_init_error("Failed to mmap shared memory file.");
1416
    }
1417
    target_fb   = &(shared_fb_data->framebuf[0]);
1418
 
1419
    shared_fb_data->connected           = 0;
1420
    shared_fb_data->fifo_to_framebuf    = -1;
1421
    shared_fb_data->fifo_from_framebuf  = -1;
1422
    shared_fb_data->devid               = target_id;
1423
    shared_fb_data->sync_x0             = 0;
1424
    shared_fb_data->sync_y0             = 0;
1425
    shared_fb_data->sync_x1             = target_viewport_width;
1426
    shared_fb_data->sync_y1             = target_viewport_height;
1427
    shared_fb_data->display_on          = 0;
1428
    shared_fb_data->blank_on            = 1;
1429
    shared_fb_data->viewport_x          = 0;
1430
    shared_fb_data->viewport_y          = 0;
1431
    shared_fb_data->page_visible        = 0;
1432
 
1433
    render_fn   = &dummy_render_fn;
1434
    msync(shared_fb_data, size, MS_SYNC);
1435
 
1436
    // Everything seems to be in order. Report back to the auxiliary.
1437
    {
1438
        char    buf[513];
1439
        if ((strlen(shm_name) + strlen(fifo_t2h_name) + strlen(fifo_h2t_name) + 3) > 512) {
1440
            report_init_error("Temporary path names too long.");
1441
        }
1442
        buf[0]  = '1';
1443
        strcpy(&(buf[1]), shm_name);
1444
        strcat(&(buf[1]), ";");
1445
        strcat(&(buf[1]), fifo_t2h_name);
1446
        strcat(&(buf[1]), ";");
1447
        strcat(&(buf[1]), fifo_h2t_name);
1448
        strcat(&(buf[1]), ";");
1449
        write(1, buf, 2 + strlen(&(buf[1])));
1450
    }
1451
 
1452
    // Now we just loop, processing events. We want to select on file descriptor
1453
    // 0 from the auxiliary, the X file descriptor, and the fifo t2h descriptor.
1454
    // The latter may go away. X should never go away, and if the auxiliary goes
1455
    // away we exit immediately.
1456
    max_fd  = MAX(ConnectionNumber(host_display), fifo_t2h_fd);
1457
    while ( 1 ) {
1458
        while (XPending(host_display) > 0) {
1459
            handle_X_event();
1460
        }
1461
        FD_ZERO(&read_fds);
1462
        FD_SET(0, &read_fds);
1463
        FD_SET(ConnectionNumber(host_display), &read_fds);
1464
        if (-1 != fifo_t2h_fd) {
1465
            FD_SET(fifo_t2h_fd, &read_fds);
1466
        }
1467
        DEBUG(3, "framebuf main loop: selecting on 0x%08x\n", *(int*)&read_fds);
1468
        do_redraw();
1469
        if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) >= 0) {
1470
            if (FD_ISSET(0, &read_fds)) {
1471
                DEBUG(2, "framebuf main loop: auxiliary request\n");
1472
                handle_auxiliary_request();
1473
            }
1474
            if ((-1 != fifo_t2h_fd) && FD_ISSET(fifo_t2h_fd, &read_fds)) {
1475
                DEBUG(2, "framebuf main loop: target request\n");
1476
                handle_target_request();
1477
            }
1478
            if (FD_ISSET(ConnectionNumber(host_display), &read_fds)) {
1479
                DEBUG(3, "framebuf main loop: X request\n");
1480
                (void)XEventsQueued(host_display, QueuedAfterReading);
1481
            }
1482
        }
1483
    }
1484
 
1485
    exit(EXIT_SUCCESS);
1486
}
1487
#endif // INSTANTIATE_CONVERTER

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.