aboutsummaryrefslogtreecommitdiff
path: root/hw/display/sm501.c
diff options
context:
space:
mode:
authorBALATON Zoltan <balaton@eik.bme.hu>2017-04-21 17:18:09 +0200
committerPeter Maydell <peter.maydell@linaro.org>2017-04-24 12:32:12 +0100
commit6a2a5aae02b9a0b53807b9ad91f15cd4988781f9 (patch)
treecbd408e8bf03553a6dd13c223fe02f6d00285ddc /hw/display/sm501.c
parentafef2e1d537dce002f15ab12d85e99baaa7b6651 (diff)
sm501: Fix hardware cursor
Rework HWC handling to simplify it and fix cursor not updating on screen as needed. Previously cursor was not updated because checking for changes in a line overrode the update flag set for the cursor but fixing this is not enough because the cursor should also be updated if its shape or location changes. Introduce hwc_invalidate() function to handle that similar to other display controller models. Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Tested-by: Aurelien Jarno <aurelien@aurel32.net> Message-id: 6970a5e9868b7246656c1d02038dc5d5fa369507.1492787889.git.balaton@eik.bme.hu Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/display/sm501.c')
-rw-r--r--hw/display/sm501.c169
1 files changed, 97 insertions, 72 deletions
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index a628ef194d..72e86bad95 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -554,6 +554,24 @@ static uint32_t get_local_mem_size_index(uint32_t size)
return index;
}
+static inline int get_width(SM501State *s, int crt)
+{
+ int width = crt ? s->dc_crt_h_total : s->dc_panel_h_total;
+ return (width & 0x00000FFF) + 1;
+}
+
+static inline int get_height(SM501State *s, int crt)
+{
+ int height = crt ? s->dc_crt_v_total : s->dc_panel_v_total;
+ return (height & 0x00000FFF) + 1;
+}
+
+static inline int get_bpp(SM501State *s, int crt)
+{
+ int bpp = crt ? s->dc_crt_control : s->dc_panel_control;
+ return 1 << (bpp & 3);
+}
+
/**
* Check the availability of hardware cursor.
* @param crt 0 for PANEL, 1 for CRT.
@@ -568,10 +586,10 @@ static inline int is_hwc_enabled(SM501State *state, int crt)
* Get the address which holds cursor pattern data.
* @param crt 0 for PANEL, 1 for CRT.
*/
-static inline uint32_t get_hwc_address(SM501State *state, int crt)
+static inline uint8_t *get_hwc_address(SM501State *state, int crt)
{
uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
- return (addr & 0x03FFFFF0)/* >> 4*/;
+ return state->local_mem + (addr & 0x03FFFFF0);
}
/**
@@ -597,50 +615,48 @@ static inline uint32_t get_hwc_x(SM501State *state, int crt)
}
/**
- * Get the cursor position in x coordinate.
+ * Get the hardware cursor palette.
* @param crt 0 for PANEL, 1 for CRT.
- * @param index 0, 1, 2 or 3 which specifies color of corsor dot.
+ * @param palette pointer to a [3 * 3] array to store color values in
*/
-static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
+static inline void get_hwc_palette(SM501State *state, int crt, uint8_t *palette)
{
- uint32_t color_reg = 0;
- uint16_t color_565 = 0;
-
- if (index == 0) {
- return 0;
- }
-
- switch (index) {
- case 1:
- case 2:
- color_reg = crt ? state->dc_crt_hwc_color_1_2
- : state->dc_panel_hwc_color_1_2;
- break;
- case 3:
- color_reg = crt ? state->dc_crt_hwc_color_3
- : state->dc_panel_hwc_color_3;
- break;
- default:
- printf("invalid hw cursor color.\n");
- abort();
- }
+ int i;
+ uint32_t color_reg;
+ uint16_t rgb565;
+
+ for (i = 0; i < 3; i++) {
+ if (i + 1 == 3) {
+ color_reg = crt ? state->dc_crt_hwc_color_3
+ : state->dc_panel_hwc_color_3;
+ } else {
+ color_reg = crt ? state->dc_crt_hwc_color_1_2
+ : state->dc_panel_hwc_color_1_2;
+ }
- switch (index) {
- case 1:
- case 3:
- color_565 = (uint16_t)(color_reg & 0xFFFF);
- break;
- case 2:
- color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
- break;
+ if (i + 1 == 2) {
+ rgb565 = (color_reg >> 16) & 0xFFFF;
+ } else {
+ rgb565 = color_reg & 0xFFFF;
+ }
+ palette[i * 3 + 0] = (rgb565 << 3) & 0xf8; /* red */
+ palette[i * 3 + 1] = (rgb565 >> 3) & 0xfc; /* green */
+ palette[i * 3 + 2] = (rgb565 >> 8) & 0xf8; /* blue */
}
- return color_565;
}
-static int within_hwc_y_range(SM501State *state, int y, int crt)
+static inline void hwc_invalidate(SM501State *s, int crt)
{
- int hwc_y = get_hwc_y(state, crt);
- return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
+ int w = get_width(s, crt);
+ int h = get_height(s, crt);
+ int bpp = get_bpp(s, crt);
+ int start = get_hwc_y(s, crt);
+ int end = MIN(h, start + SM501_HWC_HEIGHT) + 1;
+
+ start *= w * bpp;
+ end *= w * bpp;
+
+ memory_region_set_dirty(&s->local_mem_region, start, end - start);
}
static void sm501_2d_operation(SM501State *s)
@@ -1021,10 +1037,18 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
break;
case SM501_DC_PANEL_HWC_ADDR:
- s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
+ value &= 0x8FFFFFF0;
+ if (value != s->dc_panel_hwc_addr) {
+ hwc_invalidate(s, 0);
+ s->dc_panel_hwc_addr = value;
+ }
break;
case SM501_DC_PANEL_HWC_LOC:
- s->dc_panel_hwc_location = value & 0x0FFF0FFF;
+ value &= 0x0FFF0FFF;
+ if (value != s->dc_panel_hwc_location) {
+ hwc_invalidate(s, 0);
+ s->dc_panel_hwc_location = value;
+ }
break;
case SM501_DC_PANEL_HWC_COLOR_1_2:
s->dc_panel_hwc_color_1_2 = value;
@@ -1056,10 +1080,18 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
break;
case SM501_DC_CRT_HWC_ADDR:
- s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
+ value &= 0x8FFFFFF0;
+ if (value != s->dc_crt_hwc_addr) {
+ hwc_invalidate(s, 1);
+ s->dc_crt_hwc_addr = value;
+ }
break;
case SM501_DC_CRT_HWC_LOC:
- s->dc_crt_hwc_location = value & 0x0FFF0FFF;
+ value &= 0x0FFF0FFF;
+ if (value != s->dc_crt_hwc_location) {
+ hwc_invalidate(s, 1);
+ s->dc_crt_hwc_location = value;
+ }
break;
case SM501_DC_CRT_HWC_COLOR_1_2:
s->dc_crt_hwc_color_1_2 = value;
@@ -1182,8 +1214,9 @@ static const MemoryRegionOps sm501_2d_engine_ops = {
typedef void draw_line_func(uint8_t *d, const uint8_t *s,
int width, const uint32_t *pal);
-typedef void draw_hwc_line_func(SM501State *s, int crt, uint8_t *palette,
- int c_y, uint8_t *d, int width);
+typedef void draw_hwc_line_func(uint8_t *d, const uint8_t *s,
+ int width, const uint8_t *palette,
+ int c_x, int c_y);
#define DEPTH 8
#include "sm501_template.h"
@@ -1271,12 +1304,11 @@ static inline int get_depth_index(DisplaySurface *surface)
static void sm501_draw_crt(SM501State *s)
{
DisplaySurface *surface = qemu_console_surface(s->con);
- int y;
- int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
- int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
-
- uint8_t *src = s->local_mem;
- int src_bpp = 0;
+ int y, c_x = 0, c_y = 0;
+ uint8_t *hwc_src = NULL, *src = s->local_mem;
+ int width = get_width(s, 1);
+ int height = get_height(s, 1);
+ int src_bpp = get_bpp(s, 1);
int dst_bpp = surface_bytes_per_pixel(surface);
uint32_t *palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE -
SM501_DC_PANEL_PALETTE];
@@ -1291,17 +1323,14 @@ static void sm501_draw_crt(SM501State *s)
ram_addr_t offset = 0;
/* choose draw_line function */
- switch (s->dc_crt_control & 3) {
- case SM501_DC_CRT_CONTROL_8BPP:
- src_bpp = 1;
+ switch (src_bpp) {
+ case 1:
draw_line = draw_line8_funcs[ds_depth_index];
break;
- case SM501_DC_CRT_CONTROL_16BPP:
- src_bpp = 2;
+ case 2:
draw_line = draw_line16_funcs[ds_depth_index];
break;
- case SM501_DC_CRT_CONTROL_32BPP:
- src_bpp = 4;
+ case 4:
draw_line = draw_line32_funcs[ds_depth_index];
break;
default:
@@ -1313,18 +1342,12 @@ static void sm501_draw_crt(SM501State *s)
/* set up to draw hardware cursor */
if (is_hwc_enabled(s, 1)) {
- int i;
-
- /* get cursor palette */
- for (i = 0; i < 3; i++) {
- uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
- hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
- hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
- hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
- }
-
/* choose cursor draw line function */
draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
+ hwc_src = get_hwc_address(s, 1);
+ c_x = get_hwc_x(s, 1);
+ c_y = get_hwc_y(s, 1);
+ get_hwc_palette(s, 1, hwc_palette);
}
/* adjust console size */
@@ -1339,14 +1362,16 @@ static void sm501_draw_crt(SM501State *s)
/* draw each line according to conditions */
memory_region_sync_dirty_bitmap(&s->local_mem_region);
for (y = 0; y < height; y++) {
- int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
- int update = full_update || update_hwc;
+ int update, update_hwc;
ram_addr_t page0 = offset;
ram_addr_t page1 = offset + width * src_bpp - 1;
+ /* check if hardware cursor is enabled and we're within its range */
+ update_hwc = draw_hwc_line && c_y <= y && y < c_y + SM501_HWC_HEIGHT;
+ update = full_update || update_hwc;
/* check dirty flags for each line */
- update = memory_region_get_dirty(&s->local_mem_region, page0,
- page1 - page0, DIRTY_MEMORY_VGA);
+ update |= memory_region_get_dirty(&s->local_mem_region, page0,
+ page1 - page0, DIRTY_MEMORY_VGA);
/* draw line and change status */
if (update) {
@@ -1358,7 +1383,7 @@ static void sm501_draw_crt(SM501State *s)
/* draw hardware cursor */
if (update_hwc) {
- draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
+ draw_hwc_line(d, hwc_src, width, hwc_palette, c_x, y - c_y);
}
if (y_start < 0) {