Coverage Report

Created: 2024-05-20 06:11

/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 "prim_internal.h"
22
23
static primitives_t* generic = NULL;
24
25
/* ------------------------------------------------------------------------- */
26
/*static inline BOOL memory_regions_overlap_1d(*/
27
static BOOL memory_regions_overlap_1d(const BYTE* p1, const BYTE* p2, size_t bytes)
28
0
{
29
0
  const ULONG_PTR p1m = (const ULONG_PTR)p1;
30
0
  const ULONG_PTR p2m = (const ULONG_PTR)p2;
31
32
0
  if (p1m <= p2m)
33
0
  {
34
0
    if (p1m + bytes > p2m)
35
0
      return TRUE;
36
0
  }
37
0
  else
38
0
  {
39
0
    if (p2m + bytes > p1m)
40
0
      return TRUE;
41
0
  }
42
43
  /* else */
44
0
  return FALSE;
45
0
}
46
47
/* ------------------------------------------------------------------------- */
48
/*static inline BOOL memory_regions_overlap_2d( */
49
static BOOL memory_regions_overlap_2d(const BYTE* p1, int p1Step, int p1Size, const BYTE* p2,
50
                                      int p2Step, int p2Size, int width, int height)
51
0
{
52
0
  ULONG_PTR p1m = (ULONG_PTR)p1;
53
0
  ULONG_PTR p2m = (ULONG_PTR)p2;
54
55
0
  if (p1m <= p2m)
56
0
  {
57
0
    ULONG_PTR p1mEnd = p1m + 1ull * (height - 1) * p1Step + 1ull * width * p1Size;
58
59
0
    if (p1mEnd > p2m)
60
0
      return TRUE;
61
0
  }
62
0
  else
63
0
  {
64
0
    ULONG_PTR p2mEnd = p2m + 1ull * (height - 1) * p2Step + 1ull * width * p2Size;
65
66
0
    if (p2mEnd > p1m)
67
0
      return TRUE;
68
0
  }
69
70
  /* else */
71
0
  return FALSE;
72
0
}
73
74
/* ------------------------------------------------------------------------- */
75
static pstatus_t general_copy_8u(const BYTE* pSrc, BYTE* pDst, INT32 len)
76
0
{
77
0
  if (memory_regions_overlap_1d(pSrc, pDst, (size_t)len))
78
0
  {
79
0
    memmove((void*)pDst, (const void*)pSrc, (size_t)len);
80
0
  }
81
0
  else
82
0
  {
83
0
    memcpy((void*)pDst, (const void*)pSrc, (size_t)len);
84
0
  }
85
86
0
  return PRIMITIVES_SUCCESS;
87
0
}
88
89
/* ------------------------------------------------------------------------- */
90
/* Copy a block of pixels from one buffer to another.
91
 * The addresses are assumed to have been already offset to the upper-left
92
 * corners of the source and destination region of interest.
93
 */
94
static pstatus_t general_copy_8u_AC4r(const BYTE* pSrc, INT32 srcStep, BYTE* pDst, INT32 dstStep,
95
                                      INT32 width, INT32 height)
96
0
{
97
0
  const BYTE* src = (const BYTE*)pSrc;
98
0
  BYTE* dst = (BYTE*)pDst;
99
0
  int rowbytes = width * sizeof(UINT32);
100
101
0
  if ((width == 0) || (height == 0))
102
0
    return PRIMITIVES_SUCCESS;
103
104
0
  if (memory_regions_overlap_2d(pSrc, srcStep, sizeof(UINT32), pDst, dstStep, sizeof(UINT32),
105
0
                                width, height))
106
0
  {
107
0
    do
108
0
    {
109
0
      generic->copy(src, dst, rowbytes);
110
0
      src += srcStep;
111
0
      dst += dstStep;
112
0
    } while (--height);
113
0
  }
114
0
  else
115
0
  {
116
    /* TODO: do it in one operation when the rowdata is adjacent. */
117
0
    do
118
0
    {
119
      /* If we find a replacement for memcpy that is consistently
120
       * faster, this could be replaced with that.
121
       */
122
0
      memcpy(dst, src, rowbytes);
123
0
      src += srcStep;
124
0
      dst += dstStep;
125
0
    } while (--height);
126
0
  }
127
128
0
  return PRIMITIVES_SUCCESS;
129
0
}
130
131
/* ------------------------------------------------------------------------- */
132
void primitives_init_copy(primitives_t* prims)
133
1
{
134
  /* Start with the default. */
135
1
  prims->copy_8u = general_copy_8u;
136
1
  prims->copy_8u_AC4r = general_copy_8u_AC4r;
137
  /* This is just an alias with void* parameters */
138
1
  prims->copy = (__copy_t)(prims->copy_8u);
139
1
}
140
141
#if defined(WITH_SSE2) || defined(WITH_NEON)
142
void primitives_init_copy_opt(primitives_t* prims)
143
{
144
  generic = primitives_get_generic();
145
  primitives_init_copy(prims);
146
  /* Pick tuned versions if possible. */
147
  /* Performance with an SSE2 version with no prefetch seemed to be
148
   * all over the map vs. memcpy.
149
   * Sometimes it was significantly faster, sometimes dreadfully slower,
150
   * and it seemed to vary a lot depending on block size and processor.
151
   * Hence, no SSE version is used here unless once can be written that
152
   * is consistently faster than memcpy.
153
   */
154
  /* This is just an alias with void* parameters */
155
  prims->copy = (__copy_t)(prims->copy_8u);
156
}
157
#endif