blob: e95f7665b88deb3d1939526aa62f79b7258bb298 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
John Bauman89401822014-05-06 15:04:28 -04002//
Nicolas Capens0bac2852016-05-07 06:09:58 -04003// 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
John Bauman89401822014-05-06 15:04:28 -04006//
Nicolas Capens0bac2852016-05-07 06:09:58 -04007// http://www.apache.org/licenses/LICENSE-2.0
John Bauman89401822014-05-06 15:04:28 -04008//
Nicolas Capens0bac2852016-05-07 06:09:58 -04009// 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.
John Bauman89401822014-05-06 15:04:28 -040014
15#include "FrameBuffer.hpp"
16
17#include "Timer.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#define ASYNCHRONOUS_BLIT 0 // FIXME: Currently leads to rare race conditions
John Bauman89401822014-05-06 15:04:28 -040031
32namespace sw
33{
34 extern bool forceWindowed;
35
Nicolas Capens04f41252017-05-02 15:14:58 -040036 FrameBuffer::Cursor FrameBuffer::cursor = {};
John Bauman19bac1e2014-05-06 15:23:49 -040037 bool FrameBuffer::topLeftOrigin = false;
John Bauman89401822014-05-06 15:04:28 -040038
John Bauman66b8ab22014-05-06 15:57:45 -040039 FrameBuffer::FrameBuffer(int width, int height, bool fullscreen, bool topLeftOrigin)
John Bauman89401822014-05-06 15:04:28 -040040 {
John Bauman19bac1e2014-05-06 15:23:49 -040041 this->topLeftOrigin = topLeftOrigin;
42
Nicolas Capens518e41a2016-04-27 23:18:01 -040043 locked = nullptr;
John Bauman89401822014-05-06 15:04:28 -040044
John Bauman89401822014-05-06 15:04:28 -040045 this->width = width;
46 this->height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -040047 destFormat = FORMAT_X8R8G8B8;
48 sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040049 stride = 0;
50
51 if(forceWindowed)
52 {
53 fullscreen = false;
54 }
55
56 windowed = !fullscreen;
57
Nicolas Capens518e41a2016-04-27 23:18:01 -040058 blitFunction = nullptr;
59 blitRoutine = nullptr;
John Bauman89401822014-05-06 15:04:28 -040060
61 blitState.width = 0;
62 blitState.height = 0;
Nicolas Capens10219e72014-05-07 00:17:20 -040063 blitState.destFormat = FORMAT_X8R8G8B8;
64 blitState.sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040065 blitState.cursorWidth = 0;
66 blitState.cursorHeight = 0;
67
John Bauman19bac1e2014-05-06 15:23:49 -040068 if(ASYNCHRONOUS_BLIT)
69 {
John Bauman19bac1e2014-05-06 15:23:49 -040070 terminate = false;
John Bauman66b8ab22014-05-06 15:57:45 -040071 FrameBuffer *parameters = this;
72 blitThread = new Thread(threadFunction, &parameters);
John Bauman19bac1e2014-05-06 15:23:49 -040073 }
John Bauman89401822014-05-06 15:04:28 -040074 }
75
76 FrameBuffer::~FrameBuffer()
77 {
John Bauman19bac1e2014-05-06 15:23:49 -040078 if(ASYNCHRONOUS_BLIT)
79 {
80 terminate = true;
John Bauman66b8ab22014-05-06 15:57:45 -040081 blitEvent.signal();
82 blitThread->join();
83 delete blitThread;
John Bauman19bac1e2014-05-06 15:23:49 -040084 }
John Bauman89401822014-05-06 15:04:28 -040085
86 delete blitRoutine;
John Bauman89401822014-05-06 15:04:28 -040087 }
88
John Bauman89401822014-05-06 15:04:28 -040089 int FrameBuffer::getWidth() const
90 {
91 return width;
92 }
93
94 int FrameBuffer::getHeight() const
95 {
96 return height;
97 }
98
99 int FrameBuffer::getStride() const
100 {
101 return stride;
102 }
103
104 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
105 {
106 if(cursorImage)
107 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500108 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -0400109 cursorImage->unlockExternal();
110
Nicolas Capensa29d6532016-12-05 21:38:09 -0500111 cursor.width = cursorImage->getWidth();
112 cursor.height = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -0400113 }
114 else
115 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500116 cursor.width = 0;
117 cursor.height = 0;
John Bauman89401822014-05-06 15:04:28 -0400118 }
119 }
120
121 void FrameBuffer::setCursorOrigin(int x0, int y0)
122 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500123 cursor.hotspotX = x0;
124 cursor.hotspotY = y0;
John Bauman89401822014-05-06 15:04:28 -0400125 }
126
127 void FrameBuffer::setCursorPosition(int x, int y)
128 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500129 cursor.positionX = x;
130 cursor.positionY = y;
John Bauman89401822014-05-06 15:04:28 -0400131 }
132
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500133 void FrameBuffer::copy(void *source, Format format, size_t stride)
John Bauman89401822014-05-06 15:04:28 -0400134 {
135 if(!source)
136 {
137 return;
138 }
139
John Bauman89401822014-05-06 15:04:28 -0400140 if(!lock())
141 {
142 return;
143 }
144
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400145 sourceFormat = format;
146
John Bauman19bac1e2014-05-06 15:23:49 -0400147 if(topLeftOrigin)
148 {
149 target = source;
150 }
151 else
152 {
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500153 target = (byte*)source + (height - 1) * stride;
John Bauman19bac1e2014-05-06 15:23:49 -0400154 }
155
Nicolas Capensa29d6532016-12-05 21:38:09 -0500156 cursor.x = cursor.positionX - cursor.hotspotX;
157 cursor.y = cursor.positionY - cursor.hotspotY;
John Bauman89401822014-05-06 15:04:28 -0400158
John Bauman19bac1e2014-05-06 15:23:49 -0400159 if(ASYNCHRONOUS_BLIT)
160 {
John Bauman66b8ab22014-05-06 15:57:45 -0400161 blitEvent.signal();
162 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400163 }
164 else
165 {
166 copyLocked();
167 }
Nicolas Capens02704762014-11-24 15:50:51 -0500168
John Bauman89401822014-05-06 15:04:28 -0400169 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500170
171 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400172 }
173
174 void FrameBuffer::copyLocked()
175 {
Nicolas Capensc4748c52016-01-01 01:21:18 -0500176 BlitState update = {};
John Bauman89401822014-05-06 15:04:28 -0400177 update.width = width;
178 update.height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400179 update.destFormat = destFormat;
180 update.sourceFormat = sourceFormat;
John Bauman89401822014-05-06 15:04:28 -0400181 update.stride = stride;
Nicolas Capensa29d6532016-12-05 21:38:09 -0500182 update.cursorWidth = cursor.width;
183 update.cursorHeight = cursor.height;
John Bauman89401822014-05-06 15:04:28 -0400184
185 if(memcmp(&blitState, &update, sizeof(BlitState)) != 0)
186 {
187 blitState = update;
188 delete blitRoutine;
189
190 blitRoutine = copyRoutine(blitState);
Nicolas Capensa29d6532016-12-05 21:38:09 -0500191 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400192 }
193
Nicolas Capensa29d6532016-12-05 21:38:09 -0500194 blitFunction(locked, target, &cursor);
John Bauman89401822014-05-06 15:04:28 -0400195 }
196
197 Routine *FrameBuffer::copyRoutine(const BlitState &state)
198 {
John Bauman89401822014-05-06 15:04:28 -0400199 const int width = state.width;
200 const int height = state.height;
201 const int width2 = (state.width + 1) & ~1;
Nicolas Capens10219e72014-05-07 00:17:20 -0400202 const int dBytes = Surface::bytes(state.destFormat);
John Bauman89401822014-05-06 15:04:28 -0400203 const int dStride = state.stride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400204 const int sBytes = Surface::bytes(state.sourceFormat);
John Bauman19bac1e2014-05-06 15:23:49 -0400205 const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2);
John Bauman89401822014-05-06 15:04:28 -0400206
Nicolas Capensa29d6532016-12-05 21:38:09 -0500207 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
John Bauman89401822014-05-06 15:04:28 -0400208 {
Nicolas Capens81f18302016-01-14 09:32:35 -0500209 Pointer<Byte> dst(function.Arg<0>());
210 Pointer<Byte> src(function.Arg<1>());
Nicolas Capensa29d6532016-12-05 21:38:09 -0500211 Pointer<Byte> cursor(function.Arg<2>());
John Bauman89401822014-05-06 15:04:28 -0400212
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
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400220 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400221 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400222 case FORMAT_X8R8G8B8:
223 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400224 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400225 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400226
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400227 switch(state.sourceFormat)
228 {
229 case FORMAT_X8R8G8B8:
230 case FORMAT_A8R8G8B8:
231 For(, x < width - 3, x += 4)
232 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500233 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400234
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 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500243 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400244
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;
Nicolas Capense0308902015-05-25 23:47:18 -0400265 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800266 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400267 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800268 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400269
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800270 *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));
Nicolas Capense0308902015-05-25 23:47:18 -0400273
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800274 s += 4 * sBytes;
275 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400276 }
277 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400278 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;
Nicolas Capense0308902015-05-25 23:47:18 -0400308 case FORMAT_R5G6B5:
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 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400318 default:
319 ASSERT(false);
320 break;
321 }
322
323 s += sBytes;
324 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400325 }
326 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400327 break;
328 case FORMAT_X8B8G8R8:
329 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400330 case FORMAT_SRGB8_X8:
331 case FORMAT_SRGB8_A8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400332 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400333 Int x = x0;
334
335 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400336 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400337 case FORMAT_X8B8G8R8:
338 case FORMAT_A8B8G8R8:
339 For(, x < width - 3, x += 4)
340 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500341 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400342
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400343 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 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500351 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400352
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400353 *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;
Nicolas Capense0308902015-05-25 23:47:18 -0400373 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800374 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400375 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800376 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400377
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800378 *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));
Nicolas Capense0308902015-05-25 23:47:18 -0400382
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800383 s += 4 * sBytes;
384 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400385 }
386 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400387 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;
Nicolas Capense0308902015-05-25 23:47:18 -0400416 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;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400426 default:
427 ASSERT(false);
428 break;
429 }
430
431 s += sBytes;
432 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400433 }
434 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700435 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400436 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400437 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400438 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400439 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400440 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;
Nicolas Capense0308902015-05-25 23:47:18 -0400459 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;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400468 default:
469 ASSERT(false);
470 break;
471 }
John Bauman89401822014-05-06 15:04:28 -0400472
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400473 s += sBytes;
474 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400475 }
476 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400477 break;
478 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400479 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400480 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400481 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400482 switch(state.sourceFormat)
483 {
484 case FORMAT_X8R8G8B8:
485 case FORMAT_A8R8G8B8:
486 {
487 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400488
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400489 *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);
Nicolas Capens296e3122014-05-07 00:10:55 -0400498
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400499 *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)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400508
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400509 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
510 (c & 0x0000FC00) >> 5 |
511 (c & 0x000000F8) << 8);
512 }
513 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400514 case FORMAT_R5G6B5:
515 *Pointer<Short>(d) = *Pointer<Short>(s);
516 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400517 default:
518 ASSERT(false);
519 break;
520 }
521
522 s += sBytes;
523 d += dBytes;
524 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400525 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400526 break;
527 default:
528 ASSERT(false);
529 break;
John Bauman89401822014-05-06 15:04:28 -0400530 }
John Bauman89401822014-05-06 15:04:28 -0400531 }
532
Nicolas Capens04f41252017-05-02 15:14:58 -0400533 if(state.cursorWidth > 0 && state.cursorHeight > 0)
John Bauman89401822014-05-06 15:04:28 -0400534 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400535 Int x0 = *Pointer<Int>(cursor + OFFSET(Cursor,x));
536 Int y0 = *Pointer<Int>(cursor + OFFSET(Cursor,y));
John Bauman89401822014-05-06 15:04:28 -0400537
Nicolas Capens04f41252017-05-02 15:14:58 -0400538 For(Int y1 = 0, y1 < state.cursorHeight, y1++)
John Bauman89401822014-05-06 15:04:28 -0400539 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400540 Int y = y0 + y1;
John Bauman89401822014-05-06 15:04:28 -0400541
Nicolas Capens04f41252017-05-02 15:14:58 -0400542 If(y >= 0 && y < height)
John Bauman89401822014-05-06 15:04:28 -0400543 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400544 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;
John Bauman89401822014-05-06 15:04:28 -0400547
Nicolas Capens04f41252017-05-02 15:14:58 -0400548 For(Int x1 = 0, x1 < state.cursorWidth, x1++)
John Bauman89401822014-05-06 15:04:28 -0400549 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400550 Int x = x0 + x1;
Nicolas Capens02704762014-11-24 15:50:51 -0500551
Nicolas Capens04f41252017-05-02 15:14:58 -0400552 If(x >= 0 && x < width)
553 {
554 blend(state, d, s, c);
555 }
556
557 c += 4;
558 s += sBytes;
559 d += dBytes;
560 }
John Bauman89401822014-05-06 15:04:28 -0400561 }
562 }
563 }
John Bauman89401822014-05-06 15:04:28 -0400564 }
565
566 return function(L"FrameBuffer");
567 }
568
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
Nicolas Capens411273e2017-01-26 15:13:36 -0800574 c1 = Unpack(*Pointer<Byte4>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500575
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400576 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400577 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400578 case FORMAT_X8R8G8B8:
579 case FORMAT_A8R8G8B8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800580 c2 = Unpack(*Pointer<Byte4>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400581 break;
582 case FORMAT_X8B8G8R8:
583 case FORMAT_A8B8G8R8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800584 c2 = Swizzle(Unpack(*Pointer<Byte4>(s)), 0xC6);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400585 break;
586 case FORMAT_A16B16G16R16:
Nicolas Capense0308902015-05-25 23:47:18 -0400587 c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
588 break;
589 case FORMAT_R5G6B5:
590 {
591 Int rgb(*Pointer<Short>(s));
592 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400593 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400594 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400595 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400596 c2 = Unpack(As<Byte4>(rgb));
597 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400598 break;
599 default:
600 ASSERT(false);
601 break;
John Bauman89401822014-05-06 15:04:28 -0400602 }
603
604 c1 = As<Short4>(As<UShort4>(c1) >> 9);
605 c2 = As<Short4>(As<UShort4>(c2) >> 9);
606
John Bauman19bac1e2014-05-06 15:23:49 -0400607 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400608
609 c1 = (c1 - c2) * alpha;
610 c1 = c1 >> 7;
611 c1 = c1 + c2;
612 c1 = c1 + c1;
613
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400614 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400615 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400616 case FORMAT_X8R8G8B8:
617 case FORMAT_A8R8G8B8:
Nicolas Capens16b5f152016-10-13 13:39:01 -0400618 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400619 break;
620 case FORMAT_X8B8G8R8:
621 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400622 case FORMAT_SRGB8_X8:
623 case FORMAT_SRGB8_A8:
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400624 {
625 c1 = Swizzle(c1, 0xC6);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400626
Nicolas Capens16b5f152016-10-13 13:39:01 -0400627 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400628 }
629 break;
630 case FORMAT_R8G8B8:
631 {
632 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
John Bauman89401822014-05-06 15:04:28 -0400633
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400634 *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))));
John Bauman89401822014-05-06 15:04:28 -0400642
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400643 *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;
John Bauman89401822014-05-06 15:04:28 -0400651 }
John Bauman89401822014-05-06 15:04:28 -0400652 }
653
John Bauman66b8ab22014-05-06 15:57:45 -0400654 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400655 {
656 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
657
John Bauman89401822014-05-06 15:04:28 -0400658 while(!frameBuffer->terminate)
659 {
John Bauman66b8ab22014-05-06 15:57:45 -0400660 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400661
662 if(!frameBuffer->terminate)
663 {
664 frameBuffer->copyLocked();
665
John Bauman66b8ab22014-05-06 15:57:45 -0400666 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400667 }
668 }
John Bauman89401822014-05-06 15:04:28 -0400669 }
Nicolas Capens02704762014-11-24 15:50:51 -0500670}