Coverage Report

Created: 2024-09-08 06:16

/src/FreeRDP/libfreerdp/primitives/prim_copy.c
Line
Count
Source (jump to first uncovered line)
1
/* FreeRDP: A Remote Desktop Protocol Client
2
 * Copy operations.
3
 * vi:ts=4 sw=4:
4
 *
5
 * (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
6
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
7
 * not use this file except in compliance with the License. You may obtain
8
 * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
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
12
 * or implied. See the License for the specific language governing
13
 * permissions and limitations under the License.
14
 */
15
16
#include <freerdp/config.h>
17
18
#include <string.h>
19
#include <freerdp/types.h>
20
#include <freerdp/primitives.h>
21
#include <freerdp/log.h>
22
23
#include "prim_internal.h"
24
#include "prim_copy.h"
25
#include "../codec/color.h"
26
27
#include <freerdp/codec/color.h>
28
29
#define TAG FREERDP_TAG("primitives.copy")
30
31
static primitives_t* generic = NULL;
32
33
/* ------------------------------------------------------------------------- */
34
/*static inline BOOL memory_regions_overlap_1d(*/
35
static BOOL memory_regions_overlap_1d(const BYTE* p1, const BYTE* p2, size_t bytes)
36
0
{
37
0
  const ULONG_PTR p1m = (const ULONG_PTR)p1;
38
0
  const ULONG_PTR p2m = (const ULONG_PTR)p2;
39
40
0
  if (p1m <= p2m)
41
0
  {
42
0
    if (p1m + bytes > p2m)
43
0
      return TRUE;
44
0
  }
45
0
  else
46
0
  {
47
0
    if (p2m + bytes > p1m)
48
0
      return TRUE;
49
0
  }
50
51
  /* else */
52
0
  return FALSE;
53
0
}
54
55
/* ------------------------------------------------------------------------- */
56
/*static inline BOOL memory_regions_overlap_2d( */
57
static BOOL memory_regions_overlap_2d(const BYTE* p1, int p1Step, int p1Size, const BYTE* p2,
58
                                      int p2Step, int p2Size, int width, int height)
59
0
{
60
0
  ULONG_PTR p1m = (ULONG_PTR)p1;
61
0
  ULONG_PTR p2m = (ULONG_PTR)p2;
62
63
0
  if (p1m <= p2m)
64
0
  {
65
0
    ULONG_PTR p1mEnd = p1m + 1ull * (height - 1) * p1Step + 1ull * width * p1Size;
66
67
0
    if (p1mEnd > p2m)
68
0
      return TRUE;
69
0
  }
70
0
  else
71
0
  {
72
0
    ULONG_PTR p2mEnd = p2m + 1ull * (height - 1) * p2Step + 1ull * width * p2Size;
73
74
0
    if (p2mEnd > p1m)
75
0
      return TRUE;
76
0
  }
77
78
  /* else */
79
0
  return FALSE;
80
0
}
81
82
/* ------------------------------------------------------------------------- */
83
static pstatus_t general_copy_8u(const BYTE* pSrc, BYTE* pDst, INT32 len)
84
0
{
85
0
  if (memory_regions_overlap_1d(pSrc, pDst, (size_t)len))
86
0
  {
87
0
    memmove((void*)pDst, (const void*)pSrc, (size_t)len);
88
0
  }
89
0
  else
90
0
  {
91
0
    memcpy((void*)pDst, (const void*)pSrc, (size_t)len);
92
0
  }
93
94
0
  return PRIMITIVES_SUCCESS;
95
0
}
96
97
/* ------------------------------------------------------------------------- */
98
/* Copy a block of pixels from one buffer to another.
99
 * The addresses are assumed to have been already offset to the upper-left
100
 * corners of the source and destination region of interest.
101
 */
102
static pstatus_t general_copy_8u_AC4r(const BYTE* pSrc, INT32 srcStep, BYTE* pDst, INT32 dstStep,
103
                                      INT32 width, INT32 height)
104
0
{
105
0
  const BYTE* src = pSrc;
106
0
  BYTE* dst = pDst;
107
0
  int rowbytes = width * sizeof(UINT32);
108
109
0
  if ((width == 0) || (height == 0))
110
0
    return PRIMITIVES_SUCCESS;
111
112
0
  if (memory_regions_overlap_2d(pSrc, srcStep, sizeof(UINT32), pDst, dstStep, sizeof(UINT32),
113
0
                                width, height))
114
0
  {
115
0
    do
116
0
    {
117
0
      generic->copy(src, dst, rowbytes);
118
0
      src += srcStep;
119
0
      dst += dstStep;
120
0
    } while (--height);
121
0
  }
122
0
  else
123
0
  {
124
    /* TODO: do it in one operation when the rowdata is adjacent. */
125
0
    do
126
0
    {
127
      /* If we find a replacement for memcpy that is consistently
128
       * faster, this could be replaced with that.
129
       */
130
0
      memcpy(dst, src, rowbytes);
131
0
      src += srcStep;
132
0
      dst += dstStep;
133
0
    } while (--height);
134
0
  }
135
136
0
  return PRIMITIVES_SUCCESS;
137
0
}
138
139
static INLINE pstatus_t generic_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData,
140
                                                        UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
