1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "FrameBuffer.hpp" 16 17 #include "Timer.hpp" 18 #include "Renderer/Surface.hpp" 19 #include "Reactor/Reactor.hpp" 20 #include "Common/Debug.hpp" 21 22 #include <stdio.h> 23 #include <string.h> 24 #include <time.h> 25 26 #ifdef __ANDROID__ 27 #include <cutils/properties.h> 28 #endif 29 30 #define ASYNCHRONOUS_BLIT 0 // FIXME: Currently leads to rare race conditions 31 32 namespace sw 33 { 34 extern bool forceWindowed; 35 36 FrameBuffer::Cursor FrameBuffer::cursor = {}; 37 bool FrameBuffer::topLeftOrigin = false; 38 FrameBuffer(int width,int height,bool fullscreen,bool topLeftOrigin)39 FrameBuffer::FrameBuffer(int width, int height, bool fullscreen, bool topLeftOrigin) 40 { 41 this->topLeftOrigin = topLeftOrigin; 42 43 locked = nullptr; 44 45 this->width = width; 46 this->height = height; 47 destFormat = FORMAT_X8R8G8B8; 48 sourceFormat = FORMAT_X8R8G8B8; 49 stride = 0; 50 51 if(forceWindowed) 52 { 53 fullscreen = false; 54 } 55 56 windowed = !fullscreen; 57 58 blitFunction = nullptr; 59 blitRoutine = nullptr; 60 61 blitState.width = 0; 62 blitState.height = 0; 63 blitState.destFormat = FORMAT_X8R8G8B8; 64 blitState.sourceFormat = FORMAT_X8R8G8B8; 65 blitState.cursorWidth = 0; 66 blitState.cursorHeight = 0; 67 68 if(ASYNCHRONOUS_BLIT) 69 { 70 terminate = false; 71 FrameBuffer *parameters = this; 72 blitThread = new Thread(threadFunction, ¶meters); 73 } 74 } 75 ~FrameBuffer()76 FrameBuffer::~FrameBuffer() 77 { 78 if(ASYNCHRONOUS_BLIT) 79 { 80 terminate = true; 81 blitEvent.signal(); 82 blitThread->join(); 83 delete blitThread; 84 } 85 86 delete blitRoutine; 87 } 88 getWidth() const89 int FrameBuffer::getWidth() const 90 { 91 return width; 92 } 93 getHeight() const94 int FrameBuffer::getHeight() const 95 { 96 return height; 97 } 98 getStride() const99 int FrameBuffer::getStride() const 100 { 101 return stride; 102 } 103 setCursorImage(sw::Surface * cursorImage)104 void FrameBuffer::setCursorImage(sw::Surface *cursorImage) 105 { 106 if(cursorImage) 107 { 108 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); 109 cursorImage->unlockExternal(); 110 111 cursor.width = cursorImage->getWidth(); 112 cursor.height = cursorImage->getHeight(); 113 } 114 else 115 { 116 cursor.width = 0; 117 cursor.height = 0; 118 } 119 } 120 setCursorOrigin(int x0,int y0)121 void FrameBuffer::setCursorOrigin(int x0, int y0) 122 { 123 cursor.hotspotX = x0; 124 cursor.hotspotY = y0; 125 } 126 setCursorPosition(int x,int y)127 void FrameBuffer::setCursorPosition(int x, int y) 128 { 129 cursor.positionX = x; 130 cursor.positionY = y; 131 } 132 copy(void * source,Format format,size_t stride)133 void FrameBuffer::copy(void *source, Format format, size_t stride) 134 { 135 if(!source) 136 { 137 return; 138 } 139 140 if(!lock()) 141 { 142 return; 143 } 144 145 sourceFormat = format; 146 147 if(topLeftOrigin) 148 { 149 target = source; 150 } 151 else 152 { 153 target = (byte*)source + (height - 1) * stride; 154 } 155 156 cursor.x = cursor.positionX - cursor.hotspotX; 157 cursor.y = cursor.positionY - cursor.hotspotY; 158 159 if(ASYNCHRONOUS_BLIT) 160 { 161 blitEvent.signal(); 162 syncEvent.wait(); 163 } 164 else 165 { 166 copyLocked(); 167 } 168 169 unlock(); 170 171 profiler.nextFrame(); // Assumes every copy() is a full frame 172 } 173 copyLocked()174 void FrameBuffer::copyLocked() 175 { 176 BlitState update = {}; 177 update.width = width; 178 update.height = height; 179 update.destFormat = destFormat; 180 update.sourceFormat = sourceFormat; 181 update.stride = stride; 182 update.cursorWidth = cursor.width; 183 update.cursorHeight = cursor.height; 184 185 if(memcmp(&blitState, &update, sizeof(BlitState)) != 0) 186 { 187 blitState = update; 188 delete blitRoutine; 189 190 blitRoutine = copyRoutine(blitState); 191 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry(); 192 } 193 194 blitFunction(locked, target, &cursor); 195 } 196 copyRoutine(const BlitState & state)197 Routine *FrameBuffer::copyRoutine(const BlitState &state) 198 { 199 const int width = state.width; 200 const int height = state.height; 201 const int width2 = (state.width + 1) & ~1; 202 const int dBytes = Surface::bytes(state.destFormat); 203 const int dStride = state.stride; 204 const int sBytes = Surface::bytes(state.sourceFormat); 205 const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2); 206 207 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function; 208 { 209 Pointer<Byte> dst(function.Arg<0>()); 210 Pointer<Byte> src(function.Arg<1>()); 211 Pointer<Byte> cursor(function.Arg<2>()); 212 213 For(Int y = 0, y < height, y++) 214 { 215 Pointer<Byte> d = dst + y * dStride; 216 Pointer<Byte> s = src + y * sStride; 217 218 Int x0 = 0; 219 220 switch(state.destFormat) 221 { 222 case FORMAT_X8R8G8B8: 223 case FORMAT_A8R8G8B8: 224 { 225 Int x = x0; 226 227 switch(state.sourceFormat) 228 { 229 case FORMAT_X8R8G8B8: 230 case FORMAT_A8R8G8B8: 231 For(, x < width - 3, x += 4) 232 { 233 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16); 234 235 s += 4 * sBytes; 236 d += 4 * dBytes; 237 } 238 break; 239 case FORMAT_X8B8G8R8: 240 case FORMAT_A8B8G8R8: 241 For(, x < width - 3, x += 4) 242 { 243 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16); 244 245 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) | 246 ((bgra & Int4(0x000000FF)) << 16) | 247 (bgra & Int4(0xFF00FF00)); 248 249 s += 4 * sBytes; 250 d += 4 * dBytes; 251 } 252 break; 253 case FORMAT_A16B16G16R16: 254 For(, x < width - 1, x += 2) 255 { 256 UShort4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8; 257 UShort4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8; 258 259 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1)); 260 261 s += 2 * sBytes; 262 d += 2 * dBytes; 263 } 264 break; 265 case FORMAT_R5G6B5: 266 For(, x < width - 3, x += 4) 267 { 268 Int4 rgb = Int4(*Pointer<Short4>(s)); 269 270 *Pointer<Int4>(d) = (((rgb & Int4(0xF800)) << 8) | ((rgb & Int4(0xE01F)) << 3)) | 271 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) | 272 (((rgb & Int4(0x001C)) >> 2) | Int4(0xFF000000)); 273 274 s += 4 * sBytes; 275 d += 4 * dBytes; 276 } 277 break; 278 default: 279 ASSERT(false); 280 break; 281 } 282 283 For(, x < width, x++) 284 { 285 switch(state.sourceFormat) 286 { 287 case FORMAT_X8R8G8B8: 288 case FORMAT_A8R8G8B8: 289 *Pointer<Int>(d) = *Pointer<Int>(s); 290 break; 291 case FORMAT_X8B8G8R8: 292 case FORMAT_A8B8G8R8: 293 { 294 Int rgba = *Pointer<Int>(s); 295 296 *Pointer<Int>(d) = ((rgba & Int(0x00FF0000)) >> 16) | 297 ((rgba & Int(0x000000FF)) << 16) | 298 (rgba & Int(0xFF00FF00)); 299 } 300 break; 301 case FORMAT_A16B16G16R16: 302 { 303 UShort4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8; 304 305 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c))); 306 } 307 break; 308 case FORMAT_R5G6B5: 309 { 310 Int rgb = Int(*Pointer<Short>(s)); 311 312 *Pointer<Int>(d) = 0xFF000000 | 313 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) | 314 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) | 315 ((rgb & 0x001C) >> 2); 316 } 317 break; 318 default: 319 ASSERT(false); 320 break; 321 } 322 323 s += sBytes; 324 d += dBytes; 325 } 326 } 327 break; 328 case FORMAT_X8B8G8R8: 329 case FORMAT_A8B8G8R8: 330 case FORMAT_SRGB8_X8: 331 case FORMAT_SRGB8_A8: 332 { 333 Int x = x0; 334 335 switch(state.sourceFormat) 336 { 337 case FORMAT_X8B8G8R8: 338 case FORMAT_A8B8G8R8: 339 For(, x < width - 3, x += 4) 340 { 341 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16); 342 343 s += 4 * sBytes; 344 d += 4 * dBytes; 345 } 346 break; 347 case FORMAT_X8R8G8B8: 348 case FORMAT_A8R8G8B8: 349 For(, x < width - 3, x += 4) 350 { 351 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16); 352 353 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) | 354 ((bgra & Int4(0x000000FF)) << 16) | 355 (bgra & Int4(0xFF00FF00)); 356 357 s += 4 * sBytes; 358 d += 4 * dBytes; 359 } 360 break; 361 case FORMAT_A16B16G16R16: 362 For(, x < width - 1, x += 2) 363 { 364 UShort4 c0 = *Pointer<UShort4>(s + 0) >> 8; 365 UShort4 c1 = *Pointer<UShort4>(s + 8) >> 8; 366 367 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1)); 368 369 s += 2 * sBytes; 370 d += 2 * dBytes; 371 } 372 break; 373 case FORMAT_R5G6B5: 374 For(, x < width - 3, x += 4) 375 { 376 Int4 rgb = Int4(*Pointer<Short4>(s)); 377 378 *Pointer<Int4>(d) = Int4(0xFF000000) | 379 (((rgb & Int4(0x001F)) << 19) | ((rgb & Int4(0x001C)) << 14)) | 380 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) | 381 (((rgb & Int4(0xF800)) >> 8) | ((rgb & Int4(0xE000)) >> 13)); 382 383 s += 4 * sBytes; 384 d += 4 * dBytes; 385 } 386 break; 387 default: 388 ASSERT(false); 389 break; 390 } 391 392 For(, x < width, x++) 393 { 394 switch(state.sourceFormat) 395 { 396 case FORMAT_X8B8G8R8: 397 case FORMAT_A8B8G8R8: 398 *Pointer<Int>(d) = *Pointer<Int>(s); 399 break; 400 case FORMAT_X8R8G8B8: 401 case FORMAT_A8R8G8B8: 402 { 403 Int bgra = *Pointer<Int>(s); 404 *Pointer<Int>(d) = ((bgra & Int(0x00FF0000)) >> 16) | 405 ((bgra & Int(0x000000FF)) << 16) | 406 (bgra & Int(0xFF00FF00)); 407 } 408 break; 409 case FORMAT_A16B16G16R16: 410 { 411 UShort4 c = *Pointer<UShort4>(s) >> 8; 412 413 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c))); 414 } 415 break; 416 case FORMAT_R5G6B5: 417 { 418 Int rgb = Int(*Pointer<Short>(s)); 419 420 *Pointer<Int>(d) = 0xFF000000 | 421 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) | 422 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) | 423 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13); 424 } 425 break; 426 default: 427 ASSERT(false); 428 break; 429 } 430 431 s += sBytes; 432 d += dBytes; 433 } 434 } 435 break; 436 case FORMAT_R8G8B8: 437 { 438 For(Int x = x0, x < width, x++) 439 { 440 switch(state.sourceFormat) 441 { 442 case FORMAT_X8R8G8B8: 443 case FORMAT_A8R8G8B8: 444 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0); 445 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1); 446 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2); 447 break; 448 case FORMAT_X8B8G8R8: 449 case FORMAT_A8B8G8R8: 450 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 2); 451 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1); 452 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 0); 453 break; 454 case FORMAT_A16B16G16R16: 455 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5); 456 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3); 457 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1); 458 break; 459 case FORMAT_R5G6B5: 460 { 461 Int rgb = Int(*Pointer<Short>(s)); 462 463 *Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2)); 464 *Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1)); 465 *Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3)); 466 } 467 break; 468 default: 469 ASSERT(false); 470 break; 471 } 472 473 s += sBytes; 474 d += dBytes; 475 } 476 } 477 break; 478 case FORMAT_R5G6B5: 479 { 480 For(Int x = x0, x < width, x++) 481 { 482 switch(state.sourceFormat) 483 { 484 case FORMAT_X8R8G8B8: 485 case FORMAT_A8R8G8B8: 486 { 487 Int c = *Pointer<Int>(s); 488 489 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 | 490 (c & 0x0000FC00) >> 5 | 491 (c & 0x000000F8) >> 3); 492 } 493 break; 494 case FORMAT_X8B8G8R8: 495 case FORMAT_A8B8G8R8: 496 { 497 Int c = *Pointer<Int>(s); 498 499 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 | 500 (c & 0x0000FC00) >> 5 | 501 (c & 0x000000F8) << 8); 502 } 503 break; 504 case FORMAT_A16B16G16R16: 505 { 506 UShort4 cc = *Pointer<UShort4>(s) >> 8; 507 Int c = Int(As<Int2>(Pack(cc, cc))); 508 509 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 | 510 (c & 0x0000FC00) >> 5 | 511 (c & 0x000000F8) << 8); 512 } 513 break; 514 case FORMAT_R5G6B5: 515 *Pointer<Short>(d) = *Pointer<Short>(s); 516 break; 517 default: 518 ASSERT(false); 519 break; 520 } 521 522 s += sBytes; 523 d += dBytes; 524 } 525 } 526 break; 527 default: 528 ASSERT(false); 529 break; 530 } 531 } 532 533 if(state.cursorWidth > 0 && state.cursorHeight > 0) 534 { 535 Int x0 = *Pointer<Int>(cursor + OFFSET(Cursor,x)); 536 Int y0 = *Pointer<Int>(cursor + OFFSET(Cursor,y)); 537 538 For(Int y1 = 0, y1 < state.cursorHeight, y1++) 539 { 540 Int y = y0 + y1; 541 542 If(y >= 0 && y < height) 543 { 544 Pointer<Byte> d = dst + y * dStride + x0 * dBytes; 545 Pointer<Byte> s = src + y * sStride + x0 * sBytes; 546 Pointer<Byte> c = *Pointer<Pointer<Byte>>(cursor + OFFSET(Cursor,image)) + y1 * state.cursorWidth * 4; 547 548 For(Int x1 = 0, x1 < state.cursorWidth, x1++) 549 { 550 Int x = x0 + x1; 551 552 If(x >= 0 && x < width) 553 { 554 blend(state, d, s, c); 555 } 556 557 c += 4; 558 s += sBytes; 559 d += dBytes; 560 } 561 } 562 } 563 } 564 } 565 566 return function(L"FrameBuffer"); 567 } 568 blend(const BlitState & state,const Pointer<Byte> & d,const Pointer<Byte> & s,const Pointer<Byte> & c)569 void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c) 570 { 571 Short4 c1; 572 Short4 c2; 573 574 c1 = Unpack(*Pointer<Byte4>(c)); 575 576 switch(state.sourceFormat) 577 { 578 case FORMAT_X8R8G8B8: 579 case FORMAT_A8R8G8B8: 580 c2 = Unpack(*Pointer<Byte4>(s)); 581 break; 582 case FORMAT_X8B8G8R8: 583 case FORMAT_A8B8G8R8: 584 c2 = Swizzle(Unpack(*Pointer<Byte4>(s)), 0xC6); 585 break; 586 case FORMAT_A16B16G16R16: 587 c2 = Swizzle(*Pointer<Short4>(s), 0xC6); 588 break; 589 case FORMAT_R5G6B5: 590 { 591 Int rgb(*Pointer<Short>(s)); 592 rgb = 0xFF000000 | 593 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) | 594 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) | 595 ((rgb & 0x001C) >> 2); 596 c2 = Unpack(As<Byte4>(rgb)); 597 } 598 break; 599 default: 600 ASSERT(false); 601 break; 602 } 603 604 c1 = As<Short4>(As<UShort4>(c1) >> 9); 605 c2 = As<Short4>(As<UShort4>(c2) >> 9); 606 607 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000); 608 609 c1 = (c1 - c2) * alpha; 610 c1 = c1 >> 7; 611 c1 = c1 + c2; 612 c1 = c1 + c1; 613 614 switch(state.destFormat) 615 { 616 case FORMAT_X8R8G8B8: 617 case FORMAT_A8R8G8B8: 618 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1))); 619 break; 620 case FORMAT_X8B8G8R8: 621 case FORMAT_A8B8G8R8: 622 case FORMAT_SRGB8_X8: 623 case FORMAT_SRGB8_A8: 624 { 625 c1 = Swizzle(c1, 0xC6); 626 627 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1))); 628 } 629 break; 630 case FORMAT_R8G8B8: 631 { 632 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1)))); 633 634 *Pointer<Byte>(d + 0) = Byte(c >> 0); 635 *Pointer<Byte>(d + 1) = Byte(c >> 8); 636 *Pointer<Byte>(d + 2) = Byte(c >> 16); 637 } 638 break; 639 case FORMAT_R5G6B5: 640 { 641 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1)))); 642 643 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 | 644 (c & 0x0000FC00) >> 5 | 645 (c & 0x000000F8) >> 3); 646 } 647 break; 648 default: 649 ASSERT(false); 650 break; 651 } 652 } 653 threadFunction(void * parameters)654 void FrameBuffer::threadFunction(void *parameters) 655 { 656 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters); 657 658 while(!frameBuffer->terminate) 659 { 660 frameBuffer->blitEvent.wait(); 661 662 if(!frameBuffer->terminate) 663 { 664 frameBuffer->copyLocked(); 665 666 frameBuffer->syncEvent.signal(); 667 } 668 } 669 } 670 } 671