Made gamma ramp functions per-monitor.

This commit is contained in:
Camilla Berglund 2013-02-12 13:50:41 +01:00
parent 20ccf0bc60
commit 92a71e07d3
12 changed files with 139 additions and 126 deletions

View File

@ -883,27 +883,28 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count);
*/ */
GLFWAPI GLFWvidmode glfwGetVideoMode(GLFWmonitor* monitor); GLFWAPI GLFWvidmode glfwGetVideoMode(GLFWmonitor* monitor);
/*! @brief Sets the system gamma ramp for all connected monitors to one /*! @brief Generates a gamma ramp and sets it for the specified monitor.
* generated from the specified exponent. * @param[in] monitor The monitor whose gamma ramp to set.
* @param[in] gamma The desired exponent. * @param[in] gamma The desired exponent.
* @ingroup gamma * @ingroup gamma
* *
* @remarks This is a helper function layered on top of @ref glfwSetGammaRamp. * @remarks This is a helper function on top of @ref glfwSetGammaRamp.
*/ */
GLFWAPI void glfwSetGamma(float gamma); GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
/*! @brief Retrieves the current system gamma ramp. /*! @brief Retrieves the current gamma ramp for the specified monitor.
* @param[in] monitor The monitor to query.
* @param[out] ramp Where to store the gamma ramp. * @param[out] ramp Where to store the gamma ramp.
* @ingroup gamma * @ingroup gamma
*/ */
GLFWAPI void glfwGetGammaRamp(GLFWgammaramp* ramp); GLFWAPI void glfwGetGammaRamp(GLFWmonitor* monitor, GLFWgammaramp* ramp);
/*! @brief Sets the system gamma ramp for all connected monitors to the one /*! @brief Sets the gamma ramp for the specified monitor.
* specified. * @param[in] monitor The monitor whose gamma ramp to set.
* @param[in] ramp The gamma ramp to use. * @param[in] ramp The gamma ramp to use.
* @ingroup gamma * @ingroup gamma
*/ */
GLFWAPI void glfwSetGammaRamp(const GLFWgammaramp* ramp); GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
/*! @brief Resets all window hints to their default values /*! @brief Resets all window hints to their default values
* *

View File

@ -39,19 +39,27 @@
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp) void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
// TODO: Support ramp sizes other than 256
uint32_t sampleCount; uint32_t sampleCount;
int i; int i;
CGGammaValue red[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue red[GLFW_GAMMA_RAMP_SIZE];
CGGammaValue green[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue green[GLFW_GAMMA_RAMP_SIZE];
CGGammaValue blue[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue blue[GLFW_GAMMA_RAMP_SIZE];
// For now, don't support anything that is not GLFW_GAMMA_RAMP_SIZE if (CGDisplayGammaTableCapacity(monitor->ns.displayID) !=
if (_glfw.originalRampSize != GLFW_GAMMA_RAMP_SIZE) GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Only gamma ramps of size 256 supported");
return; return;
}
CGGetDisplayTransferByTable(CGMainDisplayID(), GLFW_GAMMA_RAMP_SIZE, red, green, blue, CGGetDisplayTransferByTable(monitor->ns.displayID,
GLFW_GAMMA_RAMP_SIZE,
red, green, blue,
&sampleCount); &sampleCount);
for (i = 0; i < GLFW_GAMMA_RAMP_SIZE; i++) for (i = 0; i < GLFW_GAMMA_RAMP_SIZE; i++)
@ -62,17 +70,23 @@ void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp)
} }
} }
void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{ {
// TODO: Support ramp sizes other than 256
int i; int i;
int size = GLFW_GAMMA_RAMP_SIZE; int size = GLFW_GAMMA_RAMP_SIZE;
CGGammaValue red[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue red[GLFW_GAMMA_RAMP_SIZE];
CGGammaValue green[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue green[GLFW_GAMMA_RAMP_SIZE];
CGGammaValue blue[GLFW_GAMMA_RAMP_SIZE]; CGGammaValue blue[GLFW_GAMMA_RAMP_SIZE];
// For now, don't support anything that is not GLFW_GAMMA_RAMP_SIZE if (CGDisplayGammaTableCapacity(monitor->ns.displayID) !=
if (_glfw.originalRampSize != GLFW_GAMMA_RAMP_SIZE) GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Only gamma ramps of size 256 supported");
return; return;
}
// Convert to float & take the difference of the original gamma and // Convert to float & take the difference of the original gamma and
// the linear function. // the linear function.
@ -83,6 +97,8 @@ void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp)
blue[i] = ramp->blue[i] / 65535.f; blue[i] = ramp->blue[i] / 65535.f;
} }
CGSetDisplayTransferByTable(CGMainDisplayID(), GLFW_GAMMA_RAMP_SIZE, red, green, blue); CGSetDisplayTransferByTable(monitor->ns.displayID,
GLFW_GAMMA_RAMP_SIZE,
red, green, blue);
} }

View File

@ -93,10 +93,6 @@ int _glfwPlatformInit(void)
changeToResourcesDirectory(); changeToResourcesDirectory();
#endif #endif
// Save the original gamma ramp
_glfw.originalRampSize = CGDisplayGammaTableCapacity(CGMainDisplayID());
_glfwPlatformGetGammaRamp(&_glfw.originalRamp);
_glfwInitTimer(); _glfwInitTimer();
_glfwInitJoysticks(); _glfwInitJoysticks();
@ -123,10 +119,6 @@ void _glfwPlatformTerminate(void)
_glfw.ns.eventSource = NULL; _glfw.ns.eventSource = NULL;
} }
// Restore the original gamma ramp
if (_glfw.rampChanged)
_glfwPlatformSetGammaRamp(&_glfw.originalRamp);
[NSApp setDelegate:nil]; [NSApp setDelegate:nil];
[_glfw.ns.delegate release]; [_glfw.ns.delegate release];
_glfw.ns.delegate = nil; _glfw.ns.delegate = nil;

View File

@ -37,7 +37,7 @@
////// GLFW public API ////// ////// GLFW public API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
GLFWAPI void glfwSetGamma(float gamma) GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
{ {
int i, size = GLFW_GAMMA_RAMP_SIZE; int i, size = GLFW_GAMMA_RAMP_SIZE;
GLFWgammaramp ramp; GLFWgammaramp ramp;
@ -75,29 +75,38 @@ GLFWAPI void glfwSetGamma(float gamma)
ramp.blue[i] = (unsigned short) value; ramp.blue[i] = (unsigned short) value;
} }
glfwSetGammaRamp(&ramp); glfwSetGammaRamp(handle, &ramp);
} }
GLFWAPI void glfwGetGammaRamp(GLFWgammaramp* ramp) GLFWAPI void glfwGetGammaRamp(GLFWmonitor* handle, GLFWgammaramp* ramp)
{ {
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
if (!_glfwInitialized) if (!_glfwInitialized)
{ {
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); _glfwInputError(GLFW_NOT_INITIALIZED, NULL);
return; return;
} }
_glfwPlatformGetGammaRamp(ramp); _glfwPlatformGetGammaRamp(monitor, ramp);
} }
GLFWAPI void glfwSetGammaRamp(const GLFWgammaramp* ramp) GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
{ {
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
if (!_glfwInitialized) if (!_glfwInitialized)
{ {
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); _glfwInputError(GLFW_NOT_INITIALIZED, NULL);
return; return;
} }
_glfwPlatformSetGammaRamp(ramp); if (!monitor->rampChanged)
_glfw.rampChanged = GL_TRUE; {
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
monitor->rampChanged = GL_TRUE;
}
_glfwPlatformSetGammaRamp(monitor, ramp);
} }

View File

@ -150,6 +150,8 @@ GLFWAPI int glfwInit(void)
GLFWAPI void glfwTerminate(void) GLFWAPI void glfwTerminate(void)
{ {
int i;
if (!_glfwInitialized) if (!_glfwInitialized)
return; return;
@ -157,6 +159,13 @@ GLFWAPI void glfwTerminate(void)
while (_glfw.windowListHead) while (_glfw.windowListHead)
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
for (i = 0; i < _glfw.monitorCount; i++)
{
_GLFWmonitor* monitor = _glfw.monitors[i];
if (monitor->rampChanged)
_glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
}
_glfwDestroyMonitors(); _glfwDestroyMonitors();
_glfwPlatformTerminate(); _glfwPlatformTerminate();

View File

@ -267,6 +267,9 @@ struct _GLFWmonitor
GLFWvidmode* modes; GLFWvidmode* modes;
int modeCount; int modeCount;
GLFWgammaramp originalRamp;
GLboolean rampChanged;
// This is defined in the window API's platform.h // This is defined in the window API's platform.h
_GLFW_PLATFORM_MONITOR_STATE; _GLFW_PLATFORM_MONITOR_STATE;
}; };
@ -285,10 +288,6 @@ struct _GLFWlibrary
int monitorCount; int monitorCount;
GLFWmonitorfun monitorCallback; GLFWmonitorfun monitorCallback;
GLFWgammaramp originalRamp;
int originalRampSize;
GLboolean rampChanged;
// This is defined in the window API's platform.h // This is defined in the window API's platform.h
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE; _GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
// This is defined in the context API's platform.h // This is defined in the context API's platform.h
@ -376,17 +375,19 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
*/ */
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
/*! @brief Returns the current system gamma ramp. /*! @brief Retrieves the current gamma ramp for the specified monitor.
* @param[in] monitor The monitor to query.
* @param[out] ramp The current system gamma ramp. * @param[out] ramp The current system gamma ramp.
* @ingroup platform * @ingroup platform
*/ */
void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
/*! @brief Sets the system gamma ramp. /*! @brief Sets the gamma ramp for the specified monitor.
* @param[in] monitor The monitor whose gamma ramp to set.
* @param[in] ramp The desired system gamma ramp. * @param[in] ramp The desired system gamma ramp.
* @ingroup platform * @ingroup platform
*/ */
void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
/*! @brief Sets the system clipboard to the specified string. /*! @brief Sets the system clipboard to the specified string.
* @param[in] window The window who will own the system clipboard contents, on * @param[in] window The window who will own the system clipboard contents, on

View File

@ -36,13 +36,31 @@
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp) void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
GetDeviceGammaRamp(GetDC(GetDesktopWindow()), (WORD*) ramp); HDC dc;
DISPLAY_DEVICE display;
ZeroMemory(&display, sizeof(DISPLAY_DEVICE));
display.cb = sizeof(DISPLAY_DEVICE);
EnumDisplayDevices(monitor->win32.name, 0, &display, 0);
dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL);
GetDeviceGammaRamp(dc, (WORD*) ramp);
DeleteDC(dc);
} }
void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{ {
SetDeviceGammaRamp(GetDC(GetDesktopWindow()), (WORD*) ramp); HDC dc;
DISPLAY_DEVICE display;
ZeroMemory(&display, sizeof(DISPLAY_DEVICE));
display.cb = sizeof(DISPLAY_DEVICE);
EnumDisplayDevices(monitor->win32.name, 0, &display, 0);
dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL);
SetDeviceGammaRamp(dc, (WORD*) ramp);
DeleteDC(dc);
} }

View File

@ -168,10 +168,6 @@ int _glfwPlatformInit(void)
_control87(MCW_EM, MCW_EM); _control87(MCW_EM, MCW_EM);
#endif #endif
// Save the original gamma ramp
_glfw.originalRampSize = 256;
_glfwPlatformGetGammaRamp(&_glfw.originalRamp);
if (!_glfwInitContextAPI()) if (!_glfwInitContextAPI())
return GL_FALSE; return GL_FALSE;
@ -184,10 +180,6 @@ int _glfwPlatformInit(void)
void _glfwPlatformTerminate(void) void _glfwPlatformTerminate(void)
{ {
// Restore the original gamma ramp
if (_glfw.rampChanged)
_glfwPlatformSetGammaRamp(&_glfw.originalRamp);
if (_glfw.win32.classAtom) if (_glfw.win32.classAtom)
{ {
UnregisterClass(_GLFW_WNDCLASSNAME, GetModuleHandle(NULL)); UnregisterClass(_GLFW_WNDCLASSNAME, GetModuleHandle(NULL));

View File

@ -37,7 +37,7 @@
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Detect gamma ramp support and save original gamma ramp, if available // Detect gamma ramp support
// //
void _glfwInitGammaRamp(void) void _glfwInitGammaRamp(void)
{ {
@ -54,9 +54,7 @@ void _glfwInitGammaRamp(void)
XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display,
_glfw.x11.root); _glfw.x11.root);
_glfw.originalRampSize = XRRGetCrtcGammaSize(_glfw.x11.display, if (XRRGetCrtcGammaSize(_glfw.x11.display, rr->crtcs[0]))
rr->crtcs[0]);
if (_glfw.originalRampSize == 0)
{ {
// This is probably older Nvidia RandR with broken gamma support // This is probably older Nvidia RandR with broken gamma support
// Flag it as useless and try Xf86VidMode below, if available // Flag it as useless and try Xf86VidMode below, if available
@ -65,28 +63,6 @@ void _glfwInitGammaRamp(void)
XRRFreeScreenResources(rr); XRRFreeScreenResources(rr);
} }
if (_glfw.x11.vidmode.available && !_glfw.originalRampSize)
{
// Get the gamma size using XF86VidMode
XF86VidModeGetGammaRampSize(_glfw.x11.display,
_glfw.x11.screen,
&_glfw.originalRampSize);
}
if (_glfw.originalRampSize)
{
// Save the original gamma ramp
_glfwPlatformGetGammaRamp(&_glfw.originalRamp);
}
}
// Restore original gamma ramp if necessary
//
void _glfwTerminateGammaRamp(void)
{
if (_glfw.originalRampSize && _glfw.rampChanged)
_glfwPlatformSetGammaRamp(&_glfw.originalRamp);
} }
@ -94,83 +70,85 @@ void _glfwTerminateGammaRamp(void)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwPlatformGetGammaRamp(GLFWgammaramp* ramp) void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{ {
// For now, don't support anything that is not GLFW_GAMMA_RAMP_SIZE // TODO: Support ramp sizes other than 256
if (_glfw.originalRampSize != GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to get gamma ramp due to size "
"incompatibility");
return;
}
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{ {
XRRCrtcGamma* gamma;
size_t size = GLFW_GAMMA_RAMP_SIZE * sizeof(unsigned short); size_t size = GLFW_GAMMA_RAMP_SIZE * sizeof(unsigned short);
XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) !=
_glfw.x11.root); GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Only gamma ramps of size 256 supported");
return;
}
XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, gamma = XRRGetCrtcGamma(_glfw.x11.display, monitor->x11.crtc);
rr->crtcs[0]);
// TODO: Handle case of original ramp size having a size other than 256
memcpy(ramp->red, gamma->red, size); memcpy(ramp->red, gamma->red, size);
memcpy(ramp->green, gamma->green, size); memcpy(ramp->green, gamma->green, size);
memcpy(ramp->blue, gamma->blue, size); memcpy(ramp->blue, gamma->blue, size);
XRRFreeGamma(gamma); XRRFreeGamma(gamma);
XRRFreeScreenResources(rr);
} }
else if (_glfw.x11.vidmode.available) else if (_glfw.x11.vidmode.available)
{ {
int size;
XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
if (size != GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Only gamma ramps of size 256 supported");
return;
}
XF86VidModeGetGammaRamp(_glfw.x11.display, XF86VidModeGetGammaRamp(_glfw.x11.display,
_glfw.x11.screen, _glfw.x11.screen,
GLFW_GAMMA_RAMP_SIZE, GLFW_GAMMA_RAMP_SIZE,
ramp->red, ramp->red, ramp->green, ramp->blue);
ramp->green,
ramp->blue);
} }
} }
void _glfwPlatformSetGammaRamp(const GLFWgammaramp* ramp) void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{ {
// For now, don't support anything that is not GLFW_GAMMA_RAMP_SIZE
if (_glfw.originalRampSize != GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to set gamma ramp due to size "
"incompatibility");
return;
}
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{ {
int i;
size_t size = GLFW_GAMMA_RAMP_SIZE * sizeof(unsigned short); size_t size = GLFW_GAMMA_RAMP_SIZE * sizeof(unsigned short);
XRRCrtcGamma* gamma;
XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) !=
_glfw.x11.root); GLFW_GAMMA_RAMP_SIZE)
// Update gamma per monitor
for (i = 0; i < rr->ncrtc; i++)
{ {
XRRCrtcGamma* gamma = XRRAllocGamma(GLFW_GAMMA_RAMP_SIZE); _glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Only gamma ramps of size 256 supported");
memcpy(gamma->red, ramp->red, size); return;
memcpy(gamma->green, ramp->green, size);
memcpy(gamma->blue, ramp->blue, size);
XRRSetCrtcGamma(_glfw.x11.display, rr->crtcs[i], gamma);
XRRFreeGamma(gamma);
} }
XRRFreeScreenResources(rr); gamma = XRRAllocGamma(GLFW_GAMMA_RAMP_SIZE);
memcpy(gamma->red, ramp->red, size);
memcpy(gamma->green, ramp->green, size);
memcpy(gamma->blue, ramp->blue, size);
XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
} }
else if (_glfw.x11.vidmode.available) else if (_glfw.x11.vidmode.available)
{ {
int size;
XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
if (size != GLFW_GAMMA_RAMP_SIZE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Only gamma ramps of size 256 supported");
return;
}
XF86VidModeSetGammaRamp(_glfw.x11.display, XF86VidModeSetGammaRamp(_glfw.x11.display,
_glfw.x11.screen, _glfw.x11.screen,
GLFW_GAMMA_RAMP_SIZE, GLFW_GAMMA_RAMP_SIZE,

View File

@ -603,8 +603,6 @@ void _glfwPlatformTerminate(void)
_glfw.x11.cursor = (Cursor) 0; _glfw.x11.cursor = (Cursor) 0;
} }
_glfwTerminateGammaRamp();
_glfwTerminateJoysticks(); _glfwTerminateJoysticks();
_glfwTerminateContextAPI(); _glfwTerminateContextAPI();

View File

@ -210,7 +210,6 @@ void _glfwInitTimer(void);
// Gamma // Gamma
void _glfwInitGammaRamp(void); void _glfwInitGammaRamp(void);
void _glfwTerminateGammaRamp(void);
// OpenGL support // OpenGL support
int _glfwInitContextAPI(void); int _glfwInitContextAPI(void);

View File

@ -49,7 +49,7 @@ static void set_gamma(float value)
{ {
gamma_value = value; gamma_value = value;
printf("Gamma: %f\n", gamma_value); printf("Gamma: %f\n", gamma_value);
glfwSetGamma(gamma_value); glfwSetGamma(glfwGetPrimaryMonitor(), gamma_value);
} }
static void error_callback(int error, const char* description) static void error_callback(int error, const char* description)