|
40 | 40 | #include <fcntl.h>
|
41 | 41 | #include <poll.h>
|
42 | 42 | #include <errno.h>
|
| 43 | +#include <stdatomic.h> |
43 | 44 |
|
44 | 45 | #define WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE 3
|
45 | 46 |
|
@@ -268,13 +269,20 @@ damage_thread(void *args)
|
268 | 269 | if (ok) {
|
269 | 270 |
|
270 | 271 | // If there's an unprocessed frame ready, send damage event
|
271 |
| - if (surface->ctx.framesFinished != |
272 |
| - surface->ctx.framesProcessed) { |
| 272 | + if (surface->ctx.framesFinished != surface->ctx.framesProcessed) { |
| 273 | + WlEglStreamDamage damage; |
| 274 | + |
273 | 275 | if (display->devDpy->exts.stream_flush) {
|
274 | 276 | data->egl.streamFlush(display->devDpy->eglDisplay,
|
275 | 277 | surface->ctx.eglStream);
|
276 | 278 | }
|
277 |
| - ok = wlEglSendDamageEvent(surface, queue, NULL, 0); |
| 279 | + |
| 280 | + if (wlEglGetStreamDamageForFrame(&surface->ctx.damageBuffer, surface->ctx.framesProcessed, &damage)) { |
| 281 | + ok = wlEglSendDamageEvent(surface, queue, damage.rects, damage.n_rects); |
| 282 | + } else { |
| 283 | + ok = wlEglSendDamageEvent(surface, queue, NULL, 0); |
| 284 | + } |
| 285 | + |
278 | 286 | surface->ctx.framesProcessed++;
|
279 | 287 | }
|
280 | 288 |
|
@@ -2223,3 +2231,84 @@ EGLBoolean wlEglQueryNativeResourceHook(EGLDisplay dpy,
|
2223 | 2231 | wlExternalApiUnlock();
|
2224 | 2232 | return res;
|
2225 | 2233 | }
|
| 2234 | + |
| 2235 | +void |
| 2236 | +wlEglInitializeStreamDamageBuffer(WlEglStreamDamageBuffer *buffer) |
| 2237 | +{ |
| 2238 | + memset (buffer, 0, sizeof *buffer); |
| 2239 | +} |
| 2240 | + |
| 2241 | +EGLBoolean |
| 2242 | +wlEglGetStreamDamageForFrame(WlEglStreamDamageBuffer *buffer, |
| 2243 | + EGLuint64KHR frameNumber, |
| 2244 | + WlEglStreamDamage *damage) |
| 2245 | +{ |
| 2246 | + EGLint tail = buffer->tail; |
| 2247 | + |
| 2248 | + atomic_thread_fence (memory_order_acquire); |
| 2249 | + |
| 2250 | + for (;;) { |
| 2251 | + if (buffer->head == tail) { |
| 2252 | + return EGL_FALSE; |
| 2253 | + } |
| 2254 | + |
| 2255 | + if (buffer->frames[tail].frameNumber > frameNumber) { |
| 2256 | + /* We must have dropped our desired frame damage on the floor |
| 2257 | + * because there was not space or it had too many rectangles. |
| 2258 | + */ |
| 2259 | + return EGL_FALSE; |
| 2260 | + } |
| 2261 | + |
| 2262 | + /* Avoid copying empty rectangles */ |
| 2263 | + memcpy (damage, &buffer->frames[tail], |
| 2264 | + offsetof (WlEglStreamDamage, rects) + buffer->frames[tail].n_rects * sizeof(EGLint) * 4); |
| 2265 | + |
| 2266 | + tail++; |
| 2267 | + if (tail == WL_EGL_STREAM_DAMAGE_BUFFER_N_FRAMES) { |
| 2268 | + tail = 0; |
| 2269 | + } |
| 2270 | + |
| 2271 | + atomic_thread_fence (memory_order_release); |
| 2272 | + |
| 2273 | + buffer->tail = tail; |
| 2274 | + |
| 2275 | + if (damage->frameNumber == frameNumber) { |
| 2276 | + return EGL_TRUE; |
| 2277 | + } |
| 2278 | + } |
| 2279 | + |
| 2280 | + /* Not reached */ |
| 2281 | +} |
| 2282 | + |
| 2283 | +EGLBoolean |
| 2284 | +wlEglPutStreamDamage(WlEglStreamDamageBuffer *buffer, |
| 2285 | + EGLuint64KHR frameNumber, |
| 2286 | + EGLint *rects, |
| 2287 | + EGLint n_rects) |
| 2288 | +{ |
| 2289 | + EGLint head = buffer->head + 1; |
| 2290 | + |
| 2291 | + if (n_rects == 0 || n_rects > WL_EGL_STREAM_DAMAGE_BUFFER_N_RECTS) { |
| 2292 | + return EGL_FALSE; |
| 2293 | + } |
| 2294 | + |
| 2295 | + if (head == WL_EGL_STREAM_DAMAGE_BUFFER_N_FRAMES) { |
| 2296 | + head = 0; |
| 2297 | + } |
| 2298 | + |
| 2299 | + atomic_thread_fence (memory_order_acquire); |
| 2300 | + |
| 2301 | + if (head != buffer->tail) { |
| 2302 | + buffer->frames[buffer->head].frameNumber = frameNumber; |
| 2303 | + buffer->frames[buffer->head].n_rects = n_rects; |
| 2304 | + memcpy (buffer->frames[buffer->head].rects, rects, sizeof (EGLint) * 4 * n_rects); |
| 2305 | + |
| 2306 | + atomic_thread_fence (memory_order_release); |
| 2307 | + |
| 2308 | + buffer->head = head; |
| 2309 | + |
| 2310 | + return EGL_TRUE; |
| 2311 | + } |
| 2312 | + |
| 2313 | + return EGL_FALSE; |
| 2314 | +} |
0 commit comments