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