Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/swiftshader/src/Renderer/Blitter.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2
//
3
// 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
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// 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.
14
15
#include "Blitter.hpp"
16
17
#include "Shader/ShaderCore.hpp"
18
#include "Reactor/Reactor.hpp"
19
#include "Common/Memory.hpp"
20
#include "Common/Debug.hpp"
21
22
namespace sw
23
{
24
  using namespace rr;
25
26
  Blitter::Blitter()
27
0
  {
28
0
    blitCache = new RoutineCache<State>(1024);
29
0
  }
30
31
  Blitter::~Blitter()
32
0
  {
33
0
    delete blitCache;
34
0
  }
35
36
  void Blitter::clear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
37
0
  {
38
0
    if(fastClear(pixel, format, dest, dRect, rgbaMask))
39
0
    {
40
0
      return;
41
0
    }
42
43
0
    sw::Surface *color = sw::Surface::create(1, 1, 1, format, pixel, sw::Surface::bytes(format), sw::Surface::bytes(format));
44
0
    SliceRectF sRect(0.5f, 0.5f, 0.5f, 0.5f, 0);   // Sample from the middle.
45
0
    blit(color, sRect, dest, dRect, {rgbaMask});
46
0
    delete color;
47
0
  }
48
49
  bool Blitter::fastClear(void *pixel, sw::Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
50
0
  {
51
0
    if(format != FORMAT_A32B32G32R32F)
52
0
    {
53
0
      return false;
54
0
    }
55
56
0
    float *color = (float*)pixel;
57
0
    float r = color[0];
58
0
    float g = color[1];
59
0
    float b = color[2];
60
0
    float a = color[3];
61
62
0
    uint32_t packed;
63
64
0
    switch(dest->getFormat())
65
0
    {
66
0
    case FORMAT_R5G6B5:
67
0
      if((rgbaMask & 0x7) != 0x7) return false;
68
0
      packed = ((uint16_t)(31 * b + 0.5f) << 0) |
69
0
               ((uint16_t)(63 * g + 0.5f) << 5) |
70
0
               ((uint16_t)(31 * r + 0.5f) << 11);
71
0
      break;
72
0
    case FORMAT_X8B8G8R8:
73
0
      if((rgbaMask & 0x7) != 0x7) return false;
74
0
      packed = ((uint32_t)(255) << 24) |
75
0
               ((uint32_t)(255 * b + 0.5f) << 16) |
76
0
               ((uint32_t)(255 * g + 0.5f) << 8) |
77
0
               ((uint32_t)(255 * r + 0.5f) << 0);
78
0
      break;
79
0
    case FORMAT_A8B8G8R8:
80
0
      if((rgbaMask & 0xF) != 0xF) return false;
81
0
      packed = ((uint32_t)(255 * a + 0.5f) << 24) |
82
0
               ((uint32_t)(255 * b + 0.5f) << 16) |
83
0
               ((uint32_t)(255 * g + 0.5f) << 8) |
84
0
               ((uint32_t)(255 * r + 0.5f) << 0);
85
0
      break;
86
0
    case FORMAT_X8R8G8B8:
87
0
      if((rgbaMask & 0x7) != 0x7) return false;
88
0
      packed = ((uint32_t)(255) << 24) |
89
0
               ((uint32_t)(255 * r + 0.5f) << 16) |
90
0
               ((uint32_t)(255 * g + 0.5f) << 8) |
91
0
               ((uint32_t)(255 * b + 0.5f) << 0);
92
0
      break;
93
0
    case FORMAT_A8R8G8B8:
94
0
      if((rgbaMask & 0xF) != 0xF) return false;
95
0
      packed = ((uint32_t)(255 * a + 0.5f) << 24) |
96
0
               ((uint32_t)(255 * r + 0.5f) << 16) |
97
0
               ((uint32_t)(255 * g + 0.5f) << 8) |
98
0
               ((uint32_t)(255 * b + 0.5f) << 0);
99
0
      break;
100
0
    default:
101
0
      return false;
102
0
    }
103
104
0
    bool useDestInternal = !dest->isExternalDirty();
105
0
    uint8_t *slice = (uint8_t*)dest->lock(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC, useDestInternal);
106
107
0
    for(int j = 0; j < dest->getSamples(); j++)
108
0
    {
109
0
      uint8_t *d = slice;
110
111
0
      switch(Surface::bytes(dest->getFormat()))
112
0
      {
113
0
      case 2:
114
0
        for(int i = dRect.y0; i < dRect.y1; i++)
115
0
        {
116
0
          sw::clear((uint16_t*)d, packed, dRect.x1 - dRect.x0);
117
0
          d += dest->getPitchB(useDestInternal);
118
0
        }
119
0
        break;
120
0
      case 4:
121
0
        for(int i = dRect.y0; i < dRect.y1; i++)
122
0
        {
123
0
          sw::clear((uint32_t*)d, packed, dRect.x1 - dRect.x0);
124
0
          d += dest->getPitchB(useDestInternal);
125
0
        }
126
0
        break;
127
0
      default:
128
0
        assert(false);
129
0
      }
130
131
0
      slice += dest->getSliceB(useDestInternal);
132
0
    }
133
134
0
    dest->unlock(useDestInternal);
135
136
0
    return true;
137
0
  }
138
139
  void Blitter::blit(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options& options)
140
0
  {
141
0
    if(dest->getInternalFormat() == FORMAT_NULL)
142
0
    {
143
0
      return;
144
0
    }
145
146
0
    if(blitReactor(source, sourceRect, dest, destRect, options))
147
0
    {
148
0
      return;
149
0
    }
150
151
0
    SliceRectF sRect = sourceRect;
152
0
    SliceRect dRect = destRect;
153
154
0
    bool flipX = destRect.x0 > destRect.x1;
155
0
    bool flipY = destRect.y0 > destRect.y1;
156
157
0
    if(flipX)
158
0
    {
159
0
      swap(dRect.x0, dRect.x1);
160
0
      swap(sRect.x0, sRect.x1);
161
0
    }
162
0
    if(flipY)
163
0
    {
164
0
      swap(dRect.y0, dRect.y1);
165
0
      swap(sRect.y0, sRect.y1);
166
0
    }
167
168
0
    source->lockInternal(0, 0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
169
0
    dest->lockInternal(0, 0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
170
171
0
    float w = sRect.width() / dRect.width();
172
0
    float h = sRect.height() / dRect.height();
173
174
0
    float xStart = sRect.x0 + (0.5f - dRect.x0) * w;
175
0
    float yStart = sRect.y0 + (0.5f - dRect.y0) * h;
176
177
0
    for(int j = dRect.y0; j < dRect.y1; j++)
178
0
    {
179
0
      float y = yStart + j * h;
180
181
0
      for(int i = dRect.x0; i < dRect.x1; i++)
182
0
      {
183
0
        float x = xStart + i * w;
184
185
        // FIXME: Support RGBA mask
186
0
        dest->copyInternal(source, i, j, x, y, options.filter);
187
0
      }
188
0
    }
189
190
0
    source->unlockInternal();
191
0
    dest->unlockInternal();
192
0
  }
193
194
  void Blitter::blit3D(Surface *source, Surface *dest)
195
0
  {
196
0
    source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
197
0
    dest->lockInternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC);
198
199
0
    float w = static_cast<float>(source->getWidth())  / static_cast<float>(dest->getWidth());
200
0
    float h = static_cast<float>(source->getHeight()) / static_cast<float>(dest->getHeight());
201
0
    float d = static_cast<float>(source->getDepth())  / static_cast<float>(dest->getDepth());
202
203
0
    for(int k = 0; k < dest->getDepth(); k++)
204
0
    {
205
0
      float z = (k + 0.5f) * d;
206
207
0
      for(int j = 0; j < dest->getHeight(); j++)
208
0
      {
209
0
        float y = (j + 0.5f) * h;
210
211
0
        for(int i = 0; i < dest->getWidth(); i++)
212
0
        {
213
0
          float x = (i + 0.5f) * w;
214
215
0
          dest->copyInternal(source, i, j, k, x, y, z, true);
216
0
        }
217
0
      }
218
0
    }
219
220
0
    source->unlockInternal();
221
0
    dest->unlockInternal();
222
0
  }
223
224
  bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
225
0
  {
226
0
    c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
227
228
0
    switch(state.sourceFormat)
229
0
    {
230
0
    case FORMAT_L8:
231
0
      c.xyz = Float(Int(*Pointer<Byte>(element)));
232
0
      c.w = float(0xFF);
233
0
      break;
234
0
    case FORMAT_A8:
235
0
      c.w = Float(Int(*Pointer<Byte>(element)));
236
0
      break;
237
0
    case FORMAT_R8I:
238
0
    case FORMAT_R8_SNORM:
239
0
      c.x = Float(Int(*Pointer<SByte>(element)));
240
0
      c.w = float(0x7F);
241
0
      break;
242
0
    case FORMAT_R8:
243
0
    case FORMAT_R8UI:
244
0
      c.x = Float(Int(*Pointer<Byte>(element)));
245
0
      c.w = float(0xFF);
246
0
      break;
247
0
    case FORMAT_R16I:
248
0
      c.x = Float(Int(*Pointer<Short>(element)));
249
0
      c.w = float(0x7FFF);
250
0
      break;
251
0
    case FORMAT_R16UI:
252
0
      c.x = Float(Int(*Pointer<UShort>(element)));
253
0
      c.w = float(0xFFFF);
254
0
      break;
255
0
    case FORMAT_R32I:
256
0
      c.x = Float(*Pointer<Int>(element));
257
0
      c.w = float(0x7FFFFFFF);
258
0
      break;
259
0
    case FORMAT_R32UI:
260
0
      c.x = Float(*Pointer<UInt>(element));
261
0
      c.w = float(0xFFFFFFFF);
262
0
      break;
263
0
    case FORMAT_A8R8G8B8:
264
0
      c = Float4(*Pointer<Byte4>(element)).zyxw;
265
0
      break;
266
0
    case FORMAT_A8B8G8R8I:
267
0
    case FORMAT_A8B8G8R8_SNORM:
268
0
      c = Float4(*Pointer<SByte4>(element));
269
0
      break;
270
0
    case FORMAT_A8B8G8R8:
271
0
    case FORMAT_A8B8G8R8UI:
272
0
    case FORMAT_SRGB8_A8:
273
0
      c = Float4(*Pointer<Byte4>(element));
274
0
      break;
275
0
    case FORMAT_X8R8G8B8:
276
0
      c = Float4(*Pointer<Byte4>(element)).zyxw;
277
0
      c.w = float(0xFF);
278
0
      break;
279
0
    case FORMAT_R8G8B8:
280
0
      c.z = Float(Int(*Pointer<Byte>(element + 0)));
281
0
      c.y = Float(Int(*Pointer<Byte>(element + 1)));
282
0
      c.x = Float(Int(*Pointer<Byte>(element + 2)));
283
0
      c.w = float(0xFF);
284
0
      break;
285
0
    case FORMAT_B8G8R8:
286
0
      c.x = Float(Int(*Pointer<Byte>(element + 0)));
287
0
      c.y = Float(Int(*Pointer<Byte>(element + 1)));
288
0
      c.z = Float(Int(*Pointer<Byte>(element + 2)));
289
0
      c.w = float(0xFF);
290
0
      break;
291
0
    case FORMAT_X8B8G8R8I:
292
0
    case FORMAT_X8B8G8R8_SNORM:
293
0
      c = Float4(*Pointer<SByte4>(element));
294
0
      c.w = float(0x7F);
295
0
      break;
296
0
    case FORMAT_X8B8G8R8:
297
0
    case FORMAT_X8B8G8R8UI:
298
0
    case FORMAT_SRGB8_X8:
299
0
      c = Float4(*Pointer<Byte4>(element));
300
0
      c.w = float(0xFF);
301
0
      break;
302
0
    case FORMAT_A16B16G16R16I:
303
0
      c = Float4(*Pointer<Short4>(element));
304
0
      break;
305
0
    case FORMAT_A16B16G16R16:
306
0
    case FORMAT_A16B16G16R16UI:
307
0
      c = Float4(*Pointer<UShort4>(element));
308
0
      break;
309
0
    case FORMAT_X16B16G16R16I:
310
0
      c = Float4(*Pointer<Short4>(element));
311
0
      c.w = float(0x7FFF);
312
0
      break;
313
0
    case FORMAT_X16B16G16R16UI:
314
0
      c = Float4(*Pointer<UShort4>(element));
315
0
      c.w = float(0xFFFF);
316
0
      break;
317
0
    case FORMAT_A32B32G32R32I:
318
0
      c = Float4(*Pointer<Int4>(element));
319
0
      break;
320
0
    case FORMAT_A32B32G32R32UI:
321
0
      c = Float4(*Pointer<UInt4>(element));
322
0
      break;
323
0
    case FORMAT_X32B32G32R32I:
324
0
      c = Float4(*Pointer<Int4>(element));
325
0
      c.w = float(0x7FFFFFFF);
326
0
      break;
327
0
    case FORMAT_X32B32G32R32UI:
328
0
      c = Float4(*Pointer<UInt4>(element));
329
0
      c.w = float(0xFFFFFFFF);
330
0
      break;
331
0
    case FORMAT_G8R8I:
332
0
    case FORMAT_G8R8_SNORM:
333
0
      c.x = Float(Int(*Pointer<SByte>(element + 0)));
334
0
      c.y = Float(Int(*Pointer<SByte>(element + 1)));
335
0
      c.w = float(0x7F);
336
0
      break;
337
0
    case FORMAT_G8R8:
338
0
    case FORMAT_G8R8UI:
339
0
      c.x = Float(Int(*Pointer<Byte>(element + 0)));
340
0
      c.y = Float(Int(*Pointer<Byte>(element + 1)));
341
0
      c.w = float(0xFF);
342
0
      break;
343
0
    case FORMAT_G16R16I:
344
0
      c.x = Float(Int(*Pointer<Short>(element + 0)));
345
0
      c.y = Float(Int(*Pointer<Short>(element + 2)));
346
0
      c.w = float(0x7FFF);
347
0
      break;
348
0
    case FORMAT_G16R16:
349
0
    case FORMAT_G16R16UI:
350
0
      c.x = Float(Int(*Pointer<UShort>(element + 0)));
351
0
      c.y = Float(Int(*Pointer<UShort>(element + 2)));
352
0
      c.w = float(0xFFFF);
353
0
      break;
354
0
    case FORMAT_G32R32I:
355
0
      c.x = Float(*Pointer<Int>(element + 0));
356
0
      c.y = Float(*Pointer<Int>(element + 4));
357
0
      c.w = float(0x7FFFFFFF);
358
0
      break;
359
0
    case FORMAT_G32R32UI:
360
0
      c.x = Float(*Pointer<UInt>(element + 0));
361
0
      c.y = Float(*Pointer<UInt>(element + 4));
362
0
      c.w = float(0xFFFFFFFF);
363
0
      break;
364
0
    case FORMAT_A32B32G32R32F:
365
0
      c = *Pointer<Float4>(element);
366
0
      break;
367
0
    case FORMAT_X32B32G32R32F:
368
0
    case FORMAT_X32B32G32R32F_UNSIGNED:
369
0
    case FORMAT_B32G32R32F:
370
0
      c.z = *Pointer<Float>(element + 8);
371
0
    case FORMAT_G32R32F:
372
0
      c.x = *Pointer<Float>(element + 0);
373
0
      c.y = *Pointer<Float>(element + 4);
374
0
      break;
375
0
    case FORMAT_R32F:
376
0
      c.x = *Pointer<Float>(element);
377
0
      break;
378
0
    case FORMAT_R5G6B5:
379
0
      c.x = Float(Int((*Pointer<UShort>(element) & UShort(0xF800)) >> UShort(11)));
380
0
      c.y = Float(Int((*Pointer<UShort>(element) & UShort(0x07E0)) >> UShort(5)));
381
0
      c.z = Float(Int(*Pointer<UShort>(element) & UShort(0x001F)));
382
0
      break;
383
0
    case FORMAT_A2B10G10R10:
384
0
    case FORMAT_A2B10G10R10UI:
385
0
      c.x = Float(Int((*Pointer<UInt>(element) & UInt(0x000003FF))));
386
0
      c.y = Float(Int((*Pointer<UInt>(element) & UInt(0x000FFC00)) >> 10));
387
0
      c.z = Float(Int((*Pointer<UInt>(element) & UInt(0x3FF00000)) >> 20));
388
0
      c.w = Float(Int((*Pointer<UInt>(element) & UInt(0xC0000000)) >> 30));
389
0
      break;
390
0
    case FORMAT_D16:
391
0
      c.x = Float(Int((*Pointer<UShort>(element))));
392
0
      break;
393
0
    case FORMAT_D24S8:
394
0
    case FORMAT_D24X8:
395
0
      c.x = Float(Int((*Pointer<UInt>(element) & UInt(0xFFFFFF00)) >> 8));
396
0
      break;
397
0
    case FORMAT_D32:
398
0
      c.x = Float(Int((*Pointer<UInt>(element))));
399
0
      break;
400
0
    case FORMAT_D32F_COMPLEMENTARY:
401
0
    case FORMAT_D32FS8_COMPLEMENTARY:
402
0
      c.x = 1.0f - *Pointer<Float>(element);
403
0
      break;
404
0
    case FORMAT_D32F:
405
0
    case FORMAT_D32FS8:
406
0
    case FORMAT_D32F_LOCKABLE:
407
0
    case FORMAT_D32FS8_TEXTURE:
408
0
    case FORMAT_D32F_SHADOW:
409
0
    case FORMAT_D32FS8_SHADOW:
410
0
      c.x = *Pointer<Float>(element);
411
0
      break;
412
0
    case FORMAT_S8:
413
0
      c.x = Float(Int(*Pointer<Byte>(element)));
414
0
      break;
415
0
    default:
416
0
      return false;
417
0
    }
418
419
0
    return true;
420
0
  }
421
422
  bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
423
0
  {
424
0
    bool writeR = state.writeRed;
425
0
    bool writeG = state.writeGreen;
426
0
    bool writeB = state.writeBlue;
427
0
    bool writeA = state.writeAlpha;
428
0
    bool writeRGBA = writeR && writeG && writeB && writeA;
429
430
0
    switch(state.destFormat)
431
0
    {
432
0
    case FORMAT_L8:
433
0
      *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
434
0
      break;
435
0
    case FORMAT_A8:
436
0
      if(writeA) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.w))); }
437
0
      break;
438
0
    case FORMAT_A8R8G8B8:
439
0
      if(writeRGBA)
440
0
      {
441
0
        Short4 c0 = RoundShort4(c.zyxw);
442
0
        *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
443
0
      }
444
0
      else
445
0
      {
446
0
        if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
447
0
        if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
448
0
        if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
449
0
        if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
450
0
      }
451
0
      break;
452
0
    case FORMAT_A8B8G8R8:
453
0
    case FORMAT_SRGB8_A8:
454
0
      if(writeRGBA)
455
0
      {
456
0
        Short4 c0 = RoundShort4(c);
457
0
        *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
458
0
      }
459
0
      else
460
0
      {
461
0
        if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
462
0
        if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
463
0
        if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
464
0
        if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
465
0
      }
466
0
      break;
467
0
    case FORMAT_X8R8G8B8:
468
0
      if(writeRGBA)
469
0
      {
470
0
        Short4 c0 = RoundShort4(c.zyxw) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
471
0
        *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
472
0
      }
473
0
      else
474
0
      {
475
0
        if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
476
0
        if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
477
0
        if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
478
0
        if(writeA) { *Pointer<Byte>(element + 3) = Byte(0xFF); }
479
0
      }
480
0
      break;
481
0
    case FORMAT_X8B8G8R8:
482
0
    case FORMAT_SRGB8_X8:
483
0
      if(writeRGBA)
484
0
      {
485
0
        Short4 c0 = RoundShort4(c) | Short4(0x0000, 0x0000, 0x0000, 0x00FF);
486
0
        *Pointer<Byte4>(element) = Byte4(PackUnsigned(c0, c0));
487
0
      }
488
0
      else
489
0
      {
490
0
        if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
491
0
        if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
492
0
        if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
493
0
        if(writeA) { *Pointer<Byte>(element + 3) = Byte(0xFF); }
494
0
      }
495
0
      break;
496
0
    case FORMAT_R8G8B8:
497
0
      if(writeR) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.x))); }
