1/*
2	Copyright (c) 2002, Thomas Kurschel
3
4
5	Part of Radeon accelerant
6
7	Public functions to provide 2D hardware acceleration
8*/
9
10
11#include "radeon_accelerant.h"
12#include "GlobalData.h"
13#include "generic.h"
14#include "3d_regs.h"
15#include "2d_regs.h"
16#include "radeon_regs.h"
17#include "mmio.h"
18#include "CP.h"
19
20
21// copy screen to screen
22//	et - ignored
23//	list - list of rectangles
24//	count - number of rectangles
25void SCREEN_TO_SCREEN_BLIT_DMA(engine_token *et, blit_params *list, uint32 count)
26{
27	virtual_card *vc = ai->vc;
28
29	SHOW_FLOW0( 4, "" );
30
31	(void)et;
32
33	while( count > 0 ) {
34		uint32 sub_count;
35
36		START_IB();
37
38		WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_BITBLT_MULTI, count,
39			INDIRECT_BUFFER_SIZE, 3, 2 );
40
41		*buffer++ = RADEON_GMC_BRUSH_NONE
42			| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
43			| RADEON_GMC_SRC_DATATYPE_COLOR
44			| RADEON_ROP3_S
45			| RADEON_DP_SRC_SOURCE_MEMORY;
46
47		for( ; sub_count > 0; --sub_count, ++list ) {
48			*buffer++ = (list->src_left << 16) | list->src_top;
49			*buffer++ = (list->dest_left << 16) | list->dest_top;
50			*buffer++ = ((list->width + 1) << 16) | (list->height + 1);
51		}
52
53		SUBMIT_IB_VC();
54	}
55
56	++ai->si->engine.count;
57}
58
59#define SRC_DSTCOLOR			0x00030000
60#define DP_SRC_RECT				0x00000200
61
62void SCREEN_TO_SCREEN_BLIT_PIO(engine_token *et, blit_params *list, uint32 count)
63{
64	int xdir;
65	int ydir;
66	virtual_card *vc = ai->vc;
67
68	SHOW_FLOW0( 4, "" );
69
70	Radeon_WaitForFifo ( ai , 1 );
71
72	// Setup for Screen to screen blit
73	OUTREG(ai->regs, RADEON_DP_GUI_MASTER_CNTL, (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT
74								 | RADEON_GMC_BRUSH_NONE
75								 | RADEON_GMC_SRC_DATATYPE_COLOR
76								 | RADEON_ROP3_S
77								 | RADEON_DP_SRC_SOURCE_MEMORY
78								 | RADEON_GMC_SRC_PITCH_OFFSET_CNTL));
79
80
81	for( ; count > 0; --count, ++list ) {
82
83		// make sure there is space in the FIFO for 4 register writes
84		Radeon_WaitForFifo ( ai , 4 );
85
86		xdir = ((list->src_left < list->dest_left) && (list->src_top == list->dest_top)) ? -1 : 1;
87		ydir = (list->src_top < list->dest_top) ? -1 : 1;
88
89		if (xdir < 0) list->src_left += list->width , list->dest_left += list->width ;
90    	if (ydir < 0) list->src_top += list->height , list->dest_top += list->height ;
91
92		OUTREG(ai->regs, RADEON_DP_CNTL, ((xdir >= 0 ? RADEON_DST_X_LEFT_TO_RIGHT : 0)
93										| (ydir >= 0 ? RADEON_DST_Y_TOP_TO_BOTTOM : 0)));
94
95		// Tell the engine where the source data resides.
96		OUTREG( ai->regs, RADEON_SRC_Y_X, (list->src_top << 16 ) | list->src_left);
97		OUTREG( ai->regs, RADEON_DST_Y_X, (list->dest_top << 16 ) | list->dest_left);
98
99		// this is the blt initiator.
100		OUTREG( ai->regs, RADEON_DST_HEIGHT_WIDTH, ((list->height + 1) << 16 ) | (list->width + 1));
101
102	}
103
104	++ai->si->engine.count;
105	(void)et;
106
107}
108
109
110// fill rectangles on screen
111//	et - ignored
112//	colorIndex - fill colour
113//	list - list of rectangles
114//	count - number of rectangles
115void FILL_RECTANGLE_DMA(engine_token *et, uint32 colorIndex,
116	fill_rect_params *list, uint32 count)
117{
118	virtual_card *vc = ai->vc;
119
120	SHOW_FLOW0( 4, "" );
121
122	(void)et;
123
124	while( count > 0 ) {
125		uint32 sub_count;
126
127		START_IB();
128
129		WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
130			INDIRECT_BUFFER_SIZE, 2, 3 );
131
132		*buffer++ = RADEON_GMC_BRUSH_SOLID_COLOR
133				| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
134				| RADEON_GMC_SRC_DATATYPE_COLOR
135				| RADEON_ROP3_P;
136		*buffer++ = colorIndex;
137
138		for( ; sub_count > 0; --sub_count, ++list ) {
139			*buffer++ = (list->left << 16) | list->top;
140			*buffer++ =
141				((list->right - list->left + 1) << 16) |
142				(list->bottom - list->top + 1);
143		}
144
145		SUBMIT_IB_VC();
146	}
147
148	++ai->si->engine.count;
149}
150
151
152// fill rectangles on screen
153//	et - ignored
154//	colorIndex - fill colour
155//	list - list of rectangles
156//	count - number of rectangles
157#define BRUSH_SOLIDCOLOR		0x00000d00
158
159void FILL_RECTANGLE_PIO(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count)
160{
161	virtual_card *vc = ai->vc;
162
163	SHOW_FLOW( 4, "colorIndex", colorIndex);
164
165	Radeon_WaitForFifo(ai, 3);
166    OUTREG(ai->regs, RADEON_DP_GUI_MASTER_CNTL, ((vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
167									 | RADEON_GMC_BRUSH_SOLID_COLOR
168									 | RADEON_GMC_SRC_DATATYPE_COLOR
169									 | RADEON_ROP3_P));
170	// Set brush colour
171    OUTREG(ai->regs, RADEON_DP_BRUSH_FRGD_CLR,  colorIndex);
172    OUTREG(ai->regs, RADEON_DP_CNTL, (RADEON_DST_X_LEFT_TO_RIGHT | RADEON_DST_Y_TOP_TO_BOTTOM));
173
174	for( ; count > 0; --count, ++list )
175	{
176
177		Radeon_WaitForFifo(ai, 2);
178		OUTREG(ai->regs, RADEON_DST_Y_X,          (list->top << 16) | list->left);
179		OUTREG(ai->regs, RADEON_DST_WIDTH_HEIGHT, ((list->right - list->left + 1) << 16) | (list->bottom - list->top + 1));
180
181	}
182	++ai->si->engine.count;
183	(void)et;
184}
185
186
187
188// invert rectangle on screen
189//	et - ignored
190//	list - list of rectangles
191//	count - number of rectangles
192void INVERT_RECTANGLE_DMA(engine_token *et, fill_rect_params *list, uint32 count)
193{
194	virtual_card *vc = ai->vc;
195
196	SHOW_FLOW0( 4, "" );
197
198	(void)et;
199
200	while( count > 0 ) {
201		uint32 sub_count;
202
203		START_IB();
204
205		// take core to leave space for ROP reset!
206		WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
207			INDIRECT_BUFFER_SIZE - 2, 2, 2 );
208
209		*buffer++ = RADEON_GMC_BRUSH_NONE
210			| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
211			| RADEON_GMC_SRC_DATATYPE_COLOR
212			| RADEON_ROP3_Dn;
213
214		for( ; sub_count > 0; --sub_count, ++list ) {
215			*buffer++ = (list->left << 16) | list->top;
216			*buffer++ =
217				((list->right - list->left + 1) << 16) |
218				(list->bottom - list->top + 1);
219		}
220
221		// we have to reset ROP, else we get garbage during next
222		// CPU access; it looks like some cache coherency/forwarding
223		// problem as it goes away later on; things like flushing the
224		// destination cache or waiting for 2D engine or HDP to become
225		// idle and clean didn't change a thing
226		// (I dont't really understand what exactly happens,
227		//  but this code fixes it)
228		*buffer++ = CP_PACKET0( RADEON_DP_GUI_MASTER_CNTL, 1 );
229		*buffer++ = RADEON_GMC_BRUSH_NONE
230			| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
231			| RADEON_GMC_SRC_DATATYPE_COLOR
232			| RADEON_ROP3_S
233			| RADEON_DP_SRC_SOURCE_MEMORY;
234
235		SUBMIT_IB_VC();
236	}
237
238	++ai->si->engine.count;
239}
240
241
242void INVERT_RECTANGLE_PIO(engine_token *et, fill_rect_params *list, uint32 count)
243{
244	virtual_card *vc = ai->vc;
245
246	SHOW_FLOW0( 4, "" );
247
248	Radeon_WaitForFifo(ai, 3);
249    OUTREG(ai->regs, RADEON_DP_GUI_MASTER_CNTL, ((vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
250									 | RADEON_GMC_BRUSH_NONE
251									 | RADEON_GMC_SRC_DATATYPE_COLOR
252									 | RADEON_ROP3_Dn
253									 | RADEON_DP_SRC_SOURCE_MEMORY));
254
255    OUTREG(ai->regs, RADEON_DP_CNTL, (RADEON_DST_X_LEFT_TO_RIGHT | RADEON_DST_Y_TOP_TO_BOTTOM));
256
257	for( ; count > 0; --count, ++list )
258	{
259
260		Radeon_WaitForFifo(ai, 2);
261		OUTREG(ai->regs, RADEON_DST_Y_X,          (list->top << 16) | list->left);
262		OUTREG(ai->regs, RADEON_DST_WIDTH_HEIGHT, ((list->right - list->left + 1) << 16) | (list->bottom - list->top + 1));
263	}
264
265	++ai->si->engine.count;
266	(void)et;
267
268}
269
270// fill horizontal spans on screen
271//	et - ignored
272//	colorIndex - fill colour
273//	list - list of spans
274//	count - number of spans
275void FILL_SPAN_DMA(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count)
276{
277	virtual_card *vc = ai->vc;
278
279	SHOW_FLOW0( 4, "" );
280
281	(void)et;
282
283	while( count > 0 ) {
284		uint32 sub_count;
285
286		START_IB();
287
288		WRITE_IB_PACKET3_HEAD( RADEON_CP_PACKET3_CNTL_PAINT_MULTI, count,
289			INDIRECT_BUFFER_SIZE , 2, 3 );
290
291		*buffer++ = RADEON_GMC_BRUSH_SOLID_COLOR
292			| (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
293			| RADEON_GMC_SRC_DATATYPE_COLOR
294			| RADEON_ROP3_P;
295		*buffer++ = colorIndex;
296
297		for( ; sub_count > 0; --sub_count ) {
298			uint16 y, x, width;
299
300			y = *list++;
301			x = *list++;
302			width = *list++ - x + 1;
303
304			*buffer++ = (x << 16) | y;
305			*buffer++ = (width << 16) | 1;
306		}
307
308		SUBMIT_IB_VC();
309	}
310
311	++ai->si->engine.count;
312}
313
314
315// fill horizontal spans on screen
316//	et - ignored
317//	colorIndex - fill colour
318//	list - list of spans
319//	count - number of spans
320void FILL_SPAN_PIO(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count)
321{
322
323	virtual_card *vc = ai->vc;
324	//int offset = 0;
325	uint16 y, x, width;
326
327	SHOW_FLOW0( 4, "" );
328
329	Radeon_WaitForFifo( ai , 1);
330    OUTREG( ai->regs, RADEON_DP_GUI_MASTER_CNTL, 0
331									 | RADEON_GMC_BRUSH_SOLID_COLOR
332									 | (vc->datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
333									 | RADEON_GMC_SRC_DATATYPE_COLOR
334									 | RADEON_ROP3_P);
335
336	if ( ai->si->asic >= rt_rv200 ) {
337		Radeon_WaitForFifo( ai , 1);
338		OUTREG( ai->regs, RADEON_DST_LINE_PATCOUNT, 0x55 << RADEON_BRES_CNTL_SHIFT);
339	}
340
341	Radeon_WaitForFifo( ai , 1);
342	OUTREG( ai->regs, RADEON_DP_BRUSH_FRGD_CLR,  colorIndex);
343
344	for( ; count > 0; --count ) {
345
346		Radeon_WaitForFifo( ai , 2);
347
348		y = *list++;
349		x = *list++;
350		width = *list++ - x + 1;
351
352	    OUTREG( ai->regs, RADEON_DST_LINE_START,           (y << 16) | x);
353    	OUTREG( ai->regs, RADEON_DST_LINE_END,             ((y) << 16) | (x + width));
354
355	}
356
357	++ai->si->engine.count;
358	(void)et;
359}
360
361
362void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count)
363{
364	if ( ai->si->acc_dma )
365		SCREEN_TO_SCREEN_BLIT_DMA(et,list,count);
366	else
367		SCREEN_TO_SCREEN_BLIT_PIO(et,list,count);
368}
369
370void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count)
371{
372	if ( ai->si->acc_dma )
373		FILL_RECTANGLE_DMA(et, color, list, count);
374	else
375		FILL_RECTANGLE_PIO(et, color, list, count);
376}
377
378void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count)
379{
380	if ( ai->si->acc_dma )
381		INVERT_RECTANGLE_DMA(et, list, count);
382	else
383		INVERT_RECTANGLE_PIO(et, list, count);
384}
385
386void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count)
387{
388	if ( ai->si->acc_dma )
389		FILL_SPAN_DMA(et, color, list, count);
390	else
391		FILL_SPAN_PIO(et, color, list, count);
392
393}
394
395
396// prepare 2D acceleration
397void Radeon_Init2D( accelerator_info *ai )
398{
399	SHOW_FLOW0( 3, "" );
400
401	// forget about 3D
402	if ( ai->si->acc_dma ) {
403		START_IB();
404		WRITE_IB_REG( RADEON_RB3D_CNTL, 0 );
405		SUBMIT_IB();
406	}
407	else {
408		OUTREG( ai->regs, RADEON_RB3D_CNTL, 0 );
409	}
410}
411
412// fill state buffer that sets 2D registers up for accelerated operations
413void Radeon_FillStateBuffer( accelerator_info *ai, uint32 datatype )
414{
415	virtual_card *vc = ai->vc;
416	uint32 pitch_offset;
417	uint32 *buffer = NULL, *buffer_start = NULL;
418
419	SHOW_FLOW0( 4, "" );
420
421	// set offset of frame buffer and pitch
422	pitch_offset =
423		((ai->si->memory[mt_local].virtual_addr_start + vc->fb_offset) >> 10) |
424		((vc->pitch >> 6) << 22);
425
426	if ( ai->si->acc_dma ) {
427		// make sure buffer is not used
428		Radeon_InvalidateStateBuffer( ai, vc->state_buffer_idx );
429		buffer = buffer_start = Radeon_GetIndirectBufferPtr( ai, vc->state_buffer_idx );
430
431		WRITE_IB_REG( RADEON_DEFAULT_OFFSET, pitch_offset );
432		WRITE_IB_REG( RADEON_DST_PITCH_OFFSET, pitch_offset );
433		WRITE_IB_REG( RADEON_SRC_PITCH_OFFSET, pitch_offset );
434		// no sissors
435		WRITE_IB_REG( RADEON_DEFAULT_SC_BOTTOM_RIGHT,
436			(RADEON_DEFAULT_SC_RIGHT_MAX | RADEON_DEFAULT_SC_BOTTOM_MAX));
437
438		// general fluff
439		WRITE_IB_REG( RADEON_DP_GUI_MASTER_CNTL,
440			(datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
441			| RADEON_GMC_CLR_CMP_CNTL_DIS
442
443			| RADEON_GMC_BRUSH_SOLID_COLOR
444			| RADEON_GMC_SRC_DATATYPE_COLOR
445
446			| RADEON_ROP3_P
447			| RADEON_DP_SRC_SOURCE_MEMORY
448			| RADEON_GMC_WR_MSK_DIS );
449
450		// most of this init is probably not necessary
451		// as we neither draw lines nor use brushes
452		WRITE_IB_REG( RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff);
453		WRITE_IB_REG( RADEON_DP_BRUSH_BKGD_CLR, 0x00000000);
454		WRITE_IB_REG( RADEON_DP_SRC_FRGD_CLR,   0xffffffff);
455		WRITE_IB_REG( RADEON_DP_SRC_BKGD_CLR,   0x00000000);
456		WRITE_IB_REG( RADEON_DP_WRITE_MASK,     0xffffffff);
457
458		// this is required
459		vc->state_buffer_size = buffer - buffer_start;
460
461	} else {
462		Radeon_WaitForFifo( ai, 10 );
463		OUTREG( ai->regs, RADEON_DEFAULT_OFFSET, pitch_offset );
464		OUTREG( ai->regs, RADEON_DST_PITCH_OFFSET, pitch_offset );
465		OUTREG( ai->regs, RADEON_SRC_PITCH_OFFSET, pitch_offset );
466		// no sissors
467		OUTREG( ai->regs, RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX
468		    | RADEON_DEFAULT_SC_BOTTOM_MAX));
469		// general fluff
470		OUTREG( ai->regs, RADEON_DP_GUI_MASTER_CNTL,
471			(datatype << RADEON_GMC_DST_DATATYPE_SHIFT)
472			| RADEON_GMC_CLR_CMP_CNTL_DIS
473
474			| RADEON_GMC_BRUSH_SOLID_COLOR
475			| RADEON_GMC_SRC_DATATYPE_COLOR
476
477			| RADEON_ROP3_P
478			| RADEON_DP_SRC_SOURCE_MEMORY
479			| RADEON_GMC_WR_MSK_DIS );
480
481		// most of this init is probably not necessary
482		// as we neither draw lines nor use brushes
483		OUTREG( ai->regs, RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff);
484		OUTREG( ai->regs, RADEON_DP_BRUSH_BKGD_CLR, 0x00000000);
485		OUTREG( ai->regs, RADEON_DP_SRC_FRGD_CLR,   0xffffffff);
486		OUTREG( ai->regs, RADEON_DP_SRC_BKGD_CLR,   0x00000000);
487		OUTREG( ai->regs, RADEON_DP_WRITE_MASK,     0xffffffff);
488
489	}
490
491	ai->si->active_vc = vc->id;
492}
493
494
495// allocate indirect buffer to contain state of virtual card
496void Radeon_AllocateVirtualCardStateBuffer( accelerator_info *ai )
497{
498	virtual_card *vc = ai->vc;
499
500	vc->state_buffer_idx = Radeon_AllocIndirectBuffer( ai, false );
501	// mark as being unused
502	vc->state_buffer_size = -1;
503}
504
505
506// free indirect buffer containing state of virtual card
507void Radeon_FreeVirtualCardStateBuffer( accelerator_info *ai )
508{
509	virtual_card *vc = ai->vc;
510
511	// make sure it's not used anymore
512	Radeon_InvalidateStateBuffer( ai, vc->state_buffer_idx );
513
514	// get rid of it
515	Radeon_FreeIndirectBuffer( ai, vc->state_buffer_idx, false );
516}
517