pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Framebuffer device helper routines |
| 3 | * |
| 4 | * Copyright (c) 2009 CodeSourcery |
| 5 | * Written by Paul Brook <paul@codesourcery.com> |
| 6 | * |
| 7 | * This code is licensed under the GNU GPLv2. |
| 8 | */ |
| 9 | |
| 10 | /* TODO: |
| 11 | - Do something similar for framebuffers with local ram |
| 12 | - Handle rotation here instead of hacking dest_pitch |
| 13 | - Use common pixel conversion routines instead of per-device drawfn |
| 14 | - Remove all DisplayState knowledge from devices. |
| 15 | */ |
| 16 | |
| 17 | #include "hw.h" |
| 18 | #include "console.h" |
| 19 | #include "framebuffer.h" |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 20 | |
| 21 | /* Render an image from a shared memory framebuffer. */ |
| 22 | |
| 23 | void framebuffer_update_display( |
| 24 | DisplayState *ds, |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 25 | target_phys_addr_t base, |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 26 | int cols, /* Width in pixels. */ |
| 27 | int rows, /* Leight in pixels. */ |
| 28 | int src_width, /* Length of source line, in bytes. */ |
| 29 | int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */ |
| 30 | int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */ |
| 31 | int invalidate, /* nonzero to redraw the whole image. */ |
| 32 | drawfn fn, |
| 33 | void *opaque, |
| 34 | int *first_row, /* Input and output. */ |
| 35 | int *last_row /* Output only */) |
| 36 | { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 37 | target_phys_addr_t src_len; |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 38 | uint8_t *dest; |
| 39 | uint8_t *src; |
| 40 | uint8_t *src_base; |
| 41 | int first, last = 0; |
| 42 | int dirty; |
| 43 | int i; |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 44 | ram_addr_t addr; |
| 45 | ram_addr_t pd; |
| 46 | ram_addr_t pd2; |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 47 | |
| 48 | i = *first_row; |
| 49 | *first_row = -1; |
| 50 | src_len = src_width * rows; |
| 51 | |
Jan Kiszka | 93102fd | 2009-05-02 00:29:37 +0200 | [diff] [blame] | 52 | cpu_physical_sync_dirty_bitmap(base, base + src_len); |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 53 | pd = cpu_get_physical_page_desc(base); |
| 54 | pd2 = cpu_get_physical_page_desc(base + src_len - 1); |
| 55 | /* We should reall check that this is a continuous ram region. |
| 56 | Instead we just check that the first and last pages are |
| 57 | both ram, and the right distance apart. */ |
| 58 | if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM |
| 59 | || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { |
| 60 | return; |
| 61 | } |
| 62 | pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK); |
| 63 | if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) { |
| 64 | return; |
| 65 | } |
| 66 | |
| 67 | src_base = cpu_physical_memory_map(base, &src_len, 0); |
| 68 | /* If we can't map the framebuffer then bail. We could try harder, |
| 69 | but it's not really worth it as dirty flag tracking will probably |
| 70 | already have failed above. */ |
| 71 | if (!src_base) |
| 72 | return; |
| 73 | if (src_len != src_width * rows) { |
| 74 | cpu_physical_memory_unmap(src_base, src_len, 0, 0); |
| 75 | return; |
| 76 | } |
| 77 | src = src_base; |
| 78 | dest = ds_get_data(ds); |
| 79 | if (dest_col_pitch < 0) |
| 80 | dest -= dest_col_pitch * (cols - 1); |
| 81 | first = -1; |
| 82 | addr = pd; |
| 83 | |
| 84 | addr += i * src_width; |
| 85 | src += i * src_width; |
| 86 | dest += i * dest_row_pitch; |
| 87 | |
| 88 | for (; i < rows; i++) { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 89 | target_phys_addr_t dirty_offset; |
pbrook | 714fa30 | 2009-04-01 12:27:59 +0000 | [diff] [blame] | 90 | dirty = 0; |
| 91 | dirty_offset = 0; |
| 92 | while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) { |
| 93 | dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset, |
| 94 | VGA_DIRTY_FLAG); |
| 95 | dirty_offset += TARGET_PAGE_SIZE; |
| 96 | } |
| 97 | |
| 98 | if (dirty || invalidate) { |
| 99 | fn(opaque, dest, src, cols, dest_col_pitch); |
| 100 | if (first == -1) |
| 101 | first = i; |
| 102 | last = i; |
| 103 | } |
| 104 | addr += src_width; |
| 105 | src += src_width; |
| 106 | dest += dest_row_pitch; |
| 107 | } |
| 108 | cpu_physical_memory_unmap(src_base, src_len, 0, 0); |
| 109 | if (first < 0) { |
| 110 | return; |
| 111 | } |
| 112 | cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG); |
| 113 | *first_row = first; |
| 114 | *last_row = last; |
| 115 | return; |
| 116 | } |