blob: 82dff461ce41927a2e0150da8a1346d71c28f0d5 [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 Capens135f6342015-11-11 10:49:08 -050026#ifdef __ANDROID__
27#include <cutils/properties.h>
28#endif
29
Nicolas Capense5a96372017-08-11 15:14:25 -040030#define ASYNCHRONOUS_BLIT false // 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 Capense5a96372017-08-11 15:14:25 -040043 framebuffer = 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 Capense5a96372017-08-11 15:14:25 -040047 format = FORMAT_X8R8G8B8;
John Bauman89401822014-05-06 15:04:28 -040048 stride = 0;
49
Nicolas Capense5a96372017-08-11 15:14:25 -040050 windowed = !fullscreen || forceWindowed;
John Bauman89401822014-05-06 15:04:28 -040051
Nicolas Capens518e41a2016-04-27 23:18:01 -040052 blitFunction = nullptr;
53 blitRoutine = nullptr;
Nicolas Capense5a96372017-08-11 15:14:25 -040054 blitState = {};
John Bauman89401822014-05-06 15:04:28 -040055
John Bauman19bac1e2014-05-06 15:23:49 -040056 if(ASYNCHRONOUS_BLIT)
57 {
John Bauman19bac1e2014-05-06 15:23:49 -040058 terminate = false;
John Bauman66b8ab22014-05-06 15:57:45 -040059 FrameBuffer *parameters = this;
60 blitThread = new Thread(threadFunction, &parameters);
John Bauman19bac1e2014-05-06 15:23:49 -040061 }
John Bauman89401822014-05-06 15:04:28 -040062 }
63
64 FrameBuffer::~FrameBuffer()
65 {
John Bauman19bac1e2014-05-06 15:23:49 -040066 if(ASYNCHRONOUS_BLIT)
67 {
68 terminate = true;
John Bauman66b8ab22014-05-06 15:57:45 -040069 blitEvent.signal();
70 blitThread->join();
71 delete blitThread;
John Bauman19bac1e2014-05-06 15:23:49 -040072 }
John Bauman89401822014-05-06 15:04:28 -040073
74 delete blitRoutine;
John Bauman89401822014-05-06 15:04:28 -040075 }
76
John Bauman89401822014-05-06 15:04:28 -040077 void FrameBuffer::setCursorImage(sw::Surface *cursorImage)
78 {
79 if(cursorImage)
80 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050081 cursor.image = cursorImage->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -040082 cursorImage->unlockExternal();
83
Nicolas Capensa29d6532016-12-05 21:38:09 -050084 cursor.width = cursorImage->getWidth();
85 cursor.height = cursorImage->getHeight();
John Bauman89401822014-05-06 15:04:28 -040086 }
87 else
88 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050089 cursor.width = 0;
90 cursor.height = 0;
John Bauman89401822014-05-06 15:04:28 -040091 }
92 }
93
94 void FrameBuffer::setCursorOrigin(int x0, int y0)
95 {
Nicolas Capensa29d6532016-12-05 21:38:09 -050096 cursor.hotspotX = x0;
97 cursor.hotspotY = y0;
John Bauman89401822014-05-06 15:04:28 -040098 }
99
100 void FrameBuffer::setCursorPosition(int x, int y)
101 {
Nicolas Capensa29d6532016-12-05 21:38:09 -0500102 cursor.positionX = x;
103 cursor.positionY = y;
John Bauman89401822014-05-06 15:04:28 -0400104 }
105
Nicolas Capens241f7892015-12-30 23:40:45 -0500106 void FrameBuffer::copy(sw::Surface *source)
John Bauman89401822014-05-06 15:04:28 -0400107 {
108 if(!source)
109 {
110 return;
111 }
112
John Bauman89401822014-05-06 15:04:28 -0400113 if(!lock())
114 {
115 return;
116 }
117
Nicolas Capens241f7892015-12-30 23:40:45 -0500118 int sourceStride = source->getInternalPitchB();
119
Nicolas Capense5a96372017-08-11 15:14:25 -0400120 updateState = {};
121 updateState.width = width;
122 updateState.height = height;
123 updateState.destFormat = format;
Nicolas Capensd3206e62015-12-28 11:13:48 -0500124 updateState.destStride = stride;
Nicolas Capens241f7892015-12-30 23:40:45 -0500125 updateState.sourceFormat = source->getInternalFormat();
126 updateState.sourceStride = topLeftOrigin ? sourceStride : -sourceStride;
Nicolas Capense5a96372017-08-11 15:14:25 -0400127 updateState.cursorWidth = cursor.width;
128 updateState.cursorHeight = cursor.height;
Nicolas Capens8aaf6712015-05-11 15:15:32 -0400129
Nicolas Capens241f7892015-12-30 23:40:45 -0500130 renderbuffer = source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
131
132 if(!topLeftOrigin)
John Bauman19bac1e2014-05-06 15:23:49 -0400133 {
Nicolas Capens241f7892015-12-30 23:40:45 -0500134 renderbuffer = (byte*)renderbuffer + (height - 1) * sourceStride;
John Bauman19bac1e2014-05-06 15:23:49 -0400135 }
136
Nicolas Capensa29d6532016-12-05 21:38:09 -0500137 cursor.x = cursor.positionX - cursor.hotspotX;
138 cursor.y = cursor.positionY - cursor.hotspotY;
John Bauman89401822014-05-06 15:04:28 -0400139
John Bauman19bac1e2014-05-06 15:23:49 -0400140 if(ASYNCHRONOUS_BLIT)
141 {
John Bauman66b8ab22014-05-06 15:57:45 -0400142 blitEvent.signal();
143 syncEvent.wait();
John Bauman19bac1e2014-05-06 15:23:49 -0400144 }
145 else
146 {
147 copyLocked();
148 }
Nicolas Capens02704762014-11-24 15:50:51 -0500149
Nicolas Capens241f7892015-12-30 23:40:45 -0500150 source->unlockInternal();
John Bauman89401822014-05-06 15:04:28 -0400151 unlock();
Nicolas Capens6ef6d2a2015-02-23 14:23:11 -0500152
153 profiler.nextFrame(); // Assumes every copy() is a full frame
John Bauman89401822014-05-06 15:04:28 -0400154 }
155
156 void FrameBuffer::copyLocked()
157 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400158 if(memcmp(&blitState, &updateState, sizeof(BlitState)) != 0)
John Bauman89401822014-05-06 15:04:28 -0400159 {
Nicolas Capense5a96372017-08-11 15:14:25 -0400160 blitState = updateState;
John Bauman89401822014-05-06 15:04:28 -0400161 delete blitRoutine;
162
163 blitRoutine = copyRoutine(blitState);
Nicolas Capensa29d6532016-12-05 21:38:09 -0500164 blitFunction = (void(*)(void*, void*, Cursor*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400165 }
166
Nicolas Capense5a96372017-08-11 15:14:25 -0400167 blitFunction(framebuffer, renderbuffer, &cursor);
John Bauman89401822014-05-06 15:04:28 -0400168 }
169
170 Routine *FrameBuffer::copyRoutine(const BlitState &state)
171 {
John Bauman89401822014-05-06 15:04:28 -0400172 const int width = state.width;
173 const int height = state.height;
Nicolas Capens10219e72014-05-07 00:17:20 -0400174 const int dBytes = Surface::bytes(state.destFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500175 const int dStride = state.destStride;
Nicolas Capens10219e72014-05-07 00:17:20 -0400176 const int sBytes = Surface::bytes(state.sourceFormat);
Nicolas Capensd3206e62015-12-28 11:13:48 -0500177 const int sStride = state.sourceStride;
John Bauman89401822014-05-06 15:04:28 -0400178
Nicolas Capensa29d6532016-12-05 21:38:09 -0500179 Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
John Bauman89401822014-05-06 15:04:28 -0400180 {
Nicolas Capens81f18302016-01-14 09:32:35 -0500181 Pointer<Byte> dst(function.Arg<0>());
182 Pointer<Byte> src(function.Arg<1>());
Nicolas Capensa29d6532016-12-05 21:38:09 -0500183 Pointer<Byte> cursor(function.Arg<2>());
John Bauman89401822014-05-06 15:04:28 -0400184
185 For(Int y = 0, y < height, y++)
186 {
187 Pointer<Byte> d = dst + y * dStride;
188 Pointer<Byte> s = src + y * sStride;
189
190 Int x0 = 0;
191
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400192 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400193 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400194 case FORMAT_X8R8G8B8:
195 case FORMAT_A8R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400196 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400197 Int x = x0;
John Bauman89401822014-05-06 15:04:28 -0400198
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400199 switch(state.sourceFormat)
200 {
201 case FORMAT_X8R8G8B8:
202 case FORMAT_A8R8G8B8:
203 For(, x < width - 3, x += 4)
204 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500205 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400206
207 s += 4 * sBytes;
208 d += 4 * dBytes;
209 }
210 break;
211 case FORMAT_X8B8G8R8:
212 case FORMAT_A8B8G8R8:
213 For(, x < width - 3, x += 4)
214 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500215 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400216
217 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
218 ((bgra & Int4(0x000000FF)) << 16) |
219 (bgra & Int4(0xFF00FF00));
220
221 s += 4 * sBytes;
222 d += 4 * dBytes;
223 }
224 break;
225 case FORMAT_A16B16G16R16:
226 For(, x < width - 1, x += 2)
227 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400228 Short4 c0 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 0), 0xC6)) >> 8;
229 Short4 c1 = As<UShort4>(Swizzle(*Pointer<Short4>(s + 8), 0xC6)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400230
Nicolas Capens33438a62017-09-27 11:47:35 -0400231 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400232
233 s += 2 * sBytes;
234 d += 2 * dBytes;
235 }
236 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400237 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800238 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400239 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800240 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400241
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800242 *Pointer<Int4>(d) = (((rgb & Int4(0xF800)) << 8) | ((rgb & Int4(0xE01F)) << 3)) |
243 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) |
244 (((rgb & Int4(0x001C)) >> 2) | Int4(0xFF000000));
Nicolas Capense0308902015-05-25 23:47:18 -0400245
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800246 s += 4 * sBytes;
247 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400248 }
249 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400250 default:
251 ASSERT(false);
252 break;
253 }
254
255 For(, x < width, x++)
256 {
257 switch(state.sourceFormat)
258 {
259 case FORMAT_X8R8G8B8:
260 case FORMAT_A8R8G8B8:
261 *Pointer<Int>(d) = *Pointer<Int>(s);
262 break;
263 case FORMAT_X8B8G8R8:
264 case FORMAT_A8B8G8R8:
265 {
266 Int rgba = *Pointer<Int>(s);
267
268 *Pointer<Int>(d) = ((rgba & Int(0x00FF0000)) >> 16) |
269 ((rgba & Int(0x000000FF)) << 16) |
270 (rgba & Int(0xFF00FF00));
271 }
272 break;
273 case FORMAT_A16B16G16R16:
274 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400275 Short4 c = As<UShort4>(Swizzle(*Pointer<Short4>(s), 0xC6)) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400276
Nicolas Capens33438a62017-09-27 11:47:35 -0400277 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400278 }
279 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400280 case FORMAT_R5G6B5:
281 {
282 Int rgb = Int(*Pointer<Short>(s));
283
284 *Pointer<Int>(d) = 0xFF000000 |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400285 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400286 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capenscf0cdf62015-05-26 11:20:46 -0400287 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400288 }
289 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400290 default:
291 ASSERT(false);
292 break;
293 }
294
295 s += sBytes;
296 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400297 }
298 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400299 break;
300 case FORMAT_X8B8G8R8:
301 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400302 case FORMAT_SRGB8_X8:
303 case FORMAT_SRGB8_A8:
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400304 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400305 Int x = x0;
306
307 switch(state.sourceFormat)
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400308 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400309 case FORMAT_X8B8G8R8:
310 case FORMAT_A8B8G8R8:
311 For(, x < width - 3, x += 4)
312 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500313 *Pointer<Int4>(d, 1) = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400314
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400315 s += 4 * sBytes;
316 d += 4 * dBytes;
317 }
318 break;
319 case FORMAT_X8R8G8B8:
320 case FORMAT_A8R8G8B8:
321 For(, x < width - 3, x += 4)
322 {
Nicolas Capensc0fb8a02016-01-06 13:44:09 -0500323 Int4 bgra = *Pointer<Int4>(s, sStride % 16 ? 1 : 16);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400324
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400325 *Pointer<Int4>(d, 1) = ((bgra & Int4(0x00FF0000)) >> 16) |
326 ((bgra & Int4(0x000000FF)) << 16) |
327 (bgra & Int4(0xFF00FF00));
328
329 s += 4 * sBytes;
330 d += 4 * dBytes;
331 }
332 break;
333 case FORMAT_A16B16G16R16:
334 For(, x < width - 1, x += 2)
335 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400336 Short4 c0 = *Pointer<UShort4>(s + 0) >> 8;
337 Short4 c1 = *Pointer<UShort4>(s + 8) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400338
Nicolas Capens33438a62017-09-27 11:47:35 -0400339 *Pointer<Int2>(d) = As<Int2>(PackUnsigned(c0, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400340
341 s += 2 * sBytes;
342 d += 2 * dBytes;
343 }
344 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400345 case FORMAT_R5G6B5:
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800346 For(, x < width - 3, x += 4)
Nicolas Capense0308902015-05-25 23:47:18 -0400347 {
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800348 Int4 rgb = Int4(*Pointer<Short4>(s));
Nicolas Capense0308902015-05-25 23:47:18 -0400349
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800350 *Pointer<Int4>(d) = Int4(0xFF000000) |
351 (((rgb & Int4(0x001F)) << 19) | ((rgb & Int4(0x001C)) << 14)) |
352 (((rgb & Int4(0x07E0)) << 5) | ((rgb & Int4(0x0600)) >> 1)) |
353 (((rgb & Int4(0xF800)) >> 8) | ((rgb & Int4(0xE000)) >> 13));
Nicolas Capense0308902015-05-25 23:47:18 -0400354
Nicolas Capensf549e3b2017-01-24 08:53:47 -0800355 s += 4 * sBytes;
356 d += 4 * dBytes;
Nicolas Capense0308902015-05-25 23:47:18 -0400357 }
358 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400359 default:
360 ASSERT(false);
361 break;
362 }
363
364 For(, x < width, x++)
365 {
366 switch(state.sourceFormat)
367 {
368 case FORMAT_X8B8G8R8:
369 case FORMAT_A8B8G8R8:
370 *Pointer<Int>(d) = *Pointer<Int>(s);
371 break;
372 case FORMAT_X8R8G8B8:
373 case FORMAT_A8R8G8B8:
374 {
375 Int bgra = *Pointer<Int>(s);
376 *Pointer<Int>(d) = ((bgra & Int(0x00FF0000)) >> 16) |
377 ((bgra & Int(0x000000FF)) << 16) |
378 (bgra & Int(0xFF00FF00));
379 }
380 break;
381 case FORMAT_A16B16G16R16:
382 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400383 Short4 c = *Pointer<UShort4>(s) >> 8;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400384
Nicolas Capens33438a62017-09-27 11:47:35 -0400385 *Pointer<Int>(d) = Int(As<Int2>(PackUnsigned(c, c)));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400386 }
387 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400388 case FORMAT_R5G6B5:
389 {
390 Int rgb = Int(*Pointer<Short>(s));
391
392 *Pointer<Int>(d) = 0xFF000000 |
393 ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
394 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
395 ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
396 }
397 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400398 default:
399 ASSERT(false);
400 break;
401 }
402
403 s += sBytes;
404 d += dBytes;
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400405 }
406 }
Ping-Hao Wue04f28a2015-05-26 16:16:00 -0700407 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400408 case FORMAT_R8G8B8:
John Bauman89401822014-05-06 15:04:28 -0400409 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400410 For(Int x = x0, x < width, x++)
John Bauman89401822014-05-06 15:04:28 -0400411 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400412 switch(state.sourceFormat)
413 {
414 case FORMAT_X8R8G8B8:
415 case FORMAT_A8R8G8B8:
416 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 0);
417 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
418 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 2);
419 break;
420 case FORMAT_X8B8G8R8:
421 case FORMAT_A8B8G8R8:
422 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 2);
423 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 1);
424 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 0);
425 break;
426 case FORMAT_A16B16G16R16:
427 *Pointer<Byte>(d + 0) = *Pointer<Byte>(s + 5);
428 *Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3);
429 *Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1);
430 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400431 case FORMAT_R5G6B5:
432 {
433 Int rgb = Int(*Pointer<Short>(s));
434
435 *Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2));
436 *Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1));
437 *Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3));
438 }
439 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400440 default:
441 ASSERT(false);
442 break;
443 }
John Bauman89401822014-05-06 15:04:28 -0400444
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400445 s += sBytes;
446 d += dBytes;
John Bauman89401822014-05-06 15:04:28 -0400447 }
448 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400449 break;
450 case FORMAT_R5G6B5:
Nicolas Capens296e3122014-05-07 00:10:55 -0400451 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400452 For(Int x = x0, x < width, x++)
Nicolas Capens296e3122014-05-07 00:10:55 -0400453 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400454 switch(state.sourceFormat)
455 {
456 case FORMAT_X8R8G8B8:
457 case FORMAT_A8R8G8B8:
458 {
459 Int c = *Pointer<Int>(s);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400460
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400461 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
462 (c & 0x0000FC00) >> 5 |
463 (c & 0x000000F8) >> 3);
464 }
465 break;
466 case FORMAT_X8B8G8R8:
467 case FORMAT_A8B8G8R8:
468 {
469 Int c = *Pointer<Int>(s);
Nicolas Capens296e3122014-05-07 00:10:55 -0400470
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400471 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
472 (c & 0x0000FC00) >> 5 |
473 (c & 0x000000F8) << 8);
474 }
475 break;
476 case FORMAT_A16B16G16R16:
477 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400478 Short4 cc = *Pointer<UShort4>(s) >> 8;
479 Int c = Int(As<Int2>(PackUnsigned(cc, cc)));
Nicolas Capens296e3122014-05-07 00:10:55 -0400480
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400481 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 19 |
482 (c & 0x0000FC00) >> 5 |
483 (c & 0x000000F8) << 8);
484 }
485 break;
Nicolas Capense0308902015-05-25 23:47:18 -0400486 case FORMAT_R5G6B5:
487 *Pointer<Short>(d) = *Pointer<Short>(s);
488 break;
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400489 default:
490 ASSERT(false);
491 break;
492 }
493
494 s += sBytes;
495 d += dBytes;
496 }
Nicolas Capens296e3122014-05-07 00:10:55 -0400497 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400498 break;
499 default:
500 ASSERT(false);
501 break;
John Bauman89401822014-05-06 15:04:28 -0400502 }
John Bauman89401822014-05-06 15:04:28 -0400503 }
504
Nicolas Capens04f41252017-05-02 15:14:58 -0400505 if(state.cursorWidth > 0 && state.cursorHeight > 0)
John Bauman89401822014-05-06 15:04:28 -0400506 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400507 Int x0 = *Pointer<Int>(cursor + OFFSET(Cursor,x));
508 Int y0 = *Pointer<Int>(cursor + OFFSET(Cursor,y));
John Bauman89401822014-05-06 15:04:28 -0400509
Nicolas Capens04f41252017-05-02 15:14:58 -0400510 For(Int y1 = 0, y1 < state.cursorHeight, y1++)
John Bauman89401822014-05-06 15:04:28 -0400511 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400512 Int y = y0 + y1;
John Bauman89401822014-05-06 15:04:28 -0400513
Nicolas Capens04f41252017-05-02 15:14:58 -0400514 If(y >= 0 && y < height)
John Bauman89401822014-05-06 15:04:28 -0400515 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400516 Pointer<Byte> d = dst + y * dStride + x0 * dBytes;
517 Pointer<Byte> s = src + y * sStride + x0 * sBytes;
518 Pointer<Byte> c = *Pointer<Pointer<Byte>>(cursor + OFFSET(Cursor,image)) + y1 * state.cursorWidth * 4;
John Bauman89401822014-05-06 15:04:28 -0400519
Nicolas Capens04f41252017-05-02 15:14:58 -0400520 For(Int x1 = 0, x1 < state.cursorWidth, x1++)
John Bauman89401822014-05-06 15:04:28 -0400521 {
Nicolas Capens04f41252017-05-02 15:14:58 -0400522 Int x = x0 + x1;
Nicolas Capens02704762014-11-24 15:50:51 -0500523
Nicolas Capens04f41252017-05-02 15:14:58 -0400524 If(x >= 0 && x < width)
525 {
526 blend(state, d, s, c);
527 }
528
529 c += 4;
530 s += sBytes;
531 d += dBytes;
532 }
John Bauman89401822014-05-06 15:04:28 -0400533 }
534 }
535 }
John Bauman89401822014-05-06 15:04:28 -0400536 }
537
538 return function(L"FrameBuffer");
539 }
540
541 void FrameBuffer::blend(const BlitState &state, const Pointer<Byte> &d, const Pointer<Byte> &s, const Pointer<Byte> &c)
542 {
543 Short4 c1;
544 Short4 c2;
545
Nicolas Capens411273e2017-01-26 15:13:36 -0800546 c1 = Unpack(*Pointer<Byte4>(c));
Nicolas Capens02704762014-11-24 15:50:51 -0500547
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400548 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400549 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400550 case FORMAT_X8R8G8B8:
551 case FORMAT_A8R8G8B8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800552 c2 = Unpack(*Pointer<Byte4>(s));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400553 break;
554 case FORMAT_X8B8G8R8:
555 case FORMAT_A8B8G8R8:
Nicolas Capens411273e2017-01-26 15:13:36 -0800556 c2 = Swizzle(Unpack(*Pointer<Byte4>(s)), 0xC6);
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400557 break;
558 case FORMAT_A16B16G16R16:
Nicolas Capense0308902015-05-25 23:47:18 -0400559 c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
560 break;
561 case FORMAT_R5G6B5:
562 {
563 Int rgb(*Pointer<Short>(s));
564 rgb = 0xFF000000 |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400565 ((rgb & 0xF800) << 8) | ((rgb & 0xE01F) << 3) |
Nicolas Capense0308902015-05-25 23:47:18 -0400566 ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
Nicolas Capens3e3f5362015-05-26 16:36:35 -0400567 ((rgb & 0x001C) >> 2);
Nicolas Capense0308902015-05-25 23:47:18 -0400568 c2 = Unpack(As<Byte4>(rgb));
569 }
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400570 break;
571 default:
572 ASSERT(false);
573 break;
John Bauman89401822014-05-06 15:04:28 -0400574 }
575
576 c1 = As<Short4>(As<UShort4>(c1) >> 9);
577 c2 = As<Short4>(As<UShort4>(c2) >> 9);
578
John Bauman19bac1e2014-05-06 15:23:49 -0400579 Short4 alpha = Swizzle(c1, 0xFF) & Short4(0xFFFFu, 0xFFFFu, 0xFFFFu, 0x0000);
John Bauman89401822014-05-06 15:04:28 -0400580
581 c1 = (c1 - c2) * alpha;
582 c1 = c1 >> 7;
583 c1 = c1 + c2;
584 c1 = c1 + c1;
585
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400586 switch(state.destFormat)
John Bauman89401822014-05-06 15:04:28 -0400587 {
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400588 case FORMAT_X8R8G8B8:
589 case FORMAT_A8R8G8B8:
Nicolas Capens33438a62017-09-27 11:47:35 -0400590 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400591 break;
592 case FORMAT_X8B8G8R8:
593 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400594 case FORMAT_SRGB8_X8:
595 case FORMAT_SRGB8_A8:
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400596 {
597 c1 = Swizzle(c1, 0xC6);
Nicolas Capens4e0d6f62015-03-27 21:47:49 -0400598
Nicolas Capens33438a62017-09-27 11:47:35 -0400599 *Pointer<Byte4>(d) = Byte4(PackUnsigned(c1, c1));
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400600 }
601 break;
602 case FORMAT_R8G8B8:
603 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400604 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400605
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400606 *Pointer<Byte>(d + 0) = Byte(c >> 0);
607 *Pointer<Byte>(d + 1) = Byte(c >> 8);
608 *Pointer<Byte>(d + 2) = Byte(c >> 16);
609 }
610 break;
611 case FORMAT_R5G6B5:
612 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400613 Int c = Int(As<Int2>(PackUnsigned(c1, c1)));
John Bauman89401822014-05-06 15:04:28 -0400614
Alexis Hetu3b6c9cf2015-05-07 11:41:43 -0400615 *Pointer<Short>(d) = Short((c & 0x00F80000) >> 8 |
616 (c & 0x0000FC00) >> 5 |
617 (c & 0x000000F8) >> 3);
618 }
619 break;
620 default:
621 ASSERT(false);
622 break;
John Bauman89401822014-05-06 15:04:28 -0400623 }
John Bauman89401822014-05-06 15:04:28 -0400624 }
625
John Bauman66b8ab22014-05-06 15:57:45 -0400626 void FrameBuffer::threadFunction(void *parameters)
John Bauman89401822014-05-06 15:04:28 -0400627 {
628 FrameBuffer *frameBuffer = *static_cast<FrameBuffer**>(parameters);
629
John Bauman89401822014-05-06 15:04:28 -0400630 while(!frameBuffer->terminate)
631 {
John Bauman66b8ab22014-05-06 15:57:45 -0400632 frameBuffer->blitEvent.wait();
John Bauman89401822014-05-06 15:04:28 -0400633
634 if(!frameBuffer->terminate)
635 {
636 frameBuffer->copyLocked();
637
John Bauman66b8ab22014-05-06 15:57:45 -0400638 frameBuffer->syncEvent.signal();
John Bauman89401822014-05-06 15:04:28 -0400639 }
640 }
John Bauman89401822014-05-06 15:04:28 -0400641 }
Nicolas Capens02704762014-11-24 15:50:51 -0500642}