1/*
2	Haiku ATI video driver adapted from the X.org ATI driver which has the
3	following copyright:
4
5	Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
6						 Precision Insight, Inc., Cedar Park, Texas, and
7						 VA Linux Systems Inc., Fremont, California.
8
9	Copyright 2011 Haiku, Inc.  All rights reserved.
10	Distributed under the terms of the MIT license.
11
12	Authors:
13	Gerald Zajac
14 */
15
16#include "accelerant.h"
17#include "rage128.h"
18
19
20static uint32 sCurrentKeyColor = 0;
21static uint32 sCurrentKeyMask = 0;
22
23
24
25bool
26Rage128_DisplayOverlay(const overlay_window* window,
27						const overlay_buffer* buffer)
28{
29	// Return true if setup is successful.
30
31	SharedInfo& si = *gInfo.sharedInfo;
32
33	if (window == NULL || buffer == NULL)
34		return false;
35
36	if (buffer->space != B_YCbCr422)
37		return false;	// color space not supported
38
39	uint32 keyColor = 0;
40	uint32 keyMask = 0;
41
42	switch (si.displayMode.bitsPerPixel) {
43		case 15:
44			keyMask = 0x7fff;
45			keyColor = (window->blue.value & window->blue.mask) << 0
46				| (window->green.value & window->green.mask) << 5
47				| (window->red.value & window->red.mask) << 10;
48				// 15 bit color has no alpha bits
49			break;
50		case 16:
51			keyMask = 0xffff;
52			keyColor = (window->blue.value & window->blue.mask) << 0
53				| (window->green.value & window->green.mask) << 5
54				| (window->red.value & window->red.mask) << 11;
55				// 16 bit color has no alpha bits
56			break;
57		default:
58			keyMask = 0xffffffff;
59			keyColor = (window->blue.value & window->blue.mask) << 0
60				| (window->green.value & window->green.mask) << 8
61				| (window->red.value & window->red.mask) << 16
62				| (window->alpha.value & window->alpha.mask) << 24;
63			break;
64	}
65
66	// If the key color or key mask has changed since the overlay was
67	// previously initialized, initialize it again.  This is to avoid
68	// initializing the overlay video everytime the overlay buffer is
69	// switched which causes artifacts in the overlay display.
70
71	if (keyColor != sCurrentKeyColor || keyMask != sCurrentKeyMask)
72	{
73		TRACE("Rage128_DisplayOverlay() initializing overlay video\n");
74
75		// Initialize the overlay video by first resetting the video.
76
77		OUTREG(R128_OV0_SCALE_CNTL, 0);
78		OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0);
79		OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0);
80		OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f);
81
82		const uint32 brightness = 0;
83		const uint32 saturation = 16;
84		OUTREG(R128_OV0_COLOUR_CNTL, brightness | saturation << 8
85			| saturation << 16);
86
87		OUTREG(R128_OV0_GRAPHICS_KEY_MSK, keyMask);
88		OUTREG(R128_OV0_GRAPHICS_KEY_CLR, keyColor);
89		OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE);
90		OUTREG(R128_OV0_TEST, 0);
91
92		sCurrentKeyColor = keyColor;
93		sCurrentKeyMask = keyMask;
94	}
95
96	uint32 ecpDiv;
97	if (si.displayMode.timing.pixel_clock < 125000)
98		ecpDiv = 0;
99	else if (si.displayMode.timing.pixel_clock < 250000)
100		ecpDiv = 1;
101	else
102		ecpDiv = 2;
103
104	SetPLLReg(R128_VCLK_ECP_CNTL, ecpDiv << 8, R128_ECP_DIV_MASK);
105
106	int32 vertInc = (buffer->height << 20) / window->height;
107	int32 horzInc = (buffer->width << (12 + ecpDiv)) / window->width;
108	int32 stepBy = 1;
109
110	while (horzInc >= (2 << 12)) {
111		stepBy++;
112		horzInc >>= 1;
113	}
114
115	int32 x1 = window->h_start;
116	int32 y1 = window->v_start;
117
118	int32 x2 = window->h_start + window->width;
119	int32 y2 = window->v_start + window->height;
120
121	int32 left = x1;
122	int32 tmp = (left & 0x0003ffff) + 0x00028000 + (horzInc << 3);
123	int32 p1_h_accum_init = ((tmp << 4) & 0x000f8000) |
124					  ((tmp << 12) & 0xf0000000);
125
126	tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (horzInc << 2);
127	int32 p23_h_accum_init = ((tmp << 4) & 0x000f8000) |
128						((tmp << 12) & 0x70000000);
129
130	tmp = (y1 & 0x0000ffff) + 0x00018000;
131	int32 p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
132
133	// Compute offset of overlay buffer in the video memory.
134	uint32 offset = (uint32)((addr_t)buffer->buffer - si.videoMemAddr);
135
136	OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
137	while (!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)))
138		;
139
140	OUTREG(R128_OV0_H_INC, horzInc | ((horzInc >> 1) << 16));
141	OUTREG(R128_OV0_STEP_BY, stepBy | (stepBy << 8));
142	OUTREG(R128_OV0_Y_X_START, x1 | y1 << 16);
143	OUTREG(R128_OV0_Y_X_END, x2 | y2 << 16);
144	OUTREG(R128_OV0_V_INC, vertInc);
145	OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP,
146			0x00000fff | ((buffer->height - 1) << 16));
147	OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, buffer->bytes_per_row);
148
149	int32 width = window->width;
150	left = 0;
151	OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
152	width >>= 1;
153	OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16));
154	OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16));
155	OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset);
156	OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
157	OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0);
158	OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
159	OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
160
161	OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03);
162	OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
163
164	return true;
165}
166
167
168void
169Rage128_StopOverlay(void)
170{
171	OUTREG(R128_OV0_SCALE_CNTL, 0);		// reset the video
172
173	// Reset the key color and mask so that when the overlay is started again
174	// it will be initialized.
175
176	sCurrentKeyColor = 0;
177	sCurrentKeyMask = 0;
178}
179