diff options
| author | Mark Hatle <mark.hatle@amd.com> | 2025-04-22 09:16:23 -0600 |
|---|---|---|
| committer | Mark Hatle <mark.hatle@amd.com> | 2025-05-08 13:58:14 -0500 |
| commit | 80923f7036d91b7c4ba20b19ca61f258b53295dc (patch) | |
| tree | 518519e3030ef8ff50be449f65fd0ab1adbee64d /meta-xilinx-core | |
| parent | 64e4f60397802c03727270dd8b6c6ae86a6dd4bb (diff) | |
| download | meta-xilinx-80923f7036d91b7c4ba20b19ca61f258b53295dc.tar.gz | |
xf86-video-armsoc: Move mali400 changes from meta-xilinx-core to meta-xilinx-mali400
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
Diffstat (limited to 'meta-xilinx-core')
3 files changed, 0 insertions, 1175 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 deleted file mode 100644 index 3fa4d6ec..00000000 --- a/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Accelerate-picture-composition.patch +++ /dev/null | |||
| @@ -1,1058 +0,0 @@ | |||
| 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/0001-xf86-video-armosc-Option-to-control-acceleration.patch b/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Option-to-control-acceleration.patch deleted file mode 100644 index 9cc186de..00000000 --- a/meta-xilinx-core/dynamic-layers/openembedded-layer/recipes-graphics/xorg-driver/xf86-video-armsoc/0001-xf86-video-armosc-Option-to-control-acceleration.patch +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | From 83047c38b0a9e8cc535eba580ca28497f1bee544 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
| 3 | Date: Fri, 19 Jul 2024 14:10:22 -0700 | ||
| 4 | Subject: [PATCH] xf86-video-armosc: Option to control acceleration | ||
| 5 | |||
| 6 | Add xorg config option to enable / disable GPU accelerated picture | ||
| 7 | composition. Enable acceleration by default. | ||
| 8 | |||
| 9 | Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com> | ||
| 10 | --- | ||
| 11 | man/armsoc.man | 6 ++++++ | ||
| 12 | src/armsoc_driver.c | 20 +++++++++++++++----- | ||
| 13 | src/armsoc_driver.h | 3 +++ | ||
| 14 | 3 files changed, 24 insertions(+), 5 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/man/armsoc.man b/man/armsoc.man | ||
| 17 | index d85c2fa..cdeb19e 100644 | ||
| 18 | --- a/man/armsoc.man | ||
| 19 | +++ b/man/armsoc.man | ||
| 20 | @@ -69,6 +69,12 @@ Default: NULL | ||
| 21 | Use the umplock module for cross-process access synchronization. It should be only enabled for Mali400 | ||
| 22 | .IP | ||
| 23 | Default: Umplock is Disabled | ||
| 24 | +.TP | ||
| 25 | +.BI "Option \*qAccelerateComposition\*q \*q" boolean \*q | ||
| 26 | +Accelerate picture composition on GPU. | ||
| 27 | +.IP | ||
| 28 | +Default: Accelerated composition is Enabled | ||
| 29 | + | ||
| 30 | |||
| 31 | .SH DRM DEVICE SELECTION | ||
| 32 | |||
| 33 | diff --git a/src/armsoc_driver.c b/src/armsoc_driver.c | ||
| 34 | index f5b8f21..15cc620 100644 | ||
| 35 | --- a/src/armsoc_driver.c | ||
| 36 | +++ b/src/armsoc_driver.c | ||
| 37 | @@ -110,6 +110,7 @@ enum { | ||
| 38 | OPTION_DRI_NUM_BUF, | ||
| 39 | OPTION_INIT_FROM_FBDEV, | ||
| 40 | OPTION_UMP_LOCK, | ||
| 41 | + OPTION_ACCELERATE_COMPOSITION, | ||
| 42 | }; | ||
| 43 | |||
| 44 | /** Supported options. */ | ||
| 45 | @@ -122,6 +123,8 @@ static const OptionInfoRec ARMSOCOptions[] = { | ||
| 46 | { OPTION_DRI_NUM_BUF, "DRI2MaxBuffers", OPTV_INTEGER, {-1}, FALSE }, | ||
| 47 | { OPTION_INIT_FROM_FBDEV, "InitFromFBDev", OPTV_STRING, {0}, FALSE }, | ||
| 48 | { OPTION_UMP_LOCK, "UMP_LOCK", OPTV_BOOLEAN, {0}, FALSE }, | ||
| 49 | + { OPTION_ACCELERATE_COMPOSITION, "AccelerateComposition", OPTV_BOOLEAN, | ||
| 50 | + {0}, FALSE }, | ||
| 51 | { -1, NULL, OPTV_NONE, {0}, FALSE } | ||
| 52 | }; | ||
| 53 | |||
| 54 | @@ -871,6 +874,10 @@ ARMSOCPreInit(ScrnInfoPtr pScrn, int flags) | ||
| 55 | armsocDebug = xf86ReturnOptValBool(pARMSOC->pOptionInfo, | ||
| 56 | OPTION_DEBUG, FALSE); | ||
| 57 | |||
| 58 | + /* Should we enable GPU accelerated picture composition? */ | ||
| 59 | + pARMSOC->enable_repulsion = xf86ReturnOptValBool(pARMSOC->pOptionInfo, | ||
| 60 | + OPTION_ACCELERATE_COMPOSITION, TRUE); | ||
| 61 | + | ||
| 62 | if (!xf86GetOptValInteger(pARMSOC->pOptionInfo, OPTION_DRI_NUM_BUF, | ||
| 63 | &driNumBufs)) { | ||
| 64 | /* Default to double buffering */ | ||
| 65 | @@ -1119,7 +1126,6 @@ ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL) | ||
| 66 | struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); | ||
| 67 | VisualPtr visual; | ||
| 68 | xf86CrtcConfigPtr xf86_config; | ||
| 69 | - PictureScreenPtr ps; | ||
| 70 | int j; | ||
| 71 | const char *fbdev; | ||
| 72 | int depth; | ||
| 73 | @@ -1308,12 +1314,16 @@ ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL) | ||
| 74 | pARMSOC->lockFD = -1; | ||
| 75 | } | ||
| 76 | |||
| 77 | - pARMSOC->repulsion = armsoc_repulsion_init(); | ||
| 78 | + if (pARMSOC->enable_repulsion) { | ||
| 79 | + PictureScreenPtr ps; | ||
| 80 | + | ||
| 81 | + pARMSOC->repulsion = armsoc_repulsion_init(); | ||
| 82 | |||
| 83 | - ps = GetPictureScreen(pScreen); | ||
| 84 | - pARMSOC->composite_proc = ps->Composite; | ||
| 85 | + ps = GetPictureScreen(pScreen); | ||
| 86 | + pARMSOC->composite_proc = ps->Composite; | ||
| 87 | |||
| 88 | - ps->Composite = ARMSOCComposite; | ||
| 89 | + ps->Composite = ARMSOCComposite; | ||
| 90 | + } | ||
| 91 | |||
| 92 | TRACE_EXIT(); | ||
| 93 | return TRUE; | ||
| 94 | diff --git a/src/armsoc_driver.h b/src/armsoc_driver.h | ||
| 95 | index 20b0f80..27e978e 100644 | ||
| 96 | --- a/src/armsoc_driver.h | ||
| 97 | +++ b/src/armsoc_driver.h | ||
| 98 | @@ -185,6 +185,9 @@ struct ARMSOCRec { | ||
| 99 | * driNumBufs if early display enabled, otherwise driNumBufs-1 */ | ||
| 100 | unsigned int swap_chain_size; | ||
| 101 | |||
| 102 | + /* Enable GPU accelerated picture compositor? */ | ||
| 103 | + Bool enable_repulsion; | ||
| 104 | + | ||
| 105 | /* GPU accelerated picture compositor, AKA Repulsion */ | ||
| 106 | struct ARMSOCRepulsion *repulsion; | ||
| 107 | |||
| 108 | -- | ||
| 109 | 2.25.1 | ||
| 110 | |||
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 e0f62ac4..954ec514 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 | |||
| @@ -5,10 +5,3 @@ SRC_URI:append = " file://0001-src-drmmode_xilinx-Add-the-dumb-gem-support-for-X | |||
| 5 | file://0001-xf86-video-armsoc-Add-shadow-buffer-hooks.patch \ | 5 | file://0001-xf86-video-armsoc-Add-shadow-buffer-hooks.patch \ |
| 6 | file://0001-xf86-video-armsoc-Update-xilinx-drm-driver-name.patch \ | 6 | file://0001-xf86-video-armsoc-Update-xilinx-drm-driver-name.patch \ |
| 7 | " | 7 | " |
| 8 | EXTRA_MALI400_SRC = " file://0001-xf86-video-armosc-Accelerate-picture-composition.patch \ | ||
| 9 | file://0001-xf86-video-armosc-Option-to-control-acceleration.patch \ | ||
| 10 | " | ||
| 11 | SRC_URI:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', '${EXTRA_MALI400_SRC}', '', d)}" | ||
| 12 | |||
| 13 | DEPENDS:append = "${@bb.utils.contains('MACHINE_FEATURES', 'mali400', ' libmali-xlnx', '', d)}" | ||
| 14 | |||