498
0
      if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
499
0
      if(writeB) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.z))); }
500
0
      break;
501
0
    case FORMAT_B8G8R8:
502
0
      if(writeR) { *Pointer<Byte>(element + 0) = Byte(RoundInt(Float(c.x))); }
503
0
      if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
504
0
      if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
505
0
      break;
506
0
    case FORMAT_A32B32G32R32F:
507
0
      if(writeRGBA)
508
0
      {
509
0
        *Pointer<Float4>(element) = c;
510
0
      }
511
0
      else
512
0
      {
513
0
        if(writeR) { *Pointer<Float>(element) = c.x; }
514
0
        if(writeG) { *Pointer<Float>(element + 4) = c.y; }
515
0
        if(writeB) { *Pointer<Float>(element + 8) = c.z; }
516
0
        if(writeA) { *Pointer<Float>(element + 12) = c.w; }
517
0
      }
518
0
      break;
519
0
    case FORMAT_X32B32G32R32F:
520
0
    case FORMAT_X32B32G32R32F_UNSIGNED:
521
0
      if(writeA) { *Pointer<Float>(element + 12) = 1.0f; }
522
0
    case FORMAT_B32G32R32F:
523
0
      if(writeR) { *Pointer<Float>(element) = c.x; }
524
0
      if(writeG) { *Pointer<Float>(element + 4) = c.y; }
