Merge branch 'github/fork/kbrenneman/fix-tests-no-assembly' into 'master'

Fix for unit tests with no assembly support

Closes #154

See merge request glvnd/libglvnd!180
This commit is contained in:
Kyle Brenneman 2019-11-14 15:47:40 +00:00
commit 1613facce8
17 changed files with 591 additions and 289 deletions

View file

@ -66,3 +66,15 @@ build-i386-tsd:
variables:
CONFIGURE_OPTIONS: --build=i686-pc-linux-gnu CFLAGS=-m32 --disable-tls
build-pure-c-tls:
extends:
- .build-check
variables:
CONFIGURE_OPTIONS: --disable-asm
build-pure-c-tsd:
extends:
- .build-check
variables:
CONFIGURE_OPTIONS: --disable-asm --disable-tls

View file

@ -271,6 +271,9 @@ AM_CONDITIONAL([GLDISPATCH_TYPE_ARMV7_TSD], [test "x$gldispatch_entry_type" = "x
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"])
AS_IF([test "x$gldispatch_entry_type" != "xpure_c"],
[AC_DEFINE([USE_DISPATCH_ASM], 1,
[Define to 1 if libGLdispatch and libGLX should use assembly dispatch functions.])])
AC_MSG_CHECKING([for constructor attributes])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([

View file

@ -37,17 +37,7 @@
#include <sys/mman.h>
#include <assert.h>
#if defined(USE_X86_ASM) || \
defined(USE_X86_64_ASM) || \
defined(USE_ARMV7_ASM) || \
defined(USE_AARCH64_ASM) || \
defined(USE_PPC64LE_ASM)
# define USE_ASM 1
#else
# define USE_ASM 0
#endif
#if defined(__GNUC__) && USE_ASM
#if defined(USE_DISPATCH_ASM)
/// The maximum number of entrypoints that we can generate.
#define GENERATED_ENTRYPOINT_MAX 4096
@ -344,7 +334,7 @@ void *DefaultDispatchFunc(void)
return NULL;
}
#else // defined(__GNUC__) && USE_ASM
#else // defined(USE_DISPATCH_ASM)
GLVNDentrypointStub glvndGenerateEntrypoint(const char *procName)
{
@ -359,4 +349,4 @@ void glvndUpdateEntrypoints(GLVNDentrypointUpdateCallback callback, void *param)
{
}
#endif // defined(__GNUC__) && USE_ASM
#endif // defined(USE_DISPATCH_ASM)

View file

@ -71,6 +71,16 @@ testgldispatch_LDADD += dummy/libpatchentrypoints.la
testgldispatch_LDADD += $(top_builddir)/src/util/libutils_misc.la
testgldispatch_LDADD += $(PTHREAD_LIBS)
TESTS += testgldispatchthread.sh
check_PROGRAMS += testgldispatchthread
testgldispatchthread_SOURCES = \
testgldispatchthread.c
testgldispatchthread_CFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/GLdispatch \
$(PTHREAD_CFLAGS)
testgldispatchthread_LDADD = $(top_builddir)/src/GLdispatch/libGLdispatch.la
# Start of GLX-specific tests.
# Notes that the TESTS_GLX variable must be defined outside the conditional, so
# that we can include the test scripts in the EXTRA_DIST package. Otherwise,
@ -81,13 +91,11 @@ TESTS_GLX += testglxcreatecontext.sh
TESTS_GLX += testglxmcbasic.sh
TESTS_GLX += testglxmcloop.sh
TESTS_GLX += testglxmcthreads.sh
TESTS_GLX += testglxmclate.sh
TESTS_GLX += testglxmcoldlink.sh
TESTS_GLX += testglxgetprocaddress.sh
TESTS_GLX += testglxgetprocaddress_genentry.sh
TESTS_GLX += testglxgetclientstr.sh
TESTS_GLX += testglxqueryversion.sh
TESTS_GLX += testpatchentrypoints.sh
if ENABLE_GLX
@ -129,9 +137,19 @@ testglxmakecurrent_oldlink_LDADD += $(top_builddir)/src/util/libutils_misc.la
check_PROGRAMS += testglxgetprocaddress
testglxgetprocaddress_CFLAGS = $(CFLAGS_COMMON) $(X11_CFLAGS)
testglxgetprocaddress_CFLAGS = \
$(CFLAGS_COMMON) \
$(X11_CFLAGS) \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/GLdispatch
testglxgetprocaddress_LDADD = $(X11_LIBS)
testglxgetprocaddress_LDADD += $(top_builddir)/src/GLX/libGLX.la
testglxgetprocaddress_LDADD += $(top_builddir)/src/GLdispatch/libGLdispatch.la
check_PROGRAMS += testglxgetprocaddress_genentry
testglxgetprocaddress_genentry_LDADD = -lX11
testglxgetprocaddress_genentry_LDADD += $(top_builddir)/src/GLX/libGLX.la
check_PROGRAMS += testglxgetclientstr
@ -149,19 +167,6 @@ testglxqueryversion_LDADD = $(X11_LIBS)
testglxqueryversion_LDADD += $(top_builddir)/src/GLX/libGLX.la
testglxqueryversion_LDADD += $(top_builddir)/src/OpenGL/libOpenGL.la
check_PROGRAMS += testpatchentrypoints
testpatchentrypoints_SOURCES = \
testpatchentrypoints.c \
test_utils.c
testpatchentrypoints_CFLAGS = $(CFLAGS_COMMON) $(X11_CFLAGS)
testpatchentrypoints_LDADD = $(X11_LIBS) @LIB_DL@
testpatchentrypoints_LDADD += $(top_builddir)/src/GLX/libGLX.la
testpatchentrypoints_LDADD += $(top_builddir)/src/OpenGL/libOpenGL.la
testpatchentrypoints_LDADD += $(top_builddir)/src/util/libtrace.la
testpatchentrypoints_LDADD += $(top_builddir)/src/util/libutils_misc.la
endif # ENABLE_GLX

View file

@ -67,11 +67,17 @@ static GLXContext dispatch_glXCreateContextVendorDUMMY(Display *dpy,
static void dummy_glXExampleExtensionFunction(Display *dpy, int screen, int *retval);
static void dispatch_glXExampleExtensionFunction(Display *dpy, int screen, int *retval);
static void dummy_glXExampleExtensionFunction2(Display *dpy, int screen, int *retval);
static void dispatch_glXExampleExtensionFunction2(Display *dpy, int screen, int *retval);
static void dummy_glXMakeCurrentTestResults(GLint req, GLboolean *saw, void **ret);
static void dispatch_glXMakeCurrentTestResults(GLint req, GLboolean *saw, void **ret);
enum
{
DI_glXExampleExtensionFunction,
DI_glXExampleExtensionFunction2,
DI_glXCreateContextVendorDUMMY,
DI_glXMakeCurrentTestResults,
DI_COUNT,
};
static struct {
@ -82,7 +88,9 @@ static struct {
} glxExtensionProcs[] = {
#define PROC_ENTRY(name) { #name, dummy_##name, dispatch_##name, -1 }
PROC_ENTRY(glXExampleExtensionFunction),
PROC_ENTRY(glXExampleExtensionFunction2),
PROC_ENTRY(glXCreateContextVendorDUMMY),
PROC_ENTRY(glXMakeCurrentTestResults),
#undef PROC_ENTRY
};
@ -520,9 +528,7 @@ static void dummy_glEnd (void)
ctx->endHit++;
}
static void dummy_glMakeCurrentTestResults(GLint req,
GLboolean *saw,
void **ret)
static void dummy_glXMakeCurrentTestResults(GLint req, GLboolean *saw, void **ret)
{
GLXContext ctx = apiExports->getCurrentContext();
assert(ctx);
@ -538,15 +544,6 @@ static void dummy_glMakeCurrentTestResults(GLint req,
*ret = (void *)data;
}
break;
case GL_MC_VENDOR_STRING:
{
// FIXME: This is used from testglxnscreens to check that the
// correct vendor library is loaded from each display. Originally,
// it used the vendor name passed to __glx_Main, but libGLX doesn't
// provide the vendor name anymore.
*ret = NULL;
}
break;
case GL_MC_LAST_REQ:
default:
*ret = NULL;
@ -554,35 +551,76 @@ static void dummy_glMakeCurrentTestResults(GLint req,
}
}
static void dispatch_glXMakeCurrentTestResults(GLint req, GLboolean *saw, void **ret)
{
__GLXvendorInfo *dynDispatch;
PFNGLXMAKECURRENTTESTRESULTSPROC func;
const int index = glxExtensionProcs[DI_glXMakeCurrentTestResults].index;
dynDispatch = apiExports->getCurrentDynDispatch();
if (!dynDispatch) {
return;
}
func = (PFNGLXMAKECURRENTTESTRESULTSPROC)
apiExports->fetchDispatchEntry(dynDispatch, index);
if (func) {
func(req, saw, ret);
}
}
static void dummy_glXExampleExtensionFunction(Display *dpy, int screen, int *retval)
{
// Indicate that we've called the real function, and not a dispatch stub
*retval = 1;
}
static void dispatch_glXExampleExtensionFunction(Display *dpy,
static void commonDispatch_glXExampleExtensionFunction(Display *dpy,
int screen,
int *retval)
int *retval,
int funcIndex)
{
typedef void (*ExampleExtensionFunctionPtr)(Display *dpy,
int screen,
int *retval);
__GLXvendorInfo *dynDispatch;
ExampleExtensionFunctionPtr func;
const int index = glxExtensionProcs[DI_glXExampleExtensionFunction].index;
PFNGLXEXAMPLEEXTENSIONFUNCTION func;
const int index = glxExtensionProcs[funcIndex].index;
dynDispatch = apiExports->getDynDispatch(dpy, screen);
if (!dynDispatch) {
return;
}
func = (ExampleExtensionFunctionPtr)
func = (PFNGLXEXAMPLEEXTENSIONFUNCTION)
apiExports->fetchDispatchEntry(dynDispatch, index);
if (func) {
func(dpy, screen, retval);
}
}
static void dispatch_glXExampleExtensionFunction(Display *dpy,
int screen,
int *retval)
{
// Set a different value here. That way, if a test fails, you can easily
// tell if it got as far as the dispatch function.
*retval = -1;
commonDispatch_glXExampleExtensionFunction(dpy, screen, retval,
DI_glXExampleExtensionFunction);
}
static void dummy_glXExampleExtensionFunction2(Display *dpy, int screen, int *retval)
{
*retval = 2;
}
static void dispatch_glXExampleExtensionFunction2(Display *dpy,
int screen,
int *retval)
{
*retval = -2;
commonDispatch_glXExampleExtensionFunction(dpy, screen, retval,
DI_glXExampleExtensionFunction2);
}
/*
* Note we only fill in real implementations for a few core GL functions.
* The rest will dispatch to the NOP stub.
@ -595,7 +633,6 @@ static const struct {
PROC_ENTRY(glBegin),
PROC_ENTRY(glEnd),
PROC_ENTRY(glVertex3fv),
PROC_ENTRY(glMakeCurrentTestResults),
PROC_ENTRY(glXChooseVisual),
PROC_ENTRY(glXCopyContext),

View file

@ -48,11 +48,6 @@ enum {
*/
GL_MC_FUNCTION_COUNTS,
/*
* Returns a NULL-terminated string describing the name of this vendor.
*/
GL_MC_VENDOR_STRING,
/*
* Last request. Always returns NULL.
*/
@ -67,8 +62,16 @@ enum {
*/
#define GLX_CONTEX_ATTRIB_DUMMY 0x10000
/**
* glXExampleExtensionFunction(): Dummy GLX extension function.
*
* This function just assigns 1 to *retval. It's used to test dispatching
* through a venodr-supplied dispatch function.
*/
typedef void (* PFNGLXEXAMPLEEXTENSIONFUNCTION) (Display *dpy, int screen, int *retval);
/*
* glMakeCurrentTestResults(): perform queries on vendor library state.
* glXMakeCurrentTestResults(): perform queries on vendor library state.
*
* This explicitly is designed to not return anything, in case a bug causes the
* API library to dispatch this to a no-op stub. If this function returned a
@ -85,7 +88,7 @@ enum {
* set to NULL if there was an error, or a pointer to request-specific data
* otherwise. The pointer may be passed into free(3).
*/
typedef void (*PFNGLMAKECURRENTTESTRESULTSPROC)(
typedef void (*PFNGLXMAKECURRENTTESTRESULTSPROC)(
GLint req,
GLboolean *saw,
void **ret

View file

@ -1,6 +1,6 @@
#!/bin/sh
__GLX_VENDOR_LIBRARY_NAME=dummy
export __GLX_VENDOR_LIBRARY_NAME
__GLX_FORCE_VENDOR_LIBRARY_0=dummy
export __GLX_FORCE_VENDOR_LIBRARY_0
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TOP_BUILDDIR/tests/dummy/.libs
export LD_LIBRARY_PATH

View file

@ -135,6 +135,16 @@ int main(int argc, char **argv)
}
};
#if !defined(USE_DISPATCH_ASM)
// If the assembly dispatch stubs aren't enabled, then generating and
// patching entrypoints won't work. In that case, exit with 77 to tell
// automake to skip the test instead of failing.
if (enablePatching || enableGeneratedTest)
{
return 77;
}
#endif
__glDispatchInit();
InitDummyVendors();

View file

@ -0,0 +1,275 @@
/*
* Copyright (c) 2019, 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <pthread.h>
#include <semaphore.h>
#include <GL/gl.h>
#include <GLdispatch.h>
#define VENDOR_COUNT 2
#define THREAD_COUNT 4
#define CALL_COUNT 1
typedef struct {
int vendorID;
__GLdispatchTable *dispatch;
} VendorInfo;
typedef struct {
__GLdispatchThreadState dispatchThreadState;
pthread_t thread;
VendorInfo *vendor;
int callCountStatic;
int callCountEarly;
int callCountLate;
GLboolean destroyed;
} ThreadState;
typedef void (* pfn_glVertex3fv) (const GLfloat *v);
static sem_t mainSemaphore;
static sem_t threadSemaphore;
static pfn_glVertex3fv ptr_glVertex3fv = NULL;
static pfn_glVertex3fv ptr_glTestFuncEarly = NULL;
static pfn_glVertex3fv ptr_glTestFuncLate = NULL;
static ThreadState *GetCurrentThreadState(void)
{
__GLdispatchThreadState *ts = __glDispatchGetCurrentThreadState();
if (ts == NULL) {
printf("__glDispatchGetCurrentThreadState failed\n");
}
return (ThreadState *) ts;
}
static void dummy_glVertex3fv(const GLfloat *v)
{
ThreadState *ts = GetCurrentThreadState();
ts->callCountStatic++;
}
static void glTestFuncEarlyDUMMY(const GLfloat *v)
{
ThreadState *ts = GetCurrentThreadState();
ts->callCountEarly++;
}
static void glTestFuncLateDUMMY(const GLfloat *v)
{
ThreadState *ts = GetCurrentThreadState();
ts->callCountLate++;
}
static void *VendorGetProcAddressCallback(const char *procName, void *param)
{
if (strcmp(procName, "glVertex3fv") == 0) {
return dummy_glVertex3fv;
} else if (strcmp(procName, "glTestFuncEarlyDUMMY") == 0) {
return glTestFuncEarlyDUMMY;
} else if (strcmp(procName, "glTestFuncLateDUMMY") == 0) {
return glTestFuncLateDUMMY;
} else {
return NULL;
}
}
static void ThreadDestroyedCallback(__GLdispatchThreadState *dispatchThreadState)
{
ThreadState *ts = (ThreadState *) dispatchThreadState;
ts->destroyed = GL_TRUE;
}
static void *ThreadProc(void *param)
{
ThreadState *ts = (ThreadState *) param;
int i;
ts->dispatchThreadState.threadDestroyedCallback = ThreadDestroyedCallback;
if (!__glDispatchMakeCurrent(&ts->dispatchThreadState,
ts->vendor->dispatch, ts->vendor->vendorID,
NULL)) {
printf("__glDispatchMakeCurrent failed\n");
exit(1);
}
// Notify the main thread that we're ready.
if (sem_post(&mainSemaphore) != 0) {
printf("sem_post failed\n");
exit(1);
}
// Wait for the main thread to finish calling __glDispatchGetProcAddress.
if (sem_wait(&threadSemaphore) != 0) {
printf("sem_wait failed\n");
exit(1);
}
for (i=0; i<CALL_COUNT; i++) {
ptr_glVertex3fv(NULL);
if (ptr_glTestFuncEarly != NULL) {
ptr_glTestFuncEarly(NULL);
}
if (ptr_glTestFuncLate != NULL) {
ptr_glTestFuncLate(NULL);
}
}
return NULL;
}
int main(int argc, char **argv)
{
VendorInfo vendors[VENDOR_COUNT] = {};
ThreadState threads[THREAD_COUNT] = {};
int result, i;
if (sem_init(&mainSemaphore, 0, 0) != 0) {
printf("sem_init failed\n");
return 1;
}
if (sem_init(&threadSemaphore, 0, 0) != 0) {
printf("sem_init failed\n");
return 1;
}
__glDispatchInit();
ptr_glVertex3fv = (pfn_glVertex3fv) __glDispatchGetProcAddress("glVertex3fv");
if (ptr_glVertex3fv == NULL) {
printf("__glDispatchGetProcAddress(glVertex3fv) failed\n");
return 1;
}
#if defined(USE_DISPATCH_ASM)
ptr_glTestFuncEarly = (pfn_glVertex3fv) __glDispatchGetProcAddress("glTestFuncEarlyDUMMY");
if (ptr_glTestFuncEarly == NULL) {
printf("__glDispatchGetProcAddress(glTestFuncEarlyDUMMY) failed\n");
return 1;
}
#endif
// Create some dummy vendors and dispatch tables.
for (i=0; i<VENDOR_COUNT; i++) {
vendors[i].vendorID = __glDispatchNewVendorID();
vendors[i].dispatch = __glDispatchCreateTable(VendorGetProcAddressCallback, &vendors[i]);
if (vendors[i].dispatch == NULL) {
return 1;
}
}
// Start the worker threads.
for (i=0; i<THREAD_COUNT; i++) {
threads[i].vendor = &vendors[i % VENDOR_COUNT];
if (pthread_create(&threads[i].thread, NULL, ThreadProc, &threads[i]) != 0) {
printf("Failed to create thread\n");
return 1;
}
}
// Wait for each thread to be ready. After this, each thread will have
// called __glDispatchMakeCurrent, and is waiting for the main thread to
// tell it to proceed.
for (i=0; i<THREAD_COUNT; i++) {
if (sem_wait(&mainSemaphore) != 0) {
printf("sem_wait failed\n");
exit(1);
}
}
#if defined(USE_DISPATCH_ASM)
// Generate another GL function. This tests whether libGLdispatch will
// correctly update existing dispatch tables that are current to some
// thread.
ptr_glTestFuncLate = (pfn_glVertex3fv) __glDispatchGetProcAddress("glTestFuncLateDUMMY");
if (ptr_glTestFuncLate == NULL) {
printf("__glDispatchGetProcAddress(glTestFuncLateDUMMY) failed\n");
return 1;
}
#endif
// Wake up the threads and let them continue. The threads will try calling
// each of the GL functions.
for (i=0; i<THREAD_COUNT; i++) {
if (sem_post(&threadSemaphore) != 0) {
printf("sem_post failed\n");
exit(1);
}
}
// Wait for the threads to finish.
for (i=0; i<THREAD_COUNT; i++) {
pthread_join(threads[i].thread, NULL);
}
// Check the results.
result = 0;
for (i=0; i<THREAD_COUNT; i++) {
if (threads[i].callCountStatic != CALL_COUNT) {
printf("Thread %d: Static call count is wrong: %d\n", i, threads[i].callCountStatic);
result = 1;
}
if (ptr_glTestFuncEarly != NULL) {
if (threads[i].callCountEarly != CALL_COUNT) {
printf("Thread %d: Early call count is wrong: %d\n", i, threads[i].callCountEarly);
result = 1;
}
}
if (ptr_glTestFuncLate != NULL) {
if (threads[i].callCountLate != CALL_COUNT) {
printf("Thread %d: Late call count is wrong: %d\n", i, threads[i].callCountLate);
result = 1;
}
}
if (!threads[i].destroyed) {
printf("Thread %d: Destroy callback was not called\n", i);
result = 1;
}
}
for (i=0; i<VENDOR_COUNT; i++) {
if (vendors[i].dispatch != NULL) {
__glDispatchDestroyTable(vendors[i].dispatch);
}
}
sem_destroy(&mainSemaphore);
sem_destroy(&threadSemaphore);
return result;
}

4
tests/testgldispatchthread.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
./testgldispatchthread

View file

@ -27,42 +27,28 @@
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
#include <GL/glx.h>
#include <GL/gl.h>
#include <stdio.h>
#include <stdlib.h>
typedef __GLXextFuncPtr (* pfn_glXGetProcAddress) (const GLubyte *procName);
static pfn_glXGetProcAddress ptr_glXGetProcAddress;
#include <GL/glx.h>
#include <GL/gl.h>
typedef void (* pfn_glXWaitGL) (void);
static pfn_glXWaitGL ptr_glXWaitGL;
#include <GLdispatch.h>
#include "dummy/GLX_dummy.h"
typedef void (* pfn_glVertex3fv) (const GLfloat *v);
static pfn_glVertex3fv ptr_glVertex3fv;
typedef void (* pfn_glXExampleExtensionFunction) (Display *dpy, int screen, int *retval);
static pfn_glXExampleExtensionFunction ptr_glXExampleExtensionFunction;
typedef void (* pfn_glBogusFunc1) (int a, int b, int c);
static pfn_glBogusFunc1 ptr_glBogusFunc1;
typedef void (* pfn_glBogusFunc2) (int a, int b, int c);
static pfn_glBogusFunc2 ptr_glBogusFunc2;
typedef const char * (* pfn_glXQueryServerString) (Display *dpy, int screen, int name);
static void *LoadFunction(const char *name);
int main(int argc, char **argv)
{
Display *dpy = NULL;
int retval = 0;
pfn_glXQueryServerString ptr_glXQueryServerString;
PFNGLXEXAMPLEEXTENSIONFUNCTION ptr_glXExampleExtensionFunction;
/*
* Try GetProcAddress on different classes of API functions, and bogus
* functions. The API library should return entry point addresses for
* any function beginning with gl*(), though bogus functions will resolve
* to no-ops.
*/
Display *dpy = NULL;
const char *str;
__GLdispatchProc dispatchPtr, glxPtr;
int retval = 0;
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
@ -70,61 +56,44 @@ int main(int argc, char **argv)
return 1;
}
/*
* Load the function addresses up front. Note that in order to test GLX
* entrypoint generation, we have to load the functions early, before
* libGLX.so loads the vendor library.
*/
ptr_glXGetProcAddress = (pfn_glXGetProcAddress)
LoadFunction("glXGetProcAddress");
ptr_glXWaitGL = (pfn_glXWaitGL) LoadFunction("glXWaitGL");
ptr_glXExampleExtensionFunction = (pfn_glXExampleExtensionFunction)
LoadFunction("glXExampleExtensionFunction");
ptr_glVertex3fv = (pfn_glVertex3fv) LoadFunction("glVertex3fv");
ptr_glBogusFunc1 = (pfn_glBogusFunc1) LoadFunction("glBogusFunc1");
ptr_glBogusFunc2 = (pfn_glBogusFunc2) LoadFunction("glBogusFunc2");
/*
* Test core GLX dispatch functions implemented by API library. This
* simply returns the symbol exported by libGLX.
*/
ptr_glXGetProcAddress((const GLubyte *) "glBogusFunc1");
ptr_glXWaitGL();
// Call glXGetClientString to force libGLX to load the vendor library.
glXGetClientString(dpy, GLX_EXTENSIONS);
/*
* Test a "GLX extension" function with a vendor-neutral dispatcher
* implemented by the vendor library (in this case, libGLX_dummy). If we
* successfully used libGLX_dummy's dispatcher, retval should be non-zero
* (a zero value indicates we might be calling into a no-op stub generated
* by libGLdispatch).
*/
ptr_glXExampleExtensionFunction(dpy, 0, &retval);
if (!retval) {
printf("Unexpected glXExampleExtensionFunction() return value!\n");
// Test a core GLX function first.
ptr_glXQueryServerString = (pfn_glXQueryServerString) LoadFunction("glXQueryServerString");
str = ptr_glXQueryServerString(dpy, 0, GLX_VENDOR);
if (str == NULL) {
printf("glXQueryServerString returned NULL\n");
return 1;
}
if (strcmp(str, "testlib") != 0) {
printf("glXQueryServerString returned unexpected value: %s\n", str);
return 1;
}
/*
* Try getting the address of the core GL function glVertex3fv().
* This retrieves a static stub from glapi.
* Note calling this function with a NULL pointer is fine since this is a
* no-op function while there is no context current.
* Test a "GLX extension" function with a vendor-neutral dispatcher
* implemented by the vendor library (in this case, libGLX_dummy). If we
* successfully used libGLX_dummy's dispatcher, retval should be 1.
*/
ptr_glVertex3fv(NULL);
ptr_glXExampleExtensionFunction = (PFNGLXEXAMPLEEXTENSIONFUNCTION)
LoadFunction("glXExampleExtensionFunction");
ptr_glXExampleExtensionFunction(dpy, 0, &retval);
if (retval != 1) {
printf("Unexpected glXExampleExtensionFunction() return value: %d\n", retval);
return 1;
}
/*
* These are bogus functions, but will get a valid entry point since they
* are prefixed with "gl". The first GetProcAddress() will early out since
* there should be a cached copy from the explicit call made above, but
* the second one will go through glapi's dynamic stub generation path.
*
* Again, calling these functions should be a no-op.
*/
ptr_glBogusFunc1(0, 0, 0);
ptr_glBogusFunc2(1, 1, 1);
// Test loading a normal GL function. Load the function through
// glXGetProcAddress, and then again directly through libGLdispatch. We
// should get the same poiner for both.
glxPtr = LoadFunction("glVertex3fv");
dispatchPtr = __glDispatchGetProcAddress("glVertex3fv");
if (dispatchPtr != glxPtr) {
printf("Mismatch for function glVertex3fv: GLX returned %p, GLdispatch returned %p\n",
glxPtr, dispatchPtr);
return 1;
}
// Success!
return 0;
@ -132,12 +101,21 @@ int main(int argc, char **argv)
static void *LoadFunction(const char *name)
{
__GLXextFuncPtr func = glXGetProcAddress((const GLubyte *) name);
__GLXextFuncPtr func, func2;
func = glXGetProcAddress((const GLubyte *) name);
if (func == NULL) {
printf("failed to get %s!\n", name);
exit(1);
}
// Call glXGetProcAddress again to make sure that we get the same address.
func2 = glXGetProcAddress((const GLubyte *) name);
if (func != func2) {
printf("glXGetProcAddress returned different address for %s: %p, %p\n",
name, func, func2);
exit(1);
}
return (void *) func;
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2019, 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.
*/
#if defined(USE_DISPATCH_ASM)
#include <GL/glx.h>
#include <GL/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include "dummy/GLX_dummy.h"
int main(int argc, char **argv)
{
PFNGLXEXAMPLEEXTENSIONFUNCTION ptr_glXExampleExtensionFunction;
PFNGLXEXAMPLEEXTENSIONFUNCTION ptr_glXExampleExtensionFunction2;
__GLXextFuncPtr proc;
Display *dpy = NULL;
int result = 0;
int i;
// Load the function pointer first, before libGLX can load the dummy vendor
// library. That'll force libGLX to generate an entrypoint stub.
ptr_glXExampleExtensionFunction = (PFNGLXEXAMPLEEXTENSIONFUNCTION)
glXGetProcAddress((const GLubyte *) "glXExampleExtensionFunction");
if (ptr_glXExampleExtensionFunction == NULL) {
printf("Can't look up glXExampleExtensionFunction\n");
return 1;
}
printf("Got glXExampleExtensionFunction at address %p\n", ptr_glXExampleExtensionFunction);
// Call glXGetProcAddress to generate more dummy dispatch stubs, and then a
// second extension function. This tests that the generated dispatch stubs
// can correctly handle a large index.
for (i=0; i<4094; i++) {
char buf[50];
snprintf(buf, sizeof(buf), "glXUndefined%dDUMMY", i);
proc = glXGetProcAddress((const GLubyte *) buf);
if (proc == NULL) {
printf("Failed to generate stub for dummy function %d %s\n", i, buf);
return 1;
}
}
ptr_glXExampleExtensionFunction2 = (PFNGLXEXAMPLEEXTENSIONFUNCTION)
glXGetProcAddress((const GLubyte *) "glXExampleExtensionFunction2");
if (ptr_glXExampleExtensionFunction2 == NULL) {
printf("Can't look up glXExampleExtensionFunction\n");
return 1;
}
printf("Got glXExampleExtensionFunction2 at address %p\n", ptr_glXExampleExtensionFunction2);
// Make one more call to glXGetProcAddress. This should return NULL.
proc = glXGetProcAddress((const GLubyte *) "glXLastUndefinedDummy");
if (proc != NULL) {
printf("Last glXGetProcAddress returned non-NULL: %p\n", proc);
return 1;
}
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
printf("Can't open display\n");
return 1;
}
// Call glXGetClientString to force libGLX to load the vendor library.
glXGetClientString(dpy, GLX_EXTENSIONS);
ptr_glXExampleExtensionFunction(dpy, 0, &result);
if (result != 1) {
printf("Unexpected glXExampleExtensionFunction() return value: %d\n", result);
XCloseDisplay(dpy);
return 1;
}
ptr_glXExampleExtensionFunction2(dpy, 0, &result);
if (result != 2) {
printf("Unexpected glXExampleExtensionFunction2() return value: %d\n", result);
XCloseDisplay(dpy);
return 1;
}
printf("%p - %p = %d\n", ptr_glXExampleExtensionFunction2,
ptr_glXExampleExtensionFunction,
(int) (((intptr_t) ptr_glXExampleExtensionFunction2) - ((intptr_t) ptr_glXExampleExtensionFunction)));
XCloseDisplay(dpy);
return 0;
}
#else // defined(USE_DISPATCH_ASM)
int main(int argc, char **argv)
{
// If libGLX can't generate new dispatch stubs, then just skip this test.
return 77;
}
#endif // defined(USE_DISPATCH_ASM)

View file

@ -2,11 +2,4 @@
. $TOP_SRCDIR/tests/glxenv.sh
# Set __GLX_FORCE_VENDOR_LIBRARY_0 instead of __GLX_VENDOR_LIBRARY_NAME. That
# way, it won't pre-load the vendor library, which would force it to generate
# a dispatch stub for glXExampleExtensionFunction.
__GLX_FORCE_VENDOR_LIBRARY_0=$__GLX_VENDOR_LIBRARY_NAME
export __GLX_FORCE_VENDOR_LIBRARY_0
unset __GLX_VENDOR_LIBRARY_NAME
./testglxgetprocaddress
./testglxgetprocaddress_genentry

View file

@ -49,7 +49,6 @@
typedef struct TestOptionsRec {
int iterations;
int threads;
GLboolean late;
} TestOptions;
static void print_help(void)
@ -58,8 +57,7 @@ static void print_help(void)
"Options: \n"
" -h, --help Print this help message.\n"
" -i<N>, --iterations=<N> Run N make current iterations in each thread \n"
" -t<N>, --threads=<N> Run with N threads.\n"
" -l, --late Call GetProcAddress() after MakeCurrent()\n";
" -t<N>, --threads=<N> Run with N threads.\n";
printf("%s", help_string);
}
@ -71,17 +69,15 @@ void init_options(int argc, char **argv, TestOptions *t)
{ "help", no_argument, NULL, 'h'},
{ "iterations", required_argument, NULL, 'i'},
{ "threads", required_argument, NULL, 't'},
{ "late", no_argument, NULL, 'l' },
{ NULL, no_argument, NULL, 0 }
};
// Initialize defaults
t->iterations = 1;
t->threads = 1;
t->late = GL_FALSE;
do {
c = getopt_long(argc, argv, "hi:t:l", long_options, NULL);
c = getopt_long(argc, argv, "hi:t:", long_options, NULL);
switch (c) {
case -1:
default:
@ -106,36 +102,15 @@ void init_options(int argc, char **argv, TestOptions *t)
exit(1);
}
break;
case 'l':
t->late = GL_TRUE;
break;
}
} while (c != -1);
}
static PFNGLMAKECURRENTTESTRESULTSPROC GetMakeCurrentTestResults(void)
{
int i;
PFNGLMAKECURRENTTESTRESULTSPROC proc = NULL, old_proc = NULL;
// Call this multiple times to verify address caching works correctly.
for (i = 0; i < 3; i++) {
proc = (PFNGLMAKECURRENTTESTRESULTSPROC)
glXGetProcAddress((GLubyte *)"glMakeCurrentTestResults");
if ((i != 0) && (proc != old_proc))
{
printError("Got different addresses for glMakeCurrentTestResults: %p, %p\n", proc, old_proc);
return NULL;
}
old_proc = proc;
}
return proc;
}
void *MakeCurrentThread(void *arg)
{
struct window_info wi;
PFNGLMAKECURRENTTESTRESULTSPROC pMakeCurrentTestResults = NULL;
PFNGLXMAKECURRENTTESTRESULTSPROC pMakeCurrentTestResults = NULL;
GLXContext ctx = NULL;
const GLfloat v[] = { 0, 0, 0 };
struct {
@ -162,15 +137,16 @@ void *MakeCurrentThread(void *arg)
goto fail;
}
// Make sure that libGLX has loaded the vendor library.
glXGetClientString(dpy, GLX_EXTENSIONS);
// Test the robustness of GetProcAddress() by calling this separately for
// each thread.
if (!t->late) {
pMakeCurrentTestResults = GetMakeCurrentTestResults();
if (!pMakeCurrentTestResults) {
printError("Failed to get glMakeCurrentTestResults() function!\n");
goto fail;
}
pMakeCurrentTestResults = (PFNGLXMAKECURRENTTESTRESULTSPROC)
glXGetProcAddress((const GLubyte *) "glXMakeCurrentTestResults");
if (pMakeCurrentTestResults == NULL) {
printError("Failed to get glXMakeCurrentTestResults() function!\n");
goto fail;
}
success = testUtilsCreateWindow(dpy, &wi, 0);
@ -192,22 +168,13 @@ void *MakeCurrentThread(void *arg)
goto fail;
}
if (t->late) {
pMakeCurrentTestResults = GetMakeCurrentTestResults();
if (!pMakeCurrentTestResults) {
printError("Failed to get glMakeCurrentTestResults() function!\n");
goto fail;
}
}
glBegin(GL_TRIANGLES); BeginCount++;
glVertex3fv(v); Vertex3fvCount++;
glVertex3fv(v); Vertex3fvCount++;
glVertex3fv(v); Vertex3fvCount++;
glEnd(); EndCount++;
// Make a call to glMakeCurrentTestResults() to get the function counts.
// Make a call to glXMakeCurrentTestResults() to get the function counts.
makeCurrentTestResultsParams.req = GL_MC_FUNCTION_COUNTS;
makeCurrentTestResultsParams.saw = GL_FALSE;
makeCurrentTestResultsParams.ret = NULL;
@ -217,12 +184,12 @@ void *MakeCurrentThread(void *arg)
&makeCurrentTestResultsParams.ret);
if (!makeCurrentTestResultsParams.saw) {
printError("Failed to dispatch glMakeCurrentTestResults()!\n");
printError("Failed to dispatch glXMakeCurrentTestResults()!\n");
goto fail;
}
if (!makeCurrentTestResultsParams.ret) {
printError("Internal glMakeCurrentTestResults() error!\n");
printError("Internal glXMakeCurrentTestResults() error!\n");
goto fail;
}
@ -248,7 +215,7 @@ void *MakeCurrentThread(void *arg)
glVertex3fv(NULL);
glEnd();
// Similarly the call to the dynamic function glMakeCurrentTestResults()
// Similarly the call to the dynamic function glXMakeCurrentTestResults()
// should be a no-op.
makeCurrentTestResultsParams.req = GL_MC_FUNCTION_COUNTS;
makeCurrentTestResultsParams.saw = GL_FALSE;
@ -259,7 +226,7 @@ void *MakeCurrentThread(void *arg)
&makeCurrentTestResultsParams.ret);
if (makeCurrentTestResultsParams.saw) {
printError("Dynamic function glMakeCurrentTestResults() dispatched "
printError("Dynamic function glXMakeCurrentTestResults() dispatched "
"to vendor library even though no context was current!\n");
goto fail;
}

View file

@ -1,7 +0,0 @@
#!/bin/sh
. $TOP_SRCDIR/tests/glxenv.sh
# Run the make current test exactly once, but with GetProcAddress() called
# after MakeCurrent().
./testglxmakecurrent -t 1 -i 1 -l

View file

@ -1,87 +0,0 @@
#define _GNU_SOURCE 1
#include <string.h>
#include <X11/X.h>
#include <GL/gl.h>
#include <dlfcn.h>
#include "test_utils.h"
#define NUM_VERTEX3FV_CALLS 100
int main(int argc, char **argv)
{
struct window_info wi;
Display *dpy = XOpenDisplay(NULL);
int sawVertex3fv1, *pSawVertex3fv;
int i;
int ret = 1;
GLXContext ctx = None;
void *vendorHandle;
if (!dpy) {
printError("No display!\n");
goto fail;
}
memset(&wi, 0, sizeof(wi));
if (!testUtilsCreateWindow(dpy, &wi, 0)) {
printError("Failed to create window!\n");
goto fail;
}
ctx = glXCreateContext(dpy, wi.visinfo, NULL, GL_TRUE);
if (!ctx) {
printError("Failed to create a context!\n");
goto fail;
}
if (!glXMakeContextCurrent(dpy, wi.win, wi.win, ctx)) {
printError("Failed to make current\n");
goto fail;
}
vendorHandle = dlopen("libGLX_dummy.so", RTLD_LAZY);
if (!vendorHandle) {
printError("No valid vendor library handle\n");
goto fail;
}
pSawVertex3fv = (int *)dlsym(vendorHandle, "__glXSawVertex3fv");
if (!pSawVertex3fv) {
printError("Could not find __glXSawVertex3fv\n");
goto fail;
}
for (i = 0; i < NUM_VERTEX3FV_CALLS; i++) {
glVertex3fv(NULL);
}
// Read the resulting value
sawVertex3fv1 = *pSawVertex3fv;
if (!glXMakeContextCurrent(dpy, None, None, NULL)) {
printError("Could not lose current\n");
goto fail;
}
dlclose(vendorHandle);
pSawVertex3fv = NULL;
if (sawVertex3fv1 != NUM_VERTEX3FV_CALLS) {
printError("sawVertex3fv1 mismatch: expected %d, got %d\n",
NUM_VERTEX3FV_CALLS, sawVertex3fv1);
goto fail;
}
ret = 0;
fail:
if (ctx) {
glXDestroyContext(dpy, ctx);
}
testUtilsDestroyWindow(dpy, &wi);
return ret;
}

View file

@ -1,7 +0,0 @@
#!/bin/sh
. $TOP_SRCDIR/tests/glxenv.sh
export GLVND_TEST_PATCH_ENTRYPOINTS=1
# Run the patch entrypoint test.
./testpatchentrypoints