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