1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "qemu_file.h"
13#include "android/android.h"
14#include "android/utils/debug.h"
15#include "android/utils/duff.h"
16#include "goldfish_device.h"
17#include "console.h"
18
19/* These values *must* match the platform definitions found under
20 * hardware/libhardware/include/hardware/hardware.h
21 */
22enum {
23    HAL_PIXEL_FORMAT_RGBA_8888          = 1,
24    HAL_PIXEL_FORMAT_RGBX_8888          = 2,
25    HAL_PIXEL_FORMAT_RGB_888            = 3,
26    HAL_PIXEL_FORMAT_RGB_565            = 4,
27    HAL_PIXEL_FORMAT_BGRA_8888          = 5,
28    HAL_PIXEL_FORMAT_RGBA_5551          = 6,
29    HAL_PIXEL_FORMAT_RGBA_4444          = 7,
30};
31
32enum {
33    FB_GET_WIDTH        = 0x00,
34    FB_GET_HEIGHT       = 0x04,
35    FB_INT_STATUS       = 0x08,
36    FB_INT_ENABLE       = 0x0c,
37    FB_SET_BASE         = 0x10,
38    FB_SET_ROTATION     = 0x14,
39    FB_SET_BLANK        = 0x18,
40    FB_GET_PHYS_WIDTH   = 0x1c,
41    FB_GET_PHYS_HEIGHT  = 0x20,
42    FB_GET_FORMAT       = 0x24,
43
44    FB_INT_VSYNC             = 1U << 0,
45    FB_INT_BASE_UPDATE_DONE  = 1U << 1
46};
47
48struct goldfish_fb_state {
49    struct goldfish_device dev;
50    DisplayState*  ds;
51    int      pixel_format;
52    int      bytes_per_pixel;
53    uint32_t fb_base;
54    uint32_t base_valid : 1;
55    uint32_t need_update : 1;
56    uint32_t need_int : 1;
57    uint32_t set_rotation : 2;
58    uint32_t blank : 1;
59    uint32_t int_status;
60    uint32_t int_enable;
61    int      rotation;   /* 0, 1, 2 or 3 */
62    int      dpi;
63};
64
65#define  GOLDFISH_FB_SAVE_VERSION  2
66
67static void goldfish_fb_save(QEMUFile*  f, void*  opaque)
68{
69    struct goldfish_fb_state*  s = opaque;
70
71    DisplayState*  ds = s->ds;
72
73    qemu_put_be32(f, ds->surface->width);
74    qemu_put_be32(f, ds->surface->height);
75    qemu_put_be32(f, ds->surface->linesize);
76    qemu_put_byte(f, 0);
77
78    qemu_put_be32(f, s->fb_base);
79    qemu_put_byte(f, s->base_valid);
80    qemu_put_byte(f, s->need_update);
81    qemu_put_byte(f, s->need_int);
82    qemu_put_byte(f, s->set_rotation);
83    qemu_put_byte(f, s->blank);
84    qemu_put_be32(f, s->int_status);
85    qemu_put_be32(f, s->int_enable);
86    qemu_put_be32(f, s->rotation);
87    qemu_put_be32(f, s->dpi);
88}
89
90static int  goldfish_fb_load(QEMUFile*  f, void*  opaque, int  version_id)
91{
92    struct goldfish_fb_state*  s   = opaque;
93    int                        ret = -1;
94    int                        ds_w, ds_h, ds_pitch, ds_rot;
95
96    if (version_id != GOLDFISH_FB_SAVE_VERSION)
97        goto Exit;
98
99    ds_w     = qemu_get_be32(f);
100    ds_h     = qemu_get_be32(f);
101    ds_pitch = qemu_get_be32(f);
102    ds_rot   = qemu_get_byte(f);
103
104    DisplayState*  ds = s->ds;
105
106    if (ds->surface->width != ds_w ||
107        ds->surface->height != ds_h ||
108        ds->surface->linesize != ds_pitch ||
109        ds_rot != 0)
110    {
111        /* XXX: We should be able to force a resize/rotation from here ? */
112        fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__);
113        goto Exit;
114    }
115
116    s->fb_base      = qemu_get_be32(f);
117    s->base_valid   = qemu_get_byte(f);
118    s->need_update  = qemu_get_byte(f);
119    s->need_int     = qemu_get_byte(f);
120    s->set_rotation = qemu_get_byte(f);
121    s->blank        = qemu_get_byte(f);
122    s->int_status   = qemu_get_be32(f);
123    s->int_enable   = qemu_get_be32(f);
124    s->rotation     = qemu_get_be32(f);
125    s->dpi          = qemu_get_be32(f);
126
127    /* force a refresh */
128    s->need_update = 1;
129
130    ret = 0;
131Exit:
132    return ret;
133}
134
135/* Type used to record a mapping from display surface pixel format to
136 * HAL pixel format */
137typedef struct {
138    int    pixel_format; /* HAL pixel format */
139    uint8_t bits;
140    uint8_t bytes;
141    uint32_t rmask, gmask, bmask, amask;
142} FbConfig;
143
144
145/* Return the pixel format of the current framebuffer, based on
146 * the current display surface's pixel format.
147 *
148 * Note that you should not call this function from the device initialization
149 * function, because the display surface will change format before the kernel
150 * start.
151 */
152static int goldfish_fb_get_pixel_format(struct goldfish_fb_state *s)
153{
154    if (s->pixel_format >= 0) {
155        return s->pixel_format;
156    }
157    static const FbConfig fb_configs[] = {
158        { HAL_PIXEL_FORMAT_RGB_565, 16, 2, 0xf800, 0x7e0, 0x1f, 0x0 },
159        { HAL_PIXEL_FORMAT_RGBX_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0x0 },
160        { HAL_PIXEL_FORMAT_RGBA_8888, 32, 4, 0xff0000, 0xff00, 0xff, 0xff000000 },
161        { -1, }
162    };
163
164    /* Determine HAL pixel format value based on s->ds */
165    struct PixelFormat* pf = &s->ds->surface->pf;
166    if (VERBOSE_CHECK(init)) {
167        printf("%s:%d: display surface,pixel format:\n", __FUNCTION__, __LINE__);
168        printf("  bits/pixel:  %d\n", pf->bits_per_pixel);
169        printf("  bytes/pixel: %d\n", pf->bytes_per_pixel);
170        printf("  depth:       %d\n", pf->depth);
171        printf("  red:         bits=%d mask=0x%x shift=%d max=0x%x\n",
172            pf->rbits, pf->rmask, pf->rshift, pf->rmax);
173        printf("  green:       bits=%d mask=0x%x shift=%d max=0x%x\n",
174            pf->gbits, pf->gmask, pf->gshift, pf->gmax);
175        printf("  blue:        bits=%d mask=0x%x shift=%d max=0x%x\n",
176            pf->bbits, pf->bmask, pf->bshift, pf->bmax);
177        printf("  alpha:       bits=%d mask=0x%x shift=%d max=0x%x\n",
178            pf->abits, pf->amask, pf->ashift, pf->amax);
179    }
180
181    s->bytes_per_pixel = pf->bytes_per_pixel;
182    int nn;
183    for (nn = 0; fb_configs[nn].pixel_format >= 0; nn++) {
184        const FbConfig* fbc = &fb_configs[nn];
185        if (pf->bits_per_pixel == fbc->bits &&
186            pf->bytes_per_pixel == fbc->bytes &&
187            pf->rmask == fbc->rmask &&
188            pf->gmask == fbc->gmask &&
189            pf->bmask == fbc->bmask &&
190            pf->amask == fbc->amask) {
191            /* We found it */
192            s->pixel_format = fbc->pixel_format;
193            return s->pixel_format;
194        }
195    }
196    fprintf(stderr, "%s:%d: Unsupported display pixel format (depth=%d, bytespp=%d, bitspp=%d)\n",
197                __FUNCTION__, __LINE__,
198                pf->depth,
199                pf->bytes_per_pixel,
200                pf->bits_per_pixel);
201    exit(1);
202    return -1;
203}
204
205static int goldfish_fb_get_bytes_per_pixel(struct goldfish_fb_state *s)
206{
207    if (s->pixel_format < 0) {
208        (void) goldfish_fb_get_pixel_format(s);
209    }
210    return s->bytes_per_pixel;
211}
212
213static int
214pixels_to_mm(int  pixels, int dpi)
215{
216    /* dpi = dots / inch
217    ** inch = dots / dpi
218    ** mm / 25.4 = dots / dpi
219    ** mm = (dots * 25.4)/dpi
220    */
221    return (int)(0.5 + 25.4 * pixels  / dpi);
222}
223
224
225#define  STATS  0
226
227#if STATS
228static int   stats_counter;
229static long  stats_total;
230static int   stats_full_updates;
231static long  stats_total_full_updates;
232#endif
233
234/* This structure is used to hold the inputs for
235 * compute_fb_update_rect_linear below.
236 * This corresponds to the source framebuffer and destination
237 * surface pixel buffers.
238 */
239typedef struct {
240    int            width;
241    int            height;
242    int            bytes_per_pixel;
243    const uint8_t* src_pixels;
244    int            src_pitch;
245    uint8_t*       dst_pixels;
246    int            dst_pitch;
247} FbUpdateState;
248
249/* This structure is used to hold the outputs for
250 * compute_fb_update_rect_linear below.
251 * This corresponds to the smalled bounding rectangle of the
252 * latest framebuffer update.
253 */
254typedef struct {
255    int xmin, ymin, xmax, ymax;
256} FbUpdateRect;
257
258/* Determine the smallest bounding rectangle of pixels which changed
259 * between the source (framebuffer) and destination (surface) pixel
260 * buffers.
261 *
262 * Return 0 if there was no change, otherwise, populate '*rect'
263 * and return 1.
264 *
265 * If 'dirty_base' is not 0, it is a physical address that will be
266 * used to speed-up the check using the VGA dirty bits. In practice
267 * this is only used if your kernel driver does not implement.
268 *
269 * This function assumes that the framebuffers are in linear memory.
270 * This may change later when we want to support larger framebuffers
271 * that exceed the max DMA aperture size though.
272 */
273static int
274compute_fb_update_rect_linear(FbUpdateState*  fbs,
275                              uint32_t        dirty_base,
276                              FbUpdateRect*   rect)
277{
278    int  yy;
279    int  width = fbs->width;
280    const uint8_t* src_line = fbs->src_pixels;
281    uint8_t*       dst_line = fbs->dst_pixels;
282    uint32_t       dirty_addr = dirty_base;
283    rect->xmin = rect->ymin = INT_MAX;
284    rect->xmax = rect->ymax = INT_MIN;
285    for (yy = 0; yy < fbs->height; yy++) {
286        int xx1, xx2;
287        /* If dirty_addr is != 0, then use it as a physical address to
288         * use the VGA dirty bits table to speed up the detection of
289         * changed pixels.
290         */
291        if (dirty_addr != 0) {
292            int  dirty = 0;
293            int  len   = fbs->src_pitch;
294
295            while (len > 0) {
296                int  len2 = TARGET_PAGE_SIZE - (dirty_addr & (TARGET_PAGE_SIZE-1));
297
298                if (len2 > len)
299                    len2 = len;
300
301                dirty |= cpu_physical_memory_get_dirty(dirty_addr, VGA_DIRTY_FLAG);
302                dirty_addr  += len2;
303                len         -= len2;
304            }
305
306            if (!dirty) { /* this line was not modified, skip to next one */
307                goto NEXT_LINE;
308            }
309        }
310
311        /* Then compute actual bounds of the changed pixels, while
312         * copying them from 'src' to 'dst'. This depends on the pixel depth.
313         */
314        switch (fbs->bytes_per_pixel) {
315        case 2:
316        {
317            const uint16_t* src = (const uint16_t*) src_line;
318            uint16_t*       dst = (uint16_t*) dst_line;
319
320            xx1 = 0;
321            DUFF4(width, {
322                uint16_t spix = src[xx1];
323#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
324                spix = (uint16_t)((spix << 8) | (spix >> 8));
325#endif
326                if (spix != dst[xx1])
327                    break;
328                xx1++;
329            });
330            if (xx1 == width) {
331                break;
332            }
333            xx2 = width-1;
334            DUFF4(xx2-xx1, {
335                if (src[xx2] != dst[xx2])
336                    break;
337                xx2--;
338            });
339#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
340            /* Convert the guest pixels into host ones */
341            int xx = xx1;
342            DUFF4(xx2-xx1+1,{
343                unsigned   spix = src[xx];
344                dst[xx] = (uint16_t)((spix << 8) | (spix >> 8));
345                xx++;
346            });
347#else
348            memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*2 );
349#endif
350            break;
351        }
352
353        case 3:
354        {
355            xx1 = 0;
356            DUFF4(width, {
357                int xx = xx1*3;
358                if (src_line[xx+0] != dst_line[xx+0] ||
359                    src_line[xx+1] != dst_line[xx+1] ||
360                    src_line[xx+2] != dst_line[xx+2]) {
361                    break;
362                }
363                xx1 ++;
364            });
365            if (xx1 == width) {
366                break;
367            }
368            xx2 = width-1;
369            DUFF4(xx2-xx1,{
370                int xx = xx2*3;
371                if (src_line[xx+0] != dst_line[xx+0] ||
372                    src_line[xx+1] != dst_line[xx+1] ||
373                    src_line[xx+2] != dst_line[xx+2]) {
374                    break;
375                }
376                xx2--;
377            });
378            memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 );
379            break;
380        }
381
382        case 4:
383        {
384            const uint32_t* src = (const uint32_t*) src_line;
385            uint32_t*       dst = (uint32_t*) dst_line;
386
387            xx1 = 0;
388            DUFF4(width, {
389                uint32_t spix = src[xx1];
390#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
391                spix = (spix << 16) | (spix >> 16);
392                spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff);
393#endif
394                if (spix != dst[xx1]) {
395                    break;
396                }
397                xx1++;
398            });
399            if (xx1 == width) {
400                break;
401            }
402            xx2 = width-1;
403            DUFF4(xx2-xx1,{
404                if (src[xx2] != dst[xx2]) {
405                    break;
406                }
407                xx2--;
408            });
409#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
410            /* Convert the guest pixels into host ones */
411            int xx = xx1;
412            DUFF4(xx2-xx1+1,{
413                uint32_t   spix = src[xx];
414                spix = (spix << 16) | (spix >> 16);
415                spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff);
416                dst[xx] = spix;
417                xx++;
418            })
419#else
420            memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*4 );
421#endif
422            break;
423        }
424        default:
425            return 0;
426        }
427        /* Update bounds if pixels on this line were modified */
428        if (xx1 < width) {
429            if (xx1 < rect->xmin) rect->xmin = xx1;
430            if (xx2 > rect->xmax) rect->xmax = xx2;
431            if (yy < rect->ymin) rect->ymin = yy;
432            if (yy > rect->ymax) rect->ymax = yy;
433        }
434    NEXT_LINE:
435        src_line += fbs->src_pitch;
436        dst_line += fbs->dst_pitch;
437    }
438
439    if (rect->ymin > rect->ymax) { /* nothing changed */
440        return 0;
441    }
442
443    /* Always clear the dirty VGA bits */
444    cpu_physical_memory_reset_dirty(dirty_base + rect->ymin * fbs->src_pitch,
445                                    dirty_base + (rect->ymax+1)* fbs->src_pitch,
446                                    VGA_DIRTY_FLAG);
447    return 1;
448}
449
450
451static void goldfish_fb_update_display(void *opaque)
452{
453    struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
454    uint32_t base;
455    uint8_t*  dst_line;
456    uint8_t*  src_line;
457    int full_update = 0;
458    int  width, height, pitch;
459
460    base = s->fb_base;
461    if(base == 0)
462        return;
463
464    if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) {
465        s->int_status |= FB_INT_VSYNC;
466        goldfish_device_set_irq(&s->dev, 0, 1);
467    }
468
469    if(s->need_update) {
470        full_update = 1;
471        if(s->need_int) {
472            s->int_status |= FB_INT_BASE_UPDATE_DONE;
473            if(s->int_enable & FB_INT_BASE_UPDATE_DONE)
474                goldfish_device_set_irq(&s->dev, 0, 1);
475        }
476        s->need_int = 0;
477        s->need_update = 0;
478    }
479
480    src_line  = qemu_get_ram_ptr( base );
481
482    dst_line  = s->ds->surface->data;
483    pitch     = s->ds->surface->linesize;
484    width     = s->ds->surface->width;
485    height    = s->ds->surface->height;
486
487    FbUpdateState  fbs;
488    FbUpdateRect   rect;
489
490    fbs.width      = width;
491    fbs.height     = height;
492    fbs.dst_pixels = dst_line;
493    fbs.dst_pitch  = pitch;
494    fbs.bytes_per_pixel = goldfish_fb_get_bytes_per_pixel(s);
495
496    fbs.src_pixels = src_line;
497    fbs.src_pitch  = width*s->ds->surface->pf.bytes_per_pixel;
498
499
500#if STATS
501    if (full_update)
502        stats_full_updates += 1;
503    if (++stats_counter == 120) {
504        stats_total               += stats_counter;
505        stats_total_full_updates  += stats_full_updates;
506
507        printf( "full update stats:  peak %.2f %%  total %.2f %%\n",
508                stats_full_updates*100.0/stats_counter,
509                stats_total_full_updates*100.0/stats_total );
510
511        stats_counter      = 0;
512        stats_full_updates = 0;
513    }
514#endif /* STATS */
515
516    if (s->blank)
517    {
518        memset( dst_line, 0, height*pitch );
519        rect.xmin = 0;
520        rect.ymin = 0;
521        rect.xmax = width-1;
522        rect.ymax = height-1;
523    }
524    else
525    {
526        if (full_update) { /* don't use dirty-bits optimization */
527            base = 0;
528        }
529        if (compute_fb_update_rect_linear(&fbs, base, &rect) == 0) {
530            return;
531        }
532    }
533
534    rect.xmax += 1;
535    rect.ymax += 1;
536#if 0
537    printf("goldfish_fb_update_display (y:%d,h:%d,x=%d,w=%d)\n",
538           rect.ymin, rect.ymax-rect.ymin, rect.xmin, rect.xmax-rect.xmin);
539#endif
540
541    dpy_update(s->ds, rect.xmin, rect.ymin, rect.xmax-rect.xmin, rect.ymax-rect.ymin);
542}
543
544static void goldfish_fb_invalidate_display(void * opaque)
545{
546    // is this called?
547    struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
548    s->need_update = 1;
549}
550
551static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
552{
553    uint32_t ret;
554    struct goldfish_fb_state *s = opaque;
555
556    switch(offset) {
557        case FB_GET_WIDTH:
558            ret = ds_get_width(s->ds);
559            //printf("FB_GET_WIDTH => %d\n", ret);
560            return ret;
561
562        case FB_GET_HEIGHT:
563            ret = ds_get_height(s->ds);
564            //printf( "FB_GET_HEIGHT = %d\n", ret);
565            return ret;
566
567        case FB_INT_STATUS:
568            ret = s->int_status & s->int_enable;
569            if(ret) {
570                s->int_status &= ~ret;
571                goldfish_device_set_irq(&s->dev, 0, 0);
572            }
573            return ret;
574
575        case FB_GET_PHYS_WIDTH:
576            ret = pixels_to_mm( ds_get_width(s->ds), s->dpi );
577            //printf( "FB_GET_PHYS_WIDTH => %d\n", ret );
578            return ret;
579
580        case FB_GET_PHYS_HEIGHT:
581            ret = pixels_to_mm( ds_get_height(s->ds), s->dpi );
582            //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret );
583            return ret;
584
585        case FB_GET_FORMAT:
586            return goldfish_fb_get_pixel_format(s);
587
588        default:
589            cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset);
590            return 0;
591    }
592}
593
594static void goldfish_fb_write(void *opaque, target_phys_addr_t offset,
595                        uint32_t val)
596{
597    struct goldfish_fb_state *s = opaque;
598
599    switch(offset) {
600        case FB_INT_ENABLE:
601            s->int_enable = val;
602            goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
603            break;
604        case FB_SET_BASE: {
605            int need_resize = !s->base_valid;
606            s->fb_base = val;
607            s->int_status &= ~FB_INT_BASE_UPDATE_DONE;
608            s->need_update = 1;
609            s->need_int = 1;
610            s->base_valid = 1;
611            if(s->set_rotation != s->rotation) {
612                //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation);
613                s->rotation = s->set_rotation;
614                need_resize = 1;
615            }
616            goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
617            if (need_resize) {
618                //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation );
619                dpy_resize(s->ds);
620            }
621            } break;
622        case FB_SET_ROTATION:
623            //printf( "FB_SET_ROTATION %d\n", val);
624            s->set_rotation = val;
625            break;
626        case FB_SET_BLANK:
627            s->blank = val;
628            s->need_update = 1;
629            break;
630        default:
631            cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset);
632    }
633}
634
635static CPUReadMemoryFunc *goldfish_fb_readfn[] = {
636   goldfish_fb_read,
637   goldfish_fb_read,
638   goldfish_fb_read
639};
640
641static CPUWriteMemoryFunc *goldfish_fb_writefn[] = {
642   goldfish_fb_write,
643   goldfish_fb_write,
644   goldfish_fb_write
645};
646
647void goldfish_fb_init(int id)
648{
649    struct goldfish_fb_state *s;
650
651    s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s));
652    s->dev.name = "goldfish_fb";
653    s->dev.id = id;
654    s->dev.size = 0x1000;
655    s->dev.irq_count = 1;
656
657    s->ds = graphic_console_init(goldfish_fb_update_display,
658                                 goldfish_fb_invalidate_display,
659                                 NULL,
660                                 NULL,
661                                 s);
662
663    s->dpi = 165;  /* XXX: Find better way to get actual value ! */
664
665    /* IMPORTANT: DO NOT COMPUTE s->pixel_format and s->bytes_per_pixel
666     * here because the display surface is going to change later.
667     */
668    s->bytes_per_pixel = 0;
669    s->pixel_format    = -1;
670
671    goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
672
673    register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
674                     goldfish_fb_save, goldfish_fb_load, s);
675}
676