525
0
      if(writeB) { *Pointer<Float>(element + 8) = c.z; }
526
0
      break;
527
0
    case FORMAT_G32R32F:
528
0
      if(writeR && writeG)
529
0
      {
530
0
        *Pointer<Float2>(element) = Float2(c);
531
0
      }
532
0
      else
533
0
      {
534
0
        if(writeR) { *Pointer<Float>(element) = c.x; }
535
0
        if(writeG) { *Pointer<Float>(element + 4) = c.y; }
536
0
      }
537
0
      break;
538
0
    case FORMAT_R32F:
539
0
      if(writeR) { *Pointer<Float>(element) = c.x; }
540
0
      break;
541
0
    case FORMAT_A8B8G8R8I:
542
0
    case FORMAT_A8B8G8R8_SNORM:
543
0
      if(writeA) { *Pointer<SByte>(element + 3) = SByte(RoundInt(Float(c.w))); }
544
0
    case FORMAT_X8B8G8R8I:
545
0
    case FORMAT_X8B8G8R8_SNORM:
546
0
      if(writeA && (state.destFormat == FORMAT_X8B8G8R8I || state.destFormat == FORMAT_X8B8G8R8_SNORM))
547
0
      {
548
0
        *Pointer<SByte>(element + 3) = SByte(0x7F);
549
0
      }
550
0
      if(writeB) { *Pointer<SByte>(element + 2) = SByte(RoundInt(Float(c.z))); }
551
0
    case FORMAT_G8R8I:
552
0
    case FORMAT_G8R8_SNORM:
553
0
      if(writeG) { *Pointer<SByte>(element + 1) = SByte(RoundInt(Float(c.y))); }
554
0
    case FORMAT_R8I:
555
0
    case FORMAT_R8_SNORM:
556
0
      if(writeR) { *Pointer<SByte>(element) = SByte(RoundInt(Float(c.x))); }
557
0
      break;
558
0
    case FORMAT_A8B8G8R8UI:
559
0
      if(writeA) { *Pointer<Byte>(element + 3) = Byte(RoundInt(Float(c.w))); }
560
0
    case FORMAT_X8B8G8R8UI:
561
0
      if(writeA && (state.destFormat == FORMAT_X8B8G8R8UI))
562
0
      {
563
0
        *Pointer<Byte>(element + 3) = Byte(0xFF);
564
0
      }
565
0
      if(writeB) { *Pointer<Byte>(element + 2) = Byte(RoundInt(Float(c.z))); }
566
0
    case FORMAT_G8R8UI:
567
0
    case FORMAT_G8R8:
568
0
      if(writeG) { *Pointer<Byte>(element + 1) = Byte(RoundInt(Float(c.y))); }
569
0
    case FORMAT_R8UI:
570
0
    case FORMAT_R8:
571
0
      if(writeR) { *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x))); }
572
0
      break;
573
0
    case FORMAT_A16B16G16R16I:
574
0
      if(writeRGBA)
