{-# LANGUAGE CPP, Unsafe, UnliftedFFITypes, MagicHash, UnboxedTuples #-}
module Graphics.OpenGLES.Base.Proc (glGetProcAddress) where
import Foreign
import Foreign.C.String
import GHC.Base (realWorld#)
import GHC.CString (unpackCString#)
import GHC.IO (IO (IO))
import GHC.Ptr (Ptr(..))
import System.IO.Unsafe (unsafePerformIO)


#if defined(EGL_GETPROC)
foreign import ccall unsafe "eglGetProcAddress"
	getProcAddress :: CString -> IO (FunPtr a)

#elif defined(WGL_GETPROC)
foreign import ccall unsafe "wglGetProcAddress"
	getProcAddress :: CString -> IO (FunPtr a)

#elif defined(GLX_GETPROC)
foreign import ccall unsafe "glXGetProcAddress"
	getProcAddress :: CString -> IO (FunPtr a)

#elif defined(DLSYM_GETPROC)
-- | void *dlsym(void *handle, const char *symbol);
foreign import ccall unsafe "dlfcn.h dlsym"
	dlsym :: Ptr () -> CString -> IO (FunPtr a)

getProcAddress :: CString -> IO (FunPtr a)
getProcAddress procname = dlsym runtime_loader_default procname
	where runtime_loader_default = nullPtr
#else

#error "Don't know how to retrieve OpenGL ES extension entries. try -DEGL_GETPROC"

#endif


-- * Retrieve OpenGL (ES) and EGL Extension Entries

-- | Just like unsafePerformIO, but we inline it. Big performance gains as
-- it exposes lots of things to further inlining. /Very unsafe/. In
-- particular, you should do no memory allocation inside an
-- 'inlinePerformIO' block.
inlinePerformIO :: IO a -> a
inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
{-# INLINE inlinePerformIO #-}

glGetProcAddress :: String -> FunPtr a
glGetProcAddress procname =
	unsafePerformIO $ withCString procname getProcAddress
{-# INLINE [0] glGetProcAddress #-}
{-# RULES "glGetProcAddress/getProcAddress"
	forall s. glGetProcAddress (unpackCString# s) =
		inlinePerformIO (getProcAddress (Ptr s))
	#-}