blob: 2dc5cd660de31e5aabd233c33d4a754ea90bde78 [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
John Bauman89401822014-05-06 15:04:28 -040071 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
72 {
73 if(cursorImage)
74 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050075 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -040076 cursorImage->unlockExternal();
77
Nicolas Capensa29d6532016-12-05 21:38:09 -050078 cursor.width = cursorImage->getWidth();
79 cursor.height = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -040080 }
81 else
82 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050083 cursor.width = 0;
84 cursor.height = 0;
John Bauman89401822014-05-06 15:04:28 -040085 }
86 }
87
88 void FrameBuffer::setCursorOrigin(int x0, int y0)
89 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050090 cursor.hotspotX = x0;
91 cursor.hotspotY = y0;
John Bauman89401822014-05-06 15:04:28 -040092 }
93
94 void FrameBuffer::setCursorPosition(int x, int y)
95 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050096 cursor.positionX = x;
97 cursor.positionY = y;
John Bauman89401822014-05-06 15:04:28 -040098 }
99
Nicolas Capens241f7892015-12-30 23:40:45 -0500100 void FrameBuffer::copy(sw::Surface *source)
John Bauman89401822014-05-06 15:04:28 -0400101 {
102 if(!source)
103 {
104 return;
105 }
106
John Bauman89401822014-05-06 15:04:28 -0400107 if(!lock())
108 {
109 return;
110 }
111
Nicolas Capens241f7892015-12-30 23:40:45 -0500112 int sourceStride = source->getInternalPitchB();
113
Nicolas Capense5a96372017-08-11 15:14:25 -0400114 updateState = {};
115 updateState.width = width;
116 updateState.height = height;
117 updateState.destFormat = format;
Nicolas Capensd3206e62015-12-28 11:13:48 -0500118 updateState.destStride = stride;
Nicolas Capens241f7892015-12-30 23:40:45 -0500119 updateState.sourceFormat = source->getInternalFormat();
120 updateState.sourceStride = topLeftOrigin ? sourceStride : -sourceStride;
Nicolas Capense5a96372017-08-11 15:14:25 -0400121 updateState.cursorWidth = cursor.width;
122 updateState.cursorHeight = cursor.height;
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400123
Nicolas Capens241f7892015-12-30 23:40:45 -0500124 renderbuffer = source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
125
126 if(!topLeftOrigin)
John Bauman19bac1e2014-05-06 15:23:49 -0400127 {
Nicolas Capens241f7892015-12-30 23:40:45 -0500128 renderbuffer = (byte*)renderbuffer + (height - 1) * sourceStride;
John Bauman19bac1e2014-05-06 15:23:49 -0400129 }
130
Nicolas Capensa29d6532016-12-05 21:38:09 -0500131 cursor.x = cursor.positionX - cursor.hotspotX;
132 cursor.y = cursor.positionY - cursor.hotspotY;
John Bauman89401822014-05-06 15:04:28 -0400133
John Bauman19bac1e2014-05-06 15:23:49 -0400134 if(ASYNCHRONOUS_BLIT)
135 {
John Bauman66b8ab22014-05-06 15:57:45 -0400136 blitEvent.signal();
137 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400138 }
139 else
140 {
141 copyLocked();
142 }
Nicolas Capens02704762014-11-24 15:50:51 -0500143
Nicolas Capens241f7892015-12-30 23:40:45 -0500144 source->unlockInternal();
John Bauman89401822014-05-06 15:04:28 -0400145 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500146
147 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400148 }
149
150 void FrameBuffer::copyLocked()
151 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400152 if(memcmp(&blitState, &updateState, sizeof(BlitState)) != 0)
John Bauman89401822014-05-06 15:04:28 -0400153 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400154 blitState = updateState;
John Bauman89401822014-05-06 15:04:28 -0400155 blitRoutine = copyRoutine(blitState);
Nicolas Capensa29d6532016-12-05 21:38:09 -0500156 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400157 }
158
Nicolas Capense5a96372017-08-11 15:14:25 -0400159 blitFunction(framebuffer, renderbuffer, &cursor);
John Bauman89401822014-05-06 15:04:28 -0400160 }
161
Ben Clayton6897e9b2019-07-16 17:27:27 +0100162 std::shared_ptr<Routine> FrameBuffer::copyRoutine(const BlitState &state)
John Bauman89401822014-05-06 15:04:28 -0400163 {
John Bauman89401822014-05-06 15:04:28 -0400164 const int width = state.width;
165 const int height = state.height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400166 const int dBytes = Surface::bytes(state.destFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500167 const int dStride = state.destStride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400168 const int sBytes = Surface::bytes(state.sourceFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500169 const int sStride = state.sourceStride;
John Bauman89401822014-05-06 15:04:28 -0400170
Nicolas Capensa29d6532016-12-05 21:38:09 -0500171 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
John Bauman89401822014-05-06 15:04:28 -0400172 {
Nicolas Capens81f18302016-01-14 09:32:35 -0500173 Pointer<Byte> dst(function.Arg<0>());
174 Pointer<Byte> src(function.Arg<1>());
Nicolas Capensa29d6532016-12-05 21:38:09 -0500175 Pointer<Byte> cursor(function.Arg<2>());
John Bauman89401822014-05-06 15:04:28 -0400176
177 For(Int y = 0, y < height, y++)
178 {
179 Pointer<Byte> d = dst + y * dStride;
180 Pointer<Byte> s = src + y * sStride;
181
182 Int x0 = 0;
183
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400184 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400185 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400186 case FORMAT_X8R8G8B8:
187 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400188 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400189 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400190
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400191 switch(state.sourceFormat)
192 {
193 case FORMAT_X8R8G8B8:
194 case FORMAT_A8R8G8B8:
195 For(, x < width - 3, x += 4)
196 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500197 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400198
199 s += 4 * sBytes;
200 d += 4 * dBytes;
201 }
202 break;
203 case FORMAT_X8B8G8R8:
204 case FORMAT_A8B8G8R8:
205 For(, x < width - 3, x += 4)
206 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500207 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400208
209 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
210 ((bgra & Int4(0x000000FF)) << 16) |
211 (bgra & Int4(0xFF00FF00));
212
213 s += 4 * sBytes;
214 d += 4 * dBytes;
215 }
216 break;
217 case FORMAT_A16B16G16R16:
218 For(, x < width - 1, x += 2)
219 {
Ben Clayton8701dc42019-12-05 21:27:03 +0000220 Short4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0x2103)) >> 8;
221 Short4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0x2103)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400222
Nicolas Capens33438a62017-09-27 11:47:35 -0400223 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400224
225 s += 2 * sBytes;
226 d += 2 * dBytes;
227 }
228 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400229 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800230 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400231 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800232 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400233
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800234 *Pointer<Int4>(d) = (((rgb & Int4(0xF800)) << 8) | ((rgb & Int4(0xE01F)) << 3)) |
235 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) |
236 (((rgb & Int4(0x001C)) >> 2) | Int4(0xFF000000));
Nicolas Capense0308902015-05-25 23:47:18 -0400237
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800238 s += 4 * sBytes;
239 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400240 }
241 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400242 default:
243 ASSERT(false);
244 break;
245 }
246
247 For(, x < width, x++)
248 {
249 switch(state.sourceFormat)
250 {
251 case FORMAT_X8R8G8B8:
252 case FORMAT_A8R8G8B8:
253 *Pointer<Int>(d) = *Pointer<Int>(s);
254 break;
255 case FORMAT_X8B8G8R8:
256 case FORMAT_A8B8G8R8:
257 {
258 Int rgba = *Pointer<Int>(s);
259
260 *Pointer<Int>(d) = ((rgba & Int(0x00FF0000)) >> 16) |
261 ((rgba & Int(0x000000FF)) << 16) |
262 (rgba & Int(0xFF00FF00));
263 }
264 break;
265 case FORMAT_A16B16G16R16:
266 {
Ben Clayton8701dc42019-12-05 21:27:03 +0000267 Short4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0x2103)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400268
Nicolas Capens33438a62017-09-27 11:47:35 -0400269 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400270 }
271 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400272 case FORMAT_R5G6B5:
273 {
274 Int rgb = Int(*Pointer<Short>(s));
275
276 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400277 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400278 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400279 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400280 }
281 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400282 default:
283 ASSERT(false);
284 break;
285 }
286
287 s += sBytes;
288 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400289 }
290 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400291 break;
292 case FORMAT_X8B8G8R8:
293 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400294 case FORMAT_SRGB8_X8:
295 case FORMAT_SRGB8_A8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400296 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400297 Int x = x0;
298
299 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400300 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400301 case FORMAT_X8B8G8R8:
302 case FORMAT_A8B8G8R8:
303 For(, x < width - 3, x += 4)
304 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500305 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400306
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400307 s += 4 * sBytes;
308 d += 4 * dBytes;
309 }
310 break;
311 case FORMAT_X8R8G8B8:
312 case FORMAT_A8R8G8B8:
313 For(, x < width - 3, x += 4)
314 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500315 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400316
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400317 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
318 ((bgra & Int4(0x000000FF)) << 16) |
319 (bgra & Int4(0xFF00FF00));
320
321 s += 4 * sBytes;
322 d += 4 * dBytes;
323 }
324 break;
325 case FORMAT_A16B16G16R16:
326 For(, x < width - 1, x += 2)
327 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400328 Short4 c0 = *Pointer<UShort4>(s + 0) >> 8;
329 Short4 c1 = *Pointer<UShort4>(s + 8) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400330
Nicolas Capens33438a62017-09-27 11:47:35 -0400331 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400332
333 s += 2 * sBytes;
334 d += 2 * dBytes;
335 }
336 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400337 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800338 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400339 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800340 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400341
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800342 *Pointer<Int4>(d) = Int4(0xFF000000) |
343 (((rgb & Int4(0x001F)) << 19) | ((rgb & Int4(0x001C)) << 14)) |
344 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) |
345 (((rgb & Int4(0xF800)) >> 8) | ((rgb & Int4(0xE000)) >> 13));
Nicolas Capense0308902015-05-25 23:47:18 -0400346
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800347 s += 4 * sBytes;
348 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400349 }
350 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400351 default:
352 ASSERT(false);
353 break;
354 }
355
356 For(, x < width, x++)
357 {
358 switch(state.sourceFormat)
359 {
360 case FORMAT_X8B8G8R8:
361 case FORMAT_A8B8G8R8:
362 *Pointer<Int>(d) = *Pointer<Int>(s);
363 break;
364 case FORMAT_X8R8G8B8:
365 case FORMAT_A8R8G8B8:
366 {
367 Int bgra = *Pointer<Int>(s);
368 *Pointer<Int>(d) = ((bgra & Int(0x00FF0000)) >> 16) |
369 ((bgra & Int(0x000000FF)) << 16) |
370 (bgra & Int(0xFF00FF00));
371 }
372 break;
373 case FORMAT_A16B16G16R16:
374 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400375 Short4 c = *Pointer<UShort4>(s) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400376
Nicolas Capens33438a62017-09-27 11:47:35 -0400377 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400378 }
379 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400380 case FORMAT_R5G6B5:
381 {
382 Int rgb = Int(*Pointer<Short>(s));
383
384 *Pointer<Int>(d) = 0xFF000000 |
385 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
386 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
387 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
388 }
389 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400390 default:
391 ASSERT(false);
392 break;
393 }
394
395 s += sBytes;
396 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400397 }
398 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700399 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400400 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400401 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400402 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400403 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400404 switch(state.sourceFormat)
405 {
406 case FORMAT_X8R8G8B8:
407 case FORMAT_A8R8G8B8:
408 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0);
409 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
410 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2);
411 break;
412 case FORMAT_X8B8G8R8:
413 case FORMAT_A8B8G8R8:
414 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 2);
415 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
416 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 0);
417 break;
418 case FORMAT_A16B16G16R16:
419 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5);
420 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3);
421 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1);
422 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400423 case FORMAT_R5G6B5:
424 {
425 Int rgb = Int(*Pointer<Short>(s));
426
427 *Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2));
428 *Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1));
429 *Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3));
430 }
431 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400432 default:
433 ASSERT(false);
434 break;
435 }
John Bauman89401822014-05-06 15:04:28 -0400436
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400437 s += sBytes;
438 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400439 }
440 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400441 break;
442 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400443 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400444 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400445 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400446 switch(state.sourceFormat)
447 {
448 case FORMAT_X8R8G8B8:
449 case FORMAT_A8R8G8B8:
450 {
451 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400452
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400453 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
454 (c & 0x0000FC00) >> 5 |
455 (c & 0x000000F8) >> 3);
456 }
457 break;
458 case FORMAT_X8B8G8R8:
459 case FORMAT_A8B8G8R8:
460 {
461 Int c = *Pointer<Int>(s);
Nicolas Capens296e3122014-05-07 00:10:55 -0400462
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400463 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
464 (c & 0x0000FC00) >> 5 |
465 (c & 0x000000F8) << 8);
466 }
467 break;
468 case FORMAT_A16B16G16R16:
469 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400470 Short4 cc = *Pointer<UShort4>(s) >> 8;
471 Int c = Int(As<Int2>(PackUnsigned(cc, cc)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400472
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400473 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
474 (c & 0x0000FC00) >> 5 |
475 (c & 0x000000F8) << 8);
476 }
477 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400478 case FORMAT_R5G6B5:
479 *Pointer<Short>(d) = *Pointer<Short>(s);
480 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400481 default:
482 ASSERT(false);
483 break;
484 }
485
486 s += sBytes;
487 d += dBytes;
488 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400489 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400490 break;
491 default:
492 ASSERT(false);
493 break;
John Bauman89401822014-05-06 15:04:28 -0400494 }
John Bauman89401822014-05-06 15:04:28 -0400495 }
496
Nicolas Capens04f41252017-05-02 15:14:58 -0400497 if(state.cursorWidth > 0 && state.cursorHeight > 0)
John Bauman89401822014-05-06 15:04:28 -0400498 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400499 Int x0 = *Pointer<Int>(cursor + OFFSET(Cursor,x));
500 Int y0 = *Pointer<Int>(cursor + OFFSET(Cursor,y));
John Bauman89401822014-05-06 15:04:28 -0400501
Nicolas Capens04f41252017-05-02 15:14:58 -0400502 For(Int y1 = 0, y1 < state.cursorHeight, y1++)
John Bauman89401822014-05-06 15:04:28 -0400503 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400504 Int y = y0 + y1;
John Bauman89401822014-05-06 15:04:28 -0400505
Nicolas Capens04f41252017-05-02 15:14:58 -0400506 If(y >= 0 && y < height)
John Bauman89401822014-05-06 15:04:28 -0400507 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400508 Pointer<Byte> d = dst + y * dStride + x0 * dBytes;
509 Pointer<Byte> s = src + y * sStride + x0 * sBytes;
510 Pointer<Byte> c = *Pointer<Pointer<Byte>>(cursor + OFFSET(Cursor,image)) + y1 * state.cursorWidth * 4;
John Bauman89401822014-05-06 15:04:28 -0400511
Nicolas Capens04f41252017-05-02 15:14:58 -0400512 For(Int x1 = 0, x1 < state.cursorWidth, x1++)
John Bauman89401822014-05-06 15:04:28 -0400513 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400514 Int x = x0 + x1;
Nicolas Capens02704762014-11-24 15:50:51 -0500515
Nicolas Capens04f41252017-05-02 15:14:58 -0400516 If(x >= 0 && x < width)
517 {
518 blend(state, d, s, c);
519 }
520
521 c += 4;
522 s += sBytes;
523 d += dBytes;
524 }
John Bauman89401822014-05-06 15:04:28 -0400525 }
526 }
527 }
John Bauman89401822014-05-06 15:04:28 -0400528 }
529
Chris Forbes878d4b02019-01-21 10:48:35 -0800530 return function("FrameBuffer");
John Bauman89401822014-05-06 15:04:28 -0400531 }
532
533 void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c)
534 {
535 Short4 c1;
536 Short4 c2;
537
Nicolas Capens411273e2017-01-26 15:13:36 -0800538 c1 = Unpack(*Pointer<Byte4>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500539
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400540 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400541 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400542 case FORMAT_X8R8G8B8:
543 case FORMAT_A8R8G8B8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800544 c2 = Unpack(*Pointer<Byte4>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400545 break;
546 case FORMAT_X8B8G8R8:
547 case FORMAT_A8B8G8R8:
Ben Clayton8701dc42019-12-05 21:27:03 +0000548 c2 = Swizzle(Unpack(*Pointer<Byte4>(s)), 0x2103);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400549 break;
550 case FORMAT_A16B16G16R16:
Ben Clayton8701dc42019-12-05 21:27:03 +0000551 c2 = Swizzle(*Pointer<Short4>(s), 0x2103);
Nicolas Capense0308902015-05-25 23:47:18 -0400552 break;
553 case FORMAT_R5G6B5:
554 {
555 Int rgb(*Pointer<Short>(s));
556 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400557 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400558 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400559 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400560 c2 = Unpack(As<Byte4>(rgb));
561 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400562 break;
563 default:
564 ASSERT(false);
565 break;
John Bauman89401822014-05-06 15:04:28 -0400566 }
567
568 c1 = As<Short4>(As<UShort4>(c1) >> 9);
569 c2 = As<Short4>(As<UShort4>(c2) >> 9);
570
Ben Clayton8701dc42019-12-05 21:27:03 +0000571 Short4 alpha = Swizzle(c1, 0x3333) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400572
573 c1 = (c1 - c2) * alpha;
574 c1 = c1 >> 7;
575 c1 = c1 + c2;
576 c1 = c1 + c1;
577
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400578 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400579 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400580 case FORMAT_X8R8G8B8:
581 case FORMAT_A8R8G8B8:
Nicolas Capens33438a62017-09-27 11:47:35 -0400582 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400583 break;
584 case FORMAT_X8B8G8R8:
585 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400586 case FORMAT_SRGB8_X8:
587 case FORMAT_SRGB8_A8:
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400588 {
Ben Clayton8701dc42019-12-05 21:27:03 +0000589 c1 = Swizzle(c1, 0x2103);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400590
Nicolas Capens33438a62017-09-27 11:47:35 -0400591 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400592 }
593 break;
594 case FORMAT_R8G8B8:
595 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400596 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400597
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400598 *Pointer<Byte>(d + 0) = Byte(c >> 0);
599 *Pointer<Byte>(d + 1) = Byte(c >> 8);
600 *Pointer<Byte>(d + 2) = Byte(c >> 16);
601 }
602 break;
603 case FORMAT_R5G6B5:
604 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400605 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400606
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400607 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
608 (c & 0x0000FC00) >> 5 |
609 (c & 0x000000F8) >> 3);
610 }
611 break;
612 default:
613 ASSERT(false);
614 break;
John Bauman89401822014-05-06 15:04:28 -0400615 }
John Bauman89401822014-05-06 15:04:28 -0400616 }
617
John Bauman66b8ab22014-05-06 15:57:45 -0400618 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400619 {
620 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
621
John Bauman89401822014-05-06 15:04:28 -0400622 while(!frameBuffer->terminate)
623 {
John Bauman66b8ab22014-05-06 15:57:45 -0400624 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400625
626 if(!frameBuffer->terminate)
627 {
628 frameBuffer->copyLocked();
629
John Bauman66b8ab22014-05-06 15:57:45 -0400630 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400631 }
632 }
John Bauman89401822014-05-06 15:04:28 -0400633 }
Nicolas Capens02704762014-11-24 15:50:51 -0500634}