[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

libglvnd: Changes to 'upstream-unstable'



 README.md                                    |   26 
 configure.ac                                 |   35 
 include/EGL/egl.h                            |  303 +++
 include/EGL/eglext.h                         |  913 ++++++++++
 include/EGL/eglplatform.h                    |  125 +
 include/KHR/khrplatform.h                    |  282 +++
 include/Makefile.am                          |    3 
 include/glvnd/GLdispatchABI.h                |    7 
 include/glvnd/libeglabi.h                    |  436 ++++
 libglvnd.pc.in                               |    2 
 src/EGL/Makefile.am                          |  105 +
 src/EGL/egldispatchstubs.c                   |  113 +
 src/EGL/egldispatchstubs.h                   |   27 
 src/EGL/libegl.c                             | 1221 +++++++++++++
 src/EGL/libeglabipriv.h                      |  105 +
 src/EGL/libeglcurrent.c                      |  201 ++
 src/EGL/libeglcurrent.h                      |  126 +
 src/EGL/libeglerror.c                        |  257 ++
 src/EGL/libeglerror.h                        |   78 
 src/EGL/libeglmapping.c                      |  366 ++++
 src/EGL/libeglmapping.h                      |  128 +
 src/EGL/libeglvendor.c                       |  525 +++++
 src/EGL/libeglvendor.h                       |   50 
 src/GLX/Makefile.am                          |    2 
 src/GLX/libglx.c                             |  125 -
 src/GLX/libglxmapping.c                      |   29 
 src/GLX/libglxstring.c                       |   63 
 src/GLX/libglxstring.h                       |   44 
 src/GLdispatch/GLdispatch.c                  |   43 
 src/GLdispatch/GLdispatch.h                  |    9 
 src/GLdispatch/export_list.sym               |    1 
 src/GLdispatch/vnd-glapi/entry_aarch64_tsd.c |  207 ++
 src/GLdispatch/vnd-glapi/entry_armv7_tsd.c   |   47 
 src/GLdispatch/vnd-glapi/entry_files.mk      |    5 
 src/Makefile.am                              |    1 
 src/generate/eglFunctionList.py              |  148 +
 src/generate/genCommon.py                    |    2 
 src/generate/gen_egl_dispatch.py             |  223 ++
 src/generate/gen_gldispatch_mapi.py          |    6 
 src/generate/gl_inittable.py                 |    2 
 src/generate/xml/egl.xml                     | 2412 +++++++++++++++++++++++++++
 src/util/Makefile.am                         |    8 
 src/util/cJSON.c                             |  750 ++++++++
 src/util/cJSON.h                             |  149 +
 src/util/cJSON/LICENSE                       |   20 
 src/util/cJSON/README                        |  247 ++
 src/util/cJSON/test.c                        |  162 +
 src/util/cJSON/tests/test1                   |   22 
 src/util/cJSON/tests/test2                   |   11 
 src/util/cJSON/tests/test3                   |   26 
 src/util/cJSON/tests/test4                   |   88 
 src/util/cJSON/tests/test5                   |   27 
 src/util/glvnd_genentry.c                    |   44 
 src/util/glvnd_pthread.c                     |   47 
 src/util/glvnd_pthread.h                     |    3 
 src/util/utils_misc.c                        |  169 +
 src/util/utils_misc.h                        |   89 
 tests/GLX_dummy/GLX_dummy.c                  |  827 ---------
 tests/GLX_dummy/GLX_dummy.h                  |   84 
 tests/GLX_dummy/Makefile.am                  |   34 
 tests/GLX_dummy/README                       |    3 
 tests/Makefile.am                            |  101 -
 tests/dummy/EGL_dummy.c                      |  811 +++++++++
 tests/dummy/EGL_dummy.h                      |  118 +
 tests/dummy/GLX_dummy.c                      |  677 +++++++
 tests/dummy/GLX_dummy.h                      |   84 
 tests/dummy/Makefile.am                      |   58 
 tests/dummy/README                           |    3 
 tests/dummy/patchentrypoints.c               |  210 ++
 tests/dummy/patchentrypoints.h               |   47 
 tests/egl_test_utils.c                       |   48 
 tests/egl_test_utils.h                       |   71 
 tests/eglenv.sh                              |    4 
 tests/fini_test_env.sh                       |   16 
 tests/glxenv.sh                              |    4 
 tests/init_test_env.sh                       |   20 
 tests/json/10_egldummy0.json                 |    6 
 tests/json/20_egldummy1.json                 |    6 
 tests/testegldebug.c                         |  276 +++
 tests/testegldebug.sh                        |    5 
 tests/testegldevice.c                        |  139 +
 tests/testegldevice.sh                       |    5 
 tests/testegldisplay.c                       |  128 +
 tests/testegldisplay.sh                      |    5 
 tests/testeglerror.c                         |  109 +
 tests/testeglerror.sh                        |    5 
 tests/testeglgetprocaddress.c                |  140 +
 tests/testeglgetprocaddress.sh               |    5 
 tests/testeglmakecurrent.c                   |  241 ++
 tests/testeglmakecurrent.sh                  |    5 
 tests/testglxgetclientstr.sh                 |    3 
 tests/testglxgetprocaddress.c                |   90 -
 tests/testglxgetprocaddress.sh               |    3 
 tests/testglxgetprocaddress_genentry.sh      |   11 
 tests/testglxmakecurrent.c                   |    2 
 tests/testglxmcbasic.sh                      |    3 
 tests/testglxmclate.sh                       |    4 
 tests/testglxmcloop.sh                       |    3 
 tests/testglxmcoldlink.sh                    |    3 
 tests/testglxmcthreads.sh                    |    3 
 tests/testglxnscreens.c                      |  308 ---
 tests/testglxnscreens.sh                     |   10 
 tests/testglxnscrthreads.sh                  |   13 
 tests/testglxqueryversion.c                  |    9 
 tests/testglxqueryversion.sh                 |    3 
 tests/testpatchentrypoints.c                 |   15 
 tests/testpatchentrypoints.sh                |    3 
 tests/testpatchentrypoints_gldispatch.c      |  185 ++
 tests/testpatchentrypoints_gldispatch.sh     |    4 
 tests/testx11glvndproto.c                    |   86 
 tests/testx11glvndproto.sh                   |    7 
 tests/xorg.2screens.conf                     |  115 -
 tests/xorg.conf                              |   60 
 113 files changed, 13974 insertions(+), 1929 deletions(-)

New commits:
commit 522c6017999b87f1662a669b487078c83504f946
Author: Kyle Brenneman <kbrenneman@nvidia.com>
Date:   Thu May 26 11:52:37 2016 -0600

    Add support for aarch64.
    
    Add assembly code and stub generation for TSD stubs on aarch64.

diff --git a/configure.ac b/configure.ac
index 7227f5a..73cafe8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,6 +70,9 @@ if test "x$enable_asm" = xyes; then
     armv7l)
         asm_arch=armv7l
         ;;