141
                                                        UINT32 nWidth, UINT32 nHeight,
142
                                                        const BYTE* WINPR_RESTRICT pSrcData,
143
                                                        UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
144
                                                        SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
145
                                                        SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
146
0
{
147
148
0
  const SSIZE_T srcByte = 3;
149
0
  const SSIZE_T dstByte = 4;
150
151
0
  for (SSIZE_T y = 0; y < nHeight; y++)
152
0
  {
153
0
    const BYTE* WINPR_RESTRICT srcLine =
154
0
        &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
155
0
    BYTE* WINPR_RESTRICT dstLine =
156
0
        &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
157
158
0
    for (SSIZE_T x = 0; x < nWidth; x++)
159
0
    {
160
0
      dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
161
0
      dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
162
0
      dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
163
0
    }
164
0
  }
165
166
0
  return PRIMITIVES_SUCCESS;
167
0
}
168
169
static INLINE pstatus_t generic_image_copy_bgrx32_bgrx32(
170
    BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
171
    UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 nXSrc,
172
    UINT32 nYSrc, SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier,
173
    SSIZE_T dstVOffset)
174
0
{
175
176
0
  const SSIZE_T srcByte = 4;
177
0
  const SSIZE_T dstByte = 4;
178
179
0
  for (SSIZE_T y = 0; y < nHeight; y++)
180
0
  {
181
0
    const BYTE* WINPR_RESTRICT srcLine =
182
0
        &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
183
0
    BYTE* WINPR_RESTRICT dstLine =
184
0
        &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
185
186
0
    for (SSIZE_T x = 0; x < nWidth; x++)
187
0
    {
188
0
      dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
189
0
      dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
190
0
      dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
191
0
    }
192
0
  }
193
194
0
  return PRIMITIVES_SUCCESS;
195
0
}
196
197
pstatus_t generic_image_copy_no_overlap_convert(
198
    BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
199
    UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
200
    UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
201
    SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
202
0
{
203
0
  const SSIZE_T srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
204
0
  const SSIZE_T dstByte = FreeRDPGetBytesPerPixel(DstFormat);
205
206
0
  const UINT32 width = nWidth - nWidth % 8;
207
0
  for (SSIZE_T y = 0; y < nHeight; y++)
208
0
  {
209
0
    const BYTE* WINPR_RESTRICT srcLine =
210
0
        &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
211
0
    BYTE* WINPR_RESTRICT dstLine =
212
0
        &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
213
214
0
    SSIZE_T x = 0;
215
0
    WINPR_PRAGMA_UNROLL_LOOP
216
0
    for (; x < width; x++)
217
0
    {
218
0
      const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
219
0
      const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
220
0
      FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
221
0
    }
222
0
    for (; x < nWidth; x++)
223
0
    {
224
0
      const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
225
0
      const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
226
0
      FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
227
0
    }
228
0
  }
229
0
  return PRIMITIVES_SUCCESS;
230
0
}
231
232
pstatus_t generic_image_copy_no_overlap_memcpy(
233
    BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
234
    UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
235
    UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
236
    SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset,
237
    UINT32 flags)
238
0
{
239
0
  const SSIZE_T dstByte = FreeRDPGetBytesPerPixel(DstFormat);
240
0
  const SSIZE_T srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
241
0
  const SSIZE_T copyDstWidth = nWidth * dstByte;
242
0
  const SSIZE_T xSrcOffset = nXSrc * srcByte;
243
0
  const SSIZE_T xDstOffset = nXDst * dstByte;
244
245
0
  for (SSIZE_T y = 0; y < nHeight; y++)
246
0
  {
247
0
    const BYTE* WINPR_RESTRICT srcLine =
248
0
        &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
249
0
    BYTE* WINPR_RESTRICT dstLine =
250
0
        &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
251
0
    memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
252
0
  }
253
254
0
  return PRIMITIVES_SUCCESS;
255
0
}
256
257
static INLINE pstatus_t generic_image_copy_no_overlap_dst_alpha(
258
    BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
259
    UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
260
    UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
261
    SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
262
0
{
263
0
  WINPR_ASSERT(pDstData);
264
0
  WINPR_ASSERT(pSrcData);
265
266
0
  switch (SrcFormat)
267
0
  {
268
0
    case PIXEL_FORMAT_BGR24:
269
0
      switch (DstFormat)
270
0
      {
271
0
        case PIXEL_FORMAT_BGRX32:
272
0
        case PIXEL_FORMAT_BGRA32:
273
0
          return generic_image_copy_bgr24_bgrx32(
274
0
              pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
275
0
              nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
276
0
        default:
277
0
          break;
278
0
      }
279
0
      break;
280
0
    case PIXEL_FORMAT_BGRX32:
281
0
    case PIXEL_FORMAT_BGRA32:
282
0
      switch (DstFormat)
283
0
      {
284
0
        case PIXEL_FORMAT_BGRX32:
285
0
        case PIXEL_FORMAT_BGRA32:
286
0
          return generic_image_copy_bgrx32_bgrx32(
287
0
              pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
288
0
              nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
289
0
        case PIXEL_FORMAT_BGR24:
290
0
          return generic_image_copy_bgr24_bgrx32(
291
0
              pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
292
0
              nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
293
0
        default:
294
0
          break;
295
0
      }
296
0
      break;
297
0
    default:
298
0
      break;
299
0
  }
300
301
0
  return generic_image_copy_no_overlap_convert(
302
0
      pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
303
0
      nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
304
0
}
305
306
static INLINE pstatus_t generic_image_copy_no_overlap_no_alpha(
307
    BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
308
    UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
309
    UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
310
    SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset,
311
    UINT32 flags)
312
0
{
313
0
  if (FreeRDPAreColorFormatsEqualNoAlpha(SrcFormat, DstFormat))
314
0
    return generic_image_copy_no_overlap_memcpy(pDstData, DstFormat, nDstStep, nXDst, nYDst,
315
0
                                                nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
316
0
                                                nXSrc, nYSrc, palette, srcVMultiplier,
317
0
                                                srcVOffset, dstVMultiplier, dstVOffset, flags);
318
0
  else
319
0
    return generic_image_copy_no_overlap_convert(pDstData, DstFormat, nDstStep, nXDst, nYDst,
320
0
                                                 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
321
0
                                                 nXSrc, nYSrc, palette, srcVMultiplier,
322
0
                                                 srcVOffset, dstVMultiplier, dstVOffset);
323
0
}
324
325
static pstatus_t generic_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat,
326
                                               UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
327
                                               UINT32 nWidth, UINT32 nHeight,
328
                                               const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
329
                                               UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
330
                                               const gdiPalette* WINPR_RESTRICT palette,
331
                                               UINT32 flags)
332
0
{
333
0
  const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) ? TRUE : FALSE;
334
0
  SSIZE_T srcVOffset = 0;
335
0
  SSIZE_T srcVMultiplier = 1;
336
0
  SSIZE_T dstVOffset = 0;
337
0
  SSIZE_T dstVMultiplier = 1;
338
339
0
  if ((nWidth == 0) || (nHeight == 0))
340
0
    return PRIMITIVES_SUCCESS;
341
342
0
  if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
343
0
    return -1;
344
345
0
  if (!pDstData || !pSrcData)
346
0
    return -1;
347
348
0
  if (nDstStep == 0)
349
0
    nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
350
351
0
  if (nSrcStep == 0)
352
0
    nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
353
354
0
  if (vSrcVFlip)
355
0
  {
356
0
    srcVOffset = (nHeight - 1ll) * nSrcStep;
357
0
    srcVMultiplier = -1;
358
0
  }
359
360
0
  if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
361
0
    return generic_image_copy_no_overlap_dst_alpha(
362
0
        pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
363
0
        nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
364
0
        dstVOffset);
365
0
  else
366
0
    return generic_image_copy_no_overlap_no_alpha(
367
0
        pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
368
0
        nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset,
369
0
        flags);
370
371
0
  return PRIMITIVES_SUCCESS;
372
0
}
373
374
/* ------------------------------------------------------------------------- */
375
void primitives_init_copy(primitives_t* prims)
376
0
{
377
  /* Start with the default. */
378
0
  prims->copy_8u = general_copy_8u;
379
0
  prims->copy_8u_AC4r = general_copy_8u_AC4r;
380
0
  prims->copy = WINPR_FUNC_PTR_CAST(prims->copy_8u, __copy_t);
381
0
  prims->copy_no_overlap = generic_image_copy_no_overlap;
382
0
}
383
384
void primitives_init_copy_opt(primitives_t* prims)
385
0
{
386
0
  primitives_init_copy_sse41(prims);
387
0
  primitives_init_copy_avx2(prims);
388
0
}