Torque3D/Engine/source/gfx/gl/ggl/x11/glx.cpp
2012-09-19 11:15:01 -04:00

413 lines
12 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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.
//-----------------------------------------------------------------------------
#include "os/osDlibrary.h"
#include "os/osLog.h"
#include "util/utilArray.h"
#include "glx.h"
namespace GL
{
using namespace Torque;
using namespace GL;
extern bool gglBindCoreFunctions(DLibrary* dll,GLXExtensionPtrs*);
void gglBindGLX(::Display* display,int screen,GLXExtensionFlags* glx);
bool gglBindExtensions(GLExtensionFlags* gl);
struct GGLContext;
//-----------------------------------------------------------------------------
// The OpenGL DLL is shared by all the devices.
static DLibraryRef _hGL;
// Unlike WGL, GLX does not require a set of function pointers per
// context pixel format. All functions in the DLL are bound in a single
// table and shared by all contexts.
static GLXExtensionPtrs _LibraryFunctions;
//-----------------------------------------------------------------------------
struct GGLDisplay: public _GLDisplay
{
::Display* display;
int screen;
GLXExtensionFlags glx; // GLX extension flags
Array<GGLContext*> contextList;
};
#define _hasGLXExtension(display,name) (display->glx.has_##name)
GLDisplay gglCreateDisplay(::Display* display,int screen)
{
// Load and bind DLL functions
if (!_hGL) {
static LogCategory log("/Gfx/Device/GL");
_hGL = LoadLibrary("libGL.so");
if (!_hGL) {
log.print("GLDevice: OpenGL dll failed to load");
return false;
}
if (!gglBindCoreFunctions(_hGL.ptr(),&_LibraryFunctions)) {
log.print("GLDevice: Failed to bind all core functions");
return false;
}
_GGLptr = &_LibraryFunctions;
log.print("OpenGL library loaded");
}
//
GGLDisplay* dp = new GGLDisplay;
dp->display = display;
dp->screen = screen;
gglBindGLX(display,screen,&dp->glx);
return dp;
}
void gglDeleteDisplay(GLDisplay dp)
{
GGLDisplay* display = (GGLDisplay*)dp;
Assert(!display->contextList.size(),"gglDeleteDisplay: Not all context destroyed");
delete display;
}
//-----------------------------------------------------------------------------
struct GGLFormat: public _GLFormat {
GLFormatInfo mode;
U32 pformat;
};
static bool _getFBConfig(GGLDisplay* display,U32 pformat,GLXFBConfig& config)
{
// Get config info from format ID
int attributes[] = { GLX_FBCONFIG_ID, pformat, None };
int count = 0;
GLXFBConfig* configList = glXChooseFBConfig(display->display,
display->screen,attributes,&count);
if (!count)
return false;
config = *configList;
XFree(configList);
return true;
}
GLFormat gglSelectFormat(GLDisplay dp,GLFormatInfo& mode)
{
GGLDisplay* display = (GGLDisplay*)dp;
U32 pformat;
if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
// Find GL compatible X visual using 1.2 interface.
// 1.2 or earlier does not include pbuffer support.
if (mode.target != GLFormatInfo::Window)
return 0;
int attributes[] = {
GLX_RGBA,
GLX_RED_SIZE, mode.red,
GLX_BLUE_SIZE, mode.blue,
GLX_GREEN_SIZE, mode.green,
GLX_DEPTH_SIZE, mode.z,
GLX_ALPHA_SIZE, mode.alpha,
GLX_STENCIL_SIZE, mode.stencil,
GLX_DOUBLEBUFFER, true,
GLX_DOUBLEBUFFER,
None
};
XVisualInfo* visual = glXChooseVisual(display->display, display->screen, attributes);
if (!visual) {
static LogCategory log("/Gfx/Device/GL");
log.print("GGLContext: Could not get an accelerated visual");
return 0;
}
pformat = visual->visualid;
XFree(visual);
}
else {
// Find GL compatible X visual using 1.3 interface.
int attributes[] = {
GLX_DRAWABLE_TYPE, (mode.target == GLFormatInfo::Buffer)?
GLX_PBUFFER_BIT: GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, mode.red,
GLX_BLUE_SIZE, mode.blue,
GLX_GREEN_SIZE, mode.green,
GLX_DEPTH_SIZE, mode.z,
GLX_ALPHA_SIZE, mode.alpha,
GLX_STENCIL_SIZE, mode.stencil,
GLX_DOUBLEBUFFER, true,
None
};
int count = 0;
GLXFBConfig* configList = glXChooseFBConfig(display->display,
display->screen,attributes,&count);
if (!count)
return 0;
// Return the config ID
int xid;
glXGetFBConfigAttrib(display->display,configList[0],GLX_FBCONFIG_ID,&xid);
XFree(configList);
pformat = xid;
}
if (pformat) {
GGLFormat* format = new GGLFormat;
format->pformat = pformat;
format->mode = mode;
return format;
}
return 0;
}
bool gglFormatInfo(GLDisplay display,GLFormat pformat,GLFormatInfo& mode)
{
return 0;
}
bool gglAreCompatible(GLFormat,GLFormat)
{
return false;
}
void gglDeleteFormat(GLFormat fp)
{
GGLFormat* format = (GGLFormat*)fp;
delete format;
}
XVisualInfo* gglGetFormatVisual(GLDisplay dp,GLFormat fp)
{
GGLDisplay* display = (GGLDisplay*)dp;
GGLFormat* format = (GGLFormat*)fp;
if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
// Format is a visual id
int count;
XVisualInfo match;
match.visualid = format->pformat;
return XGetVisualInfo(display->display,VisualIDMask,&match,&count);
}
else {
// Format is an FBConfig id
GLXFBConfig config;
if (!_getFBConfig(display,format->pformat,config))
return 0;
return glXGetVisualFromFBConfig(display->display,config);
}
}
//-----------------------------------------------------------------------------
struct GGLSurface: public _GLSurface {
enum Type {
Window, PBuffer,
} type;
GGLDisplay* display;
GLXDrawable drawable; // Used with GLX 1.3 interface
::Window window; // Used with GLX 1.2 interface
};
GLSurface gglCreateSurface(GLDisplay dp,::Window hwin,GLFormat fp)
{
GGLDisplay* display = (GGLDisplay*)dp;
GGLFormat* format = (GGLFormat*)fp;
GGLSurface* surface = 0;
if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
// Return our own GGL surface rep.
surface = new GGLSurface;
surface->type = GGLSurface::Window;
surface->display = display;
surface->drawable = 0;
surface->window = hwin;
}
else {
// Get config info from format ID
GLXFBConfig config;
if (!_getFBConfig(display,format->pformat,config))
return 0;
// Create GLX window
GLXWindow window = glXCreateWindow(display->display,config,hwin,0);
if (!window) {
GLenum error = glGetError();
static LogCategory log("/Gfx/Device/GL");
log.print(format("Create window error: %d",error));
return 0;
}
// Return our own GGL surface rep.
surface = new GGLSurface;
surface->type = GGLSurface::Window;
surface->display = display;
surface->drawable = window;
surface->window = 0;
}
return surface;
}
bool gglGetSurfaceSize(GLSurface sp,Vector2I& size)
{
GGLSurface* surface = (GGLSurface*)sp;
if (surface->type != GGLSurface::Window)
return false;
if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3)) {
size.x = 300; size.y = 300;
}
else {
glXQueryDrawable(surface->display->display,surface->drawable,
GLX_WIDTH,(U32*)&size.x);
glXQueryDrawable(surface->display->display,surface->drawable,
GLX_HEIGHT,(U32*)&size.y);
}
return true;
}
void gglDeleteSurface(GLSurface sp)
{
GGLSurface* surface = (GGLSurface*)sp;
if (surface->type = GGLSurface::Window) {
glXDestroyWindow(surface->display->display,surface->drawable);
delete surface;
}
}
//-----------------------------------------------------------------------------
struct GGLContext: public _GLContext
{
GGLDisplay* display;
GLXContext context;
GLExtensionFlags glf; // GL has extension flags
};
GLContext gglCreateContext(GLDisplay dp,GLFormat fp)
{
GGLDisplay* display = (GGLDisplay*)dp;
GGLFormat* format = (GGLFormat*)fp;
GGLContext* context = 0;
GLXContext ctx,share = display->contextList.size()?
display->contextList[0]->context: 0;
if (!_hasGLXExtension(display,GLX_VERSION_1_3)) {
// Get visual from format id.
int count;
XVisualInfo match;
match.visualid = format->pformat;
XVisualInfo* visual = XGetVisualInfo(display->display,VisualIDMask,&match,&count);
ctx = glXCreateContext(display->display,visual,share,true);
XFree(visual);
}
else {
// Get FBConfig from format id
GLXFBConfig config;
if (!_getFBConfig(display,format->pformat,config))
return 0;
// Need to share contexts...
ctx = glXCreateNewContext(display->display,config,
GLX_RGBA_TYPE,share,true);
}
if (ctx) {
context = new GGLContext;
context->context = ctx;
context->display = display;
display->contextList.pushBack(context);
return context;
}
return 0;
}
void gglDeleteContext(GLContext ctx)
{
GGLContext* context = (GGLContext*)ctx;
glXDestroyContext(context->display->display,context->context);
erase(context->display->contextList,context);
delete context;
}
bool gglMakeCurrent(GLSurface sp,GLContext ctx)
{
GGLSurface* surface = (GGLSurface*)sp;
GGLContext* context = (GGLContext*)ctx;
if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3)) {
if (!glXMakeCurrent(surface->display->display,
surface->window,context->context))
return false;
}
else
if (!glXMakeContextCurrent(surface->display->display,
surface->drawable,surface->drawable,context->context))
return false;
// The first time a context is made current we need to
// check which extensions are valid.
if (!context->glf.bound)
gglBindExtensions(&context->glf);
_GGLflag = &context->glf;
return true;
}
void gglSwapBuffers(GLSurface sp)
{
GGLSurface* surface = (GGLSurface*)sp;
if (!_hasGLXExtension(surface->display,GLX_VERSION_1_3))
glXSwapBuffers(surface->display->display,surface->window);
else
glXSwapBuffers(surface->display->display,surface->drawable);
}
//-----------------------------------------------------------------------------
GLSurface gglCreatePBufferSurface(GLDisplay display,U32 width,U32 height,bool cubeMap,GLFormat pformat)
{
return 0;
}
bool gglBindPBufferSurface(GLSurface sp,U32 target)
{
return 0;
}
bool gglReleasePBufferSurface(GLSurface sp,U32 target)
{
return 0;
}
bool gglSetPbufferTarget(GLSurface sp,U32 mip,U32 face)
{
return 0;
}
} // Namespace