575
0
      {
576
0
        *Pointer<Short4>(element) = Short4(RoundInt(c));
577
0
      }
578
0
      else
579
0
      {
580
0
        if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
581
0
        if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
582
0
        if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
583
0
        if(writeA) { *Pointer<Short>(element + 6) = Short(RoundInt(Float(c.w))); }
584
0
      }
585
0
      break;
586
0
    case FORMAT_X16B16G16R16I:
587
0
      if(writeRGBA)
588
0
      {
589
0
        *Pointer<Short4>(element) = Short4(RoundInt(c));
590
0
      }
591
0
      else
592
0
      {
593
0
        if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
594
0
        if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
595
0
        if(writeB) { *Pointer<Short>(element + 4) = Short(RoundInt(Float(c.z))); }
596
0
      }
597
0
      if(writeA) { *Pointer<Short>(element + 6) = Short(0x7F); }
598
0
      break;
599
0
    case FORMAT_G16R16I:
600
0
      if(writeR && writeG)
601
0
      {
602
0
        *Pointer<Short2>(element) = Short2(Short4(RoundInt(c)));
603
0
      }
604
0
      else
605
0
      {
606
0
        if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
607
0
        if(writeG) { *Pointer<Short>(element + 2) = Short(RoundInt(Float(c.y))); }
608
0
      }
609
0
      break;
610
0
    case FORMAT_R16I:
611
0
      if(writeR) { *Pointer<Short>(element) = Short(RoundInt(Float(c.x))); }
612
0
      break;
613
0
    case FORMAT_A16B16G16R16UI:
614
0
    case FORMAT_A16B16G16R16:
615
0
      if(writeRGBA)
616
0
      {
617
0
        *Pointer<UShort4>(element) = UShort4(RoundInt(c));
618
0
      }
619
0
      else
620
0
      {
621
0
        if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
622
0
        if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
623
0
        if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
624
0
        if(writeA) { *Pointer<UShort>(element + 6) = UShort(RoundInt(Float(c.w))); }
625
0
      }
626
0
      break;
627
0
    case FORMAT_X16B16G16R16UI:
628
0
      if(writeRGBA)
629
0
      {
630
0
        *Pointer<UShort4>(element) = UShort4(RoundInt(c));
631
0
      }
632
0
      else
633
0
      {
634
0
        if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
635
0
        if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
636
0
        if(writeB) { *Pointer<UShort>(element + 4) = UShort(RoundInt(Float(c.z))); }
637
0
      }
638
0
      if(writeA) { *Pointer<UShort>(element + 6) = UShort(0xFF); }
639
0
      break;
640
0
    case FORMAT_G16R16UI:
641
0
    case FORMAT_G16R16:
642
0
      if(writeR && writeG)
643
0
      {
644
0
        *Pointer<UShort2>(element) = UShort2(UShort4(RoundInt(c)));
645
0
      }
646
0
      else
647
0
      {
648
0
        if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
649
0
        if(writeG) { *Pointer<UShort>(element + 2) = UShort(RoundInt(Float(c.y))); }
650
0
      }
651
0
      break;
652
0
    case FORMAT_R16UI:
653
0
      if(writeR) { *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x))); }
654
0
      break;
655
0
    case FORMAT_A32B32G32R32I:
656
0
      if(writeRGBA)
657
0
      {
658
0
        *Pointer<Int4>(element) = RoundInt(c);
659
0
      }
660
0
      else
661
0
      {
662
0
        if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
663
0
        if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
664
0
        if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
665
0
        if(writeA) { *Pointer<Int>(element + 12) = RoundInt(Float(c.w)); }
666
0
      }
667
0
      break;
668
0
    case FORMAT_X32B32G32R32I:
669
0
      if(writeRGBA)
670
0
      {
671
0
        *Pointer<Int4>(element) = RoundInt(c);
672
0
      }
673
0
      else
674
0
      {
675
0
        if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
676
0
        if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
677
0
        if(writeB) { *Pointer<Int>(element + 8) = RoundInt(Float(c.z)); }
678
0
      }
679
0
      if(writeA) { *Pointer<Int>(element + 12) = Int(0x7FFFFFFF); }
680
0
      break;
681
0
    case FORMAT_G32R32I:
682
0
      if(writeG) { *Pointer<Int>(element + 4) = RoundInt(Float(c.y)); }
683
0
    case FORMAT_R32I:
684
0
      if(writeR) { *Pointer<Int>(element) = RoundInt(Float(c.x)); }
685
0
      break;
686
0
    case FORMAT_A32B32G32R32UI:
687
0
      if(writeRGBA)
688
0
      {
689
0
        *Pointer<UInt4>(element) = UInt4(RoundInt(c));
690
0
      }
691
0
      else
692
0
      {
693
0
        if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
694
0
        if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
695
0
        if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
696
0
        if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(RoundInt(Float(c.w))); }
697
0
      }
698
0
      break;
699
0
    case FORMAT_X32B32G32R32UI:
700
0
      if(writeRGBA)
701
0
      {
702
0
        *Pointer<UInt4>(element) = UInt4(RoundInt(c));
703
0
      }
704
0
      else
705
0
      {
706
0
        if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
707
0
        if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
708
0
        if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(RoundInt(Float(c.z))); }
709
0
      }
710
0
      if(writeA) { *Pointer<UInt4>(element + 12) = UInt4(0xFFFFFFFF); }
711
0
      break;
712
0
    case FORMAT_G32R32UI:
713
0
      if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(RoundInt(Float(c.y))); }
714
0
    case FORMAT_R32UI:
715
0
      if(writeR) { *Pointer<UInt>(element) = As<UInt>(RoundInt(Float(c.x))); }
716
0
      break;
717
0
    case FORMAT_R5G6B5:
718
0
      if(writeR && writeG && writeB)
719
0
      {
720
0
        *Pointer<UShort>(element) = UShort(RoundInt(Float(c.z)) |
721
0
                                          (RoundInt(Float(c.y)) << Int(5)) |
722
0
                                          (RoundInt(Float(c.x)) << Int(11)));
723
0
      }
724
0
      else
725
0
      {
726
0
        unsigned short mask = (writeB ? 0x001F : 0x0000) | (writeG ? 0x07E0 : 0x0000) | (writeR ? 0xF800 : 0x0000);
727
0
        unsigned short unmask = ~mask;
728
0
        *Pointer<UShort>(element) = (*Pointer<UShort>(element) & UShort(unmask)) |
729
0
                                    (UShort(RoundInt(Float(c.z)) |
730
0
                                           (RoundInt(Float(c.y)) << Int(5)) |
731
0
                                           (RoundInt(Float(c.x)) << Int(11))) & UShort(mask));
732
0
      }
733
0
      break;
734
0
    case FORMAT_A2B10G10R10:
735
0
    case FORMAT_A2B10G10R10UI:
736
0
      if(writeRGBA)
737
0
      {
738
0
        *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) |
739
0
                                      (RoundInt(Float(c.y)) << 10) |
740
0
                                      (RoundInt(Float(c.z)) << 20) |
741
0
                                      (RoundInt(Float(c.w)) << 30));
742
0
      }
743
0
      else
744
0
      {
745
0
        unsigned int mask = (writeA ? 0xC0000000 : 0x0000) |
746
0
                            (writeB ? 0x3FF00000 : 0x0000) |
747
0
                            (writeG ? 0x000FFC00 : 0x0000) |
748
0
                            (writeR ? 0x000003FF : 0x0000);
749
0
        unsigned int unmask = ~mask;
750
0
        *Pointer<UInt>(element) = (*Pointer<UInt>(element) & UInt(unmask)) |
751
0
                                    (UInt(RoundInt(Float(c.x)) |
752
0
                                          (RoundInt(Float(c.y)) << 10) |
753
0
                                          (RoundInt(Float(c.z)) << 20) |
754
0
                                          (RoundInt(Float(c.w)) << 30)) & UInt(mask));
755
0
      }
756
0
      break;
757
0
    case FORMAT_D16:
758
0
      *Pointer<UShort>(element) = UShort(RoundInt(Float(c.x)));
759
0
      break;
760
0
    case FORMAT_D24S8:
761
0
    case FORMAT_D24X8:
762
0
      *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)) << 8);
763
0
      break;
764
0
    case FORMAT_D32:
765
0
      *Pointer<UInt>(element) = UInt(RoundInt(Float(c.x)));
766
0
      break;
767
0
    case FORMAT_D32F_COMPLEMENTARY:
768
0
    case FORMAT_D32FS8_COMPLEMENTARY:
769
0
      *Pointer<Float>(element) = 1.0f - c.x;
770
0
      break;
771
0
    case FORMAT_D32F:
772
0
    case FORMAT_D32FS8:
773
0
    case FORMAT_D32F_LOCKABLE:
774
0
    case FORMAT_D32FS8_TEXTURE:
775
0
    case FORMAT_D32F_SHADOW:
776
0
    case FORMAT_D32FS8_SHADOW:
777
0
      *Pointer<Float>(element) = c.x;
778
0
      break;
779
0
    case FORMAT_S8:
780
0
      *Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
781
0
      break;
782
0
    default:
783
0
      return false;
784
0
    }
785
0
    return true;
786
0
  }
787
788
  bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
789
0
  {
790
0
    c = Int4(0, 0, 0, 1);
791
792
0
    switch(state.sourceFormat)
793
0
    {
794
0
    case FORMAT_A8B8G8R8I:
795
0
      c = Insert(c, Int(*Pointer<SByte>(element + 3)), 3);
796
0
    case FORMAT_X8B8G8R8I:
797
0
      c = Insert(c, Int(*Pointer<SByte>(element + 2)), 2);
798
0
    case FORMAT_G8R8I:
799
0
      c = Insert(c, Int(*Pointer<SByte>(element + 1)), 1);
800
0
    case FORMAT_R8I:
801
0
      c = Insert(c, Int(*Pointer<SByte>(element)), 0);
802
0
      break;
803
0
    case FORMAT_A8B8G8R8UI:
804
0
      c = Insert(c, Int(*Pointer<Byte>(element + 3)), 3);
805
0
    case FORMAT_X8B8G8R8UI:
806
0
      c = Insert(c, Int(*Pointer<Byte>(element + 2)), 2);
807
0
    case FORMAT_G8R8UI:
808
0
      c = Insert(c, Int(*Pointer<Byte>(element + 1)), 1);
809
0
    case FORMAT_R8UI:
810
0
      c = Insert(c, Int(*Pointer<Byte>(element)), 0);
811
0
      break;
812
0
    case FORMAT_A16B16G16R16I:
813
0
      c = Insert(c, Int(*Pointer<Short>(element + 6)), 3);
814
0
    case FORMAT_X16B16G16R16I:
815
0
      c = Insert(c, Int(*Pointer<Short>(element + 4)), 2);
816
0
    case FORMAT_G16R16I:
817
0
      c = Insert(c, Int(*Pointer<Short>(element + 2)), 1);
818
0
    case FORMAT_R16I:
819
0
      c = Insert(c, Int(*Pointer<Short>(element)), 0);
820
0
      break;
821
0
    case FORMAT_A16B16G16R16UI:
822
0
      c = Insert(c, Int(*Pointer<UShort>(element + 6)), 3);
823
0
    case FORMAT_X16B16G16R16UI:
824
0
      c = Insert(c, Int(*Pointer<UShort>(element + 4)), 2);
825
0
    case FORMAT_G16R16UI:
826
0
      c = Insert(c, Int(*Pointer<UShort>(element + 2)), 1);
827
0
    case FORMAT_R16UI:
828
0
      c = Insert(c, Int(*Pointer<UShort>(element)), 0);
829
0
      break;
830
0
    case FORMAT_A32B32G32R32I:
831
0
    case FORMAT_A32B32G32R32UI:
832
0
      c = *Pointer<Int4>(element);
833
0
      break;
834
0
    case FORMAT_X32B32G32R32I:
835
0
    case FORMAT_X32B32G32R32UI:
836
0
      c = Insert(c, *Pointer<Int>(element + 8), 2);
837
0
    case FORMAT_G32R32I:
838
0
    case FORMAT_G32R32UI:
839
0
      c = Insert(c, *Pointer<Int>(element + 4), 1);
840
0
    case FORMAT_R32I:
841
0
    case FORMAT_R32UI:
842
0
      c = Insert(c, *Pointer<Int>(element), 0);
843
0
      break;
844
0
    default:
845
0
      return false;
846
0
    }
847
848
0
    return true;
849
0
  }
850
851
  bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
852
0
  {
853
0
    bool writeR = state.writeRed;
854
0
    bool writeG = state.writeGreen;
855
0
    bool writeB = state.writeBlue;
856
0
    bool writeA = state.writeAlpha;
857
0
    bool writeRGBA = writeR && writeG && writeB && writeA;
858
859
0
    switch(state.destFormat)
860
0
    {
861
0
    case FORMAT_A8B8G8R8I:
862
0
      if(writeA) { *Pointer<SByte>(element + 3) = SByte(Extract(c, 3)); }
863
0
    case FORMAT_X8B8G8R8I:
864
0
      if(writeA && (state.destFormat != FORMAT_A8B8G8R8I))
865
0
      {
866
0
        *Pointer<SByte>(element + 3) = SByte(0x7F);
867
0
      }
868
0
      if(writeB) { *Pointer<SByte>(element + 2) = SByte(Extract(c, 2)); }
869
0
    case FORMAT_G8R8I:
870
0
      if(writeG) { *Pointer<SByte>(element + 1) = SByte(Extract(c, 1)); }
871
0
    case FORMAT_R8I:
872
0
      if(writeR) { *Pointer<SByte>(element) = SByte(Extract(c, 0)); }
873
0
      break;
874
0
    case FORMAT_A8B8G8R8UI:
875
0
      if(writeA) { *Pointer<Byte>(element + 3) = Byte(Extract(c, 3)); }
876
0
    case FORMAT_X8B8G8R8UI:
877
0
      if(writeA && (state.destFormat != FORMAT_A8B8G8R8UI))
878
0
      {
879
0
        *Pointer<Byte>(element + 3) = Byte(0xFF);
880
0
      }
881
0
      if(writeB) { *Pointer<Byte>(element + 2) = Byte(Extract(c, 2)); }
882
0
    case FORMAT_G8R8UI:
883
0
      if(writeG) { *Pointer<Byte>(element + 1) = Byte(Extract(c, 1)); }
884
0
    case FORMAT_R8UI:
885
0
      if(writeR) { *Pointer<Byte>(element) = Byte(Extract(c, 0)); }
886
0
      break;
887
0
    case FORMAT_A16B16G16R16I:
888
0
      if(writeA) { *Pointer<Short>(element + 6) = Short(Extract(c, 3)); }
889
0
    case FORMAT_X16B16G16R16I:
890
0
      if(writeA && (state.destFormat != FORMAT_A16B16G16R16I))
891
0
      {
892
0
        *Pointer<Short>(element + 6) = Short(0x7FFF);
893
0
      }
894
0
      if(writeB) { *Pointer<Short>(element + 4) = Short(Extract(c, 2)); }
895
0
    case FORMAT_G16R16I:
896
0
      if(writeG) { *Pointer<Short>(element + 2) = Short(Extract(c, 1)); }
897
0
    case FORMAT_R16I:
898
0
      if(writeR) { *Pointer<Short>(element) = Short(Extract(c, 0)); }
899
0
      break;
900
0
    case FORMAT_A16B16G16R16UI:
901
0
      if(writeA) { *Pointer<UShort>(element + 6) = UShort(Extract(c, 3)); }
902
0
    case FORMAT_X16B16G16R16UI:
903
0
      if(writeA && (state.destFormat != FORMAT_A16B16G16R16UI))
904
0
      {
905
0
        *Pointer<UShort>(element + 6) = UShort(0xFFFF);
906
0
      }
907
0
      if(writeB) { *Pointer<UShort>(element + 4) = UShort(Extract(c, 2)); }
908
0
    case FORMAT_G16R16UI:
909
0
      if(writeG) { *Pointer<UShort>(element + 2) = UShort(Extract(c, 1)); }
910
0
    case FORMAT_R16UI:
911
0
      if(writeR) { *Pointer<UShort>(element) = UShort(Extract(c, 0)); }
912
0
      break;
913
0
    case FORMAT_A32B32G32R32I:
914
0
      if(writeRGBA)
915
0
      {
916
0
        *Pointer<Int4>(element) = c;
917
0
      }
918
0
      else
919
0
      {
920
0
        if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
921
0
        if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
922
0
        if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
923
0
        if(writeA) { *Pointer<Int>(element + 12) = Extract(c, 3); }
924
0
      }
925
0
      break;
926
0
    case FORMAT_X32B32G32R32I:
927
0
      if(writeRGBA)
928
0
      {
929
0
        *Pointer<Int4>(element) = c;
930
0
      }
931
0
      else
932
0
      {
933
0
        if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
934
0
        if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
935
0
        if(writeB) { *Pointer<Int>(element + 8) = Extract(c, 2); }
936
0
      }
937
0
      if(writeA) { *Pointer<Int>(element + 12) = Int(0x7FFFFFFF); }
938
0
      break;
939
0
    case FORMAT_G32R32I:
940
0
      if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
941
0
      if(writeG) { *Pointer<Int>(element + 4) = Extract(c, 1); }
942
0
      break;
943
0
    case FORMAT_R32I:
944
0
      if(writeR) { *Pointer<Int>(element) = Extract(c, 0); }
945
0
      break;
946
0
    case FORMAT_A32B32G32R32UI:
947
0
      if(writeRGBA)
948
0
      {
949
0
        *Pointer<UInt4>(element) = As<UInt4>(c);
950
0
      }
951
0
      else
952
0
      {
953
0
        if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
954
0
        if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
955
0
        if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
956
0
        if(writeA) { *Pointer<UInt>(element + 12) = As<UInt>(Extract(c, 3)); }
957
0
      }
958
0
      break;
959
0
    case FORMAT_X32B32G32R32UI:
960
0
      if(writeRGBA)
961
0
      {
962
0
        *Pointer<UInt4>(element) = As<UInt4>(c);
963
0
      }
964
0
      else
965
0
      {
966
0
        if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
967
0
        if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
968
0
        if(writeB) { *Pointer<UInt>(element + 8) = As<UInt>(Extract(c, 2)); }
969
0
      }
970
0
      if(writeA) { *Pointer<UInt>(element + 3) = UInt(0xFFFFFFFF); }
971
0
      break;
972
0
    case FORMAT_G32R32UI:
973
0
      if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
974
0
      if(writeG) { *Pointer<UInt>(element + 4) = As<UInt>(Extract(c, 1)); }
975
0
      break;
976
0
    case FORMAT_R32UI:
977
0
      if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
978
0
      break;
979
0
    default:
980
0
      return false;
981
0
    }
982
983
0
    return true;
984
0
  }
