This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

606 lines
22 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// glentrypoints.h
//
//===============================================================================
#ifndef GLENTRYPOINTS_H
#define GLENTRYPOINTS_H
#pragma once
#ifdef DX_TO_GL_ABSTRACTION
#include "interface.h"
#include "tier0/platform.h"
#include "tier0/vprof_telemetry.h"
#include "togl/rendermechanism.h"
void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired,
void *fallback = NULL);
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
class CGLExecuteHelperBase {
public:
inline void StartCall(const char *pName);
inline void StopCall(const char *pName);
#if GL_TRACK_API_TIME
TmU64 m_nStartTime;
#endif
};
template <class FunctionType, typename Result>
class CGLExecuteHelper : public CGLExecuteHelperBase {
public:
inline CGLExecuteHelper(FunctionType pFn, const char *pName) : m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)();
StopCall(pName);
}
template <typename A>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a);
StopCall(pName);
}
template <typename A, typename B>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b);
StopCall(pName);
}
template <typename A, typename B, typename C>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e, f);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e, f, g);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e, f, g, h);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H, typename I>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h, I i)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H, typename I, typename J>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h, I i, J j)
: m_pFn(pFn) {
StartCall(pName);
m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i, j);
StopCall(pName);
}
inline operator Result() const { return m_Result; }
inline operator char *() const { return (char *)m_Result; }
FunctionType m_pFn;
Result m_Result;
};
template <class FunctionType>
class CGLExecuteHelper<FunctionType, void> : public CGLExecuteHelperBase {
public:
inline CGLExecuteHelper(FunctionType pFn, const char *pName) : m_pFn(pFn) {
StartCall(pName);
(*m_pFn)();
StopCall(pName);
}
template <typename A>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a);
StopCall(pName);
}
template <typename A, typename B>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b);
StopCall(pName);
}
template <typename A, typename B, typename C>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e, f);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e, f, g);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e, f, g, h);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H, typename I>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h, I i)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e, f, g, h, i);
StopCall(pName);
}
template <typename A, typename B, typename C, typename D, typename E,
typename F, typename G, typename H, typename I, typename J>
inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c,
D d, E e, F f, G g, H h, I i, J j)
: m_pFn(pFn) {
StartCall(pName);
(*m_pFn)(a, b, c, d, e, f, g, h, i, j);
StopCall(pName);
}
FunctionType m_pFn;
};
#endif
template <class FunctionType, typename Result>
class CDynamicFunctionOpenGLBase {
public:
// Construct with a NULL function pointer. You must manually call
// Lookup() before you can call a dynamic function through this interface.
CDynamicFunctionOpenGLBase() : m_pFn(NULL) {}
// Construct and do a lookup right away. You will need to make sure that
// the lookup actually succeeded, as the gl library might have failed to
// load or (fn) might not exist in it.
CDynamicFunctionOpenGLBase(const char *fn, FunctionType fallback = NULL)
: m_pFn(NULL) {
Lookup(fn, fallback);
}
// Construct and do a lookup right away. See comments in Lookup() about what
// (okay) does.
CDynamicFunctionOpenGLBase(const char *fn, bool &okay,
FunctionType fallback = NULL)
: m_pFn(NULL) {
Lookup(fn, okay, fallback);
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// This allows you to chain lookups like this:
// bool okay = true;
// x.Lookup(lib, "x", okay);
// y.Lookup(lib, "y", okay);
// z.Lookup(lib, "z", okay);
// if (okay) { printf("All functions were loaded successfully!\n"); }
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return (okay)).
bool Lookup(const char *fn, bool &okay, FunctionType fallback = NULL) {
if (!okay)
return false;
else if (this->m_pFn == NULL) {
this->m_pFn = (FunctionType)VoidFnPtrLookup_GlMgr(fn, okay, false,
(void *)fallback);
this->SetFuncName(fn);
}
okay = m_pFn != NULL;
return okay;
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return true).
bool Lookup(const char *fn, FunctionType fallback = NULL) {
bool okay = true;
return Lookup(fn, okay, fallback);
}
// Invalidates the current lookup. Makes the function pointer NULL. You
// will need to call Lookup() before you can call a dynamic function
// through this interface again.
void Reset() { m_pFn = NULL; }
// Force this to be a specific function pointer.
void Force(FunctionType ptr) { m_pFn = ptr; }
// Retrieve the actual function pointer.
FunctionType Pointer() const { return m_pFn; }
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
#if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS
#define GL_FUNC_NAME m_szName
#else
#define GL_FUNC_NAME ""
#endif
inline CGLExecuteHelper<FunctionType, Result> operator()() const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME);
}
template <typename T>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a);
}
template <typename T, typename U>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a,
b);
}
template <typename T, typename U, typename V>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b,
V c) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c);
}
template <typename T, typename U, typename V, typename W>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c,
W d) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d);
}
template <typename T, typename U, typename V, typename W, typename X>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e);
}
template <typename T, typename U, typename V, typename W, typename X,
typename Y>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e, Y f) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e, f);
}
template <typename T, typename U, typename V, typename W, typename X,
typename Y, typename Z>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e, Y f,
Z g) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e, f, g);
}
template <typename T, typename U, typename V, typename W, typename X,
typename Y, typename Z, typename A>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e, Y f, Z g,
A h) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e, f, g, h);
}
template <typename T, typename U, typename V, typename W, typename X,
typename Y, typename Z, typename A, typename B>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e, Y f, Z g, A h,
B i) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e, f, g, h, i);
}
template <typename T, typename U, typename V, typename W, typename X,
typename Y, typename Z, typename A, typename B, typename C>
inline CGLExecuteHelper<FunctionType, Result> operator()(T a, U b, V c, W d,
X e, Y f, Z g, A h,
B i, C j) const {
return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b,
c, d, e, f, g, h, i, j);
}
#else
operator FunctionType() const { return m_pFn; }
#endif
// Can be used to verify that we have an actual function looked up and
// ready to call: if (!MyDynFunc) { printf("Function not found!\n"); }
operator bool() const { return m_pFn != NULL; }
bool operator!() const { return m_pFn == NULL; }
protected:
FunctionType m_pFn;
#if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS
char m_szName[32];
inline void SetFuncName(const char *pFn) {
V_strncpy(m_szName, pFn, sizeof(m_szName));
}
#else
inline void SetFuncName(const char *pFn) { (void)pFn; }
#endif
};
// This works a lot like CDynamicFunctionMustInit, but we use
// SDL_GL_GetProcAddress().
template <const bool bRequired, class FunctionType, typename Result>
class CDynamicFunctionOpenGL
: public CDynamicFunctionOpenGLBase<FunctionType, Result> {
private: // forbid default constructor.
CDynamicFunctionOpenGL() {}
public:
CDynamicFunctionOpenGL(const char *fn, FunctionType fallback = NULL) {
bool okay = true;
Lookup(fn, okay, fallback);
this->SetFuncName(fn);
}
CDynamicFunctionOpenGL(const char *fn, bool &okay,
FunctionType fallback = NULL) {
Lookup(fn, okay, fallback);
this->SetFuncName(fn);
}
// Please note this is not virtual.
// !!! FIXME: we might want to fall back and try "EXT" or "ARB" versions in
// some case.
bool Lookup(const char *fn, bool &okay, FunctionType fallback = NULL) {
if (this->m_pFn == NULL) {
this->m_pFn = (FunctionType)VoidFnPtrLookup_GlMgr(
fn, okay, bRequired, (void *)fallback);
this->SetFuncName(fn);
}
return okay;
}
};
enum GLDriverStrings_t {
cGLVendorString,
cGLRendererString,
cGLVersionString,
cGLExtensionsString,
cGLTotalDriverStrings
};
enum GLDriverProvider_t {
cGLDriverProviderUnknown,
cGLDriverProviderNVIDIA,
cGLDriverProviderAMD,
cGLDriverProviderIntel,
cGLDriverProviderIntelOpenSource,
cGLDriverProviderApple,
cGLTotalDriverProviders
};
// This provides all the entry points for a given OpenGL context.
// ENTRY POINTS ARE ONLY VALID FOR THE CONTEXT THAT WAS CURRENT WHEN
// YOU LOOKED THEM UP. 99% of the time, this is not a problem, but
// that 1% is really hard to track down. Always access the GL
// through this class!
class COpenGLEntryPoints {
COpenGLEntryPoints(const COpenGLEntryPoints &);
COpenGLEntryPoints &operator=(const COpenGLEntryPoints &);
public:
// The GL context you are looking up entry points for must be current when
// you construct this object!
COpenGLEntryPoints();
~COpenGLEntryPoints();
void ClearEntryPoints();
uint64 m_nTotalGLCycles, m_nTotalGLCalls;
int m_nOpenGLVersionMajor; // if GL_VERSION is 2.1.0, this will be set
// to 2.
int m_nOpenGLVersionMinor; // if GL_VERSION is 2.1.0, this will be set
// to 1.
int m_nOpenGLVersionPatch; // if GL_VERSION is 2.1.0, this will be set to
// 0.
bool m_bHave_OpenGL;
char *m_pGLDriverStrings[cGLTotalDriverStrings];
GLDriverProvider_t m_nDriverProvider;
#ifdef OSX
#define GL_EXT(x, glmajor, glminor) bool m_bHave_##x;
#define GL_FUNC(ext, req, ret, fn, arg, call) \
CDynamicFunctionOpenGL<req, ret(*) arg, ret> fn;
#define GL_FUNC_VOID(ext, req, fn, arg, call) \
CDynamicFunctionOpenGL<req, void(*) arg, void> fn;
#else
#define GL_EXT(x, glmajor, glminor) bool m_bHave_##x;
#define GL_FUNC(ext, req, ret, fn, arg, call) \
CDynamicFunctionOpenGL<req, ret(APIENTRY *) arg, ret> fn;
#define GL_FUNC_VOID(ext, req, fn, arg, call) \
CDynamicFunctionOpenGL<req, void(APIENTRY *) arg, void> fn;
#endif
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
bool HasSwapTearExtension() const {
#ifdef _WIN32
return m_bHave_WGL_EXT_swap_control_tear;
#else
return m_bHave_GLX_EXT_swap_control_tear;
#endif
}
};
// This will be set to the current OpenGL context's entry points.
extern COpenGLEntryPoints *gGL;
typedef void *(*GL_GetProcAddressCallbackFunc_t)(const char *, bool &,
const bool, void *);
#ifdef TOGL_DLL_EXPORT
DLL_EXPORT COpenGLEntryPoints *ToGLConnectLibraries(CreateInterfaceFn factory);
DLL_EXPORT void ToGLDisconnectLibraries();
DLL_EXPORT COpenGLEntryPoints *GetOpenGLEntryPoints(
GL_GetProcAddressCallbackFunc_t callback);
DLL_EXPORT void ClearOpenGLEntryPoints();
#else
DLL_IMPORT COpenGLEntryPoints *ToGLConnectLibraries(CreateInterfaceFn factory);
DLL_IMPORT void ToGLDisconnectLibraries();
DLL_IMPORT COpenGLEntryPoints *GetOpenGLEntryPoints(
GL_GetProcAddressCallbackFunc_t callback);
DLL_IMPORT void ClearOpenGLEntryPoints();
#endif
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
inline void CGLExecuteHelperBase::StartCall(const char *pName) {
(void)pName;
#if GL_TELEMETRY_ZONES
tmEnter(TELEMETRY_LEVEL3, TMZF_NONE, pName);
#endif
#if GL_TRACK_API_TIME
m_nStartTime = tmFastTime();
#endif
#if GL_DUMP_ALL_API_CALLS
static bool s_bDumpCalls;
if (s_bDumpCalls) {
char buf[128];
buf[0] = 'G';
buf[1] = 'L';
buf[2] = ':';
size_t l = strlen(pName);
memcpy(buf + 3, pName, l);
buf[3 + l] = '\n';
buf[4 + l] = '\0';
Plat_DebugString(buf);
}
#endif
}
inline void CGLExecuteHelperBase::StopCall(const char *pName) {
#if GL_TRACK_API_TIME
uint64 nTotalCycles = tmFastTime() - m_nStartTime;
#endif
#if GL_TELEMETRY_ZONES
tmLeave(TELEMETRY_LEVEL3);
#endif
#if GL_TRACK_API_TIME
// double flMilliseconds = g_Telemetry.flRDTSCToMilliSeconds * nTotalCycles;
if (gGL) {
gGL->m_nTotalGLCycles += nTotalCycles;
gGL->m_nTotalGLCalls++;
}
#endif
}
#endif
#endif // DX_TO_GL_ABSTRACTION
#endif // GLENTRYPOINTS_H