1/*
2	Copyright 2011 Haiku, Inc.  All rights reserved.
3	Distributed under the terms of the MIT license.
4
5	Authors:
6		Gerald Zajac
7 */
8
9#include "accelerant.h"
10#include "rage128.h"
11
12#include <stdlib.h>
13
14
15
16uint32
17OverlayCount(const display_mode* mode)
18{
19	(void)mode;		// avoid compiler warning for unused arg
20
21	return 1;
22}
23
24
25const uint32*
26OverlaySupportedSpaces(const display_mode* mode)
27{
28	(void)mode;		// avoid compiler warning for unused arg
29
30	static const uint32 kSupportedSpaces[] = {B_YCbCr422, 0};
31
32	return kSupportedSpaces;
33}
34
35
36uint32
37OverlaySupportedFeatures(uint32 colorSpace)
38{
39	(void)colorSpace;		// avoid compiler warning for unused arg
40
41	return B_OVERLAY_COLOR_KEY
42		| B_OVERLAY_HORIZONTAL_FILTERING
43		| B_OVERLAY_VERTICAL_FILTERING;
44}
45
46
47const overlay_buffer*
48AllocateOverlayBuffer(color_space colorSpace, uint16 width, uint16 height)
49{
50	SharedInfo& si = *gInfo.sharedInfo;
51
52	TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n",
53		width, height, colorSpace);
54
55	// If Mach 64 chip, check hardware limits.
56
57	if (MACH64_FAMILY(si.chipType)) {
58		if (height > 2048 || width > 768
59				|| (width > 384 && si.chipType < MACH64_264VTB)
60				|| (width > 720 && (si.chipType < MACH64_264GTPRO
61				|| si.chipType > MACH64_264LTPRO)))
62			return NULL;
63	}
64
65	si.overlayLock.Acquire();
66
67	// Note:  When allocating buffers, buffer allocation starts at the end of
68	// video memory, and works backward to the end of the video frame buffer.
69	// The allocated buffers are recorded in a linked list of OverlayBuffer
70	// objects which are ordered by the buffer address with the first object
71	// in the list having the highest buffer address.
72
73	if (colorSpace != B_YCbCr422) {
74		si.overlayLock.Release();
75		TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
76			colorSpace);
77		return NULL;
78	}
79
80	uint32 bytesPerPixel = 2;		// B_YCbCr422 uses 2 bytes per pixel
81
82	// Calculate required buffer size as a multiple of 1K.
83	uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
84
85	OverlayBuffer* ovBuff = si.overlayBuffer;
86	OverlayBuffer* prevOvBuff = NULL;
87
88	// If no buffers have been allocated, prevBuffAddr calculated here will be
89	// the address where the buffer area will start.  Leave a gap of about 4K
90	// between where the overlay buffers will start and the cursor image;
91	// thus, if the overlay buffer overflows it will be less apt to affect the
92	// cursor.
93
94	addr_t prevBuffAddr = (si.videoMemAddr + si.cursorOffset - 0xfff) & ~0xfff;
95
96	while (ovBuff != NULL) {
97		// Test if there is sufficient space between the end of the current
98		// buffer and the start of the previous buffer to allocate the new
99		// buffer.
100
101		addr_t currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
102		if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
103			break;		// sufficient space for the new buffer
104
105		prevBuffAddr = (addr_t)ovBuff->buffer;
106		prevOvBuff = ovBuff;
107		ovBuff = ovBuff->nextBuffer;
108	}
109
110	OverlayBuffer* nextOvBuff = ovBuff;
111
112	if (ovBuff == NULL) {
113		// No space between any current buffers of the required size was found;
114		// thus space must be allocated between the last buffer and the end of
115		// the video frame buffer.  Compute where current video frame buffer
116		// ends so that it can be determined if there is sufficient space for
117		// the new buffer to be created.
118
119		addr_t fbEndAddr = si.videoMemAddr + si.frameBufferOffset
120			+ (si.displayMode.virtual_width
121			* ((si.displayMode.bitsPerPixel + 7) / 8)	// bytes per pixel
122			* si.displayMode.virtual_height);
123
124		if (buffSize > prevBuffAddr - fbEndAddr) {
125			si.overlayLock.Release();
126			TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) "
127					"byte buffer\n", buffSize, buffSize);
128			return NULL;	// insufficient space for buffer
129		}
130
131		nextOvBuff = NULL;
132	}
133
134	ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
135	if (ovBuff == NULL) {
136		si.overlayLock.Release();
137		return NULL;		// memory not available for OverlayBuffer struct
138	}
139
140	ovBuff->nextBuffer = nextOvBuff;
141	ovBuff->size = buffSize;
142	ovBuff->space = colorSpace;
143	ovBuff->width = width;
144	ovBuff->height = height;
145	ovBuff->bytes_per_row = width * bytesPerPixel;
146	ovBuff->buffer = (void*)(prevBuffAddr - buffSize);
147	ovBuff->buffer_dma = (void*)(si.videoMemPCI
148		+ ((addr_t)ovBuff->buffer - si.videoMemAddr));
149
150	if (prevOvBuff == NULL)
151		si.overlayBuffer = ovBuff;
152	else
153		prevOvBuff->nextBuffer = ovBuff;
154
155	si.overlayLock.Release();
156	TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n",
157		buffSize, buffSize, ovBuff->buffer);
158	return ovBuff;
159}
160
161
162status_t
163ReleaseOverlayBuffer(const overlay_buffer* buffer)
164{
165	SharedInfo& si = *gInfo.sharedInfo;
166
167	if (buffer == NULL)
168		return B_BAD_VALUE;
169
170	// Find the buffer to be released.
171
172	OverlayBuffer* ovBuff = si.overlayBuffer;
173	OverlayBuffer* prevOvBuff = NULL;
174
175	while (ovBuff != NULL) {
176		if (ovBuff->buffer == buffer->buffer) {
177			// Buffer to be released has been found.  Remove the OverlayBuffer
178			// object from the chain of overlay buffers.
179
180			if (prevOvBuff == NULL)
181				si.overlayBuffer = ovBuff->nextBuffer;
182			else
183				prevOvBuff->nextBuffer = ovBuff->nextBuffer;
184
185			free(ovBuff);
186			return B_OK;
187		}
188
189		prevOvBuff = ovBuff;
190		ovBuff = ovBuff->nextBuffer;
191	}
192
193	TRACE("ReleaseOverlayBuffer() buffer to release at 0x%lx not found\n",
194		buffer->buffer);
195	return B_ERROR;		// buffer to be released not found in chain of buffers
196}
197
198
199status_t
200GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
201					overlay_constraints* constraints)
202{
203	if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
204		return B_ERROR;
205
206	// Position (values are in pixels)
207	constraints->view.h_alignment = 0;
208	constraints->view.v_alignment = 0;
209
210	if (buffer->space == B_YCbCr422)
211		constraints->view.width_alignment = 7;
212	else {
213		TRACE("GetOverlayConstraints() color space 0x%x out of range\n",
214			buffer->space);
215		return B_BAD_VALUE;
216	}
217
218	constraints->view.height_alignment = 0;
219
220	//Size
221	constraints->view.width.min = 4;
222	constraints->view.height.min = 4;
223	constraints->view.width.max = buffer->width;
224	constraints->view.height.max = buffer->height;
225
226	// Scaler output restrictions
227	constraints->window.h_alignment = 0;
228	constraints->window.v_alignment = 0;
229	constraints->window.width_alignment = 0;
230	constraints->window.height_alignment = 0;
231	constraints->window.width.min = 2;
232	constraints->window.width.max = mode->virtual_width;
233	constraints->window.height.min = 2;
234	constraints->window.height.max = mode->virtual_height;
235
236	constraints->h_scale.min = 1.0;
237	constraints->h_scale.max = 8.0;
238	constraints->v_scale.min = 1.0;
239	constraints->v_scale.max = 8.0;
240
241	return B_OK;
242}
243
244
245overlay_token
246AllocateOverlay(void)
247{
248	SharedInfo& si = *gInfo.sharedInfo;
249
250	// There is only a single overlay channel;  thus, check if it is already
251	// allocated.
252
253	if (atomic_or(&si.overlayAllocated, 1) != 0) {
254		TRACE("AllocateOverlay() overlay channel already in use\n");
255		return NULL;
256	}
257
258	return (overlay_token)(addr_t)++si.overlayToken;
259}
260
261
262status_t
263ReleaseOverlay(overlay_token overlayToken)
264{
265	SharedInfo& si = *gInfo.sharedInfo;
266
267	if (overlayToken != (overlay_token)(addr_t)si.overlayToken) {
268		TRACE("ReleaseOverlay() error - no overlay previously allocated\n");
269		return B_BAD_VALUE;
270	}
271
272	if (MACH64_FAMILY(si.chipType))
273		Mach64_StopOverlay();
274	else
275		Rage128_StopOverlay();
276
277	atomic_and(&si.overlayAllocated, 0);	// mark overlay as unallocated
278	return B_OK;
279}
280
281
282status_t
283ConfigureOverlay(overlay_token overlayToken, const overlay_buffer* buffer,
284	const overlay_window* window, const overlay_view* view)
285{
286	SharedInfo& si = *gInfo.sharedInfo;
287
288	if (overlayToken != (overlay_token)(addr_t)si.overlayToken)
289		return B_BAD_VALUE;
290
291	if (buffer == NULL)
292		return B_BAD_VALUE;
293
294	if (window == NULL || view == NULL) {
295		if (MACH64_FAMILY(si.chipType))
296			Mach64_StopOverlay();
297		else
298			Rage128_StopOverlay();
299
300		return B_OK;
301	}
302
303	// Program the overlay hardware.
304	if (MACH64_FAMILY(si.chipType)) {
305		if (!Mach64_DisplayOverlay(window, buffer)) {
306			TRACE("ConfigureOverlay(), call to Mach64_DisplayOverlay() "
307				"returned error\n");
308			return B_ERROR;
309		}
310	} else {
311		if (!Rage128_DisplayOverlay(window, buffer)) {
312			TRACE("ConfigureOverlay(), call to Rage128_DisplayOverlay() "
313				"returned error\n");
314			return B_ERROR;
315		}
316	}
317
318	return B_OK;
319}
320