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