985
986
  bool Blitter::GetScale(float4 &scale, Format format)
987
0
  {
988
0
    switch(format)
989
0
    {
990
0
    case FORMAT_L8:
991
0
    case FORMAT_A8:
992
0
    case FORMAT_A8R8G8B8:
993
0
    case FORMAT_X8R8G8B8:
994
0
    case FORMAT_R8:
995
0
    case FORMAT_G8R8:
996
0
    case FORMAT_R8G8B8:
997
0
    case FORMAT_B8G8R8:
998
0
    case FORMAT_X8B8G8R8:
999
0
    case FORMAT_A8B8G8R8:
1000
0
    case FORMAT_SRGB8_X8:
1001
0
    case FORMAT_SRGB8_A8:
1002
0
      scale = vector(0xFF, 0xFF, 0xFF, 0xFF);
1003
0
      break;
1004
0
    case FORMAT_R8_SNORM:
1005
0
    case FORMAT_G8R8_SNORM:
1006
0
    case FORMAT_X8B8G8R8_SNORM:
1007
0
    case FORMAT_A8B8G8R8_SNORM:
1008
0
      scale = vector(0x7F, 0x7F, 0x7F, 0x7F);
1009
0
      break;
1010
0
    case FORMAT_A16B16G16R16:
1011
0
      scale = vector(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
1012
0
      break;
1013
0
    case FORMAT_R8I:
1014
0
    case FORMAT_R8UI:
1015
0
    case FORMAT_G8R8I:
1016
0
    case FORMAT_G8R8UI:
1017
0
    case FORMAT_X8B8G8R8I:
1018
0
    case FORMAT_X8B8G8R8UI:
1019
0
    case FORMAT_A8B8G8R8I:
1020
0
    case FORMAT_A8B8G8R8UI:
1021
0
    case FORMAT_R16I:
1022
0
    case FORMAT_R16UI:
1023
0
    case FORMAT_G16R16:
1024
0
    case FORMAT_G16R16I:
1025
0
    case FORMAT_G16R16UI:
1026
0
    case FORMAT_X16B16G16R16I:
1027
0
    case FORMAT_X16B16G16R16UI:
1028
0
    case FORMAT_A16B16G16R16I:
1029
0
    case FORMAT_A16B16G16R16UI:
1030
0
    case FORMAT_R32I:
1031
0
    case FORMAT_R32UI:
1032
0
    case FORMAT_G32R32I:
1033
0
    case FORMAT_G32R32UI:
1034
0
    case FORMAT_X32B32G32R32I:
1035
0
    case FORMAT_X32B32G32R32UI:
1036
0
    case FORMAT_A32B32G32R32I:
1037
0
    case FORMAT_A32B32G32R32UI:
1038
0
    case FORMAT_A32B32G32R32F:
1039
0
    case FORMAT_X32B32G32R32F:
1040
0
    case FORMAT_X32B32G32R32F_UNSIGNED:
1041
0
    case FORMAT_B32G32R32F:
1042
0
    case FORMAT_G32R32F:
1043
0
    case FORMAT_R32F:
1044
0
    case FORMAT_A2B10G10R10UI:
1045
0
      scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
1046
0
      break;
1047
0
    case FORMAT_R5G6B5:
1048
0
      scale = vector(0x1F, 0x3F, 0x1F, 1.0f);
1049
0
      break;
1050
0
    case FORMAT_A2B10G10R10:
1051
0
      scale = vector(0x3FF, 0x3FF, 0x3FF, 0x03);
1052
0
      break;
1053
0
    case FORMAT_D16:
1054
0
      scale = vector(0xFFFF, 0.0f, 0.0f, 0.0f);
1055
0
      break;
1056
0
    case FORMAT_D24S8:
1057
0
    case FORMAT_D24X8:
1058
0
      scale = vector(0xFFFFFF, 0.0f, 0.0f, 0.0f);
1059
0
      break;
1060
0
    case FORMAT_D32:
1061
0
      scale = vector(static_cast<float>(0xFFFFFFFF), 0.0f, 0.0f, 0.0f);
1062
0
      break;
1063
0
    case FORMAT_D32F:
1064
0
    case FORMAT_D32FS8:
1065
0
    case FORMAT_D32F_COMPLEMENTARY:
1066
0
    case FORMAT_D32FS8_COMPLEMENTARY:
1067
0
    case FORMAT_D32F_LOCKABLE:
1068
0
    case FORMAT_D32FS8_TEXTURE:
1069
0
    case FORMAT_D32F_SHADOW:
1070
0
    case FORMAT_D32FS8_SHADOW:
1071
0
    case FORMAT_S8:
1072
0
      scale = vector(1.0f, 1.0f, 1.0f, 1.0f);
1073
0
      break;
1074
0
    default:
1075
0
      return false;
1076
0
    }
1077
1078
0
    return true;
1079
0
  }
1080
1081
  bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
1082
0
  {
1083
0
    float4 scale, unscale;
1084
0
    if(state.clearOperation &&
1085
0
       Surface::isNonNormalizedInteger(state.sourceFormat) &&
1086
0
       !Surface::isNonNormalizedInteger(state.destFormat))
1087
0
    {
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
0
      switch(state.sourceFormat)
1091
0
      {
1092
0
      case FORMAT_A32B32G32R32I:
1093
0
        unscale = replicate(static_cast<float>(0x7FFFFFFF));
1094
0
        break;
1095
0
      case FORMAT_A32B32G32R32UI:
1096
0
        unscale = replicate(static_cast<float>(0xFFFFFFFF));
1097
0
        break;
1098
0
      default:
1099
0
        return false;
1100
0
      }
1101
0
    }
1102
0
    else if(!GetScale(unscale, state.sourceFormat))
1103
0
    {
1104
0
      return false;
1105
0
    }
1106
1107
0
    if(!GetScale(scale, state.destFormat))
1108
0
    {
1109
0
      return false;
1110
0
    }
1111
1112
0
    bool srcSRGB = Surface::isSRGBformat(state.sourceFormat);
1113
0
    bool dstSRGB = Surface::isSRGBformat(state.destFormat);
1114
1115
0
    if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB))   // One of the formats is sRGB encoded.
