blob: 7d2e6a02ab21b401523888a586978fda1063eec8 [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
John Bauman66b8ab22014-05-06 15:57:45 -040017#include "Renderer/Surface.hpp"
John Bauman19bac1e2014-05-06 15:23:49 -040018#include "Reactor/Reactor.hpp"
Nicolas Capens708c24b2017-10-26 13:07:10 -040019#include "Common/Timer.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 Capense5a96372017-08-11 15:14:25 -040026#define ASYNCHRONOUS_BLIT false // FIXME: Currently leads to rare race conditions
John Bauman89401822014-05-06 15:04:28 -040027
28namespace sw
29{
30 extern bool forceWindowed;
31
Nicolas Capens04f41252017-05-02 15:14:58 -040032 FrameBuffer::Cursor FrameBuffer::cursor = {};
John Bauman19bac1e2014-05-06 15:23:49 -040033 bool FrameBuffer::topLeftOrigin = false;
John Bauman89401822014-05-06 15:04:28 -040034
John Bauman66b8ab22014-05-06 15:57:45 -040035 FrameBuffer::FrameBuffer(int width, int height, bool fullscreen, bool topLeftOrigin)
John Bauman89401822014-05-06 15:04:28 -040036 {
John Bauman19bac1e2014-05-06 15:23:49 -040037 this->topLeftOrigin = topLeftOrigin;
38
Nicolas Capense5a96372017-08-11 15:14:25 -040039 framebuffer = nullptr;
John Bauman89401822014-05-06 15:04:28 -040040
John Bauman89401822014-05-06 15:04:28 -040041 this->width = width;
42 this->height = height;
Nicolas Capense5a96372017-08-11 15:14:25 -040043 format = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040044 stride = 0;
45
Nicolas Capense5a96372017-08-11 15:14:25 -040046 windowed = !fullscreen || forceWindowed;
John Bauman89401822014-05-06 15:04:28 -040047
Nicolas Capens518e41a2016-04-27 23:18:01 -040048 blitFunction = nullptr;
49 blitRoutine = nullptr;
Nicolas Capense5a96372017-08-11 15:14:25 -040050 blitState = {};
John Bauman89401822014-05-06 15:04:28 -040051
John Bauman19bac1e2014-05-06 15:23:49 -040052 if(ASYNCHRONOUS_BLIT)
53 {
John Bauman19bac1e2014-05-06 15:23:49 -040054 terminate = false;
John Bauman66b8ab22014-05-06 15:57:45 -040055 FrameBuffer *parameters = this;
56 blitThread = new Thread(threadFunction, &parameters);
John Bauman19bac1e2014-05-06 15:23:49 -040057 }
John Bauman89401822014-05-06 15:04:28 -040058 }
59
60 FrameBuffer::~FrameBuffer()
61 {
John Bauman19bac1e2014-05-06 15:23:49 -040062 if(ASYNCHRONOUS_BLIT)
63 {
64 terminate = true;
John Bauman66b8ab22014-05-06 15:57:45 -040065 blitEvent.signal();
66 blitThread->join();
67 delete blitThread;
John Bauman19bac1e2014-05-06 15:23:49 -040068 }
John Bauman89401822014-05-06 15:04:28 -040069
70 delete blitRoutine;
John Bauman89401822014-05-06 15:04:28 -040071 }
72
John Bauman89401822014-05-06 15:04:28 -040073 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
74 {
75 if(cursorImage)
76 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050077 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -040078 cursorImage->unlockExternal();
79
Nicolas Capensa29d6532016-12-05 21:38:09 -050080 cursor.width = cursorImage->getWidth();
81 cursor.height = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -040082 }
83 else
84 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050085 cursor.width = 0;
86 cursor.height = 0;
John Bauman89401822014-05-06 15:04:28 -040087 }
88 }
89
90 void FrameBuffer::setCursorOrigin(int x0, int y0)
91 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050092 cursor.hotspotX = x0;
93 cursor.hotspotY = y0;
John Bauman89401822014-05-06 15:04:28 -040094 }
95
96 void FrameBuffer::setCursorPosition(int x, int y)
97 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050098 cursor.positionX = x;
99 cursor.positionY = y;
John Bauman89401822014-05-06 15:04:28 -0400100 }
101
Nicolas Capens241f7892015-12-30 23:40:45 -0500102 void FrameBuffer::copy(sw::Surface *source)
John Bauman89401822014-05-06 15:04:28 -0400103 {
104 if(!source)
105 {
106 return;
107 }
108
John Bauman89401822014-05-06 15:04:28 -0400109 if(!lock())
110 {
111 return;
112 }
113
Nicolas Capens241f7892015-12-30 23:40:45 -0500114 int sourceStride = source->getInternalPitchB();
115
Nicolas Capense5a96372017-08-11 15:14:25 -0400116 updateState = {};
117 updateState.width = width;
118 updateState.height = height;
119 updateState.destFormat = format;
Nicolas Capensd3206e62015-12-28 11:13:48 -0500120 updateState.destStride = stride;
Nicolas Capens241f7892015-12-30 23:40:45 -0500121 updateState.sourceFormat = source->getInternalFormat();
122 updateState.sourceStride = topLeftOrigin ? sourceStride : -sourceStride;
Nicolas Capense5a96372017-08-11 15:14:25 -0400123 updateState.cursorWidth = cursor.width;
124 updateState.cursorHeight = cursor.height;
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400125
Nicolas Capens241f7892015-12-30 23:40:45 -0500126 renderbuffer = source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
127
128 if(!topLeftOrigin)
John Bauman19bac1e2014-05-06 15:23:49 -0400129 {
Nicolas Capens241f7892015-12-30 23:40:45 -0500130 renderbuffer = (byte*)renderbuffer + (height - 1) * sourceStride;
John Bauman19bac1e2014-05-06 15:23:49 -0400131 }
132
Nicolas Capensa29d6532016-12-05 21:38:09 -0500133 cursor.x = cursor.positionX - cursor.hotspotX;
134 cursor.y = cursor.positionY - cursor.hotspotY;
John Bauman89401822014-05-06 15:04:28 -0400135
John Bauman19bac1e2014-05-06 15:23:49 -0400136 if(ASYNCHRONOUS_BLIT)
137 {
John Bauman66b8ab22014-05-06 15:57:45 -0400138 blitEvent.signal();
139 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400140 }
141 else
142 {
143 copyLocked();
144 }
Nicolas Capens02704762014-11-24 15:50:51 -0500145
Nicolas Capens241f7892015-12-30 23:40:45 -0500146 source->unlockInternal();
John Bauman89401822014-05-06 15:04:28 -0400147 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500148
149 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400150 }
151
152 void FrameBuffer::copyLocked()
153 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400154 if(memcmp(&blitState, &updateState, sizeof(BlitState)) != 0)
John Bauman89401822014-05-06 15:04:28 -0400155 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400156 blitState = updateState;
John Bauman89401822014-05-06 15:04:28 -0400157 delete blitRoutine;
158
159 blitRoutine = copyRoutine(blitState);
Nicolas Capensa29d6532016-12-05 21:38:09 -0500160 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400161 }
162
Nicolas Capense5a96372017-08-11 15:14:25 -0400163 blitFunction(framebuffer, renderbuffer, &cursor);
John Bauman89401822014-05-06 15:04:28 -0400164 }
165
166 Routine *FrameBuffer::copyRoutine(const BlitState &state)
167 {
John Bauman89401822014-05-06 15:04:28 -0400168 const int width = state.width;
169 const int height = state.height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400170 const int dBytes = Surface::bytes(state.destFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500171 const int dStride = state.destStride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400172 const int sBytes = Surface::bytes(state.sourceFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500173 const int sStride = state.sourceStride;
John Bauman89401822014-05-06 15:04:28 -0400174
Nicolas Capensa29d6532016-12-05 21:38:09 -0500175 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
John Bauman89401822014-05-06 15:04:28 -0400176 {
Nicolas Capens81f18302016-01-14 09:32:35 -0500177 Pointer<Byte> dst(function.Arg<0>());
178 Pointer<Byte> src(function.Arg<1>());
Nicolas Capensa29d6532016-12-05 21:38:09 -0500179 Pointer<Byte> cursor(function.Arg<2>());
John Bauman89401822014-05-06 15:04:28 -0400180
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
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400188 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400189 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400190 case FORMAT_X8R8G8B8:
191 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400192 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400193 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400194
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400195 switch(state.sourceFormat)
196 {
197 case FORMAT_X8R8G8B8:
198 case FORMAT_A8R8G8B8:
199 For(, x < width - 3, x += 4)
200 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500201 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400202
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 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500211 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400212
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 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400224 Short4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
225 Short4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400226
Nicolas Capens33438a62017-09-27 11:47:35 -0400227 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400228
229 s += 2 * sBytes;
230 d += 2 * dBytes;
231 }
232 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400233 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800234 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400235 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800236 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400237
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800238 *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));
Nicolas Capense0308902015-05-25 23:47:18 -0400241
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800242 s += 4 * sBytes;
243 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400244 }
245 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400246 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 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400271 Short4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400272
Nicolas Capens33438a62017-09-27 11:47:35 -0400273 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400274 }
275 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400276 case FORMAT_R5G6B5:
277 {
278 Int rgb = Int(*Pointer<Short>(s));
279
280 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400281 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400282 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400283 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400284 }
285 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400286 default:
287 ASSERT(false);
288 break;
289 }
290
291 s += sBytes;
292 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400293 }
294 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400295 break;
296 case FORMAT_X8B8G8R8:
297 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400298 case FORMAT_SRGB8_X8:
299 case FORMAT_SRGB8_A8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400300 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400301 Int x = x0;
302
303 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400304 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400305 case FORMAT_X8B8G8R8:
306 case FORMAT_A8B8G8R8:
307 For(, x < width - 3, x += 4)
308 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500309 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400310
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400311 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 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500319 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400320
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400321 *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 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400332 Short4 c0 = *Pointer<UShort4>(s + 0) >> 8;
333 Short4 c1 = *Pointer<UShort4>(s + 8) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400334
Nicolas Capens33438a62017-09-27 11:47:35 -0400335 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400336
337 s += 2 * sBytes;
338 d += 2 * dBytes;
339 }
340 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400341 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800342 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400343 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800344 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400345
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800346 *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));
Nicolas Capense0308902015-05-25 23:47:18 -0400350
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800351 s += 4 * sBytes;
352 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400353 }
354 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400355 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 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400379 Short4 c = *Pointer<UShort4>(s) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400380
Nicolas Capens33438a62017-09-27 11:47:35 -0400381 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400382 }
383 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400384 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;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400394 default:
395 ASSERT(false);
396 break;
397 }
398
399 s += sBytes;
400 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400401 }
402 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700403 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400404 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400405 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400406 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400407 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400408 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;
Nicolas Capense0308902015-05-25 23:47:18 -0400427 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;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400436 default:
437 ASSERT(false);
438 break;
439 }
John Bauman89401822014-05-06 15:04:28 -0400440
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400441 s += sBytes;
442 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400443 }
444 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400445 break;
446 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400447 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400448 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400449 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400450 switch(state.sourceFormat)
451 {
452 case FORMAT_X8R8G8B8:
453 case FORMAT_A8R8G8B8:
454 {
455 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400456
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400457 *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);
Nicolas Capens296e3122014-05-07 00:10:55 -0400466
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400467 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
468 (c & 0x0000FC00) >> 5 |
469 (c & 0x000000F8) << 8);
470 }
471 break;
472 case FORMAT_A16B16G16R16:
473 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400474 Short4 cc = *Pointer<UShort4>(s) >> 8;
475 Int c = Int(As<Int2>(PackUnsigned(cc, cc)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400476
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400477 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
478 (c & 0x0000FC00) >> 5 |
479 (c & 0x000000F8) << 8);
480 }
481 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400482 case FORMAT_R5G6B5:
483 *Pointer<Short>(d) = *Pointer<Short>(s);
484 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400485 default:
486 ASSERT(false);
487 break;
488 }
489
490 s += sBytes;
491 d += dBytes;
492 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400493 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400494 break;
495 default:
496 ASSERT(false);
497 break;
John Bauman89401822014-05-06 15:04:28 -0400498 }
John Bauman89401822014-05-06 15:04:28 -0400499 }
500
Nicolas Capens04f41252017-05-02 15:14:58 -0400501 if(state.cursorWidth > 0 && state.cursorHeight > 0)
John Bauman89401822014-05-06 15:04:28 -0400502 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400503 Int x0 = *Pointer<Int>(cursor + OFFSET(Cursor,x));
504 Int y0 = *Pointer<Int>(cursor + OFFSET(Cursor,y));
John Bauman89401822014-05-06 15:04:28 -0400505
Nicolas Capens04f41252017-05-02 15:14:58 -0400506 For(Int y1 = 0, y1 < state.cursorHeight, y1++)
John Bauman89401822014-05-06 15:04:28 -0400507 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400508 Int y = y0 + y1;
John Bauman89401822014-05-06 15:04:28 -0400509
Nicolas Capens04f41252017-05-02 15:14:58 -0400510 If(y >= 0 && y < height)
John Bauman89401822014-05-06 15:04:28 -0400511 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400512 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;
John Bauman89401822014-05-06 15:04:28 -0400515
Nicolas Capens04f41252017-05-02 15:14:58 -0400516 For(Int x1 = 0, x1 < state.cursorWidth, x1++)
John Bauman89401822014-05-06 15:04:28 -0400517 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400518 Int x = x0 + x1;
Nicolas Capens02704762014-11-24 15:50:51 -0500519
Nicolas Capens04f41252017-05-02 15:14:58 -0400520 If(x >= 0 && x < width)
521 {
522 blend(state, d, s, c);
523 }
524
525 c += 4;
526 s += sBytes;
527 d += dBytes;
528 }
John Bauman89401822014-05-06 15:04:28 -0400529 }
530 }
531 }
John Bauman89401822014-05-06 15:04:28 -0400532 }
533
Chris Forbes878d4b02019-01-21 10:48:35 -0800534 return function("FrameBuffer");
John Bauman89401822014-05-06 15:04:28 -0400535 }
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
Nicolas Capens411273e2017-01-26 15:13:36 -0800542 c1 = Unpack(*Pointer<Byte4>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500543
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400544 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400545 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400546 case FORMAT_X8R8G8B8:
547 case FORMAT_A8R8G8B8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800548 c2 = Unpack(*Pointer<Byte4>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400549 break;
550 case FORMAT_X8B8G8R8:
551 case FORMAT_A8B8G8R8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800552 c2 = Swizzle(Unpack(*Pointer<Byte4>(s)), 0xC6);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400553 break;
554 case FORMAT_A16B16G16R16:
Nicolas Capense0308902015-05-25 23:47:18 -0400555 c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
556 break;
557 case FORMAT_R5G6B5:
558 {
559 Int rgb(*Pointer<Short>(s));
560 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400561 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400562 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400563 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400564 c2 = Unpack(As<Byte4>(rgb));
565 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400566 break;
567 default:
568 ASSERT(false);
569 break;
John Bauman89401822014-05-06 15:04:28 -0400570 }
571
572 c1 = As<Short4>(As<UShort4>(c1) >> 9);
573 c2 = As<Short4>(As<UShort4>(c2) >> 9);
574
John Bauman19bac1e2014-05-06 15:23:49 -0400575 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400576
577 c1 = (c1 - c2) * alpha;
578 c1 = c1 >> 7;
579 c1 = c1 + c2;
580 c1 = c1 + c1;
581
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400582 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400583 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400584 case FORMAT_X8R8G8B8:
585 case FORMAT_A8R8G8B8:
Nicolas Capens33438a62017-09-27 11:47:35 -0400586 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400587 break;
588 case FORMAT_X8B8G8R8:
589 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400590 case FORMAT_SRGB8_X8:
591 case FORMAT_SRGB8_A8:
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400592 {
593 c1 = Swizzle(c1, 0xC6);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400594
Nicolas Capens33438a62017-09-27 11:47:35 -0400595 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400596 }
597 break;
598 case FORMAT_R8G8B8:
599 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400600 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400601
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400602 *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 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400609 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400610
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400611 *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;
John Bauman89401822014-05-06 15:04:28 -0400619 }
John Bauman89401822014-05-06 15:04:28 -0400620 }
621
John Bauman66b8ab22014-05-06 15:57:45 -0400622 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400623 {
624 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
625
John Bauman89401822014-05-06 15:04:28 -0400626 while(!frameBuffer->terminate)
627 {
John Bauman66b8ab22014-05-06 15:57:45 -0400628 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400629
630 if(!frameBuffer->terminate)
631 {
632 frameBuffer->copyLocked();
633
John Bauman66b8ab22014-05-06 15:57:45 -0400634 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400635 }
636 }
John Bauman89401822014-05-06 15:04:28 -0400637 }
Nicolas Capens02704762014-11-24 15:50:51 -0500638}