xref: /haiku/src/add-ons/accelerants/intel_extreme/overlay.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
1 /*
2  * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *
8  * The phase coefficient computation was taken from the X driver written by
9  * Alan Hourihane and David Dawes.
10  */
11 
12 
13 #include "accelerant.h"
14 #include "accelerant_protos.h"
15 #include "commands.h"
16 
17 #include <math.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <AGP.h>
22 
23 
24 //#define TRACE_OVERLAY
25 #ifdef TRACE_OVERLAY
26 extern "C" void _sPrintf(const char *format, ...);
27 #	define TRACE(x) _sPrintf x
28 #else
29 #	define TRACE(x) ;
30 #endif
31 
32 
33 #define NUM_HORIZONTAL_TAPS		5
34 #define NUM_VERTICAL_TAPS		3
35 #define NUM_HORIZONTAL_UV_TAPS	3
36 #define NUM_VERTICAL_UV_TAPS	3
37 #define NUM_PHASES				17
38 #define MAX_TAPS				5
39 
40 struct phase_coefficient {
41 	uint8	sign;
42 	uint8	exponent;
43 	uint16	mantissa;
44 };
45 
46 
47 /*!	Splits the coefficient floating point value into the 3 components
48 	sign, mantissa, and exponent.
49 */
50 static bool
51 split_coefficient(double &coefficient, int32 mantissaSize,
52 	phase_coefficient &splitCoefficient)
53 {
54 	double absCoefficient = fabs(coefficient);
55 
56 	int sign;
57 	if (coefficient < 0.0)
58 		sign = 1;
59 	else
60 		sign = 0;
61 
62 	int32 intCoefficient, res;
63 	int32 maxValue = 1 << mantissaSize;
64 	res = 12 - mantissaSize;
65 
66 	if ((intCoefficient = (int)(absCoefficient * 4 * maxValue + 0.5)) < maxValue) {
67 		splitCoefficient.exponent = 3;
68 		splitCoefficient.mantissa = intCoefficient << res;
69 		coefficient = (double)intCoefficient / (double)(4 * maxValue);
70 	} else if ((intCoefficient = (int)(absCoefficient * 2 * maxValue + 0.5)) < maxValue) {
71 		splitCoefficient.exponent = 2;
72 		splitCoefficient.mantissa = intCoefficient << res;
73 		coefficient = (double)intCoefficient / (double)(2 * maxValue);
74 	} else if ((intCoefficient = (int)(absCoefficient * maxValue + 0.5)) < maxValue) {
75 		splitCoefficient.exponent = 1;
76 		splitCoefficient.mantissa = intCoefficient << res;
77 		coefficient = (double)intCoefficient / (double)maxValue;
78 	} else if ((intCoefficient = (int)(absCoefficient * maxValue * 0.5 + 0.5)) < maxValue) {
79 		splitCoefficient.exponent = 0;
80 		splitCoefficient.mantissa = intCoefficient << res;
81 		coefficient = (double)intCoefficient / (double)(maxValue / 2);
82 	} else {
83 		// coefficient out of range
84 		return false;
85 	}
86 
87 	splitCoefficient.sign = sign;
88 	if (sign)
89 		coefficient = -coefficient;
90 
91 	return true;
92 }
93 
94 
95 static void
96 update_coefficients(int32 taps, double filterCutOff, bool horizontal, bool isY,
97 	phase_coefficient *splitCoefficients)
98 {
99 	if (filterCutOff < 1)
100 		filterCutOff = 1;
101 	if (filterCutOff > 3)
102 		filterCutOff = 3;
103 
104 	bool isVerticalUV = !horizontal && !isY;
105 	int32 mantissaSize = horizontal ? 7 : 6;
106 
107 	double rawCoefficients[MAX_TAPS * 32], coefficients[NUM_PHASES][MAX_TAPS];
108 
109 	int32 num = taps * 16;
110 	for (int32 i = 0; i < num * 2; i++) {
111 		double sinc;
112 		double value = (1.0 / filterCutOff) * taps * M_PI * (i - num)
113 			/ (2 * num);
114 		if (value == 0.0)
115 			sinc = 1.0;
116 		else
117 			sinc = sin(value) / value;
118 
119 		// Hamming window
120 		double window = (0.5 - 0.5 * cos(i * M_PI / num));
121 		rawCoefficients[i] = sinc * window;
122 	}
123 
124 	for (int32 i = 0; i < NUM_PHASES; i++) {
125 		// Normalise the coefficients
126 		double sum = 0.0;
127 		int32 pos;
128 		for (int32 j = 0; j < taps; j++) {
129 			pos = i + j * 32;
130 			sum += rawCoefficients[pos];
131 		}
132 		for (int32 j = 0; j < taps; j++) {
133 			pos = i + j * 32;
134 			coefficients[i][j] = rawCoefficients[pos] / sum;
135 		}
136 
137 		// split them into sign/mantissa/exponent
138 		for (int32 j = 0; j < taps; j++) {
139 			pos = j + i * taps;
140 
141 			split_coefficient(coefficients[i][j], mantissaSize
142 				+ (((j == (taps - 1) / 2) && !isVerticalUV) ? 2 : 0),
143 				splitCoefficients[pos]);
144 		}
145 
146 		int32 tapAdjust[MAX_TAPS];
147 		tapAdjust[0] = (taps - 1) / 2;
148 		for (int32 j = 1, k = 1; j <= tapAdjust[0]; j++, k++) {
149 			tapAdjust[k] = tapAdjust[0] - j;
150 			tapAdjust[++k] = tapAdjust[0] + j;
151 		}
152 
153 		// Adjust the coefficients
154 		sum = 0.0;
155 		for (int32 j = 0; j < taps; j++) {
156 			sum += coefficients[i][j];
157 		}
158 
159 		if (sum != 1.0) {
160 			for (int32 k = 0; k < taps; k++) {
161 				int32 tap2Fix = tapAdjust[k];
162 				double diff = 1.0 - sum;
163 
164 				coefficients[i][tap2Fix] += diff;
165 				pos = tap2Fix + i * taps;
166 
167 				split_coefficient(coefficients[i][tap2Fix], mantissaSize
168 					+ (((tap2Fix == (taps - 1) / 2) && !isVerticalUV) ? 2 : 0),
169 					splitCoefficients[pos]);
170 
171 				sum = 0.0;
172 				for (int32 j = 0; j < taps; j++) {
173 					sum += coefficients[i][j];
174 				}
175 				if (sum == 1.0)
176 					break;
177 			}
178 		}
179 	}
180 }
181 
182 
183 static void
184 set_color_key(uint8 red, uint8 green, uint8 blue, uint8 redMask,
185 	uint8 greenMask, uint8 blueMask)
186 {
187 	overlay_registers *registers = gInfo->overlay_registers;
188 
189 	registers->color_key_red = red;
190 	registers->color_key_green = green;
191 	registers->color_key_blue = blue;
192 	registers->color_key_mask_red = ~redMask;
193 	registers->color_key_mask_green = ~greenMask;
194 	registers->color_key_mask_blue = ~blueMask;
195 	registers->color_key_enabled = true;
196 }
197 
198 
199 static void
200 set_color_key(const overlay_window *window)
201 {
202 	switch (gInfo->shared_info->current_mode.space) {
203 		case B_CMAP8:
204 			set_color_key(0, 0, window->blue.value, 0x0, 0x0, 0xff);
205 			break;
206 		case B_RGB15:
207 			set_color_key(window->red.value << 3, window->green.value << 3,
208 				window->blue.value << 3, window->red.mask << 3, window->green.mask << 3,
209 				window->blue.mask << 3);
210 			break;
211 		case B_RGB16:
212 			set_color_key(window->red.value << 3, window->green.value << 2,
213 				window->blue.value << 3, window->red.mask << 3, window->green.mask << 2,
214 				window->blue.mask << 3);
215 			break;
216 
217 		default:
218 			set_color_key(window->red.value, window->green.value,
219 				window->blue.value, window->red.mask, window->green.mask,
220 				window->blue.mask);
221 			break;
222 	}
223 }
224 
225 
226 static void
227 update_overlay(bool updateCoefficients)
228 {
229 	if (!gInfo->shared_info->overlay_active
230 		|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
231 		return;
232 
233 	QueueCommands queue(gInfo->shared_info->primary_ring_buffer);
234 	queue.PutFlush();
235 	queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
236 	queue.PutOverlayFlip(COMMAND_OVERLAY_CONTINUE, updateCoefficients);
237 
238 	// make sure the flip is done now
239 	queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
240 	queue.PutFlush();
241 
242 	TRACE(("update overlay: UP: %lx, TST: %lx, ST: %lx, CMD: %lx (%lx), ERR: %lx\n",
243 		read32(INTEL_OVERLAY_UPDATE), read32(INtEL_OVERLAY_TEST), read32(INTEL_OVERLAY_STATUS),
244 		*(((uint32 *)gInfo->overlay_registers) + 0x68/4), read32(0x30168), read32(0x2024)));
245 }
246 
247 
248 static void
249 show_overlay(void)
250 {
251 	if (gInfo->shared_info->overlay_active
252 		|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
253 		return;
254 
255 	gInfo->shared_info->overlay_active = true;
256 	gInfo->overlay_registers->overlay_enabled = true;
257 
258 	QueueCommands queue(gInfo->shared_info->primary_ring_buffer);
259 	queue.PutOverlayFlip(COMMAND_OVERLAY_ON, true);
260 	queue.PutFlush();
261 
262 	TRACE(("show overlay: UP: %lx, TST: %lx, ST: %lx, CMD: %lx (%lx), ERR: %lx\n",
263 		read32(INTEL_OVERLAY_UPDATE), read32(INTEL_OVERLAY_TEST), read32(INTEL_OVERLAY_STATUS),
264 		*(((uint32 *)gInfo->overlay_registers) + 0x68/4), read32(0x30168), read32(0x2024)));
265 }
266 
267 
268 static void
269 hide_overlay(void)
270 {
271 	if (!gInfo->shared_info->overlay_active
272 		|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
273 		return;
274 
275 	overlay_registers *registers = gInfo->overlay_registers;
276 
277 	gInfo->shared_info->overlay_active = false;
278 	registers->overlay_enabled = false;
279 
280 	QueueCommands queue(gInfo->shared_info->primary_ring_buffer);
281 
282 	// flush pending commands
283 	queue.PutFlush();
284 	queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
285 
286 	// clear overlay enabled bit
287 	queue.PutOverlayFlip(COMMAND_OVERLAY_CONTINUE, false);
288 	queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
289 
290 	// turn off overlay engine
291 	queue.PutOverlayFlip(COMMAND_OVERLAY_OFF, false);
292 	queue.PutWaitFor(COMMAND_WAIT_FOR_OVERLAY_FLIP);
293 
294 	gInfo->current_overlay = NULL;
295 }
296 
297 
298 //	#pragma mark -
299 
300 
301 uint32
302 intel_overlay_count(const display_mode *mode)
303 {
304 	// TODO: make this depending on the amount of RAM and the screen mode
305 	// (and we could even have more than one when using 3D as well)
306 	return 1;
307 }
308 
309 
310 const uint32 *
311 intel_overlay_supported_spaces(const display_mode *mode)
312 {
313 	static const uint32 kSupportedSpaces[] = {B_RGB15, B_RGB16, B_RGB32,
314 		B_YCbCr422, 0};
315 	static const uint32 kSupportedi965Spaces[] = {B_YCbCr422, 0};
316 	intel_shared_info &sharedInfo = *gInfo->shared_info;
317 
318 	if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x))
319 		return kSupportedi965Spaces;
320 
321 	return kSupportedSpaces;
322 }
323 
324 
325 uint32
326 intel_overlay_supported_features(uint32 colorSpace)
327 {
328 	return B_OVERLAY_COLOR_KEY
329 		| B_OVERLAY_HORIZONTAL_FILTERING
330 		| B_OVERLAY_VERTICAL_FILTERING
331 		| B_OVERLAY_HORIZONTAL_MIRRORING;
332 }
333 
334 
335 const overlay_buffer *
336 intel_allocate_overlay_buffer(color_space colorSpace, uint16 width,
337 	uint16 height)
338 {
339 	TRACE(("intel_allocate_overlay_buffer(width %u, height %u, colorSpace %lu)\n",
340 		width, height, colorSpace));
341 
342 	intel_shared_info &sharedInfo = *gInfo->shared_info;
343 	uint32 bytesPerPixel;
344 
345 	switch (colorSpace) {
346 		case B_RGB15:
347 			bytesPerPixel = 2;
348 			break;
349 		case B_RGB16:
350 			bytesPerPixel = 2;
351 			break;
352 		case B_RGB32:
353 			bytesPerPixel = 4;
354 			break;
355 		case B_YCbCr422:
356 			bytesPerPixel = 2;
357 			break;
358 		default:
359 			return NULL;
360 	}
361 
362 	struct overlay *overlay = (struct overlay *)malloc(sizeof(struct overlay));
363 	if (overlay == NULL)
364 		return NULL;
365 
366 	// TODO: locking!
367 
368 	// alloc graphics mem
369 
370 	int32 alignment = 0x3f;
371 	if (sharedInfo.device_type.InGroup(INTEL_TYPE_965))
372 		alignment = 0xff;
373 
374 	overlay_buffer *buffer = &overlay->buffer;
375 	buffer->space = colorSpace;
376 	buffer->width = width;
377 	buffer->height = height;
378 	buffer->bytes_per_row = (width * bytesPerPixel + alignment) & ~alignment;
379 
380 	status_t status = intel_allocate_memory(buffer->bytes_per_row * height,
381 		0, overlay->buffer_base);
382 	if (status < B_OK) {
383 		free(overlay);
384 		return NULL;
385 	}
386 
387 	if (sharedInfo.device_type.InGroup(INTEL_TYPE_965)) {
388 		status = intel_allocate_memory(INTEL_i965_OVERLAY_STATE_SIZE,
389 			B_APERTURE_NON_RESERVED, overlay->state_base);
390 		if (status < B_OK) {
391 			intel_free_memory(overlay->buffer_base);
392 			free(overlay);
393 			return NULL;
394 		}
395 
396 		overlay->state_offset = overlay->state_base
397 			- (addr_t)gInfo->shared_info->graphics_memory;
398 	}
399 
400 	overlay->buffer_offset = overlay->buffer_base
401 		- (addr_t)gInfo->shared_info->graphics_memory;
402 
403 	buffer->buffer = (uint8 *)overlay->buffer_base;
404 	buffer->buffer_dma = (uint8 *)gInfo->shared_info->physical_graphics_memory
405 		+ overlay->buffer_offset;
406 
407 	TRACE(("allocated overlay buffer: base=%x, offset=%x, address=%x, "
408 		"physical address=%x\n", overlay->buffer_base, overlay->buffer_offset,
409 		buffer->buffer, buffer->buffer_dma));
410 
411 	return buffer;
412 }
413 
414 
415 status_t
416 intel_release_overlay_buffer(const overlay_buffer *buffer)
417 {
418 	TRACE(("intel_release_overlay_buffer(buffer %p)\n", buffer));
419 
420 	struct overlay *overlay = (struct overlay *)buffer;
421 
422 	// TODO: locking!
423 
424 	if (gInfo->current_overlay == overlay)
425 		hide_overlay();
426 
427 	intel_free_memory(overlay->buffer_base);
428 	if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
429 		intel_free_memory(overlay->state_base);
430 	free(overlay);
431 
432 	return B_OK;
433 }
434 
435 
436 status_t
437 intel_get_overlay_constraints(const display_mode *mode,
438 	const overlay_buffer *buffer, overlay_constraints *constraints)
439 {
440 	TRACE(("intel_get_overlay_constraints(buffer %p)\n", buffer));
441 
442 	// taken from the Radeon driver...
443 
444 	// scaler input restrictions
445 	// TODO: check all these values; most of them are probably too restrictive
446 
447 	// position
448 	constraints->view.h_alignment = 0;
449 	constraints->view.v_alignment = 0;
450 
451 	// alignment
452 	switch (buffer->space) {
453 		case B_RGB15:
454 			constraints->view.width_alignment = 7;
455 			break;
456 		case B_RGB16:
457 			constraints->view.width_alignment = 7;
458 			break;
459 		case B_RGB32:
460 			constraints->view.width_alignment = 3;
461 			break;
462 		case B_YCbCr422:
463 			constraints->view.width_alignment = 7;
464 			break;
465 		case B_YUV12:
466 			constraints->view.width_alignment = 7;
467 		default:
468 			return B_BAD_VALUE;
469 	}
470 	constraints->view.height_alignment = 0;
471 
472 	// size
473 	constraints->view.width.min = 4;		// make 4-tap filter happy
474 	constraints->view.height.min = 4;
475 	constraints->view.width.max = buffer->width;
476 	constraints->view.height.max = buffer->height;
477 
478 	// scaler output restrictions
479 	constraints->window.h_alignment = 0;
480 	constraints->window.v_alignment = 0;
481 	constraints->window.width_alignment = 0;
482 	constraints->window.height_alignment = 0;
483 	constraints->window.width.min = 2;
484 	constraints->window.width.max = mode->virtual_width;
485 	constraints->window.height.min = 2;
486 	constraints->window.height.max = mode->virtual_height;
487 
488 	// TODO: the minimum values are not tested
489 	constraints->h_scale.min = 1.0f / (1 << 4);
490 	constraints->h_scale.max = buffer->width * 7;
491 	constraints->v_scale.min = 1.0f / (1 << 4);
492 	constraints->v_scale.max = buffer->height * 7;
493 
494 	return B_OK;
495 }
496 
497 
498 overlay_token
499 intel_allocate_overlay(void)
500 {
501 	TRACE(("intel_allocate_overlay()\n"));
502 
503 	// we only have a single overlay channel
504 	if (atomic_or(&gInfo->shared_info->overlay_channel_used, 1) != 0)
505 		return NULL;
506 
507 	return (overlay_token)++gInfo->shared_info->overlay_token;
508 }
509 
510 
511 status_t
512 intel_release_overlay(overlay_token overlayToken)
513 {
514 	TRACE(("intel_allocate_overlay(token %ld)\n", (uint32)overlayToken));
515 
516 	// we only have a single token, which simplifies this
517 	if (overlayToken != (overlay_token)gInfo->shared_info->overlay_token)
518 		return B_BAD_VALUE;
519 
520 	atomic_and(&gInfo->shared_info->overlay_channel_used, 0);
521 
522 	return B_OK;
523 }
524 
525 
526 status_t
527 intel_configure_overlay(overlay_token overlayToken, const overlay_buffer *buffer,
528 	const overlay_window *window, const overlay_view *view)
529 {
530 	TRACE(("intel_configure_overlay: buffer %p, window %p, view %p\n",
531 		buffer, window, view));
532 
533 	if (overlayToken != (overlay_token)gInfo->shared_info->overlay_token)
534 		return B_BAD_VALUE;
535 
536 	if (window == NULL && view == NULL) {
537 		hide_overlay();
538 		return B_OK;
539 	}
540 
541 	struct overlay *overlay = (struct overlay *)buffer;
542 	overlay_registers *registers = gInfo->overlay_registers;
543 	bool updateCoefficients = false;
544 	uint32 bytesPerPixel = 2;
545 
546 	switch (buffer->space) {
547 		case B_RGB15:
548 			registers->source_format = OVERLAY_FORMAT_RGB15;
549 			break;
550 		case B_RGB16:
551 			registers->source_format = OVERLAY_FORMAT_RGB16;
552 			break;
553 		case B_RGB32:
554 			registers->source_format = OVERLAY_FORMAT_RGB32;
555 			bytesPerPixel = 4;
556 			break;
557 		case B_YCbCr422:
558 			registers->source_format = OVERLAY_FORMAT_YCbCr422;
559 			break;
560 	}
561 
562 	if (!gInfo->shared_info->overlay_active
563 		|| memcmp(&gInfo->last_overlay_view, view, sizeof(overlay_view))
564 		|| memcmp(&gInfo->last_overlay_frame, window, sizeof(overlay_frame))) {
565 		// scaling has changed, program window and scaling factor
566 
567 		// clip the window to on screen bounds
568 		// TODO: this is not yet complete or correct - especially if we start
569 		// to support moving the display!
570 		int32 left, top, right, bottom;
571 		left = window->h_start;
572 		right = window->h_start + window->width;
573 		top = window->v_start;
574 		bottom = window->v_start + window->height;
575 		if (left < 0)
576 			left = 0;
577 		if (top < 0)
578 			top = 0;
579 		if (right > gInfo->shared_info->current_mode.timing.h_display)
580 			right = gInfo->shared_info->current_mode.timing.h_display;
581 		if (bottom > gInfo->shared_info->current_mode.timing.v_display)
582 			bottom = gInfo->shared_info->current_mode.timing.v_display;
583 		if (left >= right || top >= bottom) {
584 			// overlay is not within visible bounds
585 			hide_overlay();
586 			return B_OK;
587 		}
588 
589 		registers->window_left = left;
590 		registers->window_top = top;
591 		registers->window_width = right - left;
592 		registers->window_height = bottom - top;
593 
594 		uint32 horizontalScale = (view->width << 12) / window->width;
595 		uint32 verticalScale = (view->height << 12) / window->height;
596 		uint32 horizontalScaleUV = horizontalScale >> 1;
597 		uint32 verticalScaleUV = verticalScale >> 1;
598 		horizontalScale = horizontalScaleUV << 1;
599 		verticalScale = verticalScaleUV << 1;
600 
601 		// we need to offset the overlay view to adapt it to the clipping
602 		// (in addition to whatever offset is desired already)
603 		left = view->h_start - (int32)((window->h_start - left)
604 			* (horizontalScale / 4096.0) + 0.5);
605 		top = view->v_start - (int32)((window->v_start - top)
606 			* (verticalScale / 4096.0) + 0.5);
607 		right = view->h_start + view->width;
608 		bottom = view->v_start + view->height;
609 
610 		gInfo->overlay_position_buffer_offset = buffer->bytes_per_row * top
611 			+ left * bytesPerPixel;
612 
613 		// Note: in non-planar mode, you *must* not program the source
614 		// width/height UV registers - they must stay cleared, or the chip is
615 		// doing strange stuff.
616 		// On the other hand, you have to program the UV scaling registers, or
617 		// the result will be wrong, too.
618 		registers->source_width_rgb = right - left;
619 		registers->source_height_rgb = bottom - top;
620 		if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx)) {
621 			registers->source_bytes_per_row_rgb = (((overlay->buffer_offset
622 				+ (view->width << 1) + 0x1f) >> 5)
623 				- (overlay->buffer_offset >> 5) - 1) << 2;
624 		} else {
625 			registers->source_bytes_per_row_rgb = ((((overlay->buffer_offset
626 				+ (view->width << 1) + 0x3f) >> 6)
627 				- (overlay->buffer_offset >> 6) << 1) - 1) << 2;
628 		}
629 
630 		// horizontal scaling
631 		registers->scale_rgb.horizontal_downscale_factor
632 			= horizontalScale >> 12;
633 		registers->scale_rgb.horizontal_scale_fraction
634 			= horizontalScale & 0xfff;
635 		registers->scale_uv.horizontal_downscale_factor
636 			= horizontalScaleUV >> 12;
637 		registers->scale_uv.horizontal_scale_fraction
638 			= horizontalScaleUV & 0xfff;
639 
640 		// vertical scaling
641 		registers->scale_rgb.vertical_scale_fraction = verticalScale & 0xfff;
642 		registers->scale_uv.vertical_scale_fraction = verticalScaleUV & 0xfff;
643 		registers->vertical_scale_rgb = verticalScale >> 12;
644 		registers->vertical_scale_uv = verticalScaleUV >> 12;
645 
646 		TRACE(("scale: h = %ld.%ld, v = %ld.%ld\n", horizontalScale >> 12,
647 			horizontalScale & 0xfff, verticalScale >> 12,
648 			verticalScale & 0xfff));
649 
650 		if (verticalScale != gInfo->last_vertical_overlay_scale
651 			|| horizontalScale != gInfo->last_horizontal_overlay_scale) {
652 			// Recompute phase coefficients (taken from X driver)
653 			updateCoefficients = true;
654 
655 			phase_coefficient coefficients[NUM_HORIZONTAL_TAPS * NUM_PHASES];
656 			update_coefficients(NUM_HORIZONTAL_TAPS, horizontalScale / 4096.0,
657 				true, true, coefficients);
658 
659 			phase_coefficient coefficientsUV[
660 				NUM_HORIZONTAL_UV_TAPS * NUM_PHASES];
661 			update_coefficients(NUM_HORIZONTAL_UV_TAPS,
662 				horizontalScaleUV / 4096.0, true, false, coefficientsUV);
663 
664 			int32 pos = 0;
665 			for (int32 i = 0; i < NUM_PHASES; i++) {
666 				for (int32 j = 0; j < NUM_HORIZONTAL_TAPS; j++) {
667 					registers->horizontal_coefficients_rgb[pos]
668 						= coefficients[pos].sign << 15
669 							| coefficients[pos].exponent << 12
670 							| coefficients[pos].mantissa;
671 					pos++;
672 				}
673 			}
674 
675 			pos = 0;
676 			for (int32 i = 0; i < NUM_PHASES; i++) {
677 				for (int32 j = 0; j < NUM_HORIZONTAL_UV_TAPS; j++) {
678 					registers->horizontal_coefficients_uv[pos]
679 						= coefficientsUV[pos].sign << 15
680 							| coefficientsUV[pos].exponent << 12
681 							| coefficientsUV[pos].mantissa;
682 					pos++;
683 				}
684 			}
685 
686 			gInfo->last_vertical_overlay_scale = verticalScale;
687 			gInfo->last_horizontal_overlay_scale = horizontalScale;
688 		}
689 
690 		gInfo->last_overlay_view = *view;
691 		gInfo->last_overlay_frame = *(overlay_frame *)window;
692 	}
693 
694 	registers->color_control_output_mode = true;
695 	registers->select_pipe = 0;
696 
697 	// program buffer
698 
699 	registers->buffer_rgb0
700 		= overlay->buffer_offset + gInfo->overlay_position_buffer_offset;
701 	registers->stride_rgb = buffer->bytes_per_row;
702 
703 	registers->mirroring_mode
704 		= (window->flags & B_OVERLAY_HORIZONTAL_MIRRORING) != 0
705 			? OVERLAY_MIRROR_HORIZONTAL : OVERLAY_MIRROR_NORMAL;
706 	registers->ycbcr422_order = 0;
707 
708 	if (!gInfo->shared_info->overlay_active) {
709 		// overlay is shown for the first time
710 		set_color_key(window);
711 		show_overlay();
712 	} else
713 		update_overlay(updateCoefficients);
714 
715 	gInfo->current_overlay = overlay;
716 	return B_OK;
717 }
718 
719