blob: 15e7e4d2decce8bf6774f618e39aef4b555fcafa [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman19bac1e2014-05-06 15:23:49 -04003// Copyright(c) 2005-2012 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "FrameBuffer.hpp"
13
14#include "Timer.hpp"
15#include "CPUID.hpp"
16#include "serialvalid.h"
John Bauman89401822014-05-06 15:04:28 -040017#include "Register.hpp"
John Bauman66b8ab22014-05-06 15:57:45 -040018#include "Renderer/Surface.hpp"
John Bauman19bac1e2014-05-06 15:23:49 -040019#include "Reactor/Reactor.hpp"
John Bauman66b8ab22014-05-06 15:57:45 -040020#include "Common/Debug.hpp"
John Bauman89401822014-05-06 15:04:28 -040021
22#include <stdio.h>
John Bauman66b8ab22014-05-06 15:57:45 -040023#include <string.h>
24#include <time.h>
John Bauman89401822014-05-06 15:04:28 -040025
Nicolas Capens135f6342015-11-11 10:49:08 -050026#ifdef __ANDROID__
27#include <cutils/properties.h>
28#endif
29
John Bauman19bac1e2014-05-06 15:23:49 -040030#ifndef DISPLAY_LOGO
Nicolas Capens135f6342015-11-11 10:49:08 -050031#define DISPLAY_LOGO ((NDEBUG | __ANDROID__) & 1)
John Bauman19bac1e2014-05-06 15:23:49 -040032#endif
33
34#define ASYNCHRONOUS_BLIT 0 // FIXME: Currently leads to rare race conditions
John Bauman89401822014-05-06 15:04:28 -040035
John Bauman66b8ab22014-05-06 15:57:45 -040036extern const int logoWidth;
37extern const int logoHeight;
38extern const unsigned int logoData[];
39
John Bauman89401822014-05-06 15:04:28 -040040namespace sw
41{
42 extern bool forceWindowed;
43
44 Surface *FrameBuffer::logo;
45 unsigned int *FrameBuffer::logoImage;
46 void *FrameBuffer::cursor;
47 int FrameBuffer::cursorWidth = 0;
48 int FrameBuffer::cursorHeight = 0;
49 int FrameBuffer::cursorHotspotX;
50 int FrameBuffer::cursorHotspotY;
51 int FrameBuffer::cursorPositionX;
52 int FrameBuffer::cursorPositionY;
53 int FrameBuffer::cursorX;
54 int FrameBuffer::cursorY;
John Bauman19bac1e2014-05-06 15:23:49 -040055 bool FrameBuffer::topLeftOrigin = false;
John Bauman89401822014-05-06 15:04:28 -040056
John Bauman66b8ab22014-05-06 15:57:45 -040057 FrameBuffer::FrameBuffer(int width, int height, bool fullscreen, bool topLeftOrigin)
John Bauman89401822014-05-06 15:04:28 -040058 {
John Bauman19bac1e2014-05-06 15:23:49 -040059 this->topLeftOrigin = topLeftOrigin;
60
John Bauman89401822014-05-06 15:04:28 -040061 locked = 0;
62
John Bauman89401822014-05-06 15:04:28 -040063 this->width = width;
64 this->height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -040065 destFormat = FORMAT_X8R8G8B8;
66 sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040067 stride = 0;
68
69 if(forceWindowed)
70 {
71 fullscreen = false;
72 }
73
74 windowed = !fullscreen;
75
John Bauman89401822014-05-06 15:04:28 -040076 blitFunction = 0;
77 blitRoutine = 0;
78
79 blitState.width = 0;
80 blitState.height = 0;
Nicolas Capens10219e72014-05-07 00:17:20 -040081 blitState.destFormat = FORMAT_X8R8G8B8;
82 blitState.sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040083 blitState.cursorWidth = 0;
84 blitState.cursorHeight = 0;
85
86 logo = 0;
87
John Bauman19bac1e2014-05-06 15:23:49 -040088 if(ASYNCHRONOUS_BLIT)
89 {
John Bauman19bac1e2014-05-06 15:23:49 -040090 terminate = false;
John Bauman66b8ab22014-05-06 15:57:45 -040091 FrameBuffer *parameters = this;
92 blitThread = new Thread(threadFunction, &parameters);
John Bauman19bac1e2014-05-06 15:23:49 -040093 }
John Bauman89401822014-05-06 15:04:28 -040094 }
95
96 FrameBuffer::~FrameBuffer()
97 {
John Bauman19bac1e2014-05-06 15:23:49 -040098 if(ASYNCHRONOUS_BLIT)
99 {
100 terminate = true;
John Bauman66b8ab22014-05-06 15:57:45 -0400101 blitEvent.signal();
102 blitThread->join();
103 delete blitThread;
John Bauman19bac1e2014-05-06 15:23:49 -0400104 }
John Bauman89401822014-05-06 15:04:28 -0400105
106 delete blitRoutine;
John Bauman89401822014-05-06 15:04:28 -0400107 }
108
John Bauman89401822014-05-06 15:04:28 -0400109 int FrameBuffer::getWidth() const
110 {
111 return width;
112 }
113
114 int FrameBuffer::getHeight() const
115 {
116 return height;
117 }
118
119 int FrameBuffer::getStride() const
120 {
121 return stride;
122 }
123
124 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
125 {
126 if(cursorImage)
127 {
128 cursor = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
129 cursorImage->unlockExternal();
130
Nicolas Capens3779ea92015-06-10 13:43:52 -0400131 cursorWidth = cursorImage->getWidth();
132 cursorHeight = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -0400133 }
134 else
135 {
136 cursorWidth = 0;
137 cursorHeight = 0;
138 }
139 }
140
141 void FrameBuffer::setCursorOrigin(int x0, int y0)
142 {
143 cursorHotspotX = x0;
144 cursorHotspotY = y0;
145 }
146
147 void FrameBuffer::setCursorPosition(int x, int y)
148 {
149 cursorPositionX = x;
150 cursorPositionY = y;
151 }
152
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500153 void FrameBuffer::copy(void *source, Format format, size_t stride)
John Bauman89401822014-05-06 15:04:28 -0400154 {
155 if(!source)
156 {
157 return;
158 }
159
John Bauman89401822014-05-06 15:04:28 -0400160 if(!lock())
161 {
162 return;
163 }
164
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400165 sourceFormat = format;
166
John Bauman19bac1e2014-05-06 15:23:49 -0400167 if(topLeftOrigin)
168 {
169 target = source;
170 }
171 else
172 {
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500173 target = (byte*)source + (height - 1) * stride;
John Bauman19bac1e2014-05-06 15:23:49 -0400174 }
175
John Bauman66b8ab22014-05-06 15:57:45 -0400176 cursorX = cursorPositionX - cursorHotspotX;
177 cursorY = cursorPositionY - cursorHotspotY;
John Bauman89401822014-05-06 15:04:28 -0400178
John Bauman19bac1e2014-05-06 15:23:49 -0400179 if(ASYNCHRONOUS_BLIT)
180 {
John Bauman66b8ab22014-05-06 15:57:45 -0400181 blitEvent.signal();
182 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400183 }
184 else
185 {
186 copyLocked();
187 }
Nicolas Capens02704762014-11-24 15:50:51 -0500188
John Bauman89401822014-05-06 15:04:28 -0400189 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500190
191 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400192 }
193
194 void FrameBuffer::copyLocked()
195 {
John Bauman66b8ab22014-05-06 15:57:45 -0400196 BlitState update = {0};
John Bauman89401822014-05-06 15:04:28 -0400197
198 update.width = width;
199 update.height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400200 update.destFormat = destFormat;
201 update.sourceFormat = sourceFormat;
John Bauman89401822014-05-06 15:04:28 -0400202 update.stride = stride;
John Bauman89401822014-05-06 15:04:28 -0400203 update.cursorWidth = cursorWidth;
204 update.cursorHeight = cursorHeight;
205
206 if(memcmp(&blitState, &update, sizeof(BlitState)) != 0)
207 {
208 blitState = update;
209 delete blitRoutine;
210
211 blitRoutine = copyRoutine(blitState);
John Bauman66b8ab22014-05-06 15:57:45 -0400212 blitFunction = (void(*)(void*, void*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400213 }
214
215 blitFunction(locked, target);
John Bauman89401822014-05-06 15:04:28 -0400216 }
217
218 Routine *FrameBuffer::copyRoutine(const BlitState &state)
219 {
220 initializeLogo();
221
222 const int width = state.width;
223 const int height = state.height;
224 const int width2 = (state.width + 1) & ~1;
Nicolas Capens10219e72014-05-07 00:17:20 -0400225 const int dBytes = Surface::bytes(state.destFormat);
John Bauman89401822014-05-06 15:04:28 -0400226 const int dStride = state.stride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400227 const int sBytes = Surface::bytes(state.sourceFormat);
John Bauman19bac1e2014-05-06 15:23:49 -0400228 const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2);
John Bauman89401822014-05-06 15:04:28 -0400229
Nicolas Capens135f6342015-11-11 10:49:08 -0500230 #ifdef __ANDROID__
231 char ro_product_model[PROPERTY_VALUE_MAX] = "";
232 property_get("ro.product.model", ro_product_model, nullptr);
233 bool validKey = strstr(ro_product_model, "Android") != nullptr;
234 #else
235 bool validKey = ValidateSerialNumber(validationKey, CHECKSUM_KEY, SERIAL_PREFIX);
236 #endif
John Bauman66b8ab22014-05-06 15:57:45 -0400237
238 Function<Void, Pointer<Byte>, Pointer<Byte> > function;
John Bauman89401822014-05-06 15:04:28 -0400239 {
240 Pointer<Byte> dst(function.arg(0));
241 Pointer<Byte> src(function.arg(1));
242
243 For(Int y = 0, y < height, y++)
244 {
245 Pointer<Byte> d = dst + y * dStride;
246 Pointer<Byte> s = src + y * sStride;
247
248 Int x0 = 0;
249
250 #if DISPLAY_LOGO
251 If(!Bool(validKey)/* || !Bool(validApp)*/)
252 {
253 If(y > height - logoHeight)
254 {
255 x0 = logoWidth;
256 s += logoWidth * sBytes;
257 d += logoWidth * dBytes;
258 }
259 }
260 #endif
261
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400262 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400263 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400264 case FORMAT_X8R8G8B8:
265 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400266 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400267 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400268
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400269 switch(state.sourceFormat)
270 {
271 case FORMAT_X8R8G8B8:
272 case FORMAT_A8R8G8B8:
273 For(, x < width - 3, x += 4)
274 {
275 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, width % 4 ? 1 : 16);
276
277 s += 4 * sBytes;
278 d += 4 * dBytes;
279 }
280 break;
281 case FORMAT_X8B8G8R8:
282 case FORMAT_A8B8G8R8:
283 For(, x < width - 3, x += 4)
284 {
285 Int4 bgra = *Pointer<Int4>(s, width % 4 ? 1 : 16);
286
287 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
288 ((bgra & Int4(0x000000FF)) << 16) |
289 (bgra & Int4(0xFF00FF00));
290
291 s += 4 * sBytes;
292 d += 4 * dBytes;
293 }
294 break;
295 case FORMAT_A16B16G16R16:
296 For(, x < width - 1, x += 2)
297 {
298 UShort4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
299 UShort4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
300
301 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
302
303 s += 2 * sBytes;
304 d += 2 * dBytes;
305 }
306 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400307 case FORMAT_R5G6B5:
308 For(, x < width, x++)
309 {
310 Int rgb = Int(*Pointer<Short>(s));
311
312 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400313 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400314 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400315 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400316
317 s += sBytes;
318 d += dBytes;
319 }
320 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400321 default:
322 ASSERT(false);
323 break;
324 }
325
326 For(, x < width, x++)
327 {
328 switch(state.sourceFormat)
329 {
330 case FORMAT_X8R8G8B8:
331 case FORMAT_A8R8G8B8:
332 *Pointer<Int>(d) = *Pointer<Int>(s);
333 break;
334 case FORMAT_X8B8G8R8:
335 case FORMAT_A8B8G8R8:
336 {
337 Int rgba = *Pointer<Int>(s);
338
339 *Pointer<Int>(d) = ((rgba & Int(0x00FF0000)) >> 16) |
340 ((rgba & Int(0x000000FF)) << 16) |
341 (rgba & Int(0xFF00FF00));
342 }
343 break;
344 case FORMAT_A16B16G16R16:
345 {
346 UShort4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
347
348 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
349 }
350 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400351 case FORMAT_R5G6B5:
352 {
353 Int rgb = Int(*Pointer<Short>(s));
354
355 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400356 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400357 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400358 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400359 }
360 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400361 default:
362 ASSERT(false);
363 break;
364 }
365
366 s += sBytes;
367 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400368 }
369 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400370 break;
371 case FORMAT_X8B8G8R8:
372 case FORMAT_A8B8G8R8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400373 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400374 Int x = x0;
375
376 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400377 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400378 case FORMAT_X8B8G8R8:
379 case FORMAT_A8B8G8R8:
380 For(, x < width - 3, x += 4)
381 {
382 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, width % 4 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400383
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400384 s += 4 * sBytes;
385 d += 4 * dBytes;
386 }
387 break;
388 case FORMAT_X8R8G8B8:
389 case FORMAT_A8R8G8B8:
390 For(, x < width - 3, x += 4)
391 {
392 Int4 bgra = *Pointer<Int4>(s, width % 4 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400393
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400394 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
395 ((bgra & Int4(0x000000FF)) << 16) |
396 (bgra & Int4(0xFF00FF00));
397
398 s += 4 * sBytes;
399 d += 4 * dBytes;
400 }
401 break;
402 case FORMAT_A16B16G16R16:
403 For(, x < width - 1, x += 2)
404 {
405 UShort4 c0 = *Pointer<UShort4>(s + 0) >> 8;
406 UShort4 c1 = *Pointer<UShort4>(s + 8) >> 8;
407
408 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
409
410 s += 2 * sBytes;
411 d += 2 * dBytes;
412 }
413 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400414 case FORMAT_R5G6B5:
415 For(, x < width, x++)
416 {
417 Int rgb = Int(*Pointer<Short>(s));
418
419 *Pointer<Int>(d) = 0xFF000000 |
420 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
421 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
422 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
423
424 s += sBytes;
425 d += dBytes;
426 }
427 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400428 default:
429 ASSERT(false);
430 break;
431 }
432
433 For(, x < width, x++)
434 {
435 switch(state.sourceFormat)
436 {
437 case FORMAT_X8B8G8R8:
438 case FORMAT_A8B8G8R8:
439 *Pointer<Int>(d) = *Pointer<Int>(s);
440 break;
441 case FORMAT_X8R8G8B8:
442 case FORMAT_A8R8G8B8:
443 {
444 Int bgra = *Pointer<Int>(s);
445 *Pointer<Int>(d) = ((bgra & Int(0x00FF0000)) >> 16) |
446 ((bgra & Int(0x000000FF)) << 16) |
447 (bgra & Int(0xFF00FF00));
448 }
449 break;
450 case FORMAT_A16B16G16R16:
451 {
452 UShort4 c = *Pointer<UShort4>(s) >> 8;
453
454 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
455 }
456 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400457 case FORMAT_R5G6B5:
458 {
459 Int rgb = Int(*Pointer<Short>(s));
460
461 *Pointer<Int>(d) = 0xFF000000 |
462 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
463 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
464 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
465 }
466 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400467 default:
468 ASSERT(false);
469 break;
470 }
471
472 s += sBytes;
473 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400474 }
475 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700476 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400477 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400478 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400479 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400480 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400481 switch(state.sourceFormat)
482 {
483 case FORMAT_X8R8G8B8:
484 case FORMAT_A8R8G8B8:
485 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0);
486 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
487 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2);
488 break;
489 case FORMAT_X8B8G8R8:
490 case FORMAT_A8B8G8R8:
491 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 2);
492 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
493 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 0);
494 break;
495 case FORMAT_A16B16G16R16:
496 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5);
497 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3);
498 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1);
499 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400500 case FORMAT_R5G6B5:
501 {
502 Int rgb = Int(*Pointer<Short>(s));
503
504 *Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2));
505 *Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1));
506 *Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3));
507 }
508 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400509 default:
510 ASSERT(false);
511 break;
512 }
John Bauman89401822014-05-06 15:04:28 -0400513
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400514 s += sBytes;
515 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400516 }
517 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400518 break;
519 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400520 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400521 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400522 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400523 switch(state.sourceFormat)
524 {
525 case FORMAT_X8R8G8B8:
526 case FORMAT_A8R8G8B8:
527 {
528 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400529
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400530 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
531 (c & 0x0000FC00) >> 5 |
532 (c & 0x000000F8) >> 3);
533 }
534 break;
535 case FORMAT_X8B8G8R8:
536 case FORMAT_A8B8G8R8:
537 {
538 Int c = *Pointer<Int>(s);
Nicolas Capens296e3122014-05-07 00:10:55 -0400539
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400540 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
541 (c & 0x0000FC00) >> 5 |
542 (c & 0x000000F8) << 8);
543 }
544 break;
545 case FORMAT_A16B16G16R16:
546 {
547 UShort4 cc = *Pointer<UShort4>(s) >> 8;
548 Int c = Int(As<Int2>(Pack(cc, cc)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400549
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400550 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
551 (c & 0x0000FC00) >> 5 |
552 (c & 0x000000F8) << 8);
553 }
554 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400555 case FORMAT_R5G6B5:
556 *Pointer<Short>(d) = *Pointer<Short>(s);
557 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400558 default:
559 ASSERT(false);
560 break;
561 }
562
563 s += sBytes;
564 d += dBytes;
565 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400566 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400567 break;
568 default:
569 ASSERT(false);
570 break;
John Bauman89401822014-05-06 15:04:28 -0400571 }
John Bauman89401822014-05-06 15:04:28 -0400572 }
573
574 #if DISPLAY_LOGO
575 If(!Bool(validKey)/* || !Bool(validApp)*/)
576 {
577 UInt hash = UInt(0x0B020C04) + UInt(0xC0F090E0); // Initial value
John Bauman66b8ab22014-05-06 15:57:45 -0400578 UInt imageHash = S3TC_SUPPORT ? UInt(0x0F0D0700) + UInt(0xA0C0A090) : UInt(0x0207040B) + UInt(0xD0406010);
John Bauman89401822014-05-06 15:04:28 -0400579
580 While(hash != imageHash)
581 {
582 For(y = (height - 1), height - 1 - y < logoHeight, y--)
583 {
John Bauman66b8ab22014-05-06 15:57:45 -0400584 Pointer<Byte> logo = *Pointer<Pointer<Byte> >(&logoImage) + 4 * (logoHeight - height + y) * logoWidth;
John Bauman89401822014-05-06 15:04:28 -0400585 Pointer<Byte> s = src + y * sStride;
586 Pointer<Byte> d = dst + y * dStride;
587
588 For(Int x = 0, x < logoWidth, x++)
589 {
590 hash *= 16777619;
591 hash ^= *Pointer<UInt>(logo);
592
593 If(y >= 0 && x < width)
594 {
595 blend(state, d, s, logo);
596 }
597
598 logo += 4;
599 s += sBytes;
600 d += dBytes;
601 }
602 }
603 }
604 }
605 #endif
606
607 Int x0 = *Pointer<Int>(&cursorX);
608 Int y0 = *Pointer<Int>(&cursorY);
609
610 For(Int y1 = 0, y1 < cursorHeight, y1++)
611 {
612 Int y = y0 + y1;
613
614 If(y >= 0 && y < height)
615 {
616 Pointer<Byte> d = dst + y * dStride + x0 * dBytes;
617 Pointer<Byte> s = src + y * sStride + x0 * sBytes;
John Bauman66b8ab22014-05-06 15:57:45 -0400618 Pointer<Byte> c = *Pointer<Pointer<Byte> >(&cursor) + y1 * cursorWidth * 4;
John Bauman89401822014-05-06 15:04:28 -0400619
620 For(Int x1 = 0, x1 < cursorWidth, x1++)
621 {
622 Int x = x0 + x1;
623
624 If(x >= 0 && x < width)
625 {
626 blend(state, d, s, c);
627 }
Nicolas Capens02704762014-11-24 15:50:51 -0500628
John Bauman89401822014-05-06 15:04:28 -0400629 c += 4;
630 s += sBytes;
631 d += dBytes;
632 }
633 }
634 }
John Bauman89401822014-05-06 15:04:28 -0400635 }
636
637 return function(L"FrameBuffer");
638 }
639
640 void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c)
641 {
642 Short4 c1;
643 Short4 c2;
644
645 c1 = UnpackLow(As<Byte8>(c1), *Pointer<Byte8>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500646
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400647 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400648 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400649 case FORMAT_X8R8G8B8:
650 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400651 c2 = UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400652 break;
653 case FORMAT_X8B8G8R8:
654 case FORMAT_A8B8G8R8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400655 c2 = Swizzle(UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s)), 0xC6);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400656 break;
657 case FORMAT_A16B16G16R16:
Nicolas Capense0308902015-05-25 23:47:18 -0400658 c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
659 break;
660 case FORMAT_R5G6B5:
661 {
662 Int rgb(*Pointer<Short>(s));
663 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400664 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400665 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400666 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400667 c2 = Unpack(As<Byte4>(rgb));
668 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400669 break;
670 default:
671 ASSERT(false);
672 break;
John Bauman89401822014-05-06 15:04:28 -0400673 }
674
675 c1 = As<Short4>(As<UShort4>(c1) >> 9);
676 c2 = As<Short4>(As<UShort4>(c2) >> 9);
677
John Bauman19bac1e2014-05-06 15:23:49 -0400678 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400679
680 c1 = (c1 - c2) * alpha;
681 c1 = c1 >> 7;
682 c1 = c1 + c2;
683 c1 = c1 + c1;
684
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400685 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400686 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400687 case FORMAT_X8R8G8B8:
688 case FORMAT_A8R8G8B8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400689 *Pointer<UInt>(d) = UInt(As<Long>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400690 break;
691 case FORMAT_X8B8G8R8:
692 case FORMAT_A8B8G8R8:
693 {
694 c1 = Swizzle(c1, 0xC6);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400695
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400696 *Pointer<UInt>(d) = UInt(As<Long>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
697 }
698 break;
699 case FORMAT_R8G8B8:
700 {
701 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
John Bauman89401822014-05-06 15:04:28 -0400702
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400703 *Pointer<Byte>(d + 0) = Byte(c >> 0);
704 *Pointer<Byte>(d + 1) = Byte(c >> 8);
705 *Pointer<Byte>(d + 2) = Byte(c >> 16);
706 }
707 break;
708 case FORMAT_R5G6B5:
709 {
710 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
John Bauman89401822014-05-06 15:04:28 -0400711
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400712 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
713 (c & 0x0000FC00) >> 5 |
714 (c & 0x000000F8) >> 3);
715 }
716 break;
717 default:
718 ASSERT(false);
719 break;
John Bauman89401822014-05-06 15:04:28 -0400720 }
John Bauman89401822014-05-06 15:04:28 -0400721 }
722
John Bauman66b8ab22014-05-06 15:57:45 -0400723 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400724 {
725 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
726
John Bauman89401822014-05-06 15:04:28 -0400727 while(!frameBuffer->terminate)
728 {
John Bauman66b8ab22014-05-06 15:57:45 -0400729 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400730
731 if(!frameBuffer->terminate)
732 {
733 frameBuffer->copyLocked();
734
John Bauman66b8ab22014-05-06 15:57:45 -0400735 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400736 }
737 }
John Bauman89401822014-05-06 15:04:28 -0400738 }
739
740 void FrameBuffer::initializeLogo()
741 {
742 #if DISPLAY_LOGO
743 if(!logo)
744 {
745 #if S3TC_SUPPORT
746 logo = new Surface(0, logoWidth, logoHeight, 1, FORMAT_DXT5, true, false);
747 void *data = logo->lockExternal(0, 0, 0, LOCK_WRITEONLY, sw::PUBLIC);
748 memcpy(data, logoData, logoWidth * logoHeight);
749 logo->unlockExternal();
750 #else
751 logo = new Surface(0, logoWidth, logoHeight, 1, FORMAT_A8R8G8B8, true, false);
752 void *data = logo->lockExternal(0, 0, 0, LOCK_WRITEONLY, sw::PUBLIC);
753 memcpy(data, logoData, logoWidth * logoHeight * 4);
754 logo->unlockExternal();
755 #endif
756
757 logoImage = (unsigned int*)logo->lockInternal(0, 0, 0, LOCK_READONLY, sw::PUBLIC);
758 logo->unlockInternal();
759 }
760 #endif
761 }
Nicolas Capens02704762014-11-24 15:50:51 -0500762}