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