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