1116
0
    {
1117
0
      value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
1118
0
                           Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
1119
0
      value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
1120
0
      value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
1121
0
    }
1122
0
    else if(unscale != scale)
1123
0
    {
1124
0
      value *= Float4(scale.x / unscale.x, scale.y / unscale.y, scale.z / unscale.z, scale.w / unscale.w);
1125
0
    }
1126
1127
0
    if(state.destFormat == FORMAT_X32B32G32R32F_UNSIGNED)
1128
0
    {
1129
0
      value = Max(value, Float4(0.0f));  // TODO: Only necessary if source is signed.
1130
0
    }
1131
0
    else if(Surface::isFloatFormat(state.sourceFormat) && !Surface::isFloatFormat(state.destFormat))
1132
0
    {
1133
0
      value = Min(value, Float4(scale.x, scale.y, scale.z, scale.w));
1134
1135
0
      value = Max(value, Float4(Surface::isUnsignedComponent(state.destFormat, 0) ? 0.0f : -scale.x,
1136
0
                                Surface::isUnsignedComponent(state.destFormat, 1) ? 0.0f : -scale.y,
1137
0
                                Surface::isUnsignedComponent(state.destFormat, 2) ? 0.0f : -scale.z,
1138
0
                                Surface::isUnsignedComponent(state.destFormat, 3) ? 0.0f : -scale.w));
1139
0
    }
1140
1141
0
    return true;
1142
0
  }
1143
1144
  Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
1145
0
  {
1146
0
    if(!quadLayout)
1147
0
    {
1148
0
      return y * pitchB + x * bytes;
1149
0
    }
1150
0
    else
1151
0
    {
1152
      // (x & ~1) * 2 + (x & 1) == (x - (x & 1)) * 2 + (x & 1) == x * 2 - (x & 1) * 2 + (x & 1) == x * 2 - (x & 1)
1153
0
      return (y & Int(~1)) * pitchB +
1154
0
             ((y & Int(1)) * 2 + x * 2 - (x & Int(1))) * bytes;
1155
0
    }
1156
0
  }
1157
1158
  Float4 Blitter::LinearToSRGB(Float4 &c)
1159
0
  {
1160
0
    Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
1161
0
    Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
1162
1163
0
    Float4 s = c;
1164
0
    s.xyz = Max(lc, ec);
1165
1166
0
    return s;
1167
0
  }
1168
1169
  Float4 Blitter::sRGBtoLinear(Float4 &c)
1170
0
  {
1171
0
    Float4 lc = c * Float4(1.0f / 12.92f);
1172
0
    Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
1173
1174
0
    Int4 linear = CmpLT(c, Float4(0.04045f));
1175
1176
0
    Float4 s = c;
1177
0
    s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec)));   // TODO: IfThenElse()
1178
1179
0
    return s;
1180
0
  }
1181
1182
  std::shared_ptr<Routine> Blitter::generate(const State &state)
1183
0
  {
1184
0
    Function<Void(Pointer<Byte>)> function;
1185
0
    {
1186
0
      Pointer<Byte> blit(function.Arg<0>());
1187
1188
0
      Pointer<Byte> source = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,source));
1189
0
      Pointer<Byte> dest = *Pointer<Pointer<Byte>>(blit + OFFSET(BlitData,dest));
1190
0
      Int sPitchB = *Pointer<Int>(blit + OFFSET(BlitData,sPitchB));
1191
0
      Int dPitchB = *Pointer<Int>(blit + OFFSET(BlitData,dPitchB));
1192
1193
0
      Float x0 = *Pointer<Float>(blit + OFFSET(BlitData,x0));
1194
0
      Float y0 = *Pointer<Float>(blit + OFFSET(BlitData,y0));
1195
0
      Float w = *Pointer<Float>(blit + OFFSET(BlitData,w));
1196
0
      Float h = *Pointer<Float>(blit + OFFSET(BlitData,h));
1197
1198
0
      Int x0d = *Pointer<Int>(blit + OFFSET(BlitData,x0d));
1199
0
      Int x1d = *Pointer<Int>(blit + OFFSET(BlitData,x1d));
1200
0
      Int y0d = *Pointer<Int>(blit + OFFSET(BlitData,y0d));
1201
0
      Int y1d = *Pointer<Int>(blit + OFFSET(BlitData,y1d));
1202
1203
0
      Int sWidth = *Pointer<Int>(blit + OFFSET(BlitData,sWidth));
1204
0
      Int sHeight = *Pointer<Int>(blit + OFFSET(BlitData,sHeight));
1205
1206
0
      bool intSrc = Surface::isNonNormalizedInteger(state.sourceFormat);
1207
0
      bool intDst = Surface::isNonNormalizedInteger(state.destFormat);
1208
0
      bool intBoth = intSrc && intDst;
1209
0
      bool srcQuadLayout = Surface::hasQuadLayout(state.sourceFormat);
1210
0
      bool dstQuadLayout = Surface::hasQuadLayout(state.destFormat);
1211
0
      int srcBytes = Surface::bytes(state.sourceFormat);
1212
0
      int dstBytes = Surface::bytes(state.destFormat);
1213
1214
0
      bool hasConstantColorI = false;
1215
0
      Int4 constantColorI;
1216
0
      bool hasConstantColorF = false;
1217
0
      Float4 constantColorF;
1218
0
      if(state.clearOperation)
1219
0
      {
1220
0
        if(intBoth) // Integer types
1221
0
        {
1222
0
          if(!read(constantColorI, source, state))
1223
0
          {
1224
0
            return nullptr;
1225
0
          }
1226
0
          hasConstantColorI = true;
1227
0
        }
1228
0
        else
1229
0
        {
1230
0
          if(!read(constantColorF, source, state))
1231
0
          {
1232
0
            return nullptr;
1233
0
          }
1234
0
          hasConstantColorF = true;
1235
1236
0
          if(!ApplyScaleAndClamp(constantColorF, state))
1237
0
          {
1238
0
            return nullptr;
1239
0
          }
1240
0
        }
1241
0
      }
1242
1243
0
      For(Int j = y0d, j < y1d, j++)
