FreeRDP
nsc_sse2.c
1 
20 #include <winpr/assert.h>
21 #include <winpr/cast.h>
22 #include <winpr/platform.h>
23 #include <freerdp/config.h>
24 
25 #include "../nsc_types.h"
26 #include "nsc_sse2.h"
27 
28 #include "../../core/simd.h"
29 
30 #if defined(SSE_AVX_INTRINSICS_ENABLED)
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <xmmintrin.h>
36 #include <emmintrin.h>
37 
38 #include <freerdp/codec/color.h>
39 #include <winpr/crt.h>
40 #include <winpr/sysinfo.h>
41 
42 static BOOL nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, const BYTE* data, UINT32 scanline)
43 {
44  size_t y = 0;
45 
46  if (!context || !data || (scanline == 0))
47  return FALSE;
48 
49  const UINT16 tempWidth = ROUND_UP_TO(context->width, 8);
50  const UINT16 rw = (context->ChromaSubsamplingLevel > 0 ? tempWidth : context->width);
51 
52  const BYTE ccl = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
53 
54  for (; y < context->height; y++)
55  {
56  const BYTE* src = data + (context->height - 1 - y) * scanline;
57  BYTE* yplane = context->priv->PlaneBuffers[0] + y * rw;
58  BYTE* coplane = context->priv->PlaneBuffers[1] + y * rw;
59  BYTE* cgplane = context->priv->PlaneBuffers[2] + y * rw;
60  BYTE* aplane = context->priv->PlaneBuffers[3] + y * context->width;
61 
62  for (UINT16 x = 0; x < context->width; x += 8)
63  {
64  __m128i r_val = { 0 };
65  __m128i g_val = { 0 };
66  __m128i b_val = { 0 };
67  __m128i a_val = { 0 };
68 
69  switch (context->format)
70  {
71  case PIXEL_FORMAT_BGRX32:
72  b_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16),
73  *(src + 12), *(src + 8), *(src + 4), *src);
74  g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17),
75  *(src + 13), *(src + 9), *(src + 5), *(src + 1));
76  r_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18),
77  *(src + 14), *(src + 10), *(src + 6), *(src + 2));
78  a_val = _mm_set1_epi16(0xFF);
79  src += 32;
80  break;
81 
82  case PIXEL_FORMAT_BGRA32:
83  b_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16),
84  *(src + 12), *(src + 8), *(src + 4), *src);
85  g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17),
86  *(src + 13), *(src + 9), *(src + 5), *(src + 1));
87  r_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18),
88  *(src + 14), *(src + 10), *(src + 6), *(src + 2));
89  a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19),
90  *(src + 15), *(src + 11), *(src + 7), *(src + 3));
91  src += 32;
92  break;
93 
94  case PIXEL_FORMAT_RGBX32:
95  r_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16),
96  *(src + 12), *(src + 8), *(src + 4), *src);
97  g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17),
98  *(src + 13), *(src + 9), *(src + 5), *(src + 1));
99  b_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18),
100  *(src + 14), *(src + 10), *(src + 6), *(src + 2));
101  a_val = _mm_set1_epi16(0xFF);
102  src += 32;
103  break;
104 
105  case PIXEL_FORMAT_RGBA32:
106  r_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16),
107  *(src + 12), *(src + 8), *(src + 4), *src);
108  g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17),
109  *(src + 13), *(src + 9), *(src + 5), *(src + 1));
110  b_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18),
111  *(src + 14), *(src + 10), *(src + 6), *(src + 2));
112  a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19),
113  *(src + 15), *(src + 11), *(src + 7), *(src + 3));
114  src += 32;
115  break;
116 
117  case PIXEL_FORMAT_BGR24:
118  b_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12),
119  *(src + 9), *(src + 6), *(src + 3), *src);
120  g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13),
121  *(src + 10), *(src + 7), *(src + 4), *(src + 1));
122  r_val = _mm_set_epi16(*(src + 23), *(src + 20), *(src + 17), *(src + 14),
123  *(src + 11), *(src + 8), *(src + 5), *(src + 2));
124  a_val = _mm_set1_epi16(0xFF);
125  src += 24;
126  break;
127 
128  case PIXEL_FORMAT_RGB24:
129  r_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12),
130  *(src + 9), *(src + 6), *(src + 3), *src);
131  g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13),
132  *(src + 10), *(src + 7), *(src + 4), *(src + 1));
133  b_val = _mm_set_epi16(*(src + 23), *(src + 20), *(src + 17), *(src + 14),
134  *(src + 11), *(src + 8), *(src + 5), *(src + 2));
135  a_val = _mm_set1_epi16(0xFF);
136  src += 24;
137  break;
138  case PIXEL_FORMAT_BGR16:
139  b_val = _mm_set_epi16(WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 15)) & 0xF8) |
140  ((*(src + 15)) >> 5)),
141  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 13)) & 0xF8) |
142  ((*(src + 13)) >> 5)),
143  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 11)) & 0xF8) |
144  ((*(src + 11)) >> 5)),
145  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 9)) & 0xF8) |
146  ((*(src + 9)) >> 5)),
147  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 7)) & 0xF8) |
148  ((*(src + 7)) >> 5)),
149  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 5)) & 0xF8) |
150  ((*(src + 5)) >> 5)),
151  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 3)) & 0xF8) |
152  ((*(src + 3)) >> 5)),
153  WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 1)) & 0xF8) |
154  ((*(src + 1)) >> 5)));
155  g_val = _mm_set_epi16(
156  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 15)) & 0x07) << 5) |
157  (((*(src + 14)) & 0xE0) >> 3)),
158  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 13)) & 0x07) << 5) |
159  (((*(src + 12)) & 0xE0) >> 3)),
160  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 11)) & 0x07) << 5) |
161  (((*(src + 10)) & 0xE0) >> 3)),
162  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 9)) & 0x07) << 5) |
163  (((*(src + 8)) & 0xE0) >> 3)),
164  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 7)) & 0x07) << 5) |
165  (((*(src + 6)) & 0xE0) >> 3)),
166  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 5)) & 0x07) << 5) |
167  (((*(src + 4)) & 0xE0) >> 3)),
168  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 3)) & 0x07) << 5) |
169  (((*(src + 2)) & 0xE0) >> 3)),
170  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 1)) & 0x07) << 5) |
171  (((*src) & 0xE0) >> 3)));
172  r_val = _mm_set_epi16(
173  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 14)) & 0x1F) << 3) |
174  (((*(src + 14)) >> 2) & 0x07)),
175  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 12)) & 0x1F) << 3) |
176  (((*(src + 12)) >> 2) & 0x07)),
177  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 10)) & 0x1F) << 3) |
178  (((*(src + 10)) >> 2) & 0x07)),
179  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 8)) & 0x1F) << 3) |
180  (((*(src + 8)) >> 2) & 0x07)),
181  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 6)) & 0x1F) << 3) |
182  (((*(src + 6)) >> 2) & 0x07)),
183  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 4)) & 0x1F) << 3) |
184  (((*(src + 4)) >> 2) & 0x07)),
185  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 2)) & 0x1F) << 3) |
186  (((*(src + 2)) >> 2) & 0x07)),
187  WINPR_ASSERTING_INT_CAST(INT16,
188  (((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)));
189  a_val = _mm_set1_epi16(0xFF);
190  src += 16;
191  break;
192 
193  case PIXEL_FORMAT_RGB16:
194  r_val = _mm_set_epi16(
195  WINPR_ASSERTING_INT_CAST(INT16, ((src[15] & 0xF8) | (src[15] >> 5))),
196  WINPR_ASSERTING_INT_CAST(INT16, ((src[13] & 0xF8) | (src[13] >> 5))),
197  WINPR_ASSERTING_INT_CAST(INT16, ((src[11] & 0xF8) | (src[11] >> 5))),
198  WINPR_ASSERTING_INT_CAST(INT16, ((src[9] & 0xF8) | (src[9] >> 5))),
199  WINPR_ASSERTING_INT_CAST(INT16, ((src[7] & 0xF8) | (src[7] >> 5))),
200  WINPR_ASSERTING_INT_CAST(INT16, ((src[5] & 0xF8) | (src[5] >> 5))),
201  WINPR_ASSERTING_INT_CAST(INT16, ((src[3] & 0xF8) | (src[3] >> 5))),
202  WINPR_ASSERTING_INT_CAST(INT16, ((src[1] & 0xF8) | (src[1] >> 5))));
203  g_val = _mm_set_epi16(
204  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 15)) & 0x07) << 5) |
205  (((*(src + 14)) & 0xE0) >> 3)),
206  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 13)) & 0x07) << 5) |
207  (((*(src + 12)) & 0xE0) >> 3)),
208  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 11)) & 0x07) << 5) |
209  (((*(src + 10)) & 0xE0) >> 3)),
210  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 9)) & 0x07) << 5) |
211  (((*(src + 8)) & 0xE0) >> 3)),
212  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 7)) & 0x07) << 5) |
213  (((*(src + 6)) & 0xE0) >> 3)),
214  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 5)) & 0x07) << 5) |
215  (((*(src + 4)) & 0xE0) >> 3)),
216  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 3)) & 0x07) << 5) |
217  (((*(src + 2)) & 0xE0) >> 3)),
218  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 1)) & 0x07) << 5) |
219  (((*src) & 0xE0) >> 3)));
220  b_val = _mm_set_epi16(
221  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 14)) & 0x1F) << 3) |
222  (((*(src + 14)) >> 2) & 0x07)),
223  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 12)) & 0x1F) << 3) |
224  (((*(src + 12)) >> 2) & 0x07)),
225  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 10)) & 0x1F) << 3) |
226  (((*(src + 10)) >> 2) & 0x07)),
227  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 8)) & 0x1F) << 3) |
228  (((*(src + 8)) >> 2) & 0x07)),
229  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 6)) & 0x1F) << 3) |
230  (((*(src + 6)) >> 2) & 0x07)),
231  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 4)) & 0x1F) << 3) |
232  (((*(src + 4)) >> 2) & 0x07)),
233  WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 2)) & 0x1F) << 3) |
234  (((*(src + 2)) >> 2) & 0x07)),
235  WINPR_ASSERTING_INT_CAST(INT16,
236  (((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)));
237  a_val = _mm_set1_epi16(0xFF);
238  src += 16;
239  break;
240 
241  case PIXEL_FORMAT_A4:
242  {
243  BYTE idx[8] = { 0 };
244 
245  for (int shift = 7; shift >= 0; shift--)
246  {
247  idx[shift] = ((*src) >> shift) & 1;
248  idx[shift] |= (((*(src + 1)) >> shift) & 1) << 1;
249  idx[shift] |= (((*(src + 2)) >> shift) & 1) << 2;
250  idx[shift] |= (((*(src + 3)) >> shift) & 1) << 3;
251  idx[shift] *= 3;
252  }
253 
254  r_val = _mm_set_epi16(context->palette[idx[0]], context->palette[idx[1]],
255  context->palette[idx[2]], context->palette[idx[3]],
256  context->palette[idx[4]], context->palette[idx[5]],
257  context->palette[idx[6]], context->palette[idx[7]]);
258  g_val =
259  _mm_set_epi16(context->palette[idx[0] + 1], context->palette[idx[1] + 1],
260  context->palette[idx[2] + 1], context->palette[idx[3] + 1],
261  context->palette[idx[4] + 1], context->palette[idx[5] + 1],
262  context->palette[idx[6] + 1], context->palette[idx[7] + 1]);
263  b_val =
264  _mm_set_epi16(context->palette[idx[0] + 2], context->palette[idx[1] + 2],
265  context->palette[idx[2] + 2], context->palette[idx[3] + 2],
266  context->palette[idx[4] + 2], context->palette[idx[5] + 2],
267  context->palette[idx[6] + 2], context->palette[idx[7] + 2]);
268  src += 4;
269  }
270 
271  a_val = _mm_set1_epi16(0xFF);
272  break;
273 
274  case PIXEL_FORMAT_RGB8:
275  {
276  r_val = _mm_set_epi16(context->palette[(*(src + 7ULL)) * 3ULL],
277  context->palette[(*(src + 6ULL)) * 3ULL],
278  context->palette[(*(src + 5ULL)) * 3ULL],
279  context->palette[(*(src + 4ULL)) * 3ULL],
280  context->palette[(*(src + 3ULL)) * 3ULL],
281  context->palette[(*(src + 2ULL)) * 3ULL],
282  context->palette[(*(src + 1ULL)) * 3ULL],
283  context->palette[(*src) * 3ULL]);
284  g_val = _mm_set_epi16(context->palette[(*(src + 7ULL)) * 3ULL + 1ULL],
285  context->palette[(*(src + 6ULL)) * 3ULL + 1ULL],
286  context->palette[(*(src + 5ULL)) * 3ULL + 1ULL],
287  context->palette[(*(src + 4ULL)) * 3ULL + 1ULL],
288  context->palette[(*(src + 3ULL)) * 3ULL + 1ULL],
289  context->palette[(*(src + 2ULL)) * 3ULL + 1ULL],
290  context->palette[(*(src + 1ULL)) * 3ULL + 1ULL],
291  context->palette[(*src) * 3ULL + 1ULL]);
292  b_val = _mm_set_epi16(context->palette[(*(src + 7ULL)) * 3ULL + 2ULL],
293  context->palette[(*(src + 6ULL)) * 3ULL + 2ULL],
294  context->palette[(*(src + 5ULL)) * 3ULL + 2ULL],
295  context->palette[(*(src + 4ULL)) * 3ULL + 2ULL],
296  context->palette[(*(src + 3ULL)) * 3ULL + 2ULL],
297  context->palette[(*(src + 2ULL)) * 3ULL + 2ULL],
298  context->palette[(*(src + 1ULL)) * 3ULL + 2ULL],
299  context->palette[(*src) * 3ULL + 2ULL]);
300  src += 8;
301  }
302 
303  a_val = _mm_set1_epi16(0xFF);
304  break;
305 
306  default:
307  r_val = g_val = b_val = a_val = _mm_set1_epi16(0);
308  break;
309  }
310 
311  __m128i y_val = _mm_srai_epi16(r_val, 2);
312  y_val = _mm_add_epi16(y_val, _mm_srai_epi16(g_val, 1));
313  y_val = _mm_add_epi16(y_val, _mm_srai_epi16(b_val, 2));
314  __m128i co_val = _mm_sub_epi16(r_val, b_val);
315  co_val = _mm_srai_epi16(co_val, ccl);
316  __m128i cg_val = _mm_sub_epi16(g_val, _mm_srai_epi16(r_val, 1));
317  cg_val = _mm_sub_epi16(cg_val, _mm_srai_epi16(b_val, 1));
318  cg_val = _mm_srai_epi16(cg_val, ccl);
319  y_val = _mm_packus_epi16(y_val, y_val);
320  _mm_storeu_si128((__m128i*)yplane, y_val);
321  co_val = _mm_packs_epi16(co_val, co_val);
322  _mm_storeu_si128((__m128i*)coplane, co_val);
323  cg_val = _mm_packs_epi16(cg_val, cg_val);
324  _mm_storeu_si128((__m128i*)cgplane, cg_val);
325  a_val = _mm_packus_epi16(a_val, a_val);
326  _mm_storeu_si128((__m128i*)aplane, a_val);
327  yplane += 8;
328  coplane += 8;
329  cgplane += 8;
330  aplane += 8;
331  }
332 
333  if (context->ChromaSubsamplingLevel > 0 && (context->width % 2) == 1)
334  {
335  context->priv->PlaneBuffers[0][y * rw + context->width] =
336  context->priv->PlaneBuffers[0][y * rw + context->width - 1];
337  context->priv->PlaneBuffers[1][y * rw + context->width] =
338  context->priv->PlaneBuffers[1][y * rw + context->width - 1];
339  context->priv->PlaneBuffers[2][y * rw + context->width] =
340  context->priv->PlaneBuffers[2][y * rw + context->width - 1];
341  }
342  }
343 
344  if (context->ChromaSubsamplingLevel > 0 && (y % 2) == 1)
345  {
346  BYTE* yplane = context->priv->PlaneBuffers[0] + y * rw;
347  BYTE* coplane = context->priv->PlaneBuffers[1] + y * rw;
348  BYTE* cgplane = context->priv->PlaneBuffers[2] + y * rw;
349  CopyMemory(yplane, yplane - rw, rw);
350  CopyMemory(coplane, coplane - rw, rw);
351  CopyMemory(cgplane, cgplane - rw, rw);
352  }
353 
354  return TRUE;
355 }
356 
357 static void nsc_encode_subsampling_sse2(NSC_CONTEXT* context)
358 {
359  BYTE* co_dst = NULL;
360  BYTE* cg_dst = NULL;
361  INT8* co_src0 = NULL;
362  INT8* co_src1 = NULL;
363  INT8* cg_src0 = NULL;
364  INT8* cg_src1 = NULL;
365  UINT32 tempWidth = 0;
366  UINT32 tempHeight = 0;
367  __m128i t;
368  __m128i val;
369  __m128i mask = _mm_set1_epi16(0xFF);
370  tempWidth = ROUND_UP_TO(context->width, 8);
371  tempHeight = ROUND_UP_TO(context->height, 2);
372 
373  for (size_t y = 0; y < tempHeight >> 1; y++)
374  {
375  co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1);
376  cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1);
377  co_src0 = (INT8*)context->priv->PlaneBuffers[1] + (y << 1) * tempWidth;
378  co_src1 = co_src0 + tempWidth;
379  cg_src0 = (INT8*)context->priv->PlaneBuffers[2] + (y << 1) * tempWidth;
380  cg_src1 = cg_src0 + tempWidth;
381 
382  for (UINT32 x = 0; x < tempWidth >> 1; x += 8)
383  {
384  t = _mm_loadu_si128((__m128i*)co_src0);
385  t = _mm_avg_epu8(t, _mm_loadu_si128((__m128i*)co_src1));
386  val = _mm_and_si128(_mm_srli_si128(t, 1), mask);
387  val = _mm_avg_epu16(val, _mm_and_si128(t, mask));
388  val = _mm_packus_epi16(val, val);
389  _mm_storeu_si128((__m128i*)co_dst, val);
390  co_dst += 8;
391  co_src0 += 16;
392  co_src1 += 16;
393  t = _mm_loadu_si128((__m128i*)cg_src0);
394  t = _mm_avg_epu8(t, _mm_loadu_si128((__m128i*)cg_src1));
395  val = _mm_and_si128(_mm_srli_si128(t, 1), mask);
396  val = _mm_avg_epu16(val, _mm_and_si128(t, mask));
397  val = _mm_packus_epi16(val, val);
398  _mm_storeu_si128((__m128i*)cg_dst, val);
399  cg_dst += 8;
400  cg_src0 += 16;
401  cg_src1 += 16;
402  }
403  }
404 }
405 
406 static BOOL nsc_encode_sse2(NSC_CONTEXT* context, const BYTE* data, UINT32 scanline)
407 {
408  if (!nsc_encode_argb_to_aycocg_sse2(context, data, scanline))
409  return FALSE;
410 
411  if (context->ChromaSubsamplingLevel > 0)
412  nsc_encode_subsampling_sse2(context);
413 
414  return TRUE;
415 }
416 #endif
417 
418 void nsc_init_sse2(NSC_CONTEXT* context)
419 {
420 #if defined(SSE_AVX_INTRINSICS_ENABLED)
421  if (!IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
422  return;
423 
424  PROFILER_RENAME(context->priv->prof_nsc_encode, "nsc_encode_sse2")
425  context->encode = nsc_encode_sse2;
426 #else
427  WINPR_UNUSED(context);
428 #endif
429 }