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