diff options
2 files changed, 1065 insertions, 1 deletions
diff --git a/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Accelerate-picture-composition.patch b/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Accelerate-picture-composition.patch new file mode 100644 index 00000000..3fa4d6ec --- /dev/null +++ b/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Accelerate-picture-composition.patch | |||
@@ -0,0 +1,1058 @@ | |||
1 | From 015f8a54f7e5a754e1cefba1aa7b1f6992a8aa9b Mon Sep 17 00:00:00 2001 | ||
2 | From: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
3 | Date: Tue, 16 Jul 2024 19:48:47 +0000 | ||
4 | Subject: [PATCH] xf86-video-armosc: Accelerate picture composition | ||
5 | |||
6 | Introduce Repulsion - simplistic GPU accelerated compositor to back RandR | ||
7 | display manipulation features. This library is inspired by Glamor extension | ||
8 | https://www.freedesktop.org/wiki/Software/Glamor/. Unfortunately Glamor | ||
9 | doesn't work as is on ARM Mali-400 MP due to the lack of required features | ||
10 | and several bugs in Mali EGL/GLES implementation. | ||
11 | |||
12 | Install and manage picture compositor hooks. | ||
13 | |||
14 | Provide access to dma-buf fd from ARSOC buffer object. | ||
15 | |||
16 | Attach shadow buffer object to corresponding pixmap. | ||
17 | |||
18 | Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
19 | --- | ||
20 | src/Makefile.am | 3 +- | ||
21 | src/armsoc_driver.c | 145 ++++++++++ | ||
22 | src/armsoc_driver.h | 7 + | ||
23 | src/armsoc_dumb.c | 8 + | ||
24 | src/armsoc_dumb.h | 1 + | ||
25 | src/armsoc_exa.c | 18 +- | ||
26 | src/armsoc_repulsion.c | 624 +++++++++++++++++++++++++++++++++++++++++ | ||
27 | src/armsoc_repulsion.h | 67 +++++ | ||
28 | 8 files changed, 867 insertions(+), 6 deletions(-) | ||
29 | create mode 100644 src/armsoc_repulsion.c | ||
30 | create mode 100644 src/armsoc_repulsion.h | ||
31 | |||
32 | diff --git a/src/Makefile.am b/src/Makefile.am | ||
33 | index db5f110..cd4f795 100644 | ||
34 | --- a/src/Makefile.am | ||
35 | +++ b/src/Makefile.am | ||
36 | @@ -38,7 +38,7 @@ ERROR_CFLAGS = -Werror -Wall -Wdeclaration-after-statement -Wvla \ | ||
37 | AM_CFLAGS = @XORG_CFLAGS@ $(ERROR_CFLAGS) | ||
38 | armsoc_drv_la_LTLIBRARIES = armsoc_drv.la | ||
39 | armsoc_drv_la_LDFLAGS = -module -avoid-version -no-undefined | ||
40 | -armsoc_drv_la_LIBADD = @XORG_LIBS@ | ||
41 | +armsoc_drv_la_LIBADD = -lMali @XORG_LIBS@ | ||
42 | armsoc_drv_ladir = @moduledir@/drivers | ||
43 | DRMMODE_SRCS = drmmode_exynos/drmmode_exynos.c \ | ||
44 | drmmode_pl111/drmmode_pl111.c \ | ||
45 | @@ -54,4 +54,5 @@ armsoc_drv_la_SOURCES = \ | ||
46 | armsoc_dri2.c \ | ||
47 | armsoc_driver.c \ | ||
48 | armsoc_dumb.c \ | ||
49 | + armsoc_repulsion.c \ | ||
50 | $(DRMMODE_SRCS) | ||
51 | diff --git a/src/armsoc_driver.c b/src/armsoc_driver.c | ||
52 | index a4a1ba3..f5b8f21 100644 | ||
53 | --- a/src/armsoc_driver.c | ||
54 | +++ b/src/armsoc_driver.c | ||
55 | @@ -42,6 +42,7 @@ | ||
56 | #include <pixman.h> | ||
57 | |||
58 | #include "armsoc_driver.h" | ||
59 | +#include "armsoc_repulsion.h" | ||
60 | |||
61 | #include "micmap.h" | ||
62 | |||
63 | @@ -971,6 +972,138 @@ ARMSOCAccelInit(ScreenPtr pScreen) | ||
64 | pARMSOC->dri = FALSE; | ||
65 | } | ||
66 | |||
67 | +#define ARMSOC_ACCEL_MIN_DIMS 200 | ||
68 | + | ||
69 | +/** | ||
70 | + * Classify compositor input to figure out if we can accelerate composition | ||
71 | + */ | ||
72 | +static Bool | ||
73 | +ARMSOCCanAccelerateComposition(CARD8 op, | ||
74 | + PicturePtr src, | ||
75 | + PicturePtr mask, | ||
76 | + PicturePtr dest, | ||
77 | + CARD16 width, | ||
78 | + CARD16 height) | ||
79 | +{ | ||
80 | + /* We only support source to destination pixmap copy */ | ||
81 | + if (op != PictOpSrc) | ||
82 | + return FALSE; | ||
83 | + | ||
84 | + /* | ||
85 | + * Don't accelerate small picture compositions, e.g. toolbars, cursor, | ||
86 | + * icons, etc. | ||
87 | + */ | ||
88 | + if (width < ARMSOC_ACCEL_MIN_DIMS || height < ARMSOC_ACCEL_MIN_DIMS) | ||
89 | + return FALSE; | ||
90 | + | ||
91 | + /* Check source picture */ | ||
92 | + if (!src || !src->pDrawable) | ||
93 | + return FALSE; | ||
94 | + | ||
95 | + /* Check destination picture constraints */ | ||
96 | + if (!dest || !dest->pDrawable || dest->pDrawable->type != DRAWABLE_PIXMAP) | ||
97 | + return FALSE; | ||
98 | + | ||
99 | + /* We don't support masking */ | ||
100 | + if (mask) | ||
101 | + return FALSE; | ||
102 | + | ||
103 | + /* | ||
104 | + * We expect source transform to be assigned, otherwise there is not much | ||
105 | + * to accelerate | ||
106 | + */ | ||
107 | + if (!src->transform) | ||
108 | + return FALSE; | ||
109 | + | ||
110 | + /* We expect buffer object to be assigned to source */ | ||
111 | + if (!draw2pix(src->pDrawable)) | ||
112 | + return FALSE; | ||
113 | + | ||
114 | + /* We expect buffer object to be assigned to destination */ | ||
115 | + if (!draw2pix(dest->pDrawable)) | ||
116 | + return FALSE; | ||
117 | + | ||
118 | + return TRUE; | ||
119 | +} | ||
120 | + | ||
121 | +/** | ||
122 | + * This callback will be invoked every time xserver needs to combine 2 | ||
123 | + * pictures. Our special interest is the case when we need to blit draw buffer | ||
124 | + * into shadow buffer while performing rotation or reflection. Without | ||
125 | + * acceleration such composition will end up in tons of matrix multiplications | ||
126 | + * for every pixel, which is obviously very slow. Here we need to detect such | ||
127 | + * cases and accelerate the composition on the GPU. | ||
128 | + */ | ||
129 | +static void | ||
130 | +ARMSOCComposite(CARD8 op, | ||
131 | + PicturePtr src, | ||
132 | + PicturePtr mask, | ||
133 | + PicturePtr dest, | ||
134 | + INT16 x_src, | ||
135 | + INT16 y_src, | ||
136 | + INT16 x_mask, | ||
137 | + INT16 y_mask, | ||
138 | + INT16 x_dest, | ||
139 | + INT16 y_dest, | ||
140 | + CARD16 width, | ||
141 | + CARD16 height) | ||
142 | +{ | ||
143 | + ScreenPtr pScreen = dest->pDrawable->pScreen; | ||
144 | + PictureScreenPtr ps = GetPictureScreen(pScreen); | ||
145 | + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); | ||
146 | + struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); | ||
147 | + struct armsoc_bo *src_bo = NULL, *dest_bo = NULL; | ||
148 | + float xform_matrix[3][3] = {}; | ||
149 | + | ||
150 | + Bool can_accelerate = | ||
151 | + ARMSOCCanAccelerateComposition(op, src, mask, dest, width, height); | ||
152 | + | ||
153 | + | ||
154 | + if (can_accelerate) { | ||
155 | + /* Transpose, scale & adjust transformation matrix */ | ||
156 | + int x, y; | ||
157 | + for (y = 0; y < 3; ++y) | ||
158 | + for (x = 0; x < 3; ++x) | ||
159 | + xform_matrix[x][y] = | ||
160 | + (float)src->transform->matrix[y][x] / 65536.f; | ||
161 | + /* | ||
162 | + * TODO: Figure out coordinate system where these sins make sence, | ||
163 | + * insted of just reversing them | ||
164 | + */ | ||
165 | + xform_matrix[0][1] = -xform_matrix[0][1]; | ||
166 | + xform_matrix[1][0] = -xform_matrix[1][0]; | ||
167 | + } | ||
168 | + | ||
169 | + /* Extract source buffer object */ | ||
170 | + if (can_accelerate) { | ||
171 | + PixmapPtr pm = draw2pix(src->pDrawable); | ||
172 | + src_bo = ARMSOCPixmapBo(pm); | ||
173 | + } | ||
174 | + | ||
175 | + /* Extract destination buffer object */ | ||
176 | + if (can_accelerate) { | ||
177 | + PixmapPtr pm = draw2pix(dest->pDrawable); | ||
178 | + dest_bo = ARMSOCPixmapBo(pm); | ||
179 | + } | ||
180 | + | ||
181 | + if (can_accelerate && | ||
182 | + armsoc_repulsion_composite(pARMSOC->repulsion, | ||
183 | + src_bo, | ||
184 | + dest_bo, | ||
185 | + xform_matrix)) { | ||
186 | + } else { | ||
187 | + /* Fallback to saved compositor if accelerated composition fails */ | ||
188 | + pARMSOC->composite_proc(op, src, mask, dest, | ||
189 | + x_src, y_src, x_mask, y_mask, | ||
190 | + x_dest, y_dest, width, height); | ||
191 | + } | ||
192 | + | ||
193 | + if (ps->Composite != ARMSOCComposite) { | ||
194 | + pARMSOC->composite_proc = ps->Composite; | ||
195 | + ps->Composite = ARMSOCComposite; | ||
196 | + } | ||
197 | +} | ||
198 | + | ||
199 | /** | ||
200 | * The driver's ScreenInit() function, called at the start of each server | ||
201 | * generation. Fill in pScreen, map the frame buffer, save state, | ||
202 | @@ -986,6 +1119,7 @@ ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL) | ||
203 | struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); | ||
204 | VisualPtr visual; | ||
205 | xf86CrtcConfigPtr xf86_config; | ||
206 | + PictureScreenPtr ps; | ||
207 | int j; | ||
208 | const char *fbdev; | ||
209 | int depth; | ||
210 | @@ -1174,6 +1308,13 @@ ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL) | ||
211 | pARMSOC->lockFD = -1; | ||
212 | } | ||
213 | |||
214 | + pARMSOC->repulsion = armsoc_repulsion_init(); | ||
215 | + | ||
216 | + ps = GetPictureScreen(pScreen); | ||
217 | + pARMSOC->composite_proc = ps->Composite; | ||
218 | + | ||
219 | + ps->Composite = ARMSOCComposite; | ||
220 | + | ||
221 | TRACE_EXIT(); | ||
222 | return TRUE; | ||
223 | |||
224 | @@ -1250,6 +1391,8 @@ ARMSOCCloseScreen(CLOSE_SCREEN_ARGS_DECL) | ||
225 | |||
226 | TRACE_ENTER(); | ||
227 | |||
228 | + armsoc_repulsion_release(pARMSOC->repulsion); | ||
229 | + | ||
230 | drmmode_screen_fini(pScrn); | ||
231 | drmmode_cursor_fini(pScreen); | ||
232 | |||
233 | @@ -1294,6 +1437,8 @@ ARMSOCCloseScreen(CLOSE_SCREEN_ARGS_DECL) | ||
234 | pARMSOC->lockFD = -1; | ||
235 | } | ||
236 | |||
237 | + armsoc_repulsion_release(pARMSOC->repulsion); | ||
238 | + | ||
239 | TRACE_EXIT(); | ||
240 | |||
241 | return ret; | ||
242 | diff --git a/src/armsoc_driver.h b/src/armsoc_driver.h | ||
243 | index eae76ca..20b0f80 100644 | ||
244 | --- a/src/armsoc_driver.h | ||
245 | +++ b/src/armsoc_driver.h | ||
246 | @@ -38,6 +38,7 @@ | ||
247 | #include "xf86drm.h" | ||
248 | #include <errno.h> | ||
249 | #include "armsoc_exa.h" | ||
250 | +#include "armsoc_repulsion.h" | ||
251 | |||
252 | /* Apparently not used by X server */ | ||
253 | #define ARMSOC_VERSION 1000 | ||
254 | @@ -183,6 +184,12 @@ struct ARMSOCRec { | ||
255 | /* Size of the swap chain. Set to 1 if DRI2SwapLimit unsupported, | ||
256 | * driNumBufs if early display enabled, otherwise driNumBufs-1 */ | ||
257 | unsigned int swap_chain_size; | ||
258 | + | ||
259 | + /* GPU accelerated picture compositor, AKA Repulsion */ | ||
260 | + struct ARMSOCRepulsion *repulsion; | ||
261 | + | ||
262 | + /* SW (pixman based) picture compositor fallback */ | ||
263 | + CompositeProcPtr composite_proc; | ||
264 | }; | ||
265 | |||
266 | /* | ||
267 | diff --git a/src/armsoc_dumb.c b/src/armsoc_dumb.c | ||
268 | index 7e6dbd9..3c16ed2 100644 | ||
269 | --- a/src/armsoc_dumb.c | ||
270 | +++ b/src/armsoc_dumb.c | ||
271 | @@ -130,6 +130,14 @@ int armsoc_bo_has_dmabuf(struct armsoc_bo *bo) | ||
272 | return bo->dmabuf >= 0; | ||
273 | } | ||
274 | |||
275 | +int armsoc_bo_get_dmabuf(struct armsoc_bo *bo) | ||
276 | +{ | ||
277 | + if (!armsoc_bo_has_dmabuf(bo)) | ||
278 | + armsoc_bo_set_dmabuf(bo); | ||
279 | + | ||
280 | + return bo->dmabuf; | ||
281 | +} | ||
282 | + | ||
283 | struct armsoc_bo *armsoc_bo_new_with_dim(struct armsoc_device *dev, | ||
284 | uint32_t width, uint32_t height, uint8_t depth, | ||
285 | uint8_t bpp, enum armsoc_buf_type buf_type) | ||
286 | diff --git a/src/armsoc_dumb.h b/src/armsoc_dumb.h | ||
287 | index a299ccf..3b687c7 100644 | ||
288 | --- a/src/armsoc_dumb.h | ||
289 | +++ b/src/armsoc_dumb.h | ||
290 | @@ -89,6 +89,7 @@ void armsoc_bo_unreference(struct armsoc_bo *bo); | ||
291 | int armsoc_bo_set_dmabuf(struct armsoc_bo *bo); | ||
292 | void armsoc_bo_clear_dmabuf(struct armsoc_bo *bo); | ||
293 | int armsoc_bo_has_dmabuf(struct armsoc_bo *bo); | ||
294 | +int armsoc_bo_get_dmabuf(struct armsoc_bo *bo); | ||
295 | int armsoc_bo_clear(struct armsoc_bo *bo); | ||
296 | int armsoc_bo_rm_fb(struct armsoc_bo *bo); | ||
297 | int armsoc_bo_resize(struct armsoc_bo *bo, uint32_t new_width, | ||
298 | diff --git a/src/armsoc_exa.c b/src/armsoc_exa.c | ||
299 | index a310727..7edf0ac 100644 | ||
300 | --- a/src/armsoc_exa.c | ||
301 | +++ b/src/armsoc_exa.c | ||
302 | @@ -161,10 +161,16 @@ ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, | ||
303 | ScrnInfoPtr pScrn = pix2scrn(pPixmap); | ||
304 | struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); | ||
305 | enum armsoc_buf_type buf_type = ARMSOC_BO_NON_SCANOUT; | ||
306 | + struct armsoc_bo *fb_bo = NULL; | ||
307 | |||
308 | /* Only modify specified fields, keeping all others intact. */ | ||
309 | - if (pPixData) | ||
310 | + if (pPixData) { | ||
311 | pPixmap->devPrivate.ptr = pPixData; | ||
312 | + if (pARMSOC->shadow && pPixData == armsoc_bo_map(pARMSOC->shadow)) | ||
313 | + fb_bo = pARMSOC->shadow; | ||
314 | + else if (pPixData == armsoc_bo_map(pARMSOC->scanout)) | ||
315 | + fb_bo = pARMSOC->scanout; | ||
316 | + } | ||
317 | |||
318 | if (devKind > 0) | ||
319 | pPixmap->devKind = devKind; | ||
320 | @@ -173,7 +179,7 @@ ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, | ||
321 | * We can't accelerate this pixmap, and don't ever want to | ||
322 | * see it again.. | ||
323 | */ | ||
324 | - if (pPixData && pPixData != armsoc_bo_map(pARMSOC->scanout)) { | ||
325 | + if (pPixData && fb_bo && pPixData != armsoc_bo_map(fb_bo)) { | ||
326 | /* scratch-pixmap (see GetScratchPixmapHeader()) gets recycled, | ||
327 | * so could have a previous bo! | ||
328 | * Pixmap drops ref on its old bo */ | ||
329 | @@ -185,10 +191,10 @@ ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, | ||
330 | } | ||
331 | |||
332 | /* Replacing the pixmap's current bo with the scanout bo */ | ||
333 | - if (pPixData == armsoc_bo_map(pARMSOC->scanout) && priv->bo != pARMSOC->scanout) { | ||
334 | + if (fb_bo && pPixData == armsoc_bo_map(fb_bo) && priv->bo != fb_bo) { | ||
335 | struct armsoc_bo *old_bo = priv->bo; | ||
336 | |||
337 | - priv->bo = pARMSOC->scanout; | ||
338 | + priv->bo = fb_bo; | ||
339 | /* pixmap takes a ref on its new bo */ | ||
340 | armsoc_bo_reference(priv->bo); | ||
341 | |||
342 | @@ -225,7 +231,9 @@ ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, | ||
343 | if (!pPixmap->drawable.width || !pPixmap->drawable.height) | ||
344 | return TRUE; | ||
345 | |||
346 | - assert(priv->bo); | ||
347 | + if(!priv->bo) | ||
348 | + return FALSE; | ||
349 | + | ||
350 | if (armsoc_bo_width(priv->bo) != pPixmap->drawable.width || | ||
351 | armsoc_bo_height(priv->bo) != pPixmap->drawable.height || | ||
352 | armsoc_bo_bpp(priv->bo) != pPixmap->drawable.bitsPerPixel) { | ||
353 | diff --git a/src/armsoc_repulsion.c b/src/armsoc_repulsion.c | ||
354 | new file mode 100644 | ||
355 | index 0000000..1a7c0cd | ||
356 | --- /dev/null | ||
357 | +++ b/src/armsoc_repulsion.c | ||
358 | @@ -0,0 +1,624 @@ | ||
359 | +/* | ||
360 | + * Copyright (C) 2024 AMD, Inc. | ||
361 | + * | ||
362 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
363 | + * copy of this software and associated documentation files (the "Software"), | ||
364 | + * to deal in the Software without restriction, including without limitation | ||
365 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
366 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
367 | + * Software is furnished to do so, subject to the following conditions: | ||
368 | + * | ||
369 | + * The above copyright notice and this permission notice (including the next | ||
370 | + * paragraph) shall be included in all copies or substantial portions of the | ||
371 | + * Software. | ||
372 | + * | ||
373 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
374 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
375 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
376 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
377 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
378 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
379 | + * SOFTWARE. | ||
380 | + * | ||
381 | + * Author: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
382 | + * | ||
383 | + */ | ||
384 | + | ||
385 | +#include "armsoc_repulsion.h" | ||
386 | + | ||
387 | +#include <stdlib.h> | ||
388 | +#include <drm_fourcc.h> | ||
389 | + | ||
390 | +#define EGL_GL_PROTOTYPES 1 | ||
391 | +#include <EGL/egl.h> | ||
392 | +#define EGL_EGLEXT_PROTOTYPES 1 | ||
393 | +#include <EGL/eglext.h> | ||
394 | +#include <GLES2/gl2.h> | ||
395 | +#define GL_GLEXT_PROTOTYPES 1 | ||
396 | +#include <GLES2/gl2ext.h> | ||
397 | + | ||
398 | +#include <xf86.h> | ||
399 | + | ||
400 | +/* ----------------------------------------------------------------------------- | ||
401 | + * Utilities | ||
402 | + */ | ||
403 | + | ||
404 | +#define INFO_LOG(fmt, ...) \ | ||
405 | +do { xf86DrvMsg(0, X_INFO, fmt "\n", ##__VA_ARGS__); } while (0) | ||
406 | + | ||
407 | +#define WARN_LOG(fmt, ...) \ | ||
408 | +do { xf86DrvMsg(0, X_WARNING, "WARNING: " fmt "\n", ##__VA_ARGS__); } while (0) | ||
409 | + | ||
410 | +#define ERROR_LOG(fmt, ...) \ | ||
411 | +do { xf86DrvMsg(0, X_ERROR, "ERROR: " fmt "\n", ##__VA_ARGS__); } while (0) | ||
412 | + | ||
413 | +/** | ||
414 | + * struct RepulsiveVertex - vertex data used for rendering | ||
415 | + * @pos: vertex position in the screen coordinate space | ||
416 | + * @uv: texture coordinate bound to this vertex | ||
417 | + */ | ||
418 | +struct RepulsiveVertex { | ||
419 | + GLfloat pos[3]; | ||
420 | + GLfloat uv[2]; | ||
421 | +}; | ||
422 | + | ||
423 | +/** | ||
424 | + * struct ARMSOCRepulsion - GPU acceleration data | ||
425 | + * @egl: EGL specific bits | ||
426 | + * @egl.display: EGL display connection | ||
427 | + * @egl.context: EGL context | ||
428 | + * @egl.surface: primary EGL surface | ||
429 | + * @gles: OpenGL ES related bits | ||
430 | + * @gles.vbo: Vertex buffer object | ||
431 | + * @gles.ibo: Index buffer object | ||
432 | + * @gles.texture: External texture object | ||
433 | + * @gles.proj_location: Shader location for projection matrix | ||
434 | + * @gles.xform_location: Shader location for transformation matrix | ||
435 | + * @gles.vertices: Array of vertices used in rendering | ||
436 | + */ | ||
437 | +struct ARMSOCRepulsion { | ||
438 | + struct { | ||
439 | + EGLDisplay display; | ||
440 | + EGLContext context; | ||
441 | + EGLSurface surface; | ||
442 | + } egl; | ||
443 | + struct { | ||
444 | + GLuint vbo; | ||
445 | + GLuint ibo; | ||
446 | + GLuint texture; | ||
447 | + GLuint program; | ||
448 | + GLint proj_location; | ||
449 | + GLint xform_location; | ||
450 | + struct RepulsiveVertex vertices[4]; | ||
451 | + } gles; | ||
452 | +}; | ||
453 | + | ||
454 | +/* ----------------------------------------------------------------------------- | ||
455 | + * GLES2 Functions | ||
456 | + */ | ||
457 | + | ||
458 | +static const char *vertex_shader = " \ | ||
459 | +precision highp float; \ | ||
460 | + \ | ||
461 | +uniform mat3 u_projection; \ | ||
462 | +uniform mat3 u_transform; \ | ||
463 | +attribute vec3 a_position; \ | ||
464 | +attribute vec2 a_texcoord; \ | ||
465 | + \ | ||
466 | +varying vec2 v_texcoord; \ | ||
467 | + \ | ||
468 | +void main() \ | ||
469 | +{ \ | ||
470 | + gl_Position.xyz = u_transform * u_projection * a_position; \ | ||
471 | + gl_Position.w = 1.0; \ | ||
472 | + v_texcoord = a_texcoord; \ | ||
473 | +} \ | ||
474 | +"; | ||
475 | + | ||
476 | +static const char *fragment_shader = " \ | ||
477 | +#extension GL_OES_EGL_image_external : require\n \ | ||
478 | +precision highp float; \ | ||
479 | + \ | ||
480 | +uniform samplerExternalOES texture; \ | ||
481 | +varying vec2 v_texcoord; \ | ||
482 | + \ | ||
483 | +void main() \ | ||
484 | +{ \ | ||
485 | + gl_FragColor = texture2D(texture, v_texcoord); \ | ||
486 | +} \ | ||
487 | +"; | ||
488 | + | ||
489 | +#define SHADER_POSITION_ATTR_SLOT 0 | ||
490 | +#define SHADER_TEX_COOR_ATTR_SLOT 1 | ||
491 | + | ||
492 | +static void armsoc_repulsion_gles_log(GLenum source, GLenum type, GLuint id, | ||
493 | + GLenum severity, GLsizei length, | ||
494 | + const GLchar *message, const void *data) | ||
495 | +{ | ||
496 | + switch (severity) { | ||
497 | + case GL_DEBUG_SEVERITY_HIGH_KHR: | ||
498 | + ERROR_LOG("GLES2: %s", message); | ||
499 | + break; | ||
500 | + case GL_DEBUG_SEVERITY_MEDIUM_KHR: | ||
501 | + WARN_LOG("GLES2: %s", message); | ||
502 | + break; | ||
503 | + default: | ||
504 | + INFO_LOG("GLES2: %s", message); | ||
505 | + }; | ||
506 | +} | ||
507 | + | ||
508 | +static const char* gles_error_str(GLenum err) | ||
509 | +{ | ||
510 | + switch (err) { | ||
511 | + case GL_NO_ERROR: return "no error"; | ||
512 | + case GL_INVALID_ENUM: return "invalid enum"; | ||
513 | + case GL_INVALID_VALUE: return "invalid value"; | ||
514 | + case GL_INVALID_OPERATION: return "invalid operation"; | ||
515 | + case GL_OUT_OF_MEMORY: return "out of memory"; | ||
516 | + case GL_INVALID_FRAMEBUFFER_OPERATION: return "invalid fb operation"; | ||
517 | + default: return "unknowm error"; | ||
518 | + } | ||
519 | +}; | ||
520 | + | ||
521 | +static int armsoc_repulsion_compile_shader(struct ARMSOCRepulsion *repulsion) | ||
522 | +{ | ||
523 | + GLuint vs, fs; | ||
524 | + GLint status, texture; | ||
525 | + GLenum err; | ||
526 | + | ||
527 | + vs = glCreateShader(GL_VERTEX_SHADER); | ||
528 | + if (!vs) { | ||
529 | + err = glGetError(); | ||
530 | + return err == GL_NO_ERROR ? -1 : err; | ||
531 | + } | ||
532 | + glShaderSource(vs, 1, &vertex_shader, NULL); | ||
533 | + glCompileShader(vs); | ||
534 | + glGetShaderiv(vs, GL_COMPILE_STATUS, &status); | ||
535 | + if (status == GL_FALSE) { | ||
536 | + GLint max_len = 1024; | ||
537 | + GLchar err_log[1024]; | ||
538 | + glGetShaderInfoLog(vs, max_len, &max_len, &err_log[0]); | ||
539 | + ERROR_LOG("VS: %s", err_log); | ||
540 | + err = glGetError(); | ||
541 | + return err == GL_NO_ERROR ? -1 : err; | ||
542 | + } | ||
543 | + | ||
544 | + fs = glCreateShader(GL_FRAGMENT_SHADER); | ||
545 | + if (!fs) { | ||
546 | + err = glGetError(); | ||
547 | + return err == GL_NO_ERROR ? -1 : err; | ||
548 | + } | ||
549 | + glShaderSource(fs, 1, &fragment_shader, NULL); | ||
550 | + glCompileShader(fs); | ||
551 | + glGetShaderiv(fs, GL_COMPILE_STATUS, &status); | ||
552 | + if (status == GL_FALSE) { | ||
553 | + err = glGetError(); | ||
554 | + return err == GL_NO_ERROR ? -1 : err; | ||
555 | + } | ||
556 | + | ||
557 | + repulsion->gles.program = glCreateProgram(); | ||
558 | + if (!repulsion->gles.program) { | ||
559 | + err = glGetError(); | ||
560 | + return err == GL_NO_ERROR ? -1 : err; | ||
561 | + } | ||
562 | + glAttachShader(repulsion->gles.program, vs); | ||
563 | + glAttachShader(repulsion->gles.program, fs); | ||
564 | + glBindAttribLocation(repulsion->gles.program, SHADER_POSITION_ATTR_SLOT, | ||
565 | + "a_position"); | ||
566 | + glBindAttribLocation(repulsion->gles.program, SHADER_TEX_COOR_ATTR_SLOT, | ||
567 | + "a_texcoord"); | ||
568 | + glLinkProgram(repulsion->gles.program); | ||
569 | + glDetachShader(repulsion->gles.program, vs); | ||
570 | + glDetachShader(repulsion->gles.program, fs); | ||
571 | + glGetProgramiv(repulsion->gles.program, GL_LINK_STATUS, &status); | ||
572 | + if (status == GL_FALSE) { | ||
573 | + err = glGetError(); | ||
574 | + return err == GL_NO_ERROR ? -1 : err; | ||
575 | + } | ||
576 | + glUseProgram(repulsion->gles.program); | ||
577 | + glEnableVertexAttribArray(SHADER_POSITION_ATTR_SLOT); | ||
578 | + glEnableVertexAttribArray(SHADER_TEX_COOR_ATTR_SLOT); | ||
579 | + | ||
580 | + repulsion->gles.proj_location = | ||
581 | + glGetUniformLocation(repulsion->gles.program, "u_projection"); | ||
582 | + repulsion->gles.xform_location = | ||
583 | + glGetUniformLocation(repulsion->gles.program, "u_transform"); | ||
584 | + | ||
585 | + texture = glGetUniformLocation(repulsion->gles.program, "texture"); | ||
586 | + glUniform1i(texture, 0); | ||
587 | + glActiveTexture(GL_TEXTURE0); | ||
588 | + | ||
589 | + return GL_NO_ERROR; | ||
590 | +} | ||
591 | + | ||
592 | +static int armsoc_repulsion_create_vbo(struct ARMSOCRepulsion *repulsion) | ||
593 | +{ | ||
594 | + glGenBuffers(1, &repulsion->gles.vbo); | ||
595 | + glBindBuffer(GL_ARRAY_BUFFER, repulsion->gles.vbo); | ||
596 | + | ||
597 | + return GL_NO_ERROR; | ||
598 | +} | ||
599 | + | ||
600 | +static int armsoc_repulsion_create_ibo(struct ARMSOCRepulsion *repulsion) | ||
601 | +{ | ||
602 | + static const GLushort indices[] = {0, 1, 2, 0, 2, 3}; | ||
603 | + | ||
604 | + glGenBuffers(1, &repulsion->gles.ibo); | ||
605 | + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, repulsion->gles.ibo); | ||
606 | + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, | ||
607 | + GL_STATIC_DRAW); | ||
608 | + | ||
609 | + return GL_NO_ERROR; | ||
610 | +} | ||
611 | + | ||
612 | +static int armsoc_repulsion_create_texture(struct ARMSOCRepulsion *repulsion) | ||
613 | +{ | ||
614 | + glGenTextures(1, &repulsion->gles.texture); | ||
615 | + glBindTexture(GL_TEXTURE_EXTERNAL_OES, repulsion->gles.texture); | ||
616 | + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
617 | + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
618 | + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, | ||
619 | + GL_CLAMP_TO_EDGE); | ||
620 | + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, | ||
621 | + GL_CLAMP_TO_EDGE); | ||
622 | + | ||
623 | + return GL_NO_ERROR; | ||
624 | +} | ||
625 | + | ||
626 | +static int armsoc_repulsion_init_gles(struct ARMSOCRepulsion *repulsion) | ||
627 | +{ | ||
628 | + int rc; | ||
629 | + | ||
630 | + glEnable(GL_DEBUG_OUTPUT_KHR); | ||
631 | + glDebugMessageCallbackKHR(armsoc_repulsion_gles_log, repulsion); | ||
632 | + | ||
633 | + rc = armsoc_repulsion_compile_shader(repulsion); | ||
634 | + if (rc != GL_NO_ERROR) { | ||
635 | + ERROR_LOG("Failed to compile shader: 0x%04x (%s)", | ||
636 | + rc, gles_error_str(rc)); | ||
637 | + return rc; | ||
638 | + } | ||
639 | + | ||
640 | + rc = armsoc_repulsion_create_vbo(repulsion); | ||
641 | + if (rc != GL_NO_ERROR) { | ||
642 | + ERROR_LOG("Failed to create vertex buffer: 0x%04x (%s)", | ||
643 | + rc, gles_error_str(rc)); | ||
644 | + return rc; | ||
645 | + } | ||
646 | + | ||
647 | + rc = armsoc_repulsion_create_ibo(repulsion); | ||
648 | + if (rc != GL_NO_ERROR) { | ||
649 | + ERROR_LOG("Failed to create index buffer: 0x%04x (%s)", | ||
650 | + rc, gles_error_str(rc)); | ||
651 | + return rc; | ||
652 | + } | ||
653 | + | ||
654 | + rc = armsoc_repulsion_create_texture(repulsion); | ||
655 | + if (rc != GL_NO_ERROR) { | ||
656 | + ERROR_LOG("Failed to create texture: 0x%04x (%s)", | ||
657 | + rc, gles_error_str(rc)); | ||
658 | + return rc; | ||
659 | + } | ||
660 | + | ||
661 | + return GL_NO_ERROR; | ||
662 | +} | ||
663 | + | ||
664 | +static void armsoc_repulsion_release_texture(struct ARMSOCRepulsion *repulsion) | ||
665 | +{ | ||
666 | + glDeleteTextures(1, &repulsion->gles.texture); | ||
667 | +} | ||
668 | + | ||
669 | +static void armsoc_repulsion_release_ibo(struct ARMSOCRepulsion *repulsion) | ||
670 | +{ | ||
671 | + glDeleteBuffers(1, &repulsion->gles.ibo); | ||
672 | +} | ||
673 | + | ||
674 | +static void armsoc_repulsion_release_vbo(struct ARMSOCRepulsion *repulsion) | ||
675 | +{ | ||
676 | + glDeleteBuffers(1, &repulsion->gles.vbo); | ||
677 | +} | ||
678 | + | ||
679 | +static void armsoc_repulsion_release_shader(struct ARMSOCRepulsion *repulsion) | ||
680 | +{ | ||
681 | + glDeleteProgram(repulsion->gles.program); | ||
682 | +} | ||
683 | + | ||
684 | +static void armsoc_repulsion_release_gles(struct ARMSOCRepulsion *repulsion) | ||
685 | +{ | ||
686 | + armsoc_repulsion_release_texture(repulsion); | ||
687 | + armsoc_repulsion_release_ibo(repulsion); | ||
688 | + armsoc_repulsion_release_vbo(repulsion); | ||
689 | + armsoc_repulsion_release_shader(repulsion); | ||
690 | +} | ||
691 | + | ||
692 | +/* ----------------------------------------------------------------------------- | ||
693 | + * EGL Functions | ||
694 | + */ | ||
695 | + | ||
696 | +static const char* egl_error_str(EGLint err) | ||
697 | +{ | ||
698 | + switch (err) { | ||
699 | + case EGL_SUCCESS: return "no error"; | ||
700 | + case EGL_NOT_INITIALIZED: return "not initialized"; | ||
701 | + case EGL_BAD_ACCESS: return "bad access"; | ||
702 | + case EGL_BAD_ALLOC: return "bad alloc"; | ||
703 | + case EGL_BAD_CONFIG: return "bad config"; | ||
704 | + case EGL_BAD_CONTEXT: return "bad context"; | ||
705 | + case EGL_BAD_CURRENT_SURFACE: return "bad current surface"; | ||
706 | + case EGL_BAD_DISPLAY: return "bad display"; | ||
707 | + case EGL_BAD_MATCH: return "bad match"; | ||
708 | + case EGL_BAD_NATIVE_PIXMAP: return "bad native pixmap"; | ||
709 | + case EGL_BAD_NATIVE_WINDOW: return "bad native window"; | ||
710 | + case EGL_BAD_PARAMETER: return "bad parameter"; | ||
711 | + case EGL_BAD_SURFACE: return "bad surface"; | ||
712 | + case EGL_CONTEXT_LOST: return "context lost"; | ||
713 | + default: return "unknowm error"; | ||
714 | + } | ||
715 | +}; | ||
716 | + | ||
717 | +static int armsoc_repulsion_init_egl(struct ARMSOCRepulsion *repulsion) | ||
718 | +{ | ||
719 | + static const EGLint config_attrs[] = { | ||
720 | + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | ||
721 | + EGL_CONFORMANT, EGL_OPENGL_ES2_BIT, | ||
722 | + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, | ||
723 | + EGL_DEPTH_SIZE, 8, | ||
724 | + EGL_RED_SIZE, 8, | ||
725 | + EGL_GREEN_SIZE, 8, | ||
726 | + EGL_BLUE_SIZE, 8, | ||
727 | + EGL_ALPHA_SIZE, 8, | ||
728 | + EGL_NONE | ||
729 | + }; | ||
730 | + static const EGLint context_attrs[] = { | ||
731 | + EGL_CONTEXT_CLIENT_VERSION, 2, | ||
732 | + EGL_NONE | ||
733 | + }; | ||
734 | + EGLint count; | ||
735 | + EGLConfig config; | ||
736 | + | ||
737 | + repulsion->egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY); | ||
738 | + if (repulsion->egl.display == EGL_NO_DISPLAY) | ||
739 | + return eglGetError(); | ||
740 | + | ||
741 | + if(!eglInitialize(repulsion->egl.display, NULL, NULL)) | ||
742 | + return eglGetError(); | ||
743 | + | ||
744 | + if (!eglChooseConfig(repulsion->egl.display, config_attrs, &config, 1, | ||
745 | + &count)) | ||
746 | + return eglGetError(); | ||
747 | + | ||
748 | + if (!eglBindAPI(EGL_OPENGL_ES_API)) | ||
749 | + return eglGetError(); | ||
750 | + | ||
751 | + repulsion->egl.context = eglCreateContext(repulsion->egl.display, config, | ||
752 | + EGL_NO_CONTEXT, context_attrs); | ||
753 | + if (repulsion->egl.context == EGL_NO_CONTEXT) | ||
754 | + return eglGetError(); | ||
755 | + | ||
756 | + repulsion->egl.surface = eglCreatePbufferSurface(repulsion->egl.display, | ||
757 | + config, NULL); | ||
758 | + if (repulsion->egl.surface == EGL_NO_SURFACE) | ||
759 | + return eglGetError(); | ||
760 | + | ||
761 | + if (!eglMakeCurrent(repulsion->egl.display, repulsion->egl.surface, | ||
762 | + repulsion->egl.surface, repulsion->egl.context)) | ||
763 | + return eglGetError(); | ||
764 | + | ||
765 | + if (!eglSwapInterval(repulsion->egl.display, 0)) | ||
766 | + return eglGetError(); | ||
767 | + | ||
768 | + return EGL_SUCCESS; | ||
769 | +} | ||
770 | + | ||
771 | +static void armsoc_repulsion_release_egl(struct ARMSOCRepulsion *repulsion) | ||
772 | +{ | ||
773 | + if (repulsion->egl.surface != EGL_NO_SURFACE) | ||
774 | + eglDestroySurface(repulsion->egl.display, repulsion->egl.surface); | ||
775 | + | ||
776 | + if (repulsion->egl.context) | ||
777 | + eglDestroyContext(repulsion->egl.display, repulsion->egl.context); | ||
778 | + | ||
779 | + if (repulsion->egl.display) | ||
780 | + eglTerminate(repulsion->egl.display); | ||
781 | + | ||
782 | + repulsion->egl.display = EGL_NO_DISPLAY; | ||
783 | +} | ||
784 | + | ||
785 | +static EGLint armsoc_repulsion_guess_bo_format(struct armsoc_bo *bo) | ||
786 | +{ | ||
787 | + switch(armsoc_bo_bpp(bo)) { | ||
788 | + case 16: | ||
789 | + return DRM_FORMAT_RGB565; | ||
790 | + case 32: | ||
791 | + return DRM_FORMAT_ARGB8888; | ||
792 | + default: | ||
793 | + return 0; | ||
794 | + } | ||
795 | +} | ||
796 | + | ||
797 | +static EGLImageKHR | ||
798 | +armsoc_repulsion_create_egl_image(struct ARMSOCRepulsion *repulsion, | ||
799 | + struct armsoc_bo *bo) | ||
800 | +{ | ||
801 | + const EGLint attributes[] = { | ||
802 | + EGL_WIDTH, armsoc_bo_width(bo), | ||
803 | + EGL_HEIGHT, armsoc_bo_height(bo), | ||
804 | + EGL_LINUX_DRM_FOURCC_EXT, armsoc_repulsion_guess_bo_format(bo), | ||
805 | + EGL_DMA_BUF_PLANE0_FD_EXT, armsoc_bo_get_dmabuf(bo), | ||
806 | + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, | ||
807 | + EGL_DMA_BUF_PLANE0_PITCH_EXT, armsoc_bo_pitch(bo), | ||
808 | + EGL_NONE | ||
809 | + }; | ||
810 | + | ||
811 | + return eglCreateImageKHR(repulsion->egl.display, EGL_NO_CONTEXT, | ||
812 | + EGL_LINUX_DMA_BUF_EXT, NULL, attributes); | ||
813 | +} | ||
814 | + | ||
815 | +static void | ||
816 | +armsoc_repulsion_destroy_egl_image(struct ARMSOCRepulsion *repulsion, | ||
817 | + EGLImageKHR img) | ||
818 | +{ | ||
819 | + eglDestroyImageKHR(repulsion->egl.display, img); | ||
820 | +} | ||
821 | + | ||
822 | +/* ----------------------------------------------------------------------------- | ||
823 | + * Repulsion API | ||
824 | + */ | ||
825 | + | ||
826 | +bool armsoc_repulsion_composite(struct ARMSOCRepulsion *repulsion, | ||
827 | + struct armsoc_bo *src, | ||
828 | + struct armsoc_bo *dest, | ||
829 | + float xform_matrix[3][3]) | ||
830 | +{ | ||
831 | + GLuint tex, fbo; | ||
832 | + GLenum status; | ||
833 | + EGLImageKHR dest_img, src_img; | ||
834 | + GLsizei width, height; | ||
835 | + static GLfloat proj_matrix[3][3] = { | ||
836 | + { 2.f, 0.f, 0.f }, | ||
837 | + { 0.f, 2.f, 0.f }, | ||
838 | + { -1.f, -1.f, 0.f }, | ||
839 | + }; | ||
840 | + | ||
841 | + if (!repulsion || !src || !dest) | ||
842 | + return false; | ||
843 | + | ||
844 | + dest_img = armsoc_repulsion_create_egl_image(repulsion, dest); | ||
845 | + if (dest_img == EGL_NO_IMAGE_KHR) { | ||
846 | + EGLint err = eglGetError(); | ||
847 | + ERROR_LOG("Failed to create dest EGL image: 0x%04x (%s)", | ||
848 | + err, egl_error_str(err)); | ||
849 | + return false; | ||
850 | + } | ||
851 | + src_img = armsoc_repulsion_create_egl_image(repulsion, src); | ||
852 | + if (src_img == EGL_NO_IMAGE_KHR) { | ||
853 | + EGLint err = eglGetError(); | ||
854 | + ERROR_LOG("Failed to create src EGL image: 0x%04x (%s)", | ||
855 | + err, egl_error_str(err)); | ||
856 | + armsoc_repulsion_destroy_egl_image(repulsion, dest_img); | ||
857 | + return false; | ||
858 | + } | ||
859 | + | ||
860 | + glGenTextures(1, &tex); | ||
861 | + glBindTexture(GL_TEXTURE_2D, tex); | ||
862 | + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, dest_img); | ||
863 | + | ||
864 | + glGenFramebuffers(1, &fbo); | ||
865 | + glBindFramebuffer(GL_FRAMEBUFFER, fbo); | ||
866 | + | ||
867 | + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | ||
868 | + GL_TEXTURE_2D, tex, 0); | ||
869 | + | ||
870 | + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | ||
871 | + if (status != GL_FRAMEBUFFER_COMPLETE) { | ||
872 | + ERROR_LOG("Failed to complete framebuffer"); | ||
873 | + glDeleteFramebuffers(1, &fbo); | ||
874 | + glDeleteTextures(1, &tex); | ||
875 | + armsoc_repulsion_destroy_egl_image(repulsion, dest_img); | ||
876 | + armsoc_repulsion_destroy_egl_image(repulsion, src_img); | ||
877 | + return false; | ||
878 | + } | ||
879 | + | ||
880 | + width = armsoc_bo_width(dest); | ||
881 | + height = armsoc_bo_height(dest); | ||
882 | + proj_matrix[0][0] = 2.f / width; | ||
883 | + proj_matrix[1][1] = 2.f / height; | ||
884 | + | ||
885 | + glUniformMatrix3fv(repulsion->gles.proj_location, 1, false, | ||
886 | + &proj_matrix[0][0]); | ||
887 | + | ||
888 | + glUniformMatrix3fv(repulsion->gles.xform_location, 1, false, | ||
889 | + &xform_matrix[0][0]); | ||
890 | + | ||
891 | + glViewport(0, 0, width, height); | ||
892 | + | ||
893 | + glClearColor(0.f, 0.f, 1.f, 1.f); | ||
894 | + glClear(GL_COLOR_BUFFER_BIT); | ||
895 | + | ||
896 | + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, src_img); | ||
897 | + | ||
898 | + repulsion->gles.vertices[0].pos[0] = 0.f; | ||
899 | + repulsion->gles.vertices[0].pos[1] = height; | ||
900 | + repulsion->gles.vertices[0].pos[2] = 1.f; | ||
901 | + repulsion->gles.vertices[0].uv[0] = 0.f; | ||
902 | + repulsion->gles.vertices[0].uv[1] = 1.f; | ||
903 | + | ||
904 | + repulsion->gles.vertices[1].pos[0] = 0.f; | ||
905 | + repulsion->gles.vertices[1].pos[1] = 0.f; | ||
906 | + repulsion->gles.vertices[1].pos[2] = 1.f; | ||
907 | + repulsion->gles.vertices[1].uv[0] = 0.f; | ||
908 | + repulsion->gles.vertices[1].uv[1] = 0.f; | ||
909 | + | ||
910 | + repulsion->gles.vertices[2].pos[0] = width; | ||
911 | + repulsion->gles.vertices[2].pos[1] = 0.f; | ||
912 | + repulsion->gles.vertices[2].pos[2] = 1.f; | ||
913 | + repulsion->gles.vertices[2].uv[0] = 1.f; | ||
914 | + repulsion->gles.vertices[2].uv[1] = 0.f; | ||
915 | + | ||
916 | + repulsion->gles.vertices[3].pos[0] = width; | ||
917 | + repulsion->gles.vertices[3].pos[1] = height; | ||
918 | + repulsion->gles.vertices[3].pos[2] = 1.f; | ||
919 | + repulsion->gles.vertices[3].uv[0] = 1.f; | ||
920 | + repulsion->gles.vertices[3].uv[1] = 1.f; | ||
921 | + | ||
922 | + glBufferData(GL_ARRAY_BUFFER, sizeof(repulsion->gles.vertices), | ||
923 | + repulsion->gles.vertices, GL_STATIC_DRAW); | ||
924 | + | ||
925 | + glVertexAttribPointer(SHADER_POSITION_ATTR_SLOT, 3, GL_FLOAT, GL_FALSE, | ||
926 | + sizeof(*repulsion->gles.vertices), (const void *)(0)); | ||
927 | + glVertexAttribPointer(SHADER_TEX_COOR_ATTR_SLOT, 2, GL_FLOAT, GL_FALSE, | ||
928 | + sizeof(*repulsion->gles.vertices), | ||
929 | + (const void *)(sizeof(repulsion->gles.vertices->pos))); | ||
930 | + | ||
931 | + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); | ||
932 | + | ||
933 | + glFinish(); | ||
934 | + | ||
935 | + glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||
936 | + glDeleteFramebuffers(1, &fbo); | ||
937 | + glDeleteTextures(1, &tex); | ||
938 | + | ||
939 | + armsoc_repulsion_destroy_egl_image(repulsion, src_img); | ||
940 | + armsoc_repulsion_destroy_egl_image(repulsion, dest_img); | ||
941 | + | ||
942 | + return true; | ||
943 | +} | ||
944 | + | ||
945 | +struct ARMSOCRepulsion *armsoc_repulsion_init(void) | ||
946 | +{ | ||
947 | + int rc; | ||
948 | + struct ARMSOCRepulsion *repulsion = calloc(1, sizeof(*repulsion)); | ||
949 | + if (!repulsion) { | ||
950 | + ERROR_LOG("Out of memory"); | ||
951 | + return NULL; | ||
952 | + } | ||
953 | + | ||
954 | + rc = armsoc_repulsion_init_egl(repulsion); | ||
955 | + if (rc != EGL_SUCCESS) { | ||
956 | + ERROR_LOG("Failed to initialize EGL: 0x%04x (%s)", | ||
957 | + rc, egl_error_str(rc)); | ||
958 | + armsoc_repulsion_release(repulsion); | ||
959 | + return NULL; | ||
960 | + } | ||
961 | + | ||
962 | + rc = armsoc_repulsion_init_gles(repulsion); | ||
963 | + if (rc != GL_NO_ERROR) { | ||
964 | + ERROR_LOG("Failed to initialize GLES: 0x%04x (%s)", | ||
965 | + rc, gles_error_str(rc)); | ||
966 | + armsoc_repulsion_release(repulsion); | ||
967 | + return NULL; | ||
968 | + } | ||
969 | + | ||
970 | + INFO_LOG("Repulsion initialized"); | ||
971 | + | ||
972 | + return repulsion; | ||
973 | +} | ||
974 | + | ||
975 | +void armsoc_repulsion_release(struct ARMSOCRepulsion *repulsion) | ||
976 | +{ | ||
977 | + if (!repulsion) | ||
978 | + return; | ||
979 | + armsoc_repulsion_release_gles(repulsion); | ||
980 | + armsoc_repulsion_release_egl(repulsion); | ||
981 | + free(repulsion); | ||
982 | +} | ||
983 | diff --git a/src/armsoc_repulsion.h b/src/armsoc_repulsion.h | ||
984 | new file mode 100644 | ||
985 | index 0000000..b5e57df | ||
986 | --- /dev/null | ||
987 | +++ b/src/armsoc_repulsion.h | ||
988 | @@ -0,0 +1,67 @@ | ||
989 | +/* | ||
990 | + * Copyright (C) 2024 AMD, Inc. | ||
991 | + * | ||
992 | + * Permission is hereby granted, free of charge, to any person obtaining a | ||
993 | + * copy of this software and associated documentation files (the "Software"), | ||
994 | + * to deal in the Software without restriction, including without limitation | ||
995 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
996 | + * and/or sell copies of the Software, and to permit persons to whom the | ||
997 | + * Software is furnished to do so, subject to the following conditions: | ||
998 | + * | ||
999 | + * The above copyright notice and this permission notice (including the next | ||
1000 | + * paragraph) shall be included in all copies or substantial portions of the | ||
1001 | + * Software. | ||
1002 | + * | ||
1003 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
1004 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
1005 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
1006 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
1007 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
1008 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
1009 | + * SOFTWARE. | ||
1010 | + * | ||
1011 | + * Author: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
1012 | + * | ||
1013 | + */ | ||
1014 | + | ||
1015 | +#ifndef ARMSOC_REPULSION_H_ | ||
1016 | +#define ARMSOC_REPULSION_H_ | ||
1017 | + | ||
1018 | +#include <stdbool.h> | ||
1019 | +#include "armsoc_dumb.h" | ||
1020 | + | ||
1021 | +struct ARMSOCRepulsion; | ||
1022 | + | ||
1023 | +/** | ||
1024 | + * Initialize armsoc repulsion compositor. | ||
1025 | + * | ||
1026 | + * Return: pointer to new ARMSOCRepulsion object on success, NULL otherwise. | ||
1027 | + */ | ||
1028 | +struct ARMSOCRepulsion *armsoc_repulsion_init(void); | ||
1029 | + | ||
1030 | +/** | ||
1031 | + * Release armsoc repulsion compositor and free all resources. | ||
1032 | + * @repulsion: pointer to previously allocated ARMSOCRepulsion object. | ||
1033 | + */ | ||
1034 | +void armsoc_repulsion_release(struct ARMSOCRepulsion *repulsion); | ||
1035 | + | ||
1036 | +/** | ||
1037 | + * Perform 2 image composition. | ||
1038 | + * @repulsion: pointer to ARMSOCRepulsion object. | ||
1039 | + * @src: source buffer object. | ||
1040 | + * @dest: destination buffer object. | ||
1041 | + * @xform_matrix: transformation matrix to apply to source image before copying | ||
1042 | + * it into destination. | ||
1043 | + * | ||
1044 | + * This function performs GPU accelerated copy of @src buffer into @dest buffer | ||
1045 | + * while applying linear transformation. | ||
1046 | + * | ||
1047 | + * Return: pointer to new ARMSOCRepulsion object on success, NULL otherwise. | ||
1048 | + */ | ||
1049 | +bool armsoc_repulsion_composite(struct ARMSOCRepulsion *repulsion, | ||
1050 | + struct armsoc_bo *src, | ||
1051 | + struct armsoc_bo *dest, | ||
1052 | + float xform_matrix[3][3]); | ||
1053 | + | ||
1054 | + | ||
1055 | +#endif // ARMSOC_REPULSION_H_ | ||
1056 | -- | ||
1057 | 2.25.1 | ||
1058 | |||
diff --git a/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc_%.bbappend b/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc_%.bbappend index 82736cc8..72ebd37c 100644 --- a/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc_%.bbappend +++ b/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc_%.bbappend | |||
@@ -3,4 +3,10 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/xf86-video-armsoc:" | |||
3 | SRC_URI:append = " file://0001-src-drmmode_xilinx-Add-the-dumb-gem-support-for-Xili.patch \ | 3 | SRC_URI:append = " file://0001-src-drmmode_xilinx-Add-the-dumb-gem-support-for-Xili.patch \ |
4 | file://0001-armsoc_driver.c-Bypass-the-exa-layer-to-free-the-roo.patch \ | 4 | file://0001-armsoc_driver.c-Bypass-the-exa-layer-to-free-the-roo.patch \ |
5 | file://0001-xf86-video-armsoc-Add-shadow-buffer-hooks.patch \ | 5 | file://0001-xf86-video-armsoc-Add-shadow-buffer-hooks.patch \ |
6 | " | 6 | " |
7 | EXTRA_MALI400_SRC = " file://0001-xf86-video-armosc-Accelerate-picture-composition.patch \ | ||
8 | " | ||
9 | SRC_URI:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', '${EXTRA_MALI400_SRC}', '', d)}" | ||
10 | |||
11 | DEPENDS:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', ' libmali-xlnx', '', d)}" | ||
12 | |||