1244
0
      {
1245
0
        Float y = state.clearOperation ? RValue<Float>(y0) : y0 + Float(j) * h;
1246
0
        Pointer<Byte> destLine = dest + (dstQuadLayout ? j & Int(~1) : RValue<Int>(j)) * dPitchB;
1247
1248
0
        For(Int i = x0d, i < x1d, i++)
1249
0
        {
1250
0
          Float x = state.clearOperation ? RValue<Float>(x0) : x0 + Float(i) * w;
1251
0
          Pointer<Byte> d = destLine + (dstQuadLayout ? (((j & Int(1)) << 1) + (i * 2) - (i & Int(1))) : RValue<Int>(i)) * dstBytes;
1252
1253
0
          if(hasConstantColorI)
1254
0
          {
1255
0
            if(!write(constantColorI, d, state))
1256
0
            {
1257
0
              return nullptr;
1258
0
            }
1259
0
          }
1260
0
          else if(hasConstantColorF)
1261
0
          {
1262
0
            for(int s = 0; s < state.destSamples; s++)
1263
0
            {
1264
0
              if(!write(constantColorF, d, state))
1265
0
              {
1266
0
                return nullptr;
1267
0
              }
1268
1269
0
              d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
1270
0
            }
1271
0
          }
1272
0
          else if(intBoth) // Integer types do not support filtering
1273
0
          {
1274
0
            Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
1275
0
            Int X = Int(x);
1276
0
            Int Y = Int(y);
1277
1278
0
            if(state.clampToEdge)
1279
0
            {
1280
0
              X = Clamp(X, 0, sWidth - 1);
1281
0
              Y = Clamp(Y, 0, sHeight - 1);
1282
0
            }
1283
1284
0
            Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1285
1286
0
            if(!read(color, s, state))
1287
0
            {
1288
0
              return nullptr;
1289
0
            }
1290
1291
0
            if(!write(color, d, state))
1292
0
            {
1293
0
              return nullptr;
1294
0
            }
1295
0
          }
1296
0
          else
1297
0
          {
1298
0
            Float4 color;
1299
1300
0
            bool preScaled = false;
1301
0
            if(!state.filter || intSrc)
1302
0
            {
1303
0
              Int X = Int(x);
1304
0
              Int Y = Int(y);
1305
1306
0
              if(state.clampToEdge)
1307
0
              {
1308
0
                X = Clamp(X, 0, sWidth - 1);
1309
0
                Y = Clamp(Y, 0, sHeight - 1);
1310
0
              }
1311
1312
0
              Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
1313
1314
0
              if(!read(color, s, state))
1315
0
              {
1316
0
                return nullptr;
1317
0
              }
1318
0
            }
1319
0
            else   // Bilinear filtering
1320
0
            {
1321
0
              Float X = x;
1322
0
              Float Y = y;
1323
1324
0
              if(state.clampToEdge)
1325
0
              {
1326
0
                X = Min(Max(x, 0.5f), Float(sWidth) - 0.5f);
1327
0
                Y = Min(Max(y, 0.5f), Float(sHeight) - 0.5f);
1328
0
              }
1329
1330
0
              Float x0 = X - 0.5f;
1331
0
              Float y0 = Y - 0.5f;
1332
1333
0
              Int X0 = Max(Int(x0), 0);
1334
0
              Int Y0 = Max(Int(y0), 0);
1335
1336
0
              Int X1 = X0 + 1;
1337
0
              Int Y1 = Y0 + 1;
1338
0
              X1 = IfThenElse(X1 >= sWidth, X0, X1);
1339
0
              Y1 = IfThenElse(Y1 >= sHeight, Y0, Y1);
1340
1341
0
              Pointer<Byte> s00 = source + ComputeOffset(X0, Y0, sPitchB, srcBytes, srcQuadLayout);
1342
0
              Pointer<Byte> s01 = source + ComputeOffset(X1, Y0, sPitchB, srcBytes, srcQuadLayout);
1343
0
              Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
1344
0
              Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
1345
1346
0
              Float4 c00; if(!read(c00, s00, state)) return nullptr;
1347
0
              Float4 c01; if(!read(c01, s01, state)) return nullptr;
1348
0
              Float4 c10; if(!read(c10, s10, state)) return nullptr;
1349
0
              Float4 c11; if(!read(c11, s11, state)) return nullptr;
1350
1351
0
              if(state.convertSRGB && Surface::isSRGBformat(state.sourceFormat)) // sRGB -> RGB
1352
0
              {
1353
0
                if(!ApplyScaleAndClamp(c00, state)) return nullptr;
1354
0
                if(!ApplyScaleAndClamp(c01, state)) return nullptr;
1355
0
                if(!ApplyScaleAndClamp(c10, state)) return nullptr;
1356
0
                if(!ApplyScaleAndClamp(c11, state)) return nullptr;
1357
0
                preScaled = true;
1358
0
              }
1359
1360
0
              Float4 fx = Float4(x0 - Float(X0));
1361
0
              Float4 fy = Float4(y0 - Float(Y0));
1362
0
              Float4 ix = Float4(1.0f) - fx;
1363
0
              Float4 iy = Float4(1.0f) - fy;
1364
1365
0
              color = (c00 * ix + c01 * fx) * iy +
1366
0
                      (c10 * ix + c11 * fx) * fy;
1367
0
            }
1368
1369
0
            if(!ApplyScaleAndClamp(color, state, preScaled))
1370
0
            {
1371
0
              return nullptr;
1372
0
            }
1373
1374
0
            for(int s = 0; s < state.destSamples; s++)
1375
0
            {
1376
0
              if(!write(color, d, state))
1377
0
              {
1378
0
                return nullptr;
1379
0
              }
1380
1381
0
              d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
1382
0
            }
1383
0
          }
1384
0
        }
1385
0
      }
1386
0
    }
1387
1388
0
    return function("BlitRoutine");
1389
0
  }
1390
1391
  bool Blitter::blitReactor(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options &options)
1392
0
  {
1393
0
    ASSERT(!options.clearOperation || ((source->getWidth() == 1) && (source->getHeight() == 1) && (source->getDepth() == 1)));
1394
1395
0
    Rect dRect = destRect;
1396
0
    RectF sRect = sourceRect;
1397
0
    if(destRect.x0 > destRect.x1)
1398
0
    {
1399
0
      swap(dRect.x0, dRect.x1);
1400
0
      swap(sRect.x0, sRect.x1);
1401
0
    }
1402
0
    if(destRect.y0 > destRect.y1)
1403
0
    {
1404
0
      swap(dRect.y0, dRect.y1);
1405
0
      swap(sRect.y0, sRect.y1);
1406
0
    }
1407
1408
0
    State state(options);
1409
0
    state.clampToEdge = (sourceRect.x0 < 0.0f) ||
1410
0
                        (sourceRect.y0 < 0.0f) ||
1411
0
                        (sourceRect.x1 > (float)source->getWidth()) ||
1412
0
                        (sourceRect.y1 > (float)source->getHeight());
1413
1414
0
    bool useSourceInternal = !source->isExternalDirty();
1415
0
    bool useDestInternal = !dest->isExternalDirty();
1416
0
    bool isStencil = options.useStencil;
1417
1418
0
    state.sourceFormat = isStencil ? source->getStencilFormat() : source->getFormat(useSourceInternal);
1419
0
    state.destFormat = isStencil ? dest->getStencilFormat() : dest->getFormat(useDestInternal);
1420
0
    state.destSamples = dest->getSamples();
1421
1422
0
    criticalSection.lock();
1423
0
    auto blitRoutine = blitCache->query(state);
1424
1425
0
    if(!blitRoutine)
1426
0
    {
1427
0
      blitRoutine = generate(state);
1428
1429
0
      if(!blitRoutine)
1430
0
      {
1431
0
        criticalSection.unlock();
1432
0
        return false;
1433
0
      }
1434
1435
0
      blitCache->add(state, blitRoutine);
1436
0
    }
1437
1438
0
    criticalSection.unlock();
1439
1440
0
    void (*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry();
1441
1442
0
    BlitData data;
1443
1444
0
    bool isRGBA = options.writeMask == 0xF;
1445
0
    bool isEntireDest = dest->isEntire(destRect);
1446
1447
0
    data.source = isStencil ? source->lockStencil(0, 0, 0, sw::PUBLIC) :
1448
0
                              source->lock(0, 0, sourceRect.slice, sw::LOCK_READONLY, sw::PUBLIC, useSourceInternal);
1449
0
    data.dest = isStencil ? dest->lockStencil(0, 0, 0, sw::PUBLIC) :
1450
0
                            dest->lock(0, 0, destRect.slice, isRGBA ? (isEntireDest ? sw::LOCK_DISCARD : sw::LOCK_WRITEONLY) : sw::LOCK_READWRITE, sw::PUBLIC, useDestInternal);
1451
0
    data.sPitchB = isStencil ? source->getStencilPitchB() : source->getPitchB(useSourceInternal);
1452
0
    data.dPitchB = isStencil ? dest->getStencilPitchB() : dest->getPitchB(useDestInternal);
1453
0
    data.dSliceB = isStencil ? dest->getStencilSliceB() : dest->getSliceB(useDestInternal);
1454
1455
0
    data.w = sRect.width() / dRect.width();
1456
0
    data.h = sRect.height() / dRect.height();
1457
0
    data.x0 = sRect.x0 + (0.5f - dRect.x0) * data.w;
1458
0
    data.y0 = sRect.y0 + (0.5f - dRect.y0) * data.h;
1459
1460
0
    data.x0d = dRect.x0;
1461
0
    data.x1d = dRect.x1;
1462
0
    data.y0d = dRect.y0;
1463
0
    data.y1d = dRect.y1;
1464
1465
0
    data.sWidth = source->getWidth();
1466
0
    data.sHeight = source->getHeight();
1467
1468
0
    blitFunction(&data);
1469
1470
0
    if(isStencil)
1471
0
    {
1472
0
      source->unlockStencil();
1473
0
      dest->unlockStencil();
1474
0
    }
1475
0
    else
1476
0
    {
1477
0
      source->unlock(useSourceInternal);
1478
0
      dest->unlock(useDestInternal);
1479
0
    }
1480
1481
0
    return true;
1482
0
  }
1483
}