summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Accelerate-picture-composition.patch1058
-rw-r--r--meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc_%.bbappend8
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 @@
1From 015f8a54f7e5a754e1cefba1aa7b1f6992a8aa9b Mon Sep 17 00:00:00 2001
2From: Anatoliy Klymenko <anatoliy.klymenko@amd.com>
3Date: Tue, 16 Jul 2024 19:48:47 +0000
4Subject: [PATCH] xf86-video-armosc: Accelerate picture composition
5
6Introduce Repulsion - simplistic GPU accelerated compositor to back RandR
7display manipulation features. This library is inspired by Glamor extension
8https://www.freedesktop.org/wiki/Software/Glamor/. Unfortunately Glamor
9doesn't work as is on ARM Mali-400 MP due to the lack of required features
10and several bugs in Mali EGL/GLES implementation.
11
12Install and manage picture compositor hooks.
13
14Provide access to dma-buf fd from ARSOC buffer object.
15
16Attach shadow buffer object to corresponding pixmap.
17
18Signed-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
32diff --git a/src/Makefile.am b/src/Makefile.am
33index 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)
51diff --git a/src/armsoc_driver.c b/src/armsoc_driver.c
52index 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;
242diff --git a/src/armsoc_driver.h b/src/armsoc_driver.h
243index 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 /*
267diff --git a/src/armsoc_dumb.c b/src/armsoc_dumb.c
268index 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)
286diff --git a/src/armsoc_dumb.h b/src/armsoc_dumb.h
287index 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,
298diff --git a/src/armsoc_exa.c b/src/armsoc_exa.c
299index 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) {
353diff --git a/src/armsoc_repulsion.c b/src/armsoc_repulsion.c
354new file mode 100644
355index 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+}
983diff --git a/src/armsoc_repulsion.h b/src/armsoc_repulsion.h
984new file mode 100644
985index 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--
10572.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:"
3SRC_URI:append = " file://0001-src-drmmode_xilinx-Add-the-dumb-gem-support-for-Xili.patch \ 3SRC_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 "
7EXTRA_MALI400_SRC = " file://0001-xf86-video-armosc-Accelerate-picture-composition.patch \
8 "
9SRC_URI:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', '${EXTRA_MALI400_SRC}', '', d)}"
10
11DEPENDS:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', ' libmali-xlnx', '', d)}"
12