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