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
44struct 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*/
54static bool
55split_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
103static void
104update_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
191static void
192set_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
207static void
208set_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
234static void
235update_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
258static void
259show_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
280static void
281hide_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
313uint32
314intel_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
322const uint32*
323intel_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
337uint32
338intel_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
347const overlay_buffer*
348intel_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
427status_t
428intel_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
448status_t
449intel_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
511overlay_token
512intel_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
524status_t
525intel_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
539status_t
540intel_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