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