+    aarch64)
+        asm_arch=aarch64
+        ;;
     esac
 
     case "$asm_arch" in
@@ -85,6 +88,10 @@ if test "x$enable_asm" = xyes; then
         DEFINES="$DEFINES -DUSE_ARMV7_ASM"
         AC_MSG_RESULT([yes, armv7l])
         ;;
+    aarch64)
+        DEFINES="$DEFINES -DUSE_AARCH64_ASM"
+        AC_MSG_RESULT([yes, aarch64])
+        ;;
     *)
         AC_MSG_RESULT([no, platform not supported])
         ;;
@@ -153,6 +160,11 @@ xarmv7l)
     gldispatch_entry_type=armv7_tsd
     gldispatch_use_tls=no
     ;;
+xaarch64)
+    # For aarch64, only the TSD stubs have been implemented yet.
+    gldispatch_entry_type=aarch64_tsd
+    gldispatch_use_tls=no
+    ;;
 *)
     # The C stubs will work with either TLS or TSD.
     gldispatch_entry_type=pure_c
@@ -170,6 +182,7 @@ AM_CONDITIONAL([GLDISPATCH_TYPE_X86_TSD], [test "x$gldispatch_entry_type" = "xx8
 AM_CONDITIONAL([GLDISPATCH_TYPE_X86_64_TLS], [test "x$gldispatch_entry_type" = "xx86_64_tls"])
 AM_CONDITIONAL([GLDISPATCH_TYPE_X86_64_TSD], [test "x$gldispatch_entry_type" = "xx86_64_tsd"])
 AM_CONDITIONAL([GLDISPATCH_TYPE_ARMV7_TSD], [test "x$gldispatch_entry_type" = "xarmv7_tsd"])
+AM_CONDITIONAL([GLDISPATCH_TYPE_AARCH64_TSD], [test "x$gldispatch_entry_type" = "xaarch64_tsd"])
 AM_CONDITIONAL([GLDISPATCH_TYPE_PURE_C], [test "x$gldispatch_entry_type" = "xpure_c"])
 
 
diff --git a/include/glvnd/GLdispatchABI.h b/include/glvnd/GLdispatchABI.h
index 25d593a..9b4c43d 100644
--- a/include/glvnd/GLdispatchABI.h
+++ b/include/glvnd/GLdispatchABI.h
@@ -82,7 +82,12 @@ enum {
     /*!
      * Used for stubs on ARMv7, using the normal ARM instruction set.
      */
-    __GLDISPATCH_STUB_ARMV7_ARM
+    __GLDISPATCH_STUB_ARMV7_ARM,
+
+    /*!
+     * Used for stubs on ARMv8/aarch64.
+     */
+    __GLDISPATCH_STUB_AARCH64,
 };
 
 /*!
diff --git a/src/GLdispatch/vnd-glapi/entry_aarch64_tsd.c b/src/GLdispatch/vnd-glapi/entry_aarch64_tsd.c
new file mode 100644
index 0000000..7fbcb39
--- /dev/null
+++ b/src/GLdispatch/vnd-glapi/entry_aarch64_tsd.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include "entry.h"
+#include "entry_common.h"
+
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "glapi.h"
+#include "u_macros.h"
+#include "u_current.h"
+#include "utils_misc.h"
+#include "glvnd/GLdispatchABI.h"
+
+/*
+ * See: https://sourceware.org/binutils/docs/as/ARM-Directives.html
+ */
+
+/*
+ * u_execmem_alloc() allocates 128 bytes per stub.
+ */
+#define AARCH64_ENTRY_SIZE 128
+
+#define STUB_ASM_ENTRY(func)                        \
+    ".balign " U_STRINGIFY(AARCH64_ENTRY_SIZE) "\n\t" \
+    ".global " func "\n\t"                          \
+    ".type " func ", %function\n\t"                 \
+    func ":\n\t"
+
+/*
+ * Looks up the current dispatch table, finds the stub address at the given slot
+ * then jumps to it.
+ *
+ * First tries to find a dispatch table in _glapi_Current[GLAPI_CURRENT_DISPATCH],
+ * if not found then it jumps to the 'lookup_dispatch' and calls
+ * _glapi_get_current() then jumps back to the 'found_dispatch' label.
+ *
+ * The 'found_dispatch' section computes the correct offset in the dispatch
+ * table then does a branch without link to the function address.
+ */
+#define STUB_ASM_CODE(slot)                           \
+    "stp x1, x0, [sp, #-16]!\n\t"                     \
+    "adrp x0, :got:_glapi_Current\n\t"                \
+    "ldr x0, [x0, #:got_lo12:_glapi_Current]\n\t"     \
+    "ldr x0, [x0]\n\t"                                \
+    "cbz x0, 10f\n\t"                                 \
+    "11:\n\t"        /* found dispatch */             \
+    "ldr x1, 3f\n\t"                                  \
+    "ldr x16, [x0, x1]\n\t"                           \
+    "ldp x1, x0, [sp], #16\n\t"                       \
+    "br x16\n\t"                                      \
+    "10:\n\t"        /* lookup dispatch */            \
+    "str x30, [sp, #-16]!\n\t"                        \
+    "stp x7, x6, [sp, #-16]!\n\t"                     \
+    "stp x5, x4, [sp, #-16]!\n\t"                     \
+    "stp x3, x2, [sp, #-16]!\n\t"                     \
+    "adrp x0, :got:_glapi_get_current\n\t"            \
+    "ldr x0, [x0, #:got_lo12:_glapi_get_current]\n\t" \
+    "blr x0\n\t"                                      \
+    "ldp x3, x2, [sp], #16\n\t"                       \
+    "ldp x5, x4, [sp], #16\n\t"                       \
+    "ldp x7, x6, [sp], #16\n\t"                       \
+    "ldr x30, [sp], #16\n\t"                          \
+    "b 11b\n\t"                                       \
+    "3:\n\t"                                          \
+    ".xword " slot " * 8\n\t" /* size of (void *) */
+
+/*
+ * Bytecode for STUB_ASM_CODE()
+ */
+static const uint32_t BYTECODE_TEMPLATE[] =
+{
+    0xa9bf03e1, // <ENTRY>:	stp	x1, x0, [sp,#-16]!
+    0x58000240, // <ENTRY+4>:	ldr	x0, <ENTRY+76>
+    0xf9400000, // <ENTRY+8>:	ldr	x0, [x0]
+    0xb40000a0, // <ENTRY+12>:	cbz	x0, <ENTRY+32>
+    0x58000261, // <ENTRY+16>:	ldr	x1, <ENTRY+92>
+    0xf8616810, // <ENTRY+20>:	ldr	x16, [x0,x1]
+    0xa8c103e1, // <ENTRY+24>:	ldp	x1, x0, [sp],#16
+    0xd61f0200, // <ENTRY+28>:	br	x16
+    0xf81f0ffe, // <ENTRY+32>:	str	x30, [sp,#-16]!
+    0xa9bf1be7, // <ENTRY+36>:	stp	x7, x6, [sp,#-16]!
+    0xa9bf13e5, // <ENTRY+40>:	stp	x5, x4, [sp,#-16]!
+    0xa9bf0be3, // <ENTRY+44>:	stp	x3, x2, [sp,#-16]!
+    0x58000120, // <ENTRY+48>:	ldr	x0, <ENTRY+84>
+    0xd63f0000, // <ENTRY+52>:	blr	x0
+    0xa8c10be3, // <ENTRY+56>:	ldp	x3, x2, [sp],#16
+    0xa8c113e5, // <ENTRY+60>:	ldp	x5, x4, [sp],#16
+    0xa8c11be7, // <ENTRY+64>:	ldp	x7, x6, [sp],#16
+    0xf84107fe, // <ENTRY+68>:	ldr	x30, [sp],#16
+    0x17fffff2, // <ENTRY+72>:	b	<ENTRY+16>
+
+    // Offsets that need to be patched
+    0x00000000, 0x00000000, // <ENTRY+76>: _glapi_Current
+    0x00000000, 0x00000000, // <ENTRY+84>: _glapi_get_current
+    0x00000000, 0x00000000, // <ENTRY+92>: slot * sizeof(void*)
+};
+
+#define AARCH64_BYTECODE_SIZE sizeof(BYTECODE_TEMPLATE)
+
+__asm__(".section wtext,\"ax\"\n"
+        ".balign 4096\n"
+       ".globl public_entry_start\n"
+       ".hidden public_entry_start\n"
+        "public_entry_start:\n");
+
+#define MAPI_TMP_STUB_ASM_GCC
+#include "mapi_tmp.h"
+
+__asm__(".balign 4096\n"
+       ".globl public_entry_end\n"
+       ".hidden public_entry_end\n"
+        "public_entry_end:\n"
+        ".text\n\t");
+
+const int entry_type = __GLDISPATCH_STUB_AARCH64;
+const int entry_stub_size = AARCH64_ENTRY_SIZE;
+
+// The offsets in BYTECODE_TEMPLATE that need to be patched.
+static const int TEMPLATE_OFFSET_CURRENT_TABLE     = AARCH64_BYTECODE_SIZE - 3*8;
+static const int TEMPLATE_OFFSET_CURRENT_TABLE_GET = AARCH64_BYTECODE_SIZE - 2*8;
+static const int TEMPLATE_OFFSET_SLOT              = AARCH64_BYTECODE_SIZE - 8;
+
+void
+entry_init_public(void)
+{
+    STATIC_ASSERT(AARCH64_BYTECODE_SIZE <= AARCH64_ENTRY_SIZE);
+}
+
+void entry_generate_default_code(char *entry, int slot)
+{
+    char *writeEntry;
+
+    // Get the pointer to the writable mapping.
+    writeEntry = (char *) u_execmem_get_writable(entry);
+
+    memcpy(writeEntry, BYTECODE_TEMPLATE, AARCH64_BYTECODE_SIZE);
+
+    // Patch the slot number and whatever addresses need to be patched.
+    *((uint64_t *)(writeEntry + TEMPLATE_OFFSET_SLOT)) = (uint64_t)(slot * sizeof(mapi_func));
+    *((uint64_t *)(writeEntry + TEMPLATE_OFFSET_CURRENT_TABLE)) =
+        (uint64_t)_glapi_Current;
+    *((uint64_t *)(writeEntry + TEMPLATE_OFFSET_CURRENT_TABLE_GET)) =
+        (uint64_t)_glapi_get_current;
+
+    // See http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code
+    __builtin___clear_cache(writeEntry, writeEntry + AARCH64_BYTECODE_SIZE);
+}
+
+// Note: The rest of these functions could also be used for aarch64 TLS stubs,
+// once those are implemented.
+
+mapi_func
+entry_get_public(int index)
+{
+    return (mapi_func)(public_entry_start + (index * entry_stub_size));
+}
+
+void entry_get_patch_addresses(mapi_func entry, void **writePtr, const void **execPtr)
+{
+    // Get the actual beginning of the stub allocation
+    *execPtr = (const void *) entry;
+    *writePtr = u_execmem_get_writable((void *) entry);
+}
+
+#if !defined(STATIC_DISPATCH_ONLY)
+mapi_func entry_generate(int slot)
+{
+    void *code = u_execmem_alloc(entry_stub_size);
+    if (!code) {
+        return NULL;
+    }
+
+    entry_generate_default_code(code, slot);
+
+    return (mapi_func) code;
+}
+#endif // !defined(STATIC_DISPATCH_ONLY)
diff --git a/src/GLdispatch/vnd-glapi/entry_files.mk b/src/GLdispatch/vnd-glapi/entry_files.mk
index 628c2cd..38b6bf3 100644
--- a/src/GLdispatch/vnd-glapi/entry_files.mk
+++ b/src/GLdispatch/vnd-glapi/entry_files.mk
@@ -30,6 +30,11 @@ MAPI_GLDISPATCH_ENTRY_FILES = entry_armv7_tsd.c
 MAPI_GLDISPATCH_ENTRY_FILES += entry_common.c
 endif
 
+if GLDISPATCH_TYPE_AARCH64_TSD
+MAPI_GLDISPATCH_ENTRY_FILES = entry_aarch64_tsd.c
+MAPI_GLDISPATCH_ENTRY_FILES += entry_common.c
+endif
+
 if GLDISPATCH_TYPE_PURE_C
 MAPI_GLDISPATCH_ENTRY_FILES = entry_pure_c.c
 endif
diff --git a/src/util/glvnd_genentry.c b/src/util/glvnd_genentry.c
index d0483ca..4763633 100644
--- a/src/util/glvnd_genentry.c
+++ b/src/util/glvnd_genentry.c
@@ -39,7 +39,8 @@
 
 #define USE_ASM (defined(USE_X86_ASM) ||    \
                  defined(USE_X86_64_ASM) || \
-                 defined(USE_ARMV7_ASM))
+                 defined(USE_ARMV7_ASM) ||  \
+                 defined(USE_AARCH64_ASM))
 
 #if defined(__GNUC__) && USE_ASM
 
@@ -47,7 +48,7 @@
 #define GENERATED_ENTRYPOINT_MAX 4096
 
 /// The size of each generated entrypoint.
-static const int STUB_ENTRY_SIZE = 16;
+static const int STUB_ENTRY_SIZE = 32;
 
 #if defined(USE_X86_ASM)
 /// A template used to generate an entrypoint.
@@ -87,6 +88,23 @@ static const uint16_t STUB_TEMPLATE[] =
 
 static const int DISPATCH_FUNC_OFFSET = 8;
 
+#elif defined(USE_AARCH64_ASM)
+
+static const uint32_t STUB_TEMPLATE[] =
+{
+    // ldr x16, 1f
+    0x58000070,
+    // br x16
+    0xd61f0200,
+    // nop
+    0xd503201f,
+    // Offset that needs to be patched
+    // 1:
+    0x00000000, 0x00000000,
+};
+
+static const int DISPATCH_FUNC_OFFSET = 12;
+
 #else
 #error "Can't happen -- not implemented"
 #endif
@@ -263,6 +281,12 @@ void SetDispatchFuncPointer(GLVNDGenEntrypoint *entry,
     // See http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code
     __builtin___clear_cache((char *)entry->entrypointExec - 1,
                             (char *)entry->entrypointExec - 1 + sizeof(STUB_TEMPLATE));
+#elif defined(USE_AARCH64_ASM)
+    *((uintptr_t *)(code + DISPATCH_FUNC_OFFSET)) = (uintptr_t)dispatch;
+
+    // See http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code
+    __builtin___clear_cache((char *)entry->entrypointExec - 1,
+                            (char *)entry->entrypointExec - 1 + sizeof(STUB_TEMPLATE));
 #else
 #error "Can't happen -- not implemented"
 #endif
diff --git a/tests/dummy/patchentrypoints.c b/tests/dummy/patchentrypoints.c
index a8cf348..a822cc7 100644
--- a/tests/dummy/patchentrypoints.c
+++ b/tests/dummy/patchentrypoints.c
@@ -128,12 +128,47 @@ static void patch_armv7_thumb(char *writeEntry, const char *execEntry,
 #endif
 }
 
+static void patch_aarch64(char *writeEntry, const char *execEntry,
+        int stubSize, void *incrementPtr)
+{
+#if defined(__aarch64__)
+    const uint32_t tmpl[] = {
+        // ldr x0, 1f
+        0x580000a0,
+        // ldr x1, [x0]
+        0xf9400001,
+        // add x1, x1, #1
+        0x91000421,
+        // str x1, [x0]
+        0xf9000001,
+        // br x30
+        0xd61f03c0,
+        // 1:
+        0x00000000, 0x00000000,
+    };
+
+    static const int offsetAddr = sizeof(tmpl) - 8;
+
+    if (stubSize < sizeof(tmpl)) {
+        return;
+    }
+
+    memcpy(writeEntry, tmpl, sizeof(tmpl));
+    *((uint64_t *)(writeEntry + offsetAddr)) = (uint64_t) incrementPtr;
+
+    __builtin___clear_cache((char *) execEntry, (char *) (execEntry + sizeof(tmpl)));
+#else
+    assert(0); // Should not be calling this
+#endif
+}
+
 GLboolean dummyCheckPatchSupported(int type, int stubSize)
 {
     switch (type) {
         case __GLDISPATCH_STUB_X86_64:
         case __GLDISPATCH_STUB_X86:
         case __GLDISPATCH_STUB_ARMV7_THUMB:
+        case __GLDISPATCH_STUB_AARCH64:
             return GL_TRUE;
         default:
             return GL_FALSE;
@@ -162,6 +197,9 @@ GLboolean commonInitiatePatch(int type, int stubSize,
             case __GLDISPATCH_STUB_ARMV7_THUMB:
                 patch_armv7_thumb(writeAddr, execAddr, stubSize, incrementPtr);
                 break;
+            case __GLDISPATCH_STUB_AARCH64:
+                patch_aarch64(writeAddr, execAddr, stubSize, incrementPtr);
+                break;
             default:
                 assert(0);
         }

commit 260a54606c584183052f2496fb4d5f6335e59d26
Author: Kyle Brenneman <kbrenneman@nvidia.com>
Date:   Wed Oct 26 13:59:10 2016 -0600

    tests: Add a test for EGL_KHR_debug.

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5a3bacc..29eab01 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -53,7 +53,8 @@ TESTS = \
 	testegldevice.sh \
 	testeglgetprocaddress.sh \
 	testeglmakecurrent.sh \
-	testeglerror.sh
+	testeglerror.sh \
+	testegldebug.sh
 
 EXTRA_DIST = $(TESTS) \
 	glxenv.sh \
@@ -72,7 +73,8 @@ check_PROGRAMS = \
 	testegldevice \
 	testeglgetprocaddress \
 	testeglmakecurrent \
-	testeglerror
+	testeglerror \
+	testegldebug
 
 # The *_oldlink variant tests that linking against legacy libGL.so works
 
@@ -163,3 +165,8 @@ testeglerror_SOURCES = \
 	egl_test_utils.c
 testeglerror_LDADD = $(top_builddir)/src/EGL/libEGL.la
 testeglerror_LDADD += $(top_builddir)/src/OpenGL/libOpenGL.la
+
+testegldebug_SOURCES = \
+	testegldebug.c \
+	egl_test_utils.c
+testegldebug_LDADD = $(top_builddir)/src/EGL/libEGL.la
diff --git a/tests/dummy/EGL_dummy.c b/tests/dummy/EGL_dummy.c
index 18c6211..372e0a0 100644
--- a/tests/dummy/EGL_dummy.c
+++ b/tests/dummy/EGL_dummy.c
@@ -61,6 +61,7 @@ static const EGLint DUMMY_EGL_CONFIG_COUNT = 2;
 typedef struct DummyEGLDisplayRec {
     EGLenum platform;
     void *native_display;
+    EGLLabelKHR label;
 
     struct glvnd_list entry;
 } DummyEGLDisplay;
@@ -68,6 +69,7 @@ typedef struct DummyEGLDisplayRec {
 typedef struct DummyThreadStateRec {
     EGLint lastError;
     EGLContext currentContext;
+    EGLLabelKHR label;
 } DummyThreadState;
 
 static const __EGLapiExports *apiExports = NULL;
@@ -75,6 +77,9 @@ static glvnd_key_t threadStateKey;
 static struct glvnd_list displayList;
 static EGLint failNextMakeCurrentError = EGL_NONE;
 
+static EGLDEBUGPROCKHR debugCallbackFunc = NULL;
+static EGLBoolean debugCallbackEnabled = EGL_TRUE;
+
 static DummyThreadState *GetThreadState(void)
 {
     DummyThreadState *thr = (DummyThreadState *)
@@ -102,10 +107,16 @@ static void CommonEntrypoint(void)
     thr->lastError = EGL_SUCCESS;
 }
 
-static void SetLastError(EGLint error)
+static void SetLastError(const char *command, EGLLabelKHR label, EGLint error)
 {
     DummyThreadState *thr = GetThreadState();
+
     thr->lastError = error;
+
+    if (error != EGL_SUCCESS && debugCallbackFunc != NULL && debugCallbackEnabled) {
+        debugCallbackFunc(error, command, EGL_DEBUG_MSG_ERROR_KHR, thr->label,
+                label, DUMMY_VENDOR_NAME);
+    }
 }
 
 static DummyEGLDisplay *LookupEGLDisplay(EGLDisplay dpy)
@@ -189,7 +200,7 @@ static EGLDisplay dummyGetPlatformDisplay(EGLenum platform, void *native_display
         }
     } else {
         // We don't support this platform.
-        SetLastError(EGL_BAD_PARAMETER);
+        SetLastError("eglGetPlatformDisplay", NULL, EGL_BAD_PARAMETER);
         return EGL_NO_DISPLAY;
     }
 
@@ -258,15 +269,16 @@ static EGLContext EGLAPIENTRY dummy_eglCreateContext(EGLDisplay dpy,
         EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
 {
     DummyEGLContext *dctx;
+    DummyEGLDisplay *disp;
 
     CommonEntrypoint();
-    LookupEGLDisplay(dpy);
+    disp = LookupEGLDisplay(dpy);
 
     if (attrib_list != NULL) {
         int i;
         for (i=0; attrib_list[i] != EGL_NONE; i += 2) {
             if (attrib_list[i] == EGL_CREATE_CONTEXT_FAIL) {
-                SetLastError(attrib_list[i + 1]);
+                SetLastError("eglCreateContext", disp->label, attrib_list[i + 1]);
                 return EGL_NO_CONTEXT;
             } else {
                 printf("Invalid attribute 0x%04x in eglCreateContext\n", attrib_list[i]);
@@ -355,7 +367,7 @@ static EGLBoolean EGLAPIENTRY dummy_eglMakeCurrent(EGLDisplay dpy, EGLSurface dr
     LookupEGLDisplay(dpy);
 
     if (failNextMakeCurrentError != EGL_NONE) {
-        SetLastError(failNextMakeCurrentError);
+        SetLastError("eglMakeCurrent", NULL, failNextMakeCurrentError);
         failNextMakeCurrentError = EGL_NONE;
         return EGL_FALSE;
     }
@@ -495,6 +507,51 @@ static EGLBoolean EGLAPIENTRY dummy_eglQueryDevicesEXT(EGLint max_devices, EGLDe
     return EGL_TRUE;
 }
 
+static EGLint EGLAPIENTRY dummy_eglDebugMessageControlKHR(EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list)
+{
+    CommonEntrypoint();
+
+    if (callback != NULL) {
+        if (attrib_list != NULL) {
+            int i;
+            for (i=0; attrib_list[i] != EGL_NONE; i += 2) {
+                if (EGL_DEBUG_MSG_ERROR_KHR) {
+                    debugCallbackEnabled = (attrib_list[i + 1] != 0);
+                }
+            }
+        }
+    } else {
+        debugCallbackEnabled = EGL_TRUE;
+    }
+    debugCallbackFunc = callback;
+
+    return EGL_SUCCESS;
+}
+
+static EGLBoolean EGLAPIENTRY dummy_eglQueryDebugKHR(EGLint attribute, EGLAttrib *value)
+{
+    // eglQueryDebugKHR should never be called, because libEGL keeps track of
+    // all of the debug state.
+    printf("eglQueryDebugKHR should never be called\n");
+    abort();
+    return EGL_FALSE;
+}
+
+static EGLint EGLAPIENTRY dummy_eglLabelObjectKHR(EGLDisplay dpy,
+        EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label)
+{
+    CommonEntrypoint();
+
+    if (objectType == EGL_OBJECT_THREAD_KHR) {
+        DummyThreadState *thr = GetThreadState();
+        thr->label = label;
+    } else if (objectType == EGL_OBJECT_DISPLAY_KHR) {
+        DummyEGLDisplay *disp = LookupEGLDisplay(dpy);
+        disp->label = label;
+    }
+    return EGL_SUCCESS;
+}
+
 static const GLubyte *dummy_glGetString(GLenum name)
 {
     if (name == GL_VENDOR) {
@@ -666,6 +723,9 @@ static const struct {
     PROC_ENTRY(eglGetError),
 
     PROC_ENTRY(eglQueryDevicesEXT),
+    PROC_ENTRY(eglDebugMessageControlKHR),
+    PROC_ENTRY(eglQueryDebugKHR),
+    PROC_ENTRY(eglLabelObjectKHR),
 
     PROC_ENTRY(glGetString),
 #undef PROC_ENTRY
diff --git a/tests/egl_test_utils.c b/tests/egl_test_utils.c
index 583e4ed..cfc32e1 100644
--- a/tests/egl_test_utils.c
+++ b/tests/egl_test_utils.c
@@ -9,6 +9,9 @@ const char *DUMMY_VENDOR_NAMES[DUMMY_VENDOR_COUNT] = {
 };
 
 PFNEGLQUERYDEVICESEXTPROC ptr_eglQueryDevicesEXT;
+PFNEGLDEBUGMESSAGECONTROLKHRPROC ptr_eglDebugMessageControlKHR;
+PFNEGLQUERYDEBUGKHRPROC ptr_eglQueryDebugKHR;
+PFNEGLLABELOBJECTKHRPROC ptr_eglLabelObjectKHR;
 
 pfn_eglTestDispatchDisplay ptr_eglTestDispatchDisplay;
 pfn_eglTestDispatchDevice ptr_eglTestDispatchDevice;
@@ -28,6 +31,12 @@ void loadEGLExtensions(void)
 {
     ptr_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)
         loadEGLFunction("eglQueryDevicesEXT");
+    ptr_eglDebugMessageControlKHR = (PFNEGLDEBUGMESSAGECONTROLKHRPROC)
+        loadEGLFunction("eglDebugMessageControlKHR");
+    ptr_eglQueryDebugKHR = (PFNEGLQUERYDEBUGKHRPROC)
+        loadEGLFunction("eglQueryDebugKHR");
+    ptr_eglLabelObjectKHR = (PFNEGLLABELOBJECTKHRPROC)
+        loadEGLFunction("eglLabelObjectKHR");
 
     ptr_eglTestDispatchDisplay = (pfn_eglTestDispatchDisplay)
         loadEGLFunction("eglTestDispatchDisplay");
diff --git a/tests/egl_test_utils.h b/tests/egl_test_utils.h
index aad4c71..9703994 100644
--- a/tests/egl_test_utils.h
+++ b/tests/egl_test_utils.h
@@ -48,6 +48,9 @@
 extern const char *DUMMY_VENDOR_NAMES[DUMMY_VENDOR_COUNT];
 
 extern PFNEGLQUERYDEVICESEXTPROC ptr_eglQueryDevicesEXT;
+extern PFNEGLDEBUGMESSAGECONTROLKHRPROC ptr_eglDebugMessageControlKHR;
+extern PFNEGLQUERYDEBUGKHRPROC ptr_eglQueryDebugKHR;
+extern PFNEGLLABELOBJECTKHRPROC ptr_eglLabelObjectKHR;
 
 extern pfn_eglTestDispatchDisplay ptr_eglTestDispatchDisplay;
 extern pfn_eglTestDispatchDevice ptr_eglTestDispatchDevice;
diff --git a/tests/testegldebug.c b/tests/testegldebug.c
new file mode 100644
index 0000000..729cde3
--- /dev/null
+++ b/tests/testegldebug.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GL/gl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dummy/EGL_dummy.h"
+#include "egl_test_utils.h"
+
+/**
+ * \file
+ *
+ * Tests for EGL_KHR_debug.
+ *
+ * This test works by recording the parameters that we expect the debug
+ * callback function to get, and then calling an EGL function that generates an
+ * error.
+ *
+ * The debug callback checks its parameters against the expected values, and
+ * exits if any of them don't match.
+ */
+
+static const EGLLabelKHR THREAD_LABEL = (EGLLabelKHR) "THREAD_LABEL";
+static const EGLLabelKHR DISPLAY_LABEL = (EGLLabelKHR) "DISPLAY_LABEL";
+
+static void testCallback(EGLDisplay dpy, EGLBoolean callbackEnabled);
+
+static void EGLAPIENTRY debugCallback(EGLenum error, const char *command,
+        EGLint messageType, EGLLabelKHR threadLabel, EGLLabelKHR objectLabel,
+        const char *message);
+
+/**
+ * Records the expected parameters for the next call to the debug callback.
+ */
+static void setCallbackExpected(const char *command, EGLenum error,
+    EGLLabelKHR objectLabel, const char *message);
+static void setCallbackNotExpected(void);
+static void checkError(EGLint expectedError);
+
+/**
+ * True if the debug callback has been called since the last call to
+ * \c setCallbackExpected. This is used to make sure that the debug callback
+ * is called exactly once when a function generates an error.
+ */
+static EGLBoolean callbackWasCalled = EGL_FALSE;
+
+// These are the expected values for the next call to the debug callback, set
+// from setCallbackExpected and setCallbackNotExpected.
+static EGLBoolean shouldExpectCallback = EGL_FALSE;
+static const char *nextExpectedCommand = NULL;
+static EGLint nextExpectedError = EGL_NONE;
+static EGLLabelKHR nextExpectedObject = NULL;
+static const char *nextExpectedMessage = NULL;
+
+int main(int argc, char **argv)
+{
+    EGLDisplay dpy;
+    EGLAttrib callbackAttribs[] = {
+        EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE,
+        EGL_NONE
+    };
+
+    // We shouldn't get a callback for anything yet.
+    setCallbackNotExpected();
+
+    loadEGLExtensions();
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkError(EGL_SUCCESS);
+
+    ptr_eglLabelObjectKHR(EGL_NO_DISPLAY, EGL_OBJECT_THREAD_KHR, NULL, THREAD_LABEL);
+    ptr_eglLabelObjectKHR(dpy, EGL_OBJECT_DISPLAY_KHR, (EGLObjectKHR) dpy, DISPLAY_LABEL);
+
+    // Start by enabling the callback and generating some EGL errors. Make sure
+    // that the callback gets called with the correct parameters.
+    printf("Testing with callback\n");
+    ptr_eglDebugMessageControlKHR(debugCallback, NULL);
+    testCallback(dpy, EGL_TRUE);
+
+    // Disable the callback and try again. This time, the callback should not
+    // be called, but we should still get the same errors from eglGetError.
+    printf("Testing with no callback\n");
+    ptr_eglDebugMessageControlKHR(NULL, NULL);
+    testCallback(dpy, EGL_FALSE);
+
+    // Set a callback, but disable error messages. Again, the callback should
+    // not be called.
+    printf("Testing with callback and error messages disabled\n");
+    callbackAttribs[1] = EGL_FALSE;
+    ptr_eglDebugMessageControlKHR(debugCallback, callbackAttribs);
+    testCallback(dpy, EGL_FALSE);
+
+    return 0;
+}
+
+void testCallback(EGLDisplay dpy, EGLBoolean callbackEnabled)
+{
+    static const EGLint ERROR_ATTRIBS[] = {
+        EGL_CREATE_CONTEXT_FAIL, EGL_BAD_MATCH,
+        EGL_NONE
+    };
+
+    if (!callbackEnabled) {
+        setCallbackNotExpected();
+    }
+
+    // Generate an error from libEGL.so.
+    printf("Checking eglGetCurrentSurface\n");
+    if (callbackEnabled) {
+        setCallbackExpected("eglGetCurrentSurface", EGL_BAD_PARAMETER,
+                THREAD_LABEL, NULL);
+    }
+    eglGetCurrentSurface(EGL_NONE);
+    checkError(EGL_BAD_PARAMETER);
+
+    // Generate an error from a dispatch stub that expects a display. This
+    // should go through the same error reporting as eglGetCurrentSurface did.
+    printf("Checking eglCreateContext with invalid display\n");
+    if (callbackEnabled) {
+        setCallbackExpected("eglCreateContext", EGL_BAD_DISPLAY,
+                NULL, NULL);
+    }
+    eglCreateContext(EGL_NO_DISPLAY, NULL, EGL_NO_CONTEXT, NULL);
+    checkError(EGL_BAD_DISPLAY);
+
+    // Generate an error from the vendor library, to make sure that all of the
+    // EGL_KHR_debug calls got passed through correctly. The vendor library
+    // should pass the display label to the callback, and it uses the vendor
+    // name as the message.
+    printf("Checking eglCreateContext with valid display\n");
+    if (callbackEnabled) {
+        setCallbackExpected("eglCreateContext", EGL_BAD_MATCH,
+                DISPLAY_LABEL, DUMMY_VENDOR_NAMES[0]);
+    }
+    eglCreateContext(dpy, NULL, EGL_NO_CONTEXT, ERROR_ATTRIBS);
+    checkError(EGL_BAD_MATCH);
+}
+
+void setCallbackExpected(const char *command, EGLenum error,
+    EGLLabelKHR objectLabel, const char *message)
+{
+    shouldExpectCallback = EGL_TRUE;
+    nextExpectedCommand = command;
+    nextExpectedError = error;
+    nextExpectedObject = objectLabel;
+    nextExpectedMessage = message;
+    callbackWasCalled = EGL_FALSE;
+}
+
+void setCallbackNotExpected(void)
+{
+    shouldExpectCallback = EGL_FALSE;
+    callbackWasCalled = EGL_FALSE;
+}
+
+void EGLAPIENTRY debugCallback(EGLenum error, const char *command,
+        EGLint messageType, EGLLabelKHR threadLabel, EGLLabelKHR objectLabel,
+        const char *message)
+{
+    // First, make sure the debug callback was supposed to be called at all.
+    if (!shouldExpectCallback) {
+        printf("Unexpected callback from \"%s\"\n", command);
+        exit(1);
+    }
+
+    // Make sure the callback only gets called once.
+    if (callbackWasCalled) {
+        printf("Callback called multiple times from \"%s\"\n", command);
+        exit(1);
+    }
+    callbackWasCalled = EGL_TRUE;
+
+    if (messageType != EGL_DEBUG_MSG_ERROR_KHR) {
+        printf("Unexpected callback type: Expected 0x%04x, got 0x%04x\n",
+                EGL_DEBUG_MSG_ERROR_KHR, messageType);
+        exit(1);
+    }
+
+    if (error != nextExpectedError) {
+        printf("Unexpected callback error: Expected 0x%04x, got 0x%04x\n",
+                nextExpectedError, error);
+        exit(1);
+    }
+
+    if (command == NULL) {
+        printf("Command is NULL\n");
+        exit(1);
+    }
+
+    if (nextExpectedCommand != NULL) {
+        if (strcmp(nextExpectedCommand, command) != 0) {
+            printf("Unexpected command: Expected \"%s\", got \"%s\"\n",
+                    nextExpectedCommand, command);
+            exit(1);
+        }
+    }
+
+    if (nextExpectedMessage != NULL) {


Reply to: