blob: d4edbfab5d5f72a9a5e802d03dc4ebdc94071126 [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 "Blitter.hpp"
16
Nicolas Capens1ab837c2017-12-16 02:28:02 -050017#include "Shader/ShaderCore.hpp"
John Bauman19bac1e2014-05-06 15:23:49 -040018#include "Reactor/Reactor.hpp"
Nicolas Capens802d1422017-02-14 17:23:54 -050019#include "Common/Memory.hpp"
20#include "Common/Debug.hpp"
John Bauman89401822014-05-06 15:04:28 -040021
22namespace sw
23{
Nicolas Capens48461502018-08-06 14:20:45 -040024 using namespace rr;
25
John Bauman89401822014-05-06 15:04:28 -040026 Blitter::Blitter()
27 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -050028 blitCache = new RoutineCache<State>(1024);
John Bauman89401822014-05-06 15:04:28 -040029 }
30
31 Blitter::~Blitter()
32 {
33 delete blitCache;
34 }
35
Nicolas Capensbfa23b32017-12-11 10:06:37 -050036 void Blitter::clear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
John Bauman89401822014-05-06 15:04:28 -040037 {
Nicolas Capens802d1422017-02-14 17:23:54 -050038 if(fastClear(pixel, format, dest, dRect, rgbaMask))
39 {
40 return;
41 }
42
Nicolas Capensf41f0332017-05-30 15:25:50 -040043 sw::Surface *color = sw::Surface::create(1, 1, 1, format, pixel, sw::Surface::bytes(format), sw::Surface::bytes(format));
Nicolas Capens700a1a62018-06-15 11:41:28 -040044 SliceRectF sRect(0.5f, 0.5f, 0.5f, 0.5f, 0); // Sample from the middle.
Nicolas Capens8f7739a2017-12-16 02:06:56 -050045 blit(color, sRect, dest, dRect, {rgbaMask});
Nicolas Capensf41f0332017-05-30 15:25:50 -040046 delete color;
Alexis Hetu75b650f2015-11-19 17:40:15 -050047 }
48
Nicolas Capensbfa23b32017-12-11 10:06:37 -050049 bool Blitter::fastClear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
Nicolas Capens802d1422017-02-14 17:23:54 -050050 {
51 if(format != FORMAT_A32B32G32R32F)
52 {
53 return false;
54 }
55
56 float *color = (float*)pixel;
57 float r = color[0];
58 float g = color[1];
59 float b = color[2];
60 float a = color[3];
61
62 uint32_t packed;
63
64 switch(dest->getFormat())
65 {
66 case FORMAT_R5G6B5:
67 if((rgbaMask & 0x7) != 0x7) return false;
68 packed = ((uint16_t)(31 * b + 0.5f) << 0) |
69 ((uint16_t)(63 * g + 0.5f) << 5) |
70 ((uint16_t)(31 * r + 0.5f) << 11);
71 break;
72 case FORMAT_X8B8G8R8:
73 if((rgbaMask & 0x7) != 0x7) return false;
74 packed = ((uint32_t)(255) << 24) |
75 ((uint32_t)(255 * b + 0.5f) << 16) |
76 ((uint32_t)(255 * g + 0.5f) << 8) |
77 ((uint32_t)(255 * r + 0.5f) << 0);
78 break;
79 case FORMAT_A8B8G8R8:
80 if((rgbaMask & 0xF) != 0xF) return false;
81 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
82 ((uint32_t)(255 * b + 0.5f) << 16) |
83 ((uint32_t)(255 * g + 0.5f) << 8) |
84 ((uint32_t)(255 * r + 0.5f) << 0);
85 break;
86 case FORMAT_X8R8G8B8:
87 if((rgbaMask & 0x7) != 0x7) return false;
88 packed = ((uint32_t)(255) << 24) |
89 ((uint32_t)(255 * r + 0.5f) << 16) |
90 ((uint32_t)(255 * g + 0.5f) << 8) |
91 ((uint32_t)(255 * b + 0.5f) << 0);
92 break;
93 case FORMAT_A8R8G8B8:
94 if((rgbaMask & 0xF) != 0xF) return false;
95 packed = ((uint32_t)(255 * a + 0.5f) << 24) |
96 ((uint32_t)(255 * r + 0.5f) << 16) |
97 ((uint32_t)(255 * g + 0.5f) << 8) |
98 ((uint32_t)(255 * b + 0.5f) << 0);
99 break;
100 default:
101 return false;
102 }
103
Alexis Hetu7622b962018-03-25 21:02:17 -0400104 bool useDestInternal = !dest->isExternalDirty();
105 uint8_t *slice = (uint8_t*)dest->lock(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC, useDestInternal);
Nicolas Capens802d1422017-02-14 17:23:54 -0500106
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500107 for(int j = 0; j < dest->getSamples(); j++)
Nicolas Capens802d1422017-02-14 17:23:54 -0500108 {
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500109 uint8_t *d = slice;
110
111 switch(Surface::bytes(dest->getFormat()))
Nicolas Capens802d1422017-02-14 17:23:54 -0500112 {
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500113 case 2:
114 for(int i = dRect.y0; i < dRect.y1; i++)
115 {
116 sw::clear((uint16_t*)d, packed, dRect.x1 - dRect.x0);
Alexis Hetu7622b962018-03-25 21:02:17 -0400117 d += dest->getPitchB(useDestInternal);
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500118 }
119 break;
120 case 4:
121 for(int i = dRect.y0; i < dRect.y1; i++)
122 {
123 sw::clear((uint32_t*)d, packed, dRect.x1 - dRect.x0);
Alexis Hetu7622b962018-03-25 21:02:17 -0400124 d += dest->getPitchB(useDestInternal);
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500125 }
126 break;
127 default:
128 assert(false);
Nicolas Capens802d1422017-02-14 17:23:54 -0500129 }
Nicolas Capensbfa23b32017-12-11 10:06:37 -0500130
Alexis Hetu7622b962018-03-25 21:02:17 -0400131 slice += dest->getSliceB(useDestInternal);
Nicolas Capens802d1422017-02-14 17:23:54 -0500132 }
133
Alexis Hetu7622b962018-03-25 21:02:17 -0400134 dest->unlock(useDestInternal);
Nicolas Capens802d1422017-02-14 17:23:54 -0500135
136 return true;
137 }
138
Alexis Hetu10c74a62017-11-29 14:00:32 -0500139 void Blitter::blit(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options& options)
Alexis Hetu75b650f2015-11-19 17:40:15 -0500140 {
Nicolas Capens808074c2016-03-24 11:51:05 -0400141 if(dest->getInternalFormat() == FORMAT_NULL)
142 {
143 return;
144 }
145
Nicolas Capens6a990f82018-07-06 15:54:07 -0400146 if(blitReactor(source, sourceRect, dest, destRect, options))
147 {
148 return;
149 }
John Bauman89401822014-05-06 15:04:28 -0400150
Alexis Hetu10c74a62017-11-29 14:00:32 -0500151 SliceRectF sRect = sourceRect;
Alexis Hetue9233fb2015-02-11 10:31:58 -0500152 SliceRect dRect = destRect;
153
154 bool flipX = destRect.x0 > destRect.x1;
155 bool flipY = destRect.y0 > destRect.y1;
156
Nicolas Capens10b295c2015-03-28 18:57:56 -0400157 if(flipX)
158 {
159 swap(dRect.x0, dRect.x1);
160 swap(sRect.x0, sRect.x1);
161 }
162 if(flipY)
163 {
164 swap(dRect.y0, dRect.y1);
165 swap(sRect.y0, sRect.y1);
Alexis Hetue9233fb2015-02-11 10:31:58 -0500166 }
167
Nicolas Capensae3d8752018-06-01 10:39:50 -0400168 source->lockInternal(0, 0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
169 dest->lockInternal(0, 0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
John Bauman89401822014-05-06 15:04:28 -0400170
Alexis Hetu10c74a62017-11-29 14:00:32 -0500171 float w = sRect.width() / dRect.width();
172 float h = sRect.height() / dRect.height();
John Bauman89401822014-05-06 15:04:28 -0400173
Nicolas Capensae3d8752018-06-01 10:39:50 -0400174 float xStart = sRect.x0 + (0.5f - dRect.x0) * w;
175 float yStart = sRect.y0 + (0.5f - dRect.y0) * h;
John Bauman89401822014-05-06 15:04:28 -0400176
John Bauman19bac1e2014-05-06 15:23:49 -0400177 for(int j = dRect.y0; j < dRect.y1; j++)
John Bauman89401822014-05-06 15:04:28 -0400178 {
Nicolas Capensae3d8752018-06-01 10:39:50 -0400179 float y = yStart + j * h;
John Bauman89401822014-05-06 15:04:28 -0400180
John Bauman19bac1e2014-05-06 15:23:49 -0400181 for(int i = dRect.x0; i < dRect.x1; i++)
John Bauman89401822014-05-06 15:04:28 -0400182 {
Nicolas Capensae3d8752018-06-01 10:39:50 -0400183 float x = xStart + i * w;
184
Alexis Hetu75b650f2015-11-19 17:40:15 -0500185 // FIXME: Support RGBA mask
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500186 dest->copyInternal(source, i, j, x, y, options.filter);
John Bauman89401822014-05-06 15:04:28 -0400187 }
John Bauman89401822014-05-06 15:04:28 -0400188 }
189
190 source->unlockInternal();
191 dest->unlockInternal();
192 }
193
Alexis Hetuf68510d2015-02-24 14:33:49 -0500194 void Blitter::blit3D(Surface *source, Surface *dest)
195 {
196 source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
197 dest->lockInternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC);
198
Nicolas Capens3779ea92015-06-10 13:43:52 -0400199 float w = static_cast<float>(source->getWidth()) / static_cast<float>(dest->getWidth());
200 float h = static_cast<float>(source->getHeight()) / static_cast<float>(dest->getHeight());
201 float d = static_cast<float>(source->getDepth()) / static_cast<float>(dest->getDepth());
Alexis Hetuf68510d2015-02-24 14:33:49 -0500202
Nicolas Capens8af24c52017-12-11 14:45:01 -0500203 for(int k = 0; k < dest->getDepth(); k++)
Alexis Hetuf68510d2015-02-24 14:33:49 -0500204 {
Nicolas Capensae3d8752018-06-01 10:39:50 -0400205 float z = (k + 0.5f) * d;
206
Nicolas Capens8af24c52017-12-11 14:45:01 -0500207 for(int j = 0; j < dest->getHeight(); j++)
Alexis Hetuf68510d2015-02-24 14:33:49 -0500208 {
Nicolas Capensae3d8752018-06-01 10:39:50 -0400209 float y = (j + 0.5f) * h;
210
Nicolas Capens8af24c52017-12-11 14:45:01 -0500211 for(int i = 0; i < dest->getWidth(); i++)
Alexis Hetuf68510d2015-02-24 14:33:49 -0500212 {
Nicolas Capensae3d8752018-06-01 10:39:50 -0400213 float x = (i + 0.5f) * w;
214
Alexis Hetu43577b82015-10-21 15:32:16 -0400215 dest->copyInternal(source, i, j, k, x, y, z, true);
Alexis Hetuf68510d2015-02-24 14:33:49 -0500216 }
Alexis Hetuf68510d2015-02-24 14:33:49 -0500217 }
Alexis Hetuf68510d2015-02-24 14:33:49 -0500218 }
219
220 source->unlockInternal();
221 dest->unlockInternal();
222 }
223
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500224 bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
John Bauman89401822014-05-06 15:04:28 -0400225 {
Alexis Hetu75b650f2015-11-19 17:40:15 -0500226 c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
John Bauman89401822014-05-06 15:04:28 -0400227
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500228 switch(state.sourceFormat)
John Bauman89401822014-05-06 15:04:28 -0400229 {
230 case FORMAT_L8:
231 c.xyz = Float(Int(*Pointer<Byte>(element)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500232 c.w = float(0xFF);
John Bauman89401822014-05-06 15:04:28 -0400233 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400234 case FORMAT_A8:
John Bauman66b8ab22014-05-06 15:57:45 -0400235 c.w = Float(Int(*Pointer<Byte>(element)));
236 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400237 case FORMAT_R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500238 case FORMAT_R8_SNORM:
Alexis Hetu43577b82015-10-21 15:32:16 -0400239 c.x = Float(Int(*Pointer<SByte>(element)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500240 c.w = float(0x7F);
Alexis Hetu43577b82015-10-21 15:32:16 -0400241 break;
242 case FORMAT_R8:
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500243 case FORMAT_R8UI:
Alexis Hetu43577b82015-10-21 15:32:16 -0400244 c.x = Float(Int(*Pointer<Byte>(element)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500245 c.w = float(0xFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400246 break;
247 case FORMAT_R16I:
Alexis Hetu43577b82015-10-21 15:32:16 -0400248 c.x = Float(Int(*Pointer<Short>(element)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500249 c.w = float(0x7FFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400250 break;
251 case FORMAT_R16UI:
Alexis Hetu43577b82015-10-21 15:32:16 -0400252 c.x = Float(Int(*Pointer<UShort>(element)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500253 c.w = float(0xFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400254 break;
255 case FORMAT_R32I:
Alexis Hetucfd96322017-07-24 14:44:33 -0400256 c.x = Float(*Pointer<Int>(element));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500257 c.w = float(0x7FFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400258 break;
259 case FORMAT_R32UI:
Alexis Hetucfd96322017-07-24 14:44:33 -0400260 c.x = Float(*Pointer<UInt>(element));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500261 c.w = float(0xFFFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400262 break;
John Bauman89401822014-05-06 15:04:28 -0400263 case FORMAT_A8R8G8B8:
264 c = Float4(*Pointer<Byte4>(element)).zyxw;
265 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400266 case FORMAT_A8B8G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500267 case FORMAT_A8B8G8R8_SNORM:
Alexis Hetu43577b82015-10-21 15:32:16 -0400268 c = Float4(*Pointer<SByte4>(element));
269 break;
Nicolas Capens10b295c2015-03-28 18:57:56 -0400270 case FORMAT_A8B8G8R8:
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500271 case FORMAT_A8B8G8R8UI:
Alexis Hetu049a1872016-04-25 16:59:58 -0400272 case FORMAT_SRGB8_A8:
Nicolas Capens10b295c2015-03-28 18:57:56 -0400273 c = Float4(*Pointer<Byte4>(element));
274 break;
John Bauman89401822014-05-06 15:04:28 -0400275 case FORMAT_X8R8G8B8:
276 c = Float4(*Pointer<Byte4>(element)).zyxw;
Alexis Hetu75b650f2015-11-19 17:40:15 -0500277 c.w = float(0xFF);
John Bauman89401822014-05-06 15:04:28 -0400278 break;
Alexis Hetu925c2822015-11-24 14:09:34 -0500279 case FORMAT_R8G8B8:
280 c.z = Float(Int(*Pointer<Byte>(element + 0)));
281 c.y = Float(Int(*Pointer<Byte>(element + 1)));
282 c.x = Float(Int(*Pointer<Byte>(element + 2)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500283 c.w = float(0xFF);
Alexis Hetu925c2822015-11-24 14:09:34 -0500284 break;
285 case FORMAT_B8G8R8:
286 c.x = Float(Int(*Pointer<Byte>(element + 0)));
287 c.y = Float(Int(*Pointer<Byte>(element + 1)));
288 c.z = Float(Int(*Pointer<Byte>(element + 2)));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500289 c.w = float(0xFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400290 break;
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500291 case FORMAT_X8B8G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500292 case FORMAT_X8B8G8R8_SNORM:
Alexis Hetu43577b82015-10-21 15:32:16 -0400293 c = Float4(*Pointer<SByte4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500294 c.w = float(0x7F);
Alexis Hetu43577b82015-10-21 15:32:16 -0400295 break;
Nicolas Capens10b295c2015-03-28 18:57:56 -0400296 case FORMAT_X8B8G8R8:
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500297 case FORMAT_X8B8G8R8UI:
Alexis Hetu049a1872016-04-25 16:59:58 -0400298 case FORMAT_SRGB8_X8:
Nicolas Capens10b295c2015-03-28 18:57:56 -0400299 c = Float4(*Pointer<Byte4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500300 c.w = float(0xFF);
Nicolas Capens10b295c2015-03-28 18:57:56 -0400301 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400302 case FORMAT_A16B16G16R16I:
303 c = Float4(*Pointer<Short4>(element));
304 break;
John Bauman89401822014-05-06 15:04:28 -0400305 case FORMAT_A16B16G16R16:
Alexis Hetu43577b82015-10-21 15:32:16 -0400306 case FORMAT_A16B16G16R16UI:
John Bauman89401822014-05-06 15:04:28 -0400307 c = Float4(*Pointer<UShort4>(element));
308 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400309 case FORMAT_X16B16G16R16I:
310 c = Float4(*Pointer<Short4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500311 c.w = float(0x7FFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400312 break;
313 case FORMAT_X16B16G16R16UI:
314 c = Float4(*Pointer<UShort4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500315 c.w = float(0xFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400316 break;
317 case FORMAT_A32B32G32R32I:
318 c = Float4(*Pointer<Int4>(element));
319 break;
320 case FORMAT_A32B32G32R32UI:
321 c = Float4(*Pointer<UInt4>(element));
322 break;
323 case FORMAT_X32B32G32R32I:
324 c = Float4(*Pointer<Int4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500325 c.w = float(0x7FFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400326 break;
327 case FORMAT_X32B32G32R32UI:
328 c = Float4(*Pointer<UInt4>(element));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500329 c.w = float(0xFFFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400330 break;
331 case FORMAT_G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500332 case FORMAT_G8R8_SNORM:
Alexis Hetu43577b82015-10-21 15:32:16 -0400333 c.x = Float(Int(*Pointer<SByte>(element + 0)));
334 c.y = Float(Int(*Pointer<SByte>(element + 1)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500335 c.w = float(0x7F);
Alexis Hetu43577b82015-10-21 15:32:16 -0400336 break;
337 case FORMAT_G8R8:
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500338 case FORMAT_G8R8UI:
Alexis Hetu43577b82015-10-21 15:32:16 -0400339 c.x = Float(Int(*Pointer<Byte>(element + 0)));
340 c.y = Float(Int(*Pointer<Byte>(element + 1)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500341 c.w = float(0xFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400342 break;
343 case FORMAT_G16R16I:
344 c.x = Float(Int(*Pointer<Short>(element + 0)));
345 c.y = Float(Int(*Pointer<Short>(element + 2)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500346 c.w = float(0x7FFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400347 break;
John Bauman89401822014-05-06 15:04:28 -0400348 case FORMAT_G16R16:
Alexis Hetu43577b82015-10-21 15:32:16 -0400349 case FORMAT_G16R16UI:
John Bauman89401822014-05-06 15:04:28 -0400350 c.x = Float(Int(*Pointer<UShort>(element + 0)));
351 c.y = Float(Int(*Pointer<UShort>(element + 2)));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500352 c.w = float(0xFFFF);
John Bauman89401822014-05-06 15:04:28 -0400353 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400354 case FORMAT_G32R32I:
Alexis Hetucfd96322017-07-24 14:44:33 -0400355 c.x = Float(*Pointer<Int>(element + 0));
356 c.y = Float(*Pointer<Int>(element + 4));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500357 c.w = float(0x7FFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400358 break;
359 case FORMAT_G32R32UI:
Alexis Hetucfd96322017-07-24 14:44:33 -0400360 c.x = Float(*Pointer<UInt>(element + 0));
361 c.y = Float(*Pointer<UInt>(element + 4));
Alexis Hetuf1ea9892015-12-14 17:33:04 -0500362 c.w = float(0xFFFFFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400363 break;
John Bauman89401822014-05-06 15:04:28 -0400364 case FORMAT_A32B32G32R32F:
365 c = *Pointer<Float4>(element);
366 break;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400367 case FORMAT_X32B32G32R32F:
Nicolas Capens67fdd832017-12-21 11:20:54 -0500368 case FORMAT_X32B32G32R32F_UNSIGNED:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400369 case FORMAT_B32G32R32F:
370 c.z = *Pointer<Float>(element + 8);
John Bauman89401822014-05-06 15:04:28 -0400371 case FORMAT_G32R32F:
372 c.x = *Pointer<Float>(element + 0);
373 c.y = *Pointer<Float>(element + 4);
374 break;
375 case FORMAT_R32F:
376 c.x = *Pointer<Float>(element);
377 break;
Alexis Hetu75b650f2015-11-19 17:40:15 -0500378 case FORMAT_R5G6B5:
379 c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
380 c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
381 c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
382 break;
Alexis Hetuf999a002015-12-17 11:09:36 -0500383 case FORMAT_A2B10G10R10:
Nicolas Capens5555af42017-12-14 13:14:03 -0500384 case FORMAT_A2B10G10R10UI:
Alexis Hetuf999a002015-12-17 11:09:36 -0500385 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
386 c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
387 c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
388 c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
389 break;
John Sheubc07bf62016-04-18 18:53:47 -0700390 case FORMAT_D16:
391 c.x = Float(Int((*Pointer<UShort>(element))));
392 break;
393 case FORMAT_D24S8:
Nicolas Capens0c6ac932018-03-27 17:24:38 -0400394 case FORMAT_D24X8:
395 c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
John Sheubc07bf62016-04-18 18:53:47 -0700396 break;
397 case FORMAT_D32:
398 c.x = Float(Int((*Pointer<UInt>(element))));
399 break;
John Sheubc07bf62016-04-18 18:53:47 -0700400 case FORMAT_D32F_COMPLEMENTARY:
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500401 case FORMAT_D32FS8_COMPLEMENTARY:
John Sheubc07bf62016-04-18 18:53:47 -0700402 c.x = 1.0f - *Pointer<Float>(element);
403 break;
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500404 case FORMAT_D32F:
405 case FORMAT_D32FS8:
John Sheubc07bf62016-04-18 18:53:47 -0700406 case FORMAT_D32F_LOCKABLE:
John Sheubc07bf62016-04-18 18:53:47 -0700407 case FORMAT_D32FS8_TEXTURE:
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500408 case FORMAT_D32F_SHADOW:
John Sheubc07bf62016-04-18 18:53:47 -0700409 case FORMAT_D32FS8_SHADOW:
410 c.x = *Pointer<Float>(element);
411 break;
Alexis Hetub9dda642016-10-06 11:25:32 -0400412 case FORMAT_S8:
413 c.x = Float(Int(*Pointer<Byte>(element)));
414 break;
John Bauman89401822014-05-06 15:04:28 -0400415 default:
416 return false;
417 }
418
419 return true;
420 }
421
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500422 bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
Alexis Hetu43577b82015-10-21 15:32:16 -0400423 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500424 bool writeR = state.writeRed;
425 bool writeG = state.writeGreen;
426 bool writeB = state.writeBlue;
427 bool writeA = state.writeAlpha;
Alexis Hetu75b650f2015-11-19 17:40:15 -0500428 bool writeRGBA = writeR && writeG && writeB && writeA;
429
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500430 switch(state.destFormat)
Alexis Hetu43577b82015-10-21 15:32:16 -0400431 {
432 case FORMAT_L8:
433 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
434 break;
435 case FORMAT_A8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500436 if(writeA) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.w))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400437 break;
438 case FORMAT_A8R8G8B8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500439 if(writeRGBA)
Alexis Hetu43577b82015-10-21 15:32:16 -0400440 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400441 Short4 c0 = RoundShort4(c.zyxw);
442 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
Alexis Hetu43577b82015-10-21 15:32:16 -0400443 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500444 else
445 {
446 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
447 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
448 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
449 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
450 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400451 break;
452 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400453 case FORMAT_SRGB8_A8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500454 if(writeRGBA)
Alexis Hetu43577b82015-10-21 15:32:16 -0400455 {
Nicolas Capens33438a62017-09-27 11:47:35 -0400456 Short4 c0 = RoundShort4(c);
457 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
Alexis Hetu43577b82015-10-21 15:32:16 -0400458 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500459 else
460 {
461 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
462 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
463 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
464 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
465 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400466 break;
467 case FORMAT_X8R8G8B8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500468 if(writeRGBA)
Alexis Hetu43577b82015-10-21 15:32:16 -0400469 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500470 Short4 c0 = RoundShort4(c.zyxw) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
Nicolas Capens33438a62017-09-27 11:47:35 -0400471 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
Alexis Hetu43577b82015-10-21 15:32:16 -0400472 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500473 else
474 {
475 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
476 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
477 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
478 if(writeA) { *Pointer<Byte>(element + 3) = Byte(0xFF); }
479 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400480 break;
481 case FORMAT_X8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400482 case FORMAT_SRGB8_X8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500483 if(writeRGBA)
Alexis Hetu43577b82015-10-21 15:32:16 -0400484 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -0500485 Short4 c0 = RoundShort4(c) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
Nicolas Capens33438a62017-09-27 11:47:35 -0400486 *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
Alexis Hetu43577b82015-10-21 15:32:16 -0400487 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500488 else
489 {
490 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
491 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
492 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
493 if(writeA) { *Pointer<Byte>(element + 3) = Byte(0xFF); }
494 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400495 break;
Alexis Hetu925c2822015-11-24 14:09:34 -0500496 case FORMAT_R8G8B8:
497 if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
498 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
499 if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
500 break;
501 case FORMAT_B8G8R8:
502 if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
503 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
504 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
505 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400506 case FORMAT_A32B32G32R32F:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500507 if(writeRGBA)
508 {
509 *Pointer<Float4>(element) = c;
510 }
511 else
512 {
513 if(writeR) { *Pointer<Float>(element) = c.x; }
514 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
515 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
516 if(writeA) { *Pointer<Float>(element + 12) = c.w; }
517 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400518 break;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400519 case FORMAT_X32B32G32R32F:
Nicolas Capens67fdd832017-12-21 11:20:54 -0500520 case FORMAT_X32B32G32R32F_UNSIGNED:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400521 if(writeA) { *Pointer<Float>(element + 12) = 1.0f; }
522 case FORMAT_B32G32R32F:
523 if(writeR) { *Pointer<Float>(element) = c.x; }
524 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
525 if(writeB) { *Pointer<Float>(element + 8) = c.z; }
526 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400527 case FORMAT_G32R32F:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500528 if(writeR && writeG)
529 {
530 *Pointer<Float2>(element) = Float2(c);
531 }
532 else
533 {
534 if(writeR) { *Pointer<Float>(element) = c.x; }
535 if(writeG) { *Pointer<Float>(element + 4) = c.y; }
536 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400537 break;
538 case FORMAT_R32F:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500539 if(writeR) { *Pointer<Float>(element) = c.x; }
Alexis Hetu43577b82015-10-21 15:32:16 -0400540 break;
541 case FORMAT_A8B8G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500542 case FORMAT_A8B8G8R8_SNORM:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500543 if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400544 case FORMAT_X8B8G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500545 case FORMAT_X8B8G8R8_SNORM:
546 if(writeA && (state.destFormat == FORMAT_X8B8G8R8I || state.destFormat == FORMAT_X8B8G8R8_SNORM))
Alexis Hetu43577b82015-10-21 15:32:16 -0400547 {
548 *Pointer<SByte>(element + 3) = SByte(0x7F);
549 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500550 if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400551 case FORMAT_G8R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500552 case FORMAT_G8R8_SNORM:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500553 if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400554 case FORMAT_R8I:
Nicolas Capens975adb72017-12-19 15:34:20 -0500555 case FORMAT_R8_SNORM:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500556 if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400557 break;
558 case FORMAT_A8B8G8R8UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500559 if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400560 case FORMAT_X8B8G8R8UI:
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500561 if(writeA && (state.destFormat == FORMAT_X8B8G8R8UI))
Alexis Hetu43577b82015-10-21 15:32:16 -0400562 {
563 *Pointer<Byte>(element + 3) = Byte(0xFF);
564 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500565 if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400566 case FORMAT_G8R8UI:
567 case FORMAT_G8R8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500568 if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400569 case FORMAT_R8UI:
570 case FORMAT_R8:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500571 if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400572 break;
573 case FORMAT_A16B16G16R16I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500574 if(writeRGBA)
575 {
576 *Pointer<Short4>(element) = Short4(RoundInt(c));
577 }
578 else
579 {
580 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
581 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
582 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
583 if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
584 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400585 break;
586 case FORMAT_X16B16G16R16I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500587 if(writeRGBA)
588 {
589 *Pointer<Short4>(element) = Short4(RoundInt(c));
590 }
591 else
592 {
593 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
594 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
595 if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
596 }
597 if(writeA) { *Pointer<Short>(element + 6) = Short(0x7F); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400598 break;
599 case FORMAT_G16R16I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500600 if(writeR && writeG)
601 {
Nicolas Capens16b5f152016-10-13 13:39:01 -0400602 *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500603 }
604 else
605 {
606 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
607 if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
608 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400609 break;
610 case FORMAT_R16I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500611 if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400612 break;
613 case FORMAT_A16B16G16R16UI:
614 case FORMAT_A16B16G16R16:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500615 if(writeRGBA)
616 {
617 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
618 }
619 else
620 {
621 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
622 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
623 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
624 if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
625 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400626 break;
627 case FORMAT_X16B16G16R16UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500628 if(writeRGBA)
629 {
630 *Pointer<UShort4>(element) = UShort4(RoundInt(c));
631 }
632 else
633 {
634 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
635 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
636 if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
637 }
638 if(writeA) { *Pointer<UShort>(element + 6) = UShort(0xFF); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400639 break;
640 case FORMAT_G16R16UI:
641 case FORMAT_G16R16:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500642 if(writeR && writeG)
643 {
Nicolas Capens16b5f152016-10-13 13:39:01 -0400644 *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
Alexis Hetu75b650f2015-11-19 17:40:15 -0500645 }
646 else
647 {
648 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
649 if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
650 }
651 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400652 case FORMAT_R16UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500653 if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400654 break;
655 case FORMAT_A32B32G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500656 if(writeRGBA)
657 {
658 *Pointer<Int4>(element) = RoundInt(c);
659 }
660 else
661 {
662 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
663 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
664 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
665 if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
666 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400667 break;
668 case FORMAT_X32B32G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500669 if(writeRGBA)
670 {
671 *Pointer<Int4>(element) = RoundInt(c);
672 }
673 else
674 {
675 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
676 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
677 if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
678 }
679 if(writeA) { *Pointer<Int>(element + 12) = Int(0x7FFFFFFF); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400680 break;
681 case FORMAT_G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500682 if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400683 case FORMAT_R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500684 if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400685 break;
686 case FORMAT_A32B32G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500687 if(writeRGBA)
688 {
689 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
690 }
691 else
692 {
693 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
694 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
695 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
696 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
697 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400698 break;
699 case FORMAT_X32B32G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500700 if(writeRGBA)
701 {
702 *Pointer<UInt4>(element) = UInt4(RoundInt(c));
703 }
704 else
705 {
706 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
707 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
708 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
709 }
710 if(writeA) { *Pointer<UInt4>(element + 12) = UInt4(0xFFFFFFFF); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400711 break;
712 case FORMAT_G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500713 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400714 case FORMAT_R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500715 if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
716 break;
717 case FORMAT_R5G6B5:
718 if(writeR && writeG && writeB)
719 {
720 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
721 (RoundInt(Float(c.y)) << Int(5)) |
722 (RoundInt(Float(c.x)) << Int(11)));
723 }
724 else
725 {
726 unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
727 unsigned short unmask = ~mask;
Nicolas Capens81f18302016-01-14 09:32:35 -0500728 *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
Alexis Hetu75b650f2015-11-19 17:40:15 -0500729 (UShort(RoundInt(Float(c.z)) |
730 (RoundInt(Float(c.y)) << Int(5)) |
731 (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
732 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400733 break;
Alexis Hetuf999a002015-12-17 11:09:36 -0500734 case FORMAT_A2B10G10R10:
Nicolas Capens5555af42017-12-14 13:14:03 -0500735 case FORMAT_A2B10G10R10UI:
Alexis Hetuf999a002015-12-17 11:09:36 -0500736 if(writeRGBA)
737 {
738 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
739 (RoundInt(Float(c.y)) << 10) |
740 (RoundInt(Float(c.z)) << 20) |
741 (RoundInt(Float(c.w)) << 30));
742 }
743 else
744 {
745 unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
746 (writeB ? 0x3FF00000 : 0x0000) |
747 (writeG ? 0x000FFC00 : 0x0000) |
748 (writeR ? 0x000003FF : 0x0000);
749 unsigned int unmask = ~mask;
750 *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
751 (UInt(RoundInt(Float(c.x)) |
752 (RoundInt(Float(c.y)) << 10) |
753 (RoundInt(Float(c.z)) << 20) |
754 (RoundInt(Float(c.w)) << 30)) & UInt(mask));
755 }
756 break;
John Sheubc07bf62016-04-18 18:53:47 -0700757 case FORMAT_D16:
758 *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
759 break;
760 case FORMAT_D24S8:
Nicolas Capens0c6ac932018-03-27 17:24:38 -0400761 case FORMAT_D24X8:
762 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
John Sheubc07bf62016-04-18 18:53:47 -0700763 break;
764 case FORMAT_D32:
765 *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)));
766 break;
John Sheubc07bf62016-04-18 18:53:47 -0700767 case FORMAT_D32F_COMPLEMENTARY:
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500768 case FORMAT_D32FS8_COMPLEMENTARY:
John Sheubc07bf62016-04-18 18:53:47 -0700769 *Pointer<Float>(element) = 1.0f - c.x;
770 break;
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500771 case FORMAT_D32F:
772 case FORMAT_D32FS8:
John Sheubc07bf62016-04-18 18:53:47 -0700773 case FORMAT_D32F_LOCKABLE:
John Sheubc07bf62016-04-18 18:53:47 -0700774 case FORMAT_D32FS8_TEXTURE:
Nicolas Capens57e7cea2017-12-13 22:25:04 -0500775 case FORMAT_D32F_SHADOW:
John Sheubc07bf62016-04-18 18:53:47 -0700776 case FORMAT_D32FS8_SHADOW:
777 *Pointer<Float>(element) = c.x;
778 break;
Alexis Hetub9dda642016-10-06 11:25:32 -0400779 case FORMAT_S8:
780 *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
781 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400782 default:
783 return false;
784 }
785 return true;
786 }
787
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500788 bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
Alexis Hetu43577b82015-10-21 15:32:16 -0400789 {
Alexis Hetu5270fb32016-09-15 14:47:56 -0400790 c = Int4(0, 0, 0, 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400791
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500792 switch(state.sourceFormat)
Alexis Hetu43577b82015-10-21 15:32:16 -0400793 {
794 case FORMAT_A8B8G8R8I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500795 c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
Alexis Hetu43577b82015-10-21 15:32:16 -0400796 case FORMAT_X8B8G8R8I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500797 c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
Alexis Hetu43577b82015-10-21 15:32:16 -0400798 case FORMAT_G8R8I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500799 c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400800 case FORMAT_R8I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500801 c = Insert(c, Int(*Pointer<SByte>(element)), 0);
Alexis Hetu43577b82015-10-21 15:32:16 -0400802 break;
803 case FORMAT_A8B8G8R8UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500804 c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
Alexis Hetu43577b82015-10-21 15:32:16 -0400805 case FORMAT_X8B8G8R8UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500806 c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
Alexis Hetu43577b82015-10-21 15:32:16 -0400807 case FORMAT_G8R8UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500808 c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400809 case FORMAT_R8UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500810 c = Insert(c, Int(*Pointer<Byte>(element)), 0);
Alexis Hetu43577b82015-10-21 15:32:16 -0400811 break;
812 case FORMAT_A16B16G16R16I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500813 c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
Alexis Hetu43577b82015-10-21 15:32:16 -0400814 case FORMAT_X16B16G16R16I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500815 c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
Alexis Hetu43577b82015-10-21 15:32:16 -0400816 case FORMAT_G16R16I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500817 c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400818 case FORMAT_R16I:
Alexis Hetud18c0692015-12-16 16:54:32 -0500819 c = Insert(c, Int(*Pointer<Short>(element)), 0);
Alexis Hetu43577b82015-10-21 15:32:16 -0400820 break;
821 case FORMAT_A16B16G16R16UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500822 c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
Alexis Hetu43577b82015-10-21 15:32:16 -0400823 case FORMAT_X16B16G16R16UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500824 c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
Alexis Hetu43577b82015-10-21 15:32:16 -0400825 case FORMAT_G16R16UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500826 c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400827 case FORMAT_R16UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500828 c = Insert(c, Int(*Pointer<UShort>(element)), 0);
Alexis Hetu43577b82015-10-21 15:32:16 -0400829 break;
830 case FORMAT_A32B32G32R32I:
Alexis Hetucfd96322017-07-24 14:44:33 -0400831 case FORMAT_A32B32G32R32UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500832 c = *Pointer<Int4>(element);
833 break;
Alexis Hetu43577b82015-10-21 15:32:16 -0400834 case FORMAT_X32B32G32R32I:
Alexis Hetucfd96322017-07-24 14:44:33 -0400835 case FORMAT_X32B32G32R32UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500836 c = Insert(c, *Pointer<Int>(element + 8), 2);
Alexis Hetu43577b82015-10-21 15:32:16 -0400837 case FORMAT_G32R32I:
Alexis Hetucfd96322017-07-24 14:44:33 -0400838 case FORMAT_G32R32UI:
Alexis Hetud18c0692015-12-16 16:54:32 -0500839 c = Insert(c, *Pointer<Int>(element + 4), 1);
Alexis Hetu43577b82015-10-21 15:32:16 -0400840 case FORMAT_R32I:
Alexis Hetu43577b82015-10-21 15:32:16 -0400841 case FORMAT_R32UI:
Alexis Hetucfd96322017-07-24 14:44:33 -0400842 c = Insert(c, *Pointer<Int>(element), 0);
Alexis Hetu43577b82015-10-21 15:32:16 -0400843 break;
844 default:
845 return false;
846 }
847
848 return true;
849 }
850
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500851 bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
Alexis Hetu43577b82015-10-21 15:32:16 -0400852 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500853 bool writeR = state.writeRed;
854 bool writeG = state.writeGreen;
855 bool writeB = state.writeBlue;
856 bool writeA = state.writeAlpha;
Alexis Hetu75b650f2015-11-19 17:40:15 -0500857 bool writeRGBA = writeR && writeG && writeB && writeA;
858
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500859 switch(state.destFormat)
Alexis Hetu43577b82015-10-21 15:32:16 -0400860 {
861 case FORMAT_A8B8G8R8I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500862 if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400863 case FORMAT_X8B8G8R8I:
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500864 if(writeA && (state.destFormat != FORMAT_A8B8G8R8I))
Alexis Hetu43577b82015-10-21 15:32:16 -0400865 {
866 *Pointer<SByte>(element + 3) = SByte(0x7F);
867 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500868 if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
869 case FORMAT_G8R8I:
870 if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
871 case FORMAT_R8I:
872 if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400873 break;
874 case FORMAT_A8B8G8R8UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500875 if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400876 case FORMAT_X8B8G8R8UI:
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500877 if(writeA && (state.destFormat != FORMAT_A8B8G8R8UI))
Alexis Hetu43577b82015-10-21 15:32:16 -0400878 {
879 *Pointer<Byte>(element + 3) = Byte(0xFF);
880 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500881 if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
882 case FORMAT_G8R8UI:
883 if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
884 case FORMAT_R8UI:
885 if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400886 break;
887 case FORMAT_A16B16G16R16I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500888 if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400889 case FORMAT_X16B16G16R16I:
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500890 if(writeA && (state.destFormat != FORMAT_A16B16G16R16I))
Alexis Hetu43577b82015-10-21 15:32:16 -0400891 {
Alexis Hetu75b650f2015-11-19 17:40:15 -0500892 *Pointer<Short>(element + 6) = Short(0x7FFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400893 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500894 if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
895 case FORMAT_G16R16I:
896 if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
897 case FORMAT_R16I:
898 if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400899 break;
900 case FORMAT_A16B16G16R16UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500901 if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400902 case FORMAT_X16B16G16R16UI:
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500903 if(writeA && (state.destFormat != FORMAT_A16B16G16R16UI))
Alexis Hetu43577b82015-10-21 15:32:16 -0400904 {
Alexis Hetu75b650f2015-11-19 17:40:15 -0500905 *Pointer<UShort>(element + 6) = UShort(0xFFFF);
Alexis Hetu43577b82015-10-21 15:32:16 -0400906 }
Alexis Hetu75b650f2015-11-19 17:40:15 -0500907 if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
908 case FORMAT_G16R16UI:
909 if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
910 case FORMAT_R16UI:
911 if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400912 break;
913 case FORMAT_A32B32G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500914 if(writeRGBA)
915 {
916 *Pointer<Int4>(element) = c;
917 }
918 else
919 {
920 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
921 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
922 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
923 if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
924 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400925 break;
926 case FORMAT_X32B32G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500927 if(writeRGBA)
928 {
929 *Pointer<Int4>(element) = c;
930 }
931 else
932 {
933 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
934 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
935 if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
936 }
937 if(writeA) { *Pointer<Int>(element + 12) = Int(0x7FFFFFFF); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400938 break;
939 case FORMAT_G32R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500940 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
941 if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400942 break;
943 case FORMAT_R32I:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500944 if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400945 break;
946 case FORMAT_A32B32G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500947 if(writeRGBA)
948 {
949 *Pointer<UInt4>(element) = As<UInt4>(c);
950 }
951 else
952 {
953 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
954 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
955 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
956 if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
957 }
Alexis Hetu43577b82015-10-21 15:32:16 -0400958 break;
959 case FORMAT_X32B32G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500960 if(writeRGBA)
961 {
962 *Pointer<UInt4>(element) = As<UInt4>(c);
963 }
964 else
965 {
966 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
967 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
968 if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
969 }
970 if(writeA) { *Pointer<UInt>(element + 3) = UInt(0xFFFFFFFF); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400971 break;
972 case FORMAT_G32R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500973 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
974 if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400975 break;
976 case FORMAT_R32UI:
Alexis Hetu75b650f2015-11-19 17:40:15 -0500977 if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
Alexis Hetu43577b82015-10-21 15:32:16 -0400978 break;
979 default:
980 return false;
981 }
982
983 return true;
984 }
985
Nicolas Capens8f7739a2017-12-16 02:06:56 -0500986 bool Blitter::GetScale(float4 &scale, Format format)
Alexis Hetu43577b82015-10-21 15:32:16 -0400987 {
988 switch(format)
989 {
990 case FORMAT_L8:
991 case FORMAT_A8:
992 case FORMAT_A8R8G8B8:
993 case FORMAT_X8R8G8B8:
994 case FORMAT_R8:
995 case FORMAT_G8R8:
Alexis Hetu925c2822015-11-24 14:09:34 -0500996 case FORMAT_R8G8B8:
997 case FORMAT_B8G8R8:
Alexis Hetu43577b82015-10-21 15:32:16 -0400998 case FORMAT_X8B8G8R8:
999 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -04001000 case FORMAT_SRGB8_X8:
1001 case FORMAT_SRGB8_A8:
Alexis Hetu43577b82015-10-21 15:32:16 -04001002 scale = vector(0xFF, 0xFF, 0xFF, 0xFF);
1003 break;
Nicolas Capens975adb72017-12-19 15:34:20 -05001004 case FORMAT_R8_SNORM:
1005 case FORMAT_G8R8_SNORM:
1006 case FORMAT_X8B8G8R8_SNORM:
1007 case FORMAT_A8B8G8R8_SNORM:
Alexis Hetu43577b82015-10-21 15:32:16 -04001008 scale = vector(0x7F, 0x7F, 0x7F, 0x7F);
1009 break;
Alexis Hetuf999a002015-12-17 11:09:36 -05001010 case FORMAT_A16B16G16R16:
1011 scale = vector(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
1012 break;
Alexis Hetu43577b82015-10-21 15:32:16 -04001013 case FORMAT_R8I:
1014 case FORMAT_R8UI:
1015 case FORMAT_G8R8I:
1016 case FORMAT_G8R8UI:
1017 case FORMAT_X8B8G8R8I:
1018 case FORMAT_X8B8G8R8UI:
1019 case FORMAT_A8B8G8R8I:
1020 case FORMAT_A8B8G8R8UI:
1021 case FORMAT_R16I:
1022 case FORMAT_R16UI:
1023 case FORMAT_G16R16:
1024 case FORMAT_G16R16I:
1025 case FORMAT_G16R16UI:
1026 case FORMAT_X16B16G16R16I:
1027 case FORMAT_X16B16G16R16UI:
Alexis Hetu43577b82015-10-21 15:32:16 -04001028 case FORMAT_A16B16G16R16I:
1029 case FORMAT_A16B16G16R16UI:
1030 case FORMAT_R32I:
1031 case FORMAT_R32UI:
1032 case FORMAT_G32R32I:
1033 case FORMAT_G32R32UI:
1034 case FORMAT_X32B32G32R32I:
1035 case FORMAT_X32B32G32R32UI:
1036 case FORMAT_A32B32G32R32I:
1037 case FORMAT_A32B32G32R32UI:
1038 case FORMAT_A32B32G32R32F:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04001039 case FORMAT_X32B32G32R32F:
Nicolas Capens67fdd832017-12-21 11:20:54 -05001040 case FORMAT_X32B32G32R32F_UNSIGNED:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04001041 case FORMAT_B32G32R32F:
Alexis Hetu43577b82015-10-21 15:32:16 -04001042 case FORMAT_G32R32F:
1043 case FORMAT_R32F:
Nicolas Capens5555af42017-12-14 13:14:03 -05001044 case FORMAT_A2B10G10R10UI:
Alexis Hetu43577b82015-10-21 15:32:16 -04001045 scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
1046 break;
Alexis Hetu75b650f2015-11-19 17:40:15 -05001047 case FORMAT_R5G6B5:
1048 scale = vector(0x1F, 0x3F, 0x1F, 1.0f);
1049 break;
Alexis Hetuf999a002015-12-17 11:09:36 -05001050 case FORMAT_A2B10G10R10:
1051 scale = vector(0x3FF, 0x3FF, 0x3FF, 0x03);
1052 break;
John Sheubc07bf62016-04-18 18:53:47 -07001053 case FORMAT_D16:
1054 scale = vector(0xFFFF, 0.0f, 0.0f, 0.0f);
1055 break;
1056 case FORMAT_D24S8:
Nicolas Capens0c6ac932018-03-27 17:24:38 -04001057 case FORMAT_D24X8:
John Sheubc07bf62016-04-18 18:53:47 -07001058 scale = vector(0xFFFFFF, 0.0f, 0.0f, 0.0f);
1059 break;
1060 case FORMAT_D32:
Alexis Hetu05c32b92016-06-23 11:32:07 -04001061 scale = vector(static_cast<float>(0xFFFFFFFF), 0.0f, 0.0f, 0.0f);
John Sheubc07bf62016-04-18 18:53:47 -07001062 break;
1063 case FORMAT_D32F:
Nicolas Capens57e7cea2017-12-13 22:25:04 -05001064 case FORMAT_D32FS8:
John Sheubc07bf62016-04-18 18:53:47 -07001065 case FORMAT_D32F_COMPLEMENTARY:
Nicolas Capens57e7cea2017-12-13 22:25:04 -05001066 case FORMAT_D32FS8_COMPLEMENTARY:
John Sheubc07bf62016-04-18 18:53:47 -07001067 case FORMAT_D32F_LOCKABLE:
1068 case FORMAT_D32FS8_TEXTURE:
Nicolas Capens57e7cea2017-12-13 22:25:04 -05001069 case FORMAT_D32F_SHADOW:
John Sheubc07bf62016-04-18 18:53:47 -07001070 case FORMAT_D32FS8_SHADOW:
Alexis Hetub9dda642016-10-06 11:25:32 -04001071 case FORMAT_S8:
1072 scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
John Sheubc07bf62016-04-18 18:53:47 -07001073 break;
Alexis Hetu43577b82015-10-21 15:32:16 -04001074 default:
1075 return false;
1076 }
1077
1078 return true;
1079 }
1080
Alexis Hetud0a459f2018-01-08 17:22:15 -05001081 bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
Alexis Hetu75b650f2015-11-19 17:40:15 -05001082 {
1083 float4 scale, unscale;
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001084 if(state.clearOperation &&
1085 Surface::isNonNormalizedInteger(state.sourceFormat) &&
1086 !Surface::isNonNormalizedInteger(state.destFormat))
Alexis Hetu75b650f2015-11-19 17:40:15 -05001087 {
1088 // If we're clearing a buffer from an int or uint color into a normalized color,
1089 // then the whole range of the int or uint color must be scaled between 0 and 1.
1090 switch(state.sourceFormat)
1091 {
1092 case FORMAT_A32B32G32R32I:
Alexis Hetu05c32b92016-06-23 11:32:07 -04001093 unscale = replicate(static_cast<float>(0x7FFFFFFF));
Alexis Hetu75b650f2015-11-19 17:40:15 -05001094 break;
1095 case FORMAT_A32B32G32R32UI:
Alexis Hetu05c32b92016-06-23 11:32:07 -04001096 unscale = replicate(static_cast<float>(0xFFFFFFFF));
Alexis Hetu75b650f2015-11-19 17:40:15 -05001097 break;
1098 default:
1099 return false;
1100 }
1101 }
1102 else if(!GetScale(unscale, state.sourceFormat))
1103 {
1104 return false;
1105 }
1106
1107 if(!GetScale(scale, state.destFormat))
1108 {
1109 return false;
1110 }
1111
Nicolas Capens1ab837c2017-12-16 02:28:02 -05001112 bool srcSRGB = Surface::isSRGBformat(state.sourceFormat);
1113 bool dstSRGB = Surface::isSRGBformat(state.destFormat);
1114
Alexis Hetud0a459f2018-01-08 17:22:15 -05001115 if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB)) // One of the formats is sRGB encoded.
Nicolas Capens1ab837c2017-12-16 02:28:02 -05001116 {
Alexis Hetud0a459f2018-01-08 17:22:15 -05001117 value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1118 Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
1119 value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
1120 value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
Nicolas Capens1ab837c2017-12-16 02:28:02 -05001121 }
1122 else if(unscale != scale)
Alexis Hetu75b650f2015-11-19 17:40:15 -05001123 {
1124 value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1125 }
1126
Nicolas Capens67fdd832017-12-21 11:20:54 -05001127 if(state.destFormat == FORMAT_X32B32G32R32F_UNSIGNED)
1128 {
1129 value = Max(value, Float4(0.0f)); // TODO: Only necessary if source is signed.
1130 }
1131 else if(Surface::isFloatFormat(state.sourceFormat) && !Surface::isFloatFormat(state.destFormat))
Alexis Hetu75b650f2015-11-19 17:40:15 -05001132 {
1133 value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1134
1135 value = Max(value, Float4(Surface::isUnsignedComponent(state.destFormat, 0) ? 0.0f : -scale.x,
1136 Surface::isUnsignedComponent(state.destFormat, 1) ? 0.0f : -scale.y,
1137 Surface::isUnsignedComponent(state.destFormat, 2) ? 0.0f : -scale.z,
1138 Surface::isUnsignedComponent(state.destFormat, 3) ? 0.0f : -scale.w));
1139 }
1140
1141 return true;
1142 }
1143
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001144 Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
Alexis Hetub9dda642016-10-06 11:25:32 -04001145 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001146 if(!quadLayout)
1147 {
1148 return y * pitchB + x * bytes;
1149 }
1150 else
1151 {
1152 // (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
1153 return (y & Int(~1)) * pitchB +
1154 ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
1155 }
Alexis Hetub9dda642016-10-06 11:25:32 -04001156 }
1157
Nicolas Capens1ab837c2017-12-16 02:28:02 -05001158 Float4 Blitter::LinearToSRGB(Float4 &c)
1159 {
1160 Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1161 Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1162
1163 Float4 s = c;
1164 s.xyz = Max(lc, ec);
1165
1166 return s;
1167 }
1168
1169 Float4 Blitter::sRGBtoLinear(Float4 &c)
1170 {
1171 Float4 lc = c * Float4(1.0f / 12.92f);
1172 Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1173
1174 Int4 linear = CmpLT(c, Float4(0.04045f));
1175
1176 Float4 s = c;
Ben Clayton5e9441a2019-05-24 07:43:42 +01001177 s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec))); // TODO: IfThenElse()
Nicolas Capens1ab837c2017-12-16 02:28:02 -05001178
1179 return s;
1180 }
1181
Ben Clayton6897e9b2019-07-16 17:27:27 +01001182 std::shared_ptr<Routine> Blitter::generate(const State &state)
Nicolas Capens130c27a2015-06-10 11:03:20 -04001183 {
Nicolas Capens2ab859f2015-02-05 12:36:46 -05001184 Function<Void(Pointer<Byte>)> function;
Nicolas Capens130c27a2015-06-10 11:03:20 -04001185 {
Nicolas Capens81f18302016-01-14 09:32:35 -05001186 Pointer<Byte> blit(function.Arg<0>());
Nicolas Capens130c27a2015-06-10 11:03:20 -04001187
Nicolas Capens81f18302016-01-14 09:32:35 -05001188 Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,source));
1189 Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,dest));
Nicolas Capens130c27a2015-06-10 11:03:20 -04001190 Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData,sPitchB));
1191 Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData,dPitchB));
1192
1193 Float x0 = *Pointer<Float>(blit + OFFSET(BlitData,x0));
1194 Float y0 = *Pointer<Float>(blit + OFFSET(BlitData,y0));
1195 Float w = *Pointer<Float>(blit + OFFSET(BlitData,w));
1196 Float h = *Pointer<Float>(blit + OFFSET(BlitData,h));
1197
1198 Int x0d = *Pointer<Int>(blit + OFFSET(BlitData,x0d));
1199 Int x1d = *Pointer<Int>(blit + OFFSET(BlitData,x1d));
1200 Int y0d = *Pointer<Int>(blit + OFFSET(BlitData,y0d));
1201 Int y1d = *Pointer<Int>(blit + OFFSET(BlitData,y1d));
1202
1203 Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData,sWidth));
1204 Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData,sHeight));
1205
Alexis Hetu75b650f2015-11-19 17:40:15 -05001206 bool intSrc = Surface::isNonNormalizedInteger(state.sourceFormat);
1207 bool intDst = Surface::isNonNormalizedInteger(state.destFormat);
1208 bool intBoth = intSrc && intDst;
Alexis Hetub9dda642016-10-06 11:25:32 -04001209 bool srcQuadLayout = Surface::hasQuadLayout(state.sourceFormat);
1210 bool dstQuadLayout = Surface::hasQuadLayout(state.destFormat);
1211 int srcBytes = Surface::bytes(state.sourceFormat);
1212 int dstBytes = Surface::bytes(state.destFormat);
Alexis Hetu75b650f2015-11-19 17:40:15 -05001213
1214 bool hasConstantColorI = false;
1215 Int4 constantColorI;
1216 bool hasConstantColorF = false;
1217 Float4 constantColorF;
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001218 if(state.clearOperation)
Alexis Hetu75b650f2015-11-19 17:40:15 -05001219 {
1220 if(intBoth) // Integer types
1221 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001222 if(!read(constantColorI, source, state))
Alexis Hetu75b650f2015-11-19 17:40:15 -05001223 {
1224 return nullptr;
1225 }
1226 hasConstantColorI = true;
1227 }
1228 else
1229 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001230 if(!read(constantColorF, source, state))
Alexis Hetu75b650f2015-11-19 17:40:15 -05001231 {
1232 return nullptr;
1233 }
1234 hasConstantColorF = true;
1235
1236 if(!ApplyScaleAndClamp(constantColorF, state))
1237 {
1238 return nullptr;
1239 }
1240 }
1241 }
1242
Nicolas Capens130c27a2015-06-10 11:03:20 -04001243 For(Int j = y0d, j < y1d, j++)
1244 {
Nicolas Capens48456332018-06-01 22:02:13 -04001245 Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
Alexis Hetuf4f68e12016-11-22 14:13:01 -05001246 Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
Nicolas Capens130c27a2015-06-10 11:03:20 -04001247
1248 For(Int i = x0d, i < x1d, i++)
1249 {
Nicolas Capens48456332018-06-01 22:02:13 -04001250 Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
Alexis Hetuf4f68e12016-11-22 14:13:01 -05001251 Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
Nicolas Capensbfa23b32017-12-11 10:06:37 -05001252
Alexis Hetu75b650f2015-11-19 17:40:15 -05001253 if(hasConstantColorI)
1254 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001255 if(!write(constantColorI, d, state))
Alexis Hetu75b650f2015-11-19 17:40:15 -05001256 {
1257 return nullptr;
1258 }
1259 }
1260 else if(hasConstantColorF)
1261 {
Alexis Hetu53e83aa2018-03-25 20:32:22 -04001262 for(int s = 0; s < state.destSamples; s++)
Alexis Hetu75b650f2015-11-19 17:40:15 -05001263 {
Alexis Hetu53e83aa2018-03-25 20:32:22 -04001264 if(!write(constantColorF, d, state))
1265 {
1266 return nullptr;
1267 }
1268
1269 d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
Alexis Hetu75b650f2015-11-19 17:40:15 -05001270 }
1271 }
1272 else if(intBoth) // Integer types do not support filtering
Nicolas Capens130c27a2015-06-10 11:03:20 -04001273 {
Alexis Hetu43577b82015-10-21 15:32:16 -04001274 Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
Alexis Hetub9dda642016-10-06 11:25:32 -04001275 Int X = Int(x);
1276 Int Y = Int(y);
1277
Alexis Hetu73771b12017-12-19 15:37:46 -05001278 if(state.clampToEdge)
1279 {
1280 X = Clamp(X, 0, sWidth - 1);
1281 Y = Clamp(Y, 0, sHeight - 1);
1282 }
1283
Alexis Hetub9dda642016-10-06 11:25:32 -04001284 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1285
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001286 if(!read(color, s, state))
Nicolas Capens130c27a2015-06-10 11:03:20 -04001287 {
1288 return nullptr;
1289 }
Nicolas Capens130c27a2015-06-10 11:03:20 -04001290
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001291 if(!write(color, d, state))
Nicolas Capens130c27a2015-06-10 11:03:20 -04001292 {
Alexis Hetu43577b82015-10-21 15:32:16 -04001293 return nullptr;
Nicolas Capens130c27a2015-06-10 11:03:20 -04001294 }
Alexis Hetu43577b82015-10-21 15:32:16 -04001295 }
1296 else
1297 {
1298 Float4 color;
1299
Alexis Hetud0a459f2018-01-08 17:22:15 -05001300 bool preScaled = false;
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001301 if(!state.filter || intSrc)
Nicolas Capens130c27a2015-06-10 11:03:20 -04001302 {
Alexis Hetu43577b82015-10-21 15:32:16 -04001303 Int X = Int(x);
1304 Int Y = Int(y);
1305
Alexis Hetu73771b12017-12-19 15:37:46 -05001306 if(state.clampToEdge)
1307 {
1308 X = Clamp(X, 0, sWidth - 1);
1309 Y = Clamp(Y, 0, sHeight - 1);
1310 }
1311
Alexis Hetub9dda642016-10-06 11:25:32 -04001312 Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
Alexis Hetu43577b82015-10-21 15:32:16 -04001313
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001314 if(!read(color, s, state))
Alexis Hetu43577b82015-10-21 15:32:16 -04001315 {
1316 return nullptr;
1317 }
Nicolas Capens130c27a2015-06-10 11:03:20 -04001318 }
Alexis Hetu43577b82015-10-21 15:32:16 -04001319 else // Bilinear filtering
Nicolas Capens130c27a2015-06-10 11:03:20 -04001320 {
Alexis Hetu73771b12017-12-19 15:37:46 -05001321 Float X = x;
1322 Float Y = y;
1323
1324 if(state.clampToEdge)
1325 {
Alexis Hetud80d4c42018-01-09 08:31:02 -05001326 X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1327 Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
Alexis Hetu73771b12017-12-19 15:37:46 -05001328 }
1329
1330 Float x0 = X - 0.5f;
1331 Float y0 = Y - 0.5f;
Alexis Hetu43577b82015-10-21 15:32:16 -04001332
1333 Int X0 = Max(Int(x0), 0);
1334 Int Y0 = Max(Int(y0), 0);
1335
Alexis Hetu10c74a62017-11-29 14:00:32 -05001336 Int X1 = X0 + 1;
1337 Int Y1 = Y0 + 1;
1338 X1 = IfThenElse(X1 >= sWidth, X0, X1);
1339 Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
Alexis Hetu43577b82015-10-21 15:32:16 -04001340
Alexis Hetub9dda642016-10-06 11:25:32 -04001341 Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
1342 Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
1343 Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
1344 Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
Alexis Hetu43577b82015-10-21 15:32:16 -04001345
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001346 Float4 c00; if(!read(c00, s00, state)) return nullptr;
1347 Float4 c01; if(!read(c01, s01, state)) return nullptr;
1348 Float4 c10; if(!read(c10, s10, state)) return nullptr;
1349 Float4 c11; if(!read(c11, s11, state)) return nullptr;
Alexis Hetu43577b82015-10-21 15:32:16 -04001350
Alexis Hetud0a459f2018-01-08 17:22:15 -05001351 if(state.convertSRGB && Surface::isSRGBformat(state.sourceFormat)) // sRGB -> RGB
1352 {
1353 if(!ApplyScaleAndClamp(c00, state)) return nullptr;
1354 if(!ApplyScaleAndClamp(c01, state)) return nullptr;
1355 if(!ApplyScaleAndClamp(c10, state)) return nullptr;
1356 if(!ApplyScaleAndClamp(c11, state)) return nullptr;
1357 preScaled = true;
1358 }
1359
Alexis Hetu43577b82015-10-21 15:32:16 -04001360 Float4 fx = Float4(x0 - Float(X0));
1361 Float4 fy = Float4(y0 - Float(Y0));
Alexis Hetu10c74a62017-11-29 14:00:32 -05001362 Float4 ix = Float4(1.0f) - fx;
1363 Float4 iy = Float4(1.0f) - fy;
Alexis Hetu43577b82015-10-21 15:32:16 -04001364
Alexis Hetu10c74a62017-11-29 14:00:32 -05001365 color = (c00 * ix + c01 * fx) * iy +
1366 (c10 * ix + c11 * fx) * fy;
Nicolas Capens130c27a2015-06-10 11:03:20 -04001367 }
Alexis Hetu43577b82015-10-21 15:32:16 -04001368
Alexis Hetud0a459f2018-01-08 17:22:15 -05001369 if(!ApplyScaleAndClamp(color, state, preScaled))
Alexis Hetu43577b82015-10-21 15:32:16 -04001370 {
1371 return nullptr;
1372 }
Nicolas Capensbfa23b32017-12-11 10:06:37 -05001373
1374 for(int s = 0; s < state.destSamples; s++)
1375 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001376 if(!write(color, d, state))
Nicolas Capensbfa23b32017-12-11 10:06:37 -05001377 {
1378 return nullptr;
1379 }
1380
1381 d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
1382 }
Nicolas Capens130c27a2015-06-10 11:03:20 -04001383 }
Nicolas Capens130c27a2015-06-10 11:03:20 -04001384 }
Nicolas Capens130c27a2015-06-10 11:03:20 -04001385 }
1386 }
1387
Chris Forbes878d4b02019-01-21 10:48:35 -08001388 return function("BlitRoutine");
Nicolas Capens130c27a2015-06-10 11:03:20 -04001389 }
1390
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001391 bool Blitter::blitReactor(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options &options)
John Bauman89401822014-05-06 15:04:28 -04001392 {
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001393 ASSERT(!options.clearOperation || ((source->getWidth() == 1) && (source->getHeight() == 1) && (source->getDepth() == 1)));
Alexis Hetu75b650f2015-11-19 17:40:15 -05001394
Alexis Hetue9233fb2015-02-11 10:31:58 -05001395 Rect dRect = destRect;
Alexis Hetu10c74a62017-11-29 14:00:32 -05001396 RectF sRect = sourceRect;
Nicolas Capens10b295c2015-03-28 18:57:56 -04001397 if(destRect.x0 > destRect.x1)
1398 {
1399 swap(dRect.x0, dRect.x1);
1400 swap(sRect.x0, sRect.x1);
1401 }
1402 if(destRect.y0 > destRect.y1)
1403 {
1404 swap(dRect.y0, dRect.y1);
1405 swap(sRect.y0, sRect.y1);
Alexis Hetue9233fb2015-02-11 10:31:58 -05001406 }
1407
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001408 State state(options);
Alexis Hetu73771b12017-12-19 15:37:46 -05001409 state.clampToEdge = (sourceRect.x0 < 0.0f) ||
1410 (sourceRect.y0 < 0.0f) ||
1411 (sourceRect.x1 > (float)source->getWidth()) ||
1412 (sourceRect.y1 > (float)source->getHeight());
John Bauman89401822014-05-06 15:04:28 -04001413
Nicolas Capens9eb87992015-06-10 13:52:24 -04001414 bool useSourceInternal = !source->isExternalDirty();
1415 bool useDestInternal = !dest->isExternalDirty();
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001416 bool isStencil = options.useStencil;
Nicolas Capens9eb87992015-06-10 13:52:24 -04001417
Alexis Hetub9dda642016-10-06 11:25:32 -04001418 state.sourceFormat = isStencil ? source->getStencilFormat() : source->getFormat(useSourceInternal);
1419 state.destFormat = isStencil ? dest->getStencilFormat() : dest->getFormat(useDestInternal);
Nicolas Capensbfa23b32017-12-11 10:06:37 -05001420 state.destSamples = dest->getSamples();
John Bauman89401822014-05-06 15:04:28 -04001421
Nicolas Capens20c6f342015-06-10 11:06:16 -04001422 criticalSection.lock();
Ben Clayton6897e9b2019-07-16 17:27:27 +01001423 auto blitRoutine = blitCache->query(state);
Nicolas Capens81f18302016-01-14 09:32:35 -05001424
John Bauman89401822014-05-06 15:04:28 -04001425 if(!blitRoutine)
1426 {
Nicolas Capens130c27a2015-06-10 11:03:20 -04001427 blitRoutine = generate(state);
1428
1429 if(!blitRoutine)
John Bauman89401822014-05-06 15:04:28 -04001430 {
Nicolas Capens20c6f342015-06-10 11:06:16 -04001431 criticalSection.unlock();
Nicolas Capens130c27a2015-06-10 11:03:20 -04001432 return false;
John Bauman89401822014-05-06 15:04:28 -04001433 }
1434
John Bauman89401822014-05-06 15:04:28 -04001435 blitCache->add(state, blitRoutine);
1436 }
1437
Nicolas Capens20c6f342015-06-10 11:06:16 -04001438 criticalSection.unlock();
1439
John Bauman66b8ab22014-05-06 15:57:45 -04001440 void (*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -04001441
1442 BlitData data;
1443
Nicolas Capens8f7739a2017-12-16 02:06:56 -05001444 bool isRGBA = options.writeMask == 0xF;
Alexis Hetu75b650f2015-11-19 17:40:15 -05001445 bool isEntireDest = dest->isEntire(destRect);
1446
Alexis Hetub9dda642016-10-06 11:25:32 -04001447 data.source = isStencil ? source->lockStencil(0, 0, 0, sw::PUBLIC) :
1448 source->lock(0, 0, sourceRect.slice, sw::LOCK_READONLY, sw::PUBLIC, useSourceInternal);
1449 data.dest = isStencil ? dest->lockStencil(0, 0, 0, sw::PUBLIC) :
1450 dest->lock(0, 0, destRect.slice, isRGBA ? (isEntireDest ? sw::LOCK_DISCARD : sw::LOCK_WRITEONLY) : sw::LOCK_READWRITE, sw::PUBLIC, useDestInternal);
1451 data.sPitchB = isStencil ? source->getStencilPitchB() : source->getPitchB(useSourceInternal);
1452 data.dPitchB = isStencil ? dest->getStencilPitchB() : dest->getPitchB(useDestInternal);
Nicolas Capensbfa23b32017-12-11 10:06:37 -05001453 data.dSliceB = isStencil ? dest->getStencilSliceB() : dest->getSliceB(useDestInternal);
John Bauman89401822014-05-06 15:04:28 -04001454
Alexis Hetu10c74a62017-11-29 14:00:32 -05001455 data.w = sRect.width() / dRect.width();
1456 data.h = sRect.height() / dRect.height();
Nicolas Capensae3d8752018-06-01 10:39:50 -04001457 data.x0 = sRect.x0 + (0.5f - dRect.x0) * data.w;
1458 data.y0 = sRect.y0 + (0.5f - dRect.y0) * data.h;
Nicolas Capens81f18302016-01-14 09:32:35 -05001459
John Bauman19bac1e2014-05-06 15:23:49 -04001460 data.x0d = dRect.x0;
1461 data.x1d = dRect.x1;
1462 data.y0d = dRect.y0;
1463 data.y1d = dRect.y1;
John Bauman89401822014-05-06 15:04:28 -04001464
Nicolas Capens3779ea92015-06-10 13:43:52 -04001465 data.sWidth = source->getWidth();
1466 data.sHeight = source->getHeight();
John Bauman89401822014-05-06 15:04:28 -04001467
1468 blitFunction(&data);
1469
Alexis Hetub9dda642016-10-06 11:25:32 -04001470 if(isStencil)
1471 {
1472 source->unlockStencil();
1473 dest->unlockStencil();
1474 }
1475 else
1476 {
1477 source->unlock(useSourceInternal);
1478 dest->unlock(useDestInternal);
1479 }
John Bauman89401822014-05-06 15:04:28 -04001480
1481 return true;
1482 }
1483}