blob: db83ce4e08523bb329c3ed5762f568057ebdb920 [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"
18#include "CPUID.hpp"
John Bauman66b8ab22014-05-06 15:57:45 -040019#include "Renderer/Surface.hpp"
John Bauman19bac1e2014-05-06 15:23:49 -040020#include "Reactor/Reactor.hpp"
John Bauman66b8ab22014-05-06 15:57:45 -040021#include "Common/Debug.hpp"
John Bauman89401822014-05-06 15:04:28 -040022
23#include <stdio.h>
John Bauman66b8ab22014-05-06 15:57:45 -040024#include <string.h>
25#include <time.h>
John Bauman89401822014-05-06 15:04:28 -040026
Nicolas Capens135f6342015-11-11 10:49:08 -050027#ifdef __ANDROID__
28#include <cutils/properties.h>
29#endif
30
John Bauman19bac1e2014-05-06 15:23:49 -040031#define ASYNCHRONOUS_BLIT 0 // FIXME: Currently leads to rare race conditions
John Bauman89401822014-05-06 15:04:28 -040032
33namespace sw
34{
35 extern bool forceWindowed;
36
Nicolas Capensa29d6532016-12-05 21:38:09 -050037 FrameBuffer::Cursor FrameBuffer::cursor = {0};
John Bauman19bac1e2014-05-06 15:23:49 -040038 bool FrameBuffer::topLeftOrigin = false;
John Bauman89401822014-05-06 15:04:28 -040039
John Bauman66b8ab22014-05-06 15:57:45 -040040 FrameBuffer::FrameBuffer(int width, int height, bool fullscreen, bool topLeftOrigin)
John Bauman89401822014-05-06 15:04:28 -040041 {
John Bauman19bac1e2014-05-06 15:23:49 -040042 this->topLeftOrigin = topLeftOrigin;
43
Nicolas Capens518e41a2016-04-27 23:18:01 -040044 locked = nullptr;
John Bauman89401822014-05-06 15:04:28 -040045
John Bauman89401822014-05-06 15:04:28 -040046 this->width = width;
47 this->height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -040048 destFormat = FORMAT_X8R8G8B8;
49 sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040050 stride = 0;
51
52 if(forceWindowed)
53 {
54 fullscreen = false;
55 }
56
57 windowed = !fullscreen;
58
Nicolas Capens518e41a2016-04-27 23:18:01 -040059 blitFunction = nullptr;
60 blitRoutine = nullptr;
John Bauman89401822014-05-06 15:04:28 -040061
62 blitState.width = 0;
63 blitState.height = 0;
Nicolas Capens10219e72014-05-07 00:17:20 -040064 blitState.destFormat = FORMAT_X8R8G8B8;
65 blitState.sourceFormat = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040066 blitState.cursorWidth = 0;
67 blitState.cursorHeight = 0;
68
John Bauman19bac1e2014-05-06 15:23:49 -040069 if(ASYNCHRONOUS_BLIT)
70 {
John Bauman19bac1e2014-05-06 15:23:49 -040071 terminate = false;
John Bauman66b8ab22014-05-06 15:57:45 -040072 FrameBuffer *parameters = this;
73 blitThread = new Thread(threadFunction, &parameters);
John Bauman19bac1e2014-05-06 15:23:49 -040074 }
John Bauman89401822014-05-06 15:04:28 -040075 }
76
77 FrameBuffer::~FrameBuffer()
78 {
John Bauman19bac1e2014-05-06 15:23:49 -040079 if(ASYNCHRONOUS_BLIT)
80 {
81 terminate = true;
John Bauman66b8ab22014-05-06 15:57:45 -040082 blitEvent.signal();
83 blitThread->join();
84 delete blitThread;
John Bauman19bac1e2014-05-06 15:23:49 -040085 }
John Bauman89401822014-05-06 15:04:28 -040086
87 delete blitRoutine;
John Bauman89401822014-05-06 15:04:28 -040088 }
89
John Bauman89401822014-05-06 15:04:28 -040090 int FrameBuffer::getWidth() const
91 {
92 return width;
93 }
94
95 int FrameBuffer::getHeight() const
96 {
97 return height;
98 }
99
100 int FrameBuffer::getStride() const
101 {
102 return stride;
103 }
104
105 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
106 {
107 if(cursorImage)
108 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500109 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -0400110 cursorImage->unlockExternal();
111
Nicolas Capensa29d6532016-12-05 21:38:09 -0500112 cursor.width = cursorImage->getWidth();
113 cursor.height = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -0400114 }
115 else
116 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500117 cursor.width = 0;
118 cursor.height = 0;
John Bauman89401822014-05-06 15:04:28 -0400119 }
120 }
121
122 void FrameBuffer::setCursorOrigin(int x0, int y0)
123 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500124 cursor.hotspotX = x0;
125 cursor.hotspotY = y0;
John Bauman89401822014-05-06 15:04:28 -0400126 }
127
128 void FrameBuffer::setCursorPosition(int x, int y)
129 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500130 cursor.positionX = x;
131 cursor.positionY = y;
John Bauman89401822014-05-06 15:04:28 -0400132 }
133
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500134 void FrameBuffer::copy(void *source, Format format, size_t stride)
John Bauman89401822014-05-06 15:04:28 -0400135 {
136 if(!source)
137 {
138 return;
139 }
140
John Bauman89401822014-05-06 15:04:28 -0400141 if(!lock())
142 {
143 return;
144 }
145
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400146 sourceFormat = format;
147
John Bauman19bac1e2014-05-06 15:23:49 -0400148 if(topLeftOrigin)
149 {
150 target = source;
151 }
152 else
153 {
Nicolas Capens22bc79c2015-11-30 13:24:24 -0500154 target = (byte*)source + (height - 1) * stride;
John Bauman19bac1e2014-05-06 15:23:49 -0400155 }
156
Nicolas Capensa29d6532016-12-05 21:38:09 -0500157 cursor.x = cursor.positionX - cursor.hotspotX;
158 cursor.y = cursor.positionY - cursor.hotspotY;
John Bauman89401822014-05-06 15:04:28 -0400159
John Bauman19bac1e2014-05-06 15:23:49 -0400160 if(ASYNCHRONOUS_BLIT)
161 {
John Bauman66b8ab22014-05-06 15:57:45 -0400162 blitEvent.signal();
163 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400164 }
165 else
166 {
167 copyLocked();
168 }
Nicolas Capens02704762014-11-24 15:50:51 -0500169
John Bauman89401822014-05-06 15:04:28 -0400170 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500171
172 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400173 }
174
175 void FrameBuffer::copyLocked()
176 {
Nicolas Capensc4748c52016-01-01 01:21:18 -0500177 BlitState update = {};
John Bauman89401822014-05-06 15:04:28 -0400178 update.width = width;
179 update.height = height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400180 update.destFormat = destFormat;
181 update.sourceFormat = sourceFormat;
John Bauman89401822014-05-06 15:04:28 -0400182 update.stride = stride;
Nicolas Capensa29d6532016-12-05 21:38:09 -0500183 update.cursorWidth = cursor.width;
184 update.cursorHeight = cursor.height;
John Bauman89401822014-05-06 15:04:28 -0400185
186 if(memcmp(&blitState, &update, sizeof(BlitState)) != 0)
187 {
188 blitState = update;
189 delete blitRoutine;
190
191 blitRoutine = copyRoutine(blitState);
Nicolas Capensa29d6532016-12-05 21:38:09 -0500192 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400193 }
194
Nicolas Capensa29d6532016-12-05 21:38:09 -0500195 blitFunction(locked, target, &cursor);
John Bauman89401822014-05-06 15:04:28 -0400196 }
197
198 Routine *FrameBuffer::copyRoutine(const BlitState &state)
199 {
John Bauman89401822014-05-06 15:04:28 -0400200 const int width = state.width;
201 const int height = state.height;
202 const int width2 = (state.width + 1) & ~1;
Nicolas Capens10219e72014-05-07 00:17:20 -0400203 const int dBytes = Surface::bytes(state.destFormat);
John Bauman89401822014-05-06 15:04:28 -0400204 const int dStride = state.stride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400205 const int sBytes = Surface::bytes(state.sourceFormat);
John Bauman19bac1e2014-05-06 15:23:49 -0400206 const int sStride = topLeftOrigin ? (sBytes * width2) : -(sBytes * width2);
John Bauman89401822014-05-06 15:04:28 -0400207
Nicolas Capensa29d6532016-12-05 21:38:09 -0500208 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
John Bauman89401822014-05-06 15:04:28 -0400209 {
Nicolas Capens81f18302016-01-14 09:32:35 -0500210 Pointer<Byte> dst(function.Arg<0>());
211 Pointer<Byte> src(function.Arg<1>());
Nicolas Capensa29d6532016-12-05 21:38:09 -0500212 Pointer<Byte> cursor(function.Arg<2>());
John Bauman89401822014-05-06 15:04:28 -0400213
214 For(Int y = 0, y < height, y++)
215 {
216 Pointer<Byte> d = dst + y * dStride;
217 Pointer<Byte> s = src + y * sStride;
218
219 Int x0 = 0;
220
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400221 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400222 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400223 case FORMAT_X8R8G8B8:
224 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400225 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400226 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400227
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400228 switch(state.sourceFormat)
229 {
230 case FORMAT_X8R8G8B8:
231 case FORMAT_A8R8G8B8:
232 For(, x < width - 3, x += 4)
233 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500234 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400235
236 s += 4 * sBytes;
237 d += 4 * dBytes;
238 }
239 break;
240 case FORMAT_X8B8G8R8:
241 case FORMAT_A8B8G8R8:
242 For(, x < width - 3, x += 4)
243 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500244 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400245
246 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
247 ((bgra & Int4(0x000000FF)) << 16) |
248 (bgra & Int4(0xFF00FF00));
249
250 s += 4 * sBytes;
251 d += 4 * dBytes;
252 }
253 break;
254 case FORMAT_A16B16G16R16:
255 For(, x < width - 1, x += 2)
256 {
257 UShort4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
258 UShort4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
259
260 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
261
262 s += 2 * sBytes;
263 d += 2 * dBytes;
264 }
265 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400266 case FORMAT_R5G6B5:
267 For(, x < width, x++)
268 {
269 Int rgb = Int(*Pointer<Short>(s));
270
271 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400272 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400273 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400274 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400275
276 s += sBytes;
277 d += dBytes;
278 }
279 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400280 default:
281 ASSERT(false);
282 break;
283 }
284
285 For(, x < width, x++)
286 {
287 switch(state.sourceFormat)
288 {
289 case FORMAT_X8R8G8B8:
290 case FORMAT_A8R8G8B8:
291 *Pointer<Int>(d) = *Pointer<Int>(s);
292 break;
293 case FORMAT_X8B8G8R8:
294 case FORMAT_A8B8G8R8:
295 {
296 Int rgba = *Pointer<Int>(s);
297
298 *Pointer<Int>(d) = ((rgba & Int(0x00FF0000)) >> 16) |
299 ((rgba & Int(0x000000FF)) << 16) |
300 (rgba & Int(0xFF00FF00));
301 }
302 break;
303 case FORMAT_A16B16G16R16:
304 {
305 UShort4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
306
307 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
308 }
309 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400310 case FORMAT_R5G6B5:
311 {
312 Int rgb = Int(*Pointer<Short>(s));
313
314 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400315 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400316 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400317 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400318 }
319 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400320 default:
321 ASSERT(false);
322 break;
323 }
324
325 s += sBytes;
326 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400327 }
328 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400329 break;
330 case FORMAT_X8B8G8R8:
331 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400332 case FORMAT_SRGB8_X8:
333 case FORMAT_SRGB8_A8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400334 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400335 Int x = x0;
336
337 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400338 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400339 case FORMAT_X8B8G8R8:
340 case FORMAT_A8B8G8R8:
341 For(, x < width - 3, x += 4)
342 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500343 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400344
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400345 s += 4 * sBytes;
346 d += 4 * dBytes;
347 }
348 break;
349 case FORMAT_X8R8G8B8:
350 case FORMAT_A8R8G8B8:
351 For(, x < width - 3, x += 4)
352 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500353 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400354
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400355 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
356 ((bgra & Int4(0x000000FF)) << 16) |
357 (bgra & Int4(0xFF00FF00));
358
359 s += 4 * sBytes;
360 d += 4 * dBytes;
361 }
362 break;
363 case FORMAT_A16B16G16R16:
364 For(, x < width - 1, x += 2)
365 {
366 UShort4 c0 = *Pointer<UShort4>(s + 0) >> 8;
367 UShort4 c1 = *Pointer<UShort4>(s + 8) >> 8;
368
369 *Pointer<Int2>(d) = As<Int2>(Pack(c0, c1));
370
371 s += 2 * sBytes;
372 d += 2 * dBytes;
373 }
374 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400375 case FORMAT_R5G6B5:
376 For(, x < width, x++)
377 {
378 Int rgb = Int(*Pointer<Short>(s));
379
380 *Pointer<Int>(d) = 0xFF000000 |
381 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
382 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
383 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
384
385 s += sBytes;
386 d += dBytes;
387 }
388 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400389 default:
390 ASSERT(false);
391 break;
392 }
393
394 For(, x < width, x++)
395 {
396 switch(state.sourceFormat)
397 {
398 case FORMAT_X8B8G8R8:
399 case FORMAT_A8B8G8R8:
400 *Pointer<Int>(d) = *Pointer<Int>(s);
401 break;
402 case FORMAT_X8R8G8B8:
403 case FORMAT_A8R8G8B8:
404 {
405 Int bgra = *Pointer<Int>(s);
406 *Pointer<Int>(d) = ((bgra & Int(0x00FF0000)) >> 16) |
407 ((bgra & Int(0x000000FF)) << 16) |
408 (bgra & Int(0xFF00FF00));
409 }
410 break;
411 case FORMAT_A16B16G16R16:
412 {
413 UShort4 c = *Pointer<UShort4>(s) >> 8;
414
415 *Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
416 }
417 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400418 case FORMAT_R5G6B5:
419 {
420 Int rgb = Int(*Pointer<Short>(s));
421
422 *Pointer<Int>(d) = 0xFF000000 |
423 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
424 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
425 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
426 }
427 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400428 default:
429 ASSERT(false);
430 break;
431 }
432
433 s += sBytes;
434 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400435 }
436 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700437 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400438 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400439 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400440 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400441 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400442 switch(state.sourceFormat)
443 {
444 case FORMAT_X8R8G8B8:
445 case FORMAT_A8R8G8B8:
446 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0);
447 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
448 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2);
449 break;
450 case FORMAT_X8B8G8R8:
451 case FORMAT_A8B8G8R8:
452 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 2);
453 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
454 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 0);
455 break;
456 case FORMAT_A16B16G16R16:
457 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5);
458 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3);
459 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1);
460 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400461 case FORMAT_R5G6B5:
462 {
463 Int rgb = Int(*Pointer<Short>(s));
464
465 *Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2));
466 *Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1));
467 *Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3));
468 }
469 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400470 default:
471 ASSERT(false);
472 break;
473 }
John Bauman89401822014-05-06 15:04:28 -0400474
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400475 s += sBytes;
476 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400477 }
478 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400479 break;
480 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400481 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400482 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400483 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400484 switch(state.sourceFormat)
485 {
486 case FORMAT_X8R8G8B8:
487 case FORMAT_A8R8G8B8:
488 {
489 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400490
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400491 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
492 (c & 0x0000FC00) >> 5 |
493 (c & 0x000000F8) >> 3);
494 }
495 break;
496 case FORMAT_X8B8G8R8:
497 case FORMAT_A8B8G8R8:
498 {
499 Int c = *Pointer<Int>(s);
Nicolas Capens296e3122014-05-07 00:10:55 -0400500
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400501 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
502 (c & 0x0000FC00) >> 5 |
503 (c & 0x000000F8) << 8);
504 }
505 break;
506 case FORMAT_A16B16G16R16:
507 {
508 UShort4 cc = *Pointer<UShort4>(s) >> 8;
509 Int c = Int(As<Int2>(Pack(cc, cc)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400510
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400511 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
512 (c & 0x0000FC00) >> 5 |
513 (c & 0x000000F8) << 8);
514 }
515 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400516 case FORMAT_R5G6B5:
517 *Pointer<Short>(d) = *Pointer<Short>(s);
518 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400519 default:
520 ASSERT(false);
521 break;
522 }
523
524 s += sBytes;
525 d += dBytes;
526 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400527 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400528 break;
529 default:
530 ASSERT(false);
531 break;
John Bauman89401822014-05-06 15:04:28 -0400532 }
John Bauman89401822014-05-06 15:04:28 -0400533 }
534
Nicolas Capensa29d6532016-12-05 21:38:09 -0500535 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 Capensa29d6532016-12-05 21:38:09 -0500538 For(Int y1 = 0, y1 < state.cursorHeight, y1++)
John Bauman89401822014-05-06 15:04:28 -0400539 {
540 Int y = y0 + y1;
541
542 If(y >= 0 && y < height)
543 {
544 Pointer<Byte> d = dst + y * dStride + x0 * dBytes;
545 Pointer<Byte> s = src + y * sStride + x0 * sBytes;
Nicolas Capensa29d6532016-12-05 21:38:09 -0500546 Pointer<Byte> c = *Pointer<Pointer<Byte>>(cursor + OFFSET(Cursor,image)) + y1 * state.cursorWidth * 4;
John Bauman89401822014-05-06 15:04:28 -0400547
Nicolas Capensa29d6532016-12-05 21:38:09 -0500548 For(Int x1 = 0, x1 < state.cursorWidth, x1++)
John Bauman89401822014-05-06 15:04:28 -0400549 {
550 Int x = x0 + x1;
551
552 If(x >= 0 && x < width)
553 {
554 blend(state, d, s, c);
555 }
Nicolas Capens02704762014-11-24 15:50:51 -0500556
John Bauman89401822014-05-06 15:04:28 -0400557 c += 4;
558 s += sBytes;
559 d += dBytes;
560 }
561 }
562 }
John Bauman89401822014-05-06 15:04:28 -0400563 }
564
565 return function(L"FrameBuffer");
566 }
567
568 void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c)
569 {
570 Short4 c1;
571 Short4 c2;
572
573 c1 = UnpackLow(As<Byte8>(c1), *Pointer<Byte8>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500574
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400575 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400576 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400577 case FORMAT_X8R8G8B8:
578 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400579 c2 = UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400580 break;
581 case FORMAT_X8B8G8R8:
582 case FORMAT_A8B8G8R8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400583 c2 = Swizzle(UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s)), 0xC6);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400584 break;
585 case FORMAT_A16B16G16R16:
Nicolas Capense0308902015-05-25 23:47:18 -0400586 c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
587 break;
588 case FORMAT_R5G6B5:
589 {
590 Int rgb(*Pointer<Short>(s));
591 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400592 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400593 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400594 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400595 c2 = Unpack(As<Byte4>(rgb));
596 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400597 break;
598 default:
599 ASSERT(false);
600 break;
John Bauman89401822014-05-06 15:04:28 -0400601 }
602
603 c1 = As<Short4>(As<UShort4>(c1) >> 9);
604 c2 = As<Short4>(As<UShort4>(c2) >> 9);
605
John Bauman19bac1e2014-05-06 15:23:49 -0400606 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400607
608 c1 = (c1 - c2) * alpha;
609 c1 = c1 >> 7;
610 c1 = c1 + c2;
611 c1 = c1 + c1;
612
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400613 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400614 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400615 case FORMAT_X8R8G8B8:
616 case FORMAT_A8R8G8B8:
Nicolas Capens16b5f152016-10-13 13:39:01 -0400617 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400618 break;
619 case FORMAT_X8B8G8R8:
620 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400621 case FORMAT_SRGB8_X8:
622 case FORMAT_SRGB8_A8:
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400623 {
624 c1 = Swizzle(c1, 0xC6);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400625
Nicolas Capens16b5f152016-10-13 13:39:01 -0400626 *Pointer<Byte4>(d) = Byte4(Pack(As<UShort4>(c1), As<UShort4>(c1)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400627 }
628 break;
629 case FORMAT_R8G8B8:
630 {
631 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
John Bauman89401822014-05-06 15:04:28 -0400632
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400633 *Pointer<Byte>(d + 0) = Byte(c >> 0);
634 *Pointer<Byte>(d + 1) = Byte(c >> 8);
635 *Pointer<Byte>(d + 2) = Byte(c >> 16);
636 }
637 break;
638 case FORMAT_R5G6B5:
639 {
640 Int c = Int(As<Int2>(Pack(As<UShort4>(c1), As<UShort4>(c1))));
John Bauman89401822014-05-06 15:04:28 -0400641
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400642 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
643 (c & 0x0000FC00) >> 5 |
644 (c & 0x000000F8) >> 3);
645 }
646 break;
647 default:
648 ASSERT(false);
649 break;
John Bauman89401822014-05-06 15:04:28 -0400650 }
John Bauman89401822014-05-06 15:04:28 -0400651 }
652
John Bauman66b8ab22014-05-06 15:57:45 -0400653 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400654 {
655 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
656
John Bauman89401822014-05-06 15:04:28 -0400657 while(!frameBuffer->terminate)
658 {
John Bauman66b8ab22014-05-06 15:57:45 -0400659 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400660
661 if(!frameBuffer->terminate)
662 {
663 frameBuffer->copyLocked();
664
John Bauman66b8ab22014-05-06 15:57:45 -0400665 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400666 }
667 }
John Bauman89401822014-05-06 15:04:28 -0400668 }
Nicolas Capens02704762014-11-24 15:50:51 -0500669}