xref: /haiku/src/add-ons/accelerants/radeon/Cursor.c (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
1 /*
2 	Copyright (c) 2002-2004, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Hardware cursor support.
8 */
9 
10 
11 #include "radeon_accelerant.h"
12 #include "GlobalData.h"
13 #include "generic.h"
14 #include "mmio.h"
15 #include "crtc_regs.h"
16 
17 static void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y );
18 
19 // set standard foreground/background colours
20 void Radeon_SetCursorColors( accelerator_info *ai, int crtc_idx )
21 {
22 	SHOW_FLOW0( 3, "" );
23 
24 	if( crtc_idx == 0 ) {
25 		OUTREG( ai->regs, RADEON_CUR_CLR0, 0xffffff );
26 		OUTREG( ai->regs, RADEON_CUR_CLR1, 0 );
27 	} else {
28 		OUTREG( ai->regs, RADEON_CUR2_CLR0, 0xffffff );
29 		OUTREG( ai->regs, RADEON_CUR2_CLR1, 0 );
30 	}
31 }
32 
33 // public function to set shape of cursor
34 status_t SET_CURSOR_SHAPE( uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
35 						   uint8 *andMask, uint8 *xorMask)
36 {
37 	virtual_card *vc = ai->vc;
38 	uint8 *fb_cursor = vc->cursor.data;
39 	int row, col_byte;
40 
41 	/* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */
42 /*	if( width != 16 || height != 16 )
43 		return B_ERROR;*/
44 
45 	if( hot_x >= width || hot_y >= height )
46 		return B_ERROR;
47 
48 	// TBD: should we sync here? I'd say so, but if I fail, we deadlock
49 
50 	vc->cursor.hot_x = hot_x;
51 	vc->cursor.hot_y = hot_y;
52 
53 	for( row = 0; row < 64; ++row ) {
54 		for( col_byte = 0; col_byte < 64 / 8; ++col_byte ) {
55 			if( row < height && col_byte < (width + 7) / 8 ) {
56 				fb_cursor[row * 64/8 * 2 + col_byte] = *andMask++;
57 				fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = *xorMask++;
58 			} else {
59 				fb_cursor[row * 64/8 * 2 + col_byte] = 0xff;
60 				fb_cursor[row * 64/8 * 2 + col_byte + 64/8] = 0;
61 			}
62 		}
63 	}
64 
65 	return B_OK;
66 }
67 
68 
69 // public function to move cursor
70 void MOVE_CURSOR(uint16 x, uint16 y)
71 {
72 	virtual_card *vc = ai->vc;
73 	bool move_screen = false;
74 	uint16 hds, vds;
75 
76 	// alignment mask for horizontal position
77 	uint16 h_adjust = 7;
78 
79 	ACQUIRE_BEN( ai->si->engine.lock );
80 
81 	hds = vc->mode.h_display_start;
82 	vds = vc->mode.v_display_start;
83 
84 	// clamp cursor (negative positions are impossible due to uint16)
85 	if (x >= vc->mode.virtual_width)
86 		x = vc->mode.virtual_width - 1;
87 	if (y >= vc->mode.virtual_height)
88 		y = vc->mode.virtual_height - 1;
89 
90 	// if scrolling enabled, i.e. we have a larger virtual screen,
91 	// pan display accordingly
92 	if( vc->scroll ) {
93 		if( x >= (vc->mode.timing.h_display + hds) ) {
94 			hds = ((x - vc->mode.timing.h_display) + 1 + h_adjust) & ~h_adjust;
95 			move_screen = true;
96 		} else if( x < hds ) {
97 			hds = x & ~h_adjust;
98 			move_screen = true;
99 		}
100 		if( y >= (vc->mode.timing.v_display + vds) ) {
101 			vds = y - vc->mode.timing.v_display + 1;
102 			move_screen = true;
103 		} else if( y < vds ) {
104 			vds = y;
105 			move_screen = true;
106 		}
107 
108 		if( move_screen )
109 			Radeon_MoveDisplay( ai, hds, vds );
110 	}
111 
112 	// adjust according to virtual screen position
113 	x -= hds;
114 	y -= vds;
115 
116 	// go
117 	if( vc->used_crtc[0] )
118 		moveOneCursor( ai, 0, x, y );
119 	if( vc->used_crtc[1] )
120 		moveOneCursor( ai, 1, x, y );
121 
122 	RELEASE_BEN( ai->si->engine.lock );
123 }
124 
125 
126 // public function to show cursor
127 void SHOW_CURSOR( bool is_visible )
128 {
129 	virtual_card *vc = ai->vc;
130 
131 	SHOW_FLOW0( 4, "" );
132 
133 	ACQUIRE_BEN( ai->si->engine.lock );
134 
135 	// this is the public statement
136 	vc->cursor.is_visible = is_visible;
137 
138 	// the following functions take also care to not
139 	// show the cursor if it's on the other port
140 	if( vc->used_crtc[0] )
141 		Radeon_ShowCursor( ai, 0 );
142 	if( vc->used_crtc[1] )
143 		Radeon_ShowCursor( ai, 1 );
144 
145 	RELEASE_BEN( ai->si->engine.lock );
146 }
147 
148 
149 // move cursor on one port
150 //	main_port - common data is stored here
151 void moveOneCursor( accelerator_info *ai, int crtc_idx, int x, int y )
152 {
153 	virtual_card *vc = ai->vc;
154 	crtc_info *crtc = &ai->si->crtc[crtc_idx];
155 	int xorigin, yorigin;
156 	bool prev_state;
157 
158 	// adjust according to relative screen position
159 	x -= crtc->rel_x;
160 	y -= crtc->rel_y;
161 
162 	// and to hot spot
163 	x -= vc->cursor.hot_x;
164 	y -= vc->cursor.hot_y;
165 
166 	// check whether the cursor is (partially) visible on this screen
167    	prev_state = crtc->cursor_on_screen;
168 	crtc->cursor_on_screen = true;
169 
170 	// in theory, cursor can be up to 64 pixels off screen,
171 	// but there were display errors
172 	if( y > crtc->mode.timing.v_display ||
173 		x > crtc->mode.timing.h_display ||
174 		x <= -16 || y <= -16 )
175 	{
176 		crtc->cursor_on_screen = false;
177 	}
178 
179 	if( prev_state != crtc->cursor_on_screen )
180 		Radeon_ShowCursor( ai, crtc_idx );
181 
182 	if( !crtc->cursor_on_screen )
183 		return;
184 
185 	// if upper-left corner of cursor is outside of
186 	// screen, we have to use special registers to clip it
187 	xorigin = 0;
188 	yorigin = 0;
189 
190     if( x < 0 )
191     	xorigin = -x;
192 
193     if( y < 0 )
194     	yorigin = -y;
195 
196 	if( crtc_idx == 0 )	{
197 		OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_OFF, RADEON_CUR_LOCK
198 			| (xorigin << 16)
199 			| yorigin );
200 		OUTREG( ai->regs, RADEON_CUR_HORZ_VERT_POSN, RADEON_CUR_LOCK
201 			| ((xorigin ? 0 : x) << 16)
202 			| (yorigin ? 0 : y) );
203 		OUTREG( ai->regs, RADEON_CUR_OFFSET,
204 			vc->cursor.fb_offset + xorigin + yorigin * 16 );
205 	} else {
206 		OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_OFF, RADEON_CUR2_LOCK
207 			| (xorigin << 16)
208 			| yorigin );
209 		OUTREG( ai->regs, RADEON_CUR2_HORZ_VERT_POSN, RADEON_CUR2_LOCK
210 			| ((xorigin ? 0 : x) << 16)
211 			| (yorigin ? 0 : y) );
212 		OUTREG( ai->regs, RADEON_CUR2_OFFSET,
213 			vc->cursor.fb_offset + xorigin + yorigin * 16 );
214 	}
215 }
216 
217 
218 // show cursor on one port, depending on official whishes and whether
219 // cursor is located on this subscreen
220 void Radeon_ShowCursor( accelerator_info *ai, int crtc_idx )
221 {
222 	virtual_card *vc = ai->vc;
223 	crtc_info *crtc = &ai->si->crtc[crtc_idx];
224 	uint32 tmp;
225 
226 	if( crtc_idx == 0 ) {
227 		tmp = INREG( ai->regs, RADEON_CRTC_GEN_CNTL );
228 
229 		if( vc->cursor.is_visible && crtc->cursor_on_screen ) {
230 			tmp |= RADEON_CRTC_CUR_EN;
231 		} else {
232 			tmp &= ~RADEON_CRTC_CUR_EN;
233 		}
234 
235 		OUTREG( ai->regs, RADEON_CRTC_GEN_CNTL, tmp );
236 
237 	} else {
238 		tmp = INREG( ai->regs, RADEON_CRTC2_GEN_CNTL );
239 
240 		if( vc->cursor.is_visible && crtc->cursor_on_screen )
241 			tmp |= RADEON_CRTC2_CUR_EN;
242 		else
243 			tmp &= ~RADEON_CRTC2_CUR_EN;
244 
245 		OUTREG( ai->regs, RADEON_CRTC2_GEN_CNTL, tmp );
246 	}
247 }
248