1 #include "fade.h"
2 #include "pool-buffer.h"
3 #include "swaylock.h"
4 #include <stdio.h>
5 #include <omp.h>
6 #include <stdalign.h>
7 #include <string.h>
8
9 #ifdef FADE_PROFILE
10 #include <time.h>
get_time()11 double get_time() {
12 struct timespec tv;
13 clock_gettime(CLOCK_MONOTONIC, &tv);
14 return tv.tv_sec + (tv.tv_nsec / 1000000000.0);
15 }
16 #endif
17
18 #if defined(__SSE2__) && __GNUC__ != 8
19 #define set_alpha set_alpha_sse
20
21 #include <immintrin.h>
22
set_alpha_sse(uint32_t * orig,struct pool_buffer * buf,float alpha)23 static void set_alpha_sse(uint32_t *orig, struct pool_buffer *buf, float alpha) {
24 int alpha_factor = (int)(alpha * (1 << 16));
25 if (alpha_factor != 0)
26 alpha_factor -= 1;
27
28 __m128i alpha_vec = _mm_set_epi16(
29 alpha_factor, alpha_factor, alpha_factor, alpha_factor,
30 alpha_factor, alpha_factor, alpha_factor, alpha_factor);
31 __m128i dummy_vec = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0);
32
33 uint8_t *orig_bytes = (uint8_t *)orig;
34 uint8_t *dest_bytes = (uint8_t *)buf->data;
35 size_t length = ((size_t)buf->width * (size_t)buf->height * 4) / 8;
36
37 for (size_t i = 0; i < length; ++i) {
38 size_t index = i * 8;
39
40 // Read data into SSE register, where each byte is an u16
41 __m128i argb_vec = _mm_loadu_si64(orig_bytes + index);
42 argb_vec = _mm_unpacklo_epi8(argb_vec, dummy_vec);
43
44 // Multiply the 8 argb u16s with the 8 alpha u16s
45 argb_vec = _mm_mulhi_epu16(argb_vec, alpha_vec);
46
47 // Put the low bytes of each argb u16 into the destination buffer
48 argb_vec = _mm_packus_epi16(argb_vec, dummy_vec);
49 _mm_storeu_si64(dest_bytes + index, argb_vec);
50 }
51 }
52
53 #else
54 #define set_alpha set_alpha_slow
55
set_alpha_slow(uint32_t * orig,struct pool_buffer * buf,float alpha)56 static void set_alpha_slow(uint32_t *orig, struct pool_buffer *buf, float alpha) {
57 for (size_t y = 0; y < buf->height; ++y) {
58 for (size_t x = 0; x < buf->width; ++x) {
59 size_t index = y * buf->width + x;
60 uint32_t srcpix = orig[index];
61 int srcr = (srcpix & 0x00ff0000u) >> 16;
62 int srcg = (srcpix & 0x0000ff00u) >> 8;
63 int srcb = (srcpix & 0x000000ffu);
64
65 ((uint32_t *)buf->data)[index] = 0 |
66 (uint32_t)(alpha * 255) << 24 |
67 (uint32_t)(srcr * alpha) << 16 |
68 (uint32_t)(srcg * alpha) << 8 |
69 (uint32_t)(srcb * alpha);
70 }
71 }
72 }
73
74 #endif
75
fade_prepare(struct swaylock_fade * fade,struct pool_buffer * buffer)76 void fade_prepare(struct swaylock_fade *fade, struct pool_buffer *buffer) {
77 if (!fade->target_time) {
78 fade->original_buffer = NULL;
79 return;
80 }
81
82 size_t size = (size_t)buffer->width * (size_t)buffer->height * 4;
83 fade->original_buffer = malloc(size);
84 memcpy(fade->original_buffer, buffer->data, size);
85
86 set_alpha(fade->original_buffer, buffer, 0);
87 }
88
fade_update(struct swaylock_fade * fade,struct pool_buffer * buffer,uint32_t time)89 void fade_update(struct swaylock_fade *fade, struct pool_buffer *buffer, uint32_t time) {
90 if (fade->current_time >= fade->target_time) {
91 return;
92 }
93
94 double delta = 0;
95 if (fade->old_time != 0) {
96 delta = time - fade->old_time;
97 }
98 fade->old_time = time;
99
100 fade->current_time += delta;
101 if (fade->current_time > fade->target_time) {
102 fade->current_time = fade->target_time;
103 }
104
105 double alpha = (double)fade->current_time / (double)fade->target_time;
106
107 #ifdef FADE_PROFILE
108 double before = get_time();
109 #endif
110
111 set_alpha(fade->original_buffer, buffer, alpha);
112
113 #ifdef FADE_PROFILE
114 double after = get_time();
115 printf("set alpha in %fms (%fFPS). %fms since last time, FPS: %f\n",
116 (after - before) * 1000, 1 / (after - before),
117 delta, 1000 / delta);
118 #endif
119 }
120
fade_is_complete(struct swaylock_fade * fade)121 bool fade_is_complete(struct swaylock_fade *fade) {
122 return fade->target_time == 0 || fade->current_time >= fade->target_time;
123 }
124
fade_destroy(struct swaylock_fade * fade)125 void fade_destroy(struct swaylock_fade *fade) {
126 free(fade->original_buffer);
127 }
128