/* $Id: dri_drv.c $ */

/** @file
 * VBox OpenGL DRI driver functions
 */

/*
 * Copyright (C) 2009-2010 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 * --------------------------------------------------------------------
 *
 * This file is based in part on the tdfx driver from X.Org/Mesa, with the
 * following copyright notice:
 *
 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
 *
 * 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 (including the next
 * paragraph) 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
 * VA LINUX SYSTEMS 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.
 *
 * Original rewrite:
 *      Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
 *
 * Authors:
 *      Gareth Hughes <gareth@valinux.com>
 */

#include "cr_error.h"
#include "cr_gl.h"
#include "stub.h"
#include "dri_drv.h"
#include "DD_gl.h"

/** @todo some of those are or'ed with GL_VERSIONS and ain't needed here*/
#define need_GL_ARB_occlusion_query
#define need_GL_ARB_point_parameters
#define need_GL_NV_point_sprite
#define need_GL_ARB_texture_compression
#define need_GL_ARB_transpose_matrix
#define need_GL_ARB_vertex_buffer_object
#define need_GL_ARB_vertex_program
#define need_GL_ARB_window_pos
#define need_GL_EXT_blend_color
#define need_GL_EXT_blend_minmax
#define need_GL_EXT_blend_func_separate
#define need_GL_EXT_fog_coord
#define need_GL_EXT_multi_draw_arrays
#define need_GL_EXT_secondary_color
#define need_GL_EXT_texture_object
#define need_GL_EXT_texture3D
#define need_GL_VERSION_1_3
#define need_GL_VERSION_1_4
#define need_GL_VERSION_1_5

#include "drivers/dri/common/extension_helper.h"

/** @todo add more which are supported by chromium like GL_NV_vertex_program etc.*/
static const struct dri_extension vbox_extensions[] = {
    { "GL_ARB_depth_texture",              NULL },
    { "GL_ARB_fragment_program",           NULL },
    { "GL_ARB_multitexture",               NULL },
    { "GL_ARB_occlusion_query",            GL_ARB_occlusion_query_functions },
    { "GL_ARB_point_parameters",           GL_ARB_point_parameters_functions },
    { "GL_NV_point_sprite",                GL_NV_point_sprite_functions },
    { "GL_ARB_shadow",                     NULL },
    { "GL_ARB_shadow_ambient",             NULL },
    { "GL_ARB_texture_border_clamp",       NULL },
    { "GL_ARB_texture_compression",        GL_ARB_texture_compression_functions },
    { "GL_ARB_texture_cube_map",           NULL },
    { "GL_ARB_texture_env_add",            NULL },
    { "GL_ARB_texture_env_combine",        NULL },
    { "GL_EXT_texture_env_combine",        NULL },
    { "GL_ARB_texture_env_crossbar",       NULL },
    { "GL_ARB_texture_env_dot3",           NULL },
    { "GL_EXT_texture_env_dot3",           NULL },
    { "GL_ARB_texture_mirrored_repeat",    NULL },
    { "GL_ARB_texture_non_power_of_two",   NULL },
    { "GL_ARB_transpose_matrix",           GL_ARB_transpose_matrix_functions },
    { "GL_ARB_vertex_buffer_object",       GL_ARB_vertex_buffer_object_functions },
    { "GL_ARB_vertex_program",             GL_ARB_vertex_program_functions },
    { "GL_ARB_window_pos",                 GL_ARB_window_pos_functions },
    { "GL_EXT_blend_color",                GL_EXT_blend_color_functions },
    { "GL_EXT_blend_minmax",               GL_EXT_blend_minmax_functions },
    { "GL_EXT_blend_func_separate",        GL_EXT_blend_func_separate_functions },
    { "GL_EXT_blend_subtract",             NULL },
    { "GL_EXT_texture_env_add",            NULL }, /** @todo that's an alias to GL_ARB version, remove it?*/
    { "GL_EXT_fog_coord",                  GL_EXT_fog_coord_functions },
    { "GL_EXT_multi_draw_arrays",          GL_EXT_multi_draw_arrays_functions },
    { "GL_EXT_secondary_color",            GL_EXT_secondary_color_functions },
    { "GL_EXT_shadow_funcs",               NULL },
    { "GL_EXT_stencil_wrap",               NULL },
    { "GL_EXT_texture_cube_map",           NULL }, /** @todo another alias*/
    { "GL_EXT_texture_edge_clamp",         NULL },
    { "GL_EXT_texture_filter_anisotropic", NULL },
    { "GL_EXT_texture_lod_bias",           NULL },
    { "GL_EXT_texture_object",             GL_EXT_texture_object_functions },
    { "GL_EXT_texture3D",                  GL_EXT_texture3D_functions },
    { "GL_NV_texgen_reflection",           NULL },
    { "GL_ARB_texture_rectangle",          NULL },
    { "GL_SGIS_generate_mipmap",           NULL },
    { "GL_SGIS_texture_edge_clamp",        NULL } /** @todo another alias*/
};

static void
vboxdriInitExtensions(GLcontext * ctx)
{
    /** @todo have to check extensions supported by host here first */
    driInitExtensions(ctx, vbox_extensions, GL_FALSE);
}

static GLvertexformat vboxdriTnlVtxFmt;


/* This callback tells us that Mesa's internal state has changed.  We probably
 * don't need to handle this ourselves, so just pass it on to other parts of
 * Mesa we may be using, as the swrast driver and others do */
static void
vboxDDUpdateState(GLcontext * ctx, GLuint new_state)
{
    _swrast_InvalidateState(ctx, new_state);
    _swsetup_InvalidateState(ctx, new_state);
    _vbo_InvalidateState(ctx, new_state);
    _tnl_InvalidateState(ctx, new_state);
}

#if 0  /* See comment in vboxdriInitFuncs */
static void 
vboxDDGetBufferSize(GLframebuffer *buffer, GLuint *width, GLuint *height)
{
    /*do something, note it's obsolete*/
}

static void
vboxDDResizeBuffer( GLcontext *ctx, GLframebuffer *fb,
                          GLuint width, GLuint height)
{
    /*do something, note it's obsolete*/
}

static void
vboxDDError(GLcontext *ctx)
{
    //__GLcontextRec::ErrorValue contains the error value.
}
#endif

static void
vboxDDDrawPixels(GLcontext *ctx,
                 GLint x, GLint y, GLsizei width, GLsizei height,
                 GLenum format, GLenum type,
                 const struct gl_pixelstore_attrib *unpack,
                 const GLvoid *pixels)
{
}

static void
vboxDDReadPixels(GLcontext *ctx,
                 GLint x, GLint y, GLsizei width, GLsizei height,
                 GLenum format, GLenum type,
                 const struct gl_pixelstore_attrib *unpack,
                 GLvoid *dest)
{
}

static void
vboxDDCopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
           GLsizei width, GLsizei height,
           GLint dstx, GLint dsty, GLenum type)
{
}

static void
vboxDDBitmap(GLcontext *ctx,
             GLint x, GLint y, GLsizei width, GLsizei height,
             const struct gl_pixelstore_attrib *unpack,
             const GLubyte *bitmap)
{
}

static void
vboxDDTexImage1D(GLcontext *ctx, GLenum target, GLint level,
                 GLint internalFormat,
                 GLint width, GLint border,
                 GLenum format, GLenum type, const GLvoid *pixels,
                 const struct gl_pixelstore_attrib *packing,
                 struct gl_texture_object *texObj,
                 struct gl_texture_image *texImage)
{
}

static void
vboxDDTexImage2D(GLcontext *ctx, GLenum target, GLint level,
                 GLint internalFormat,
                 GLint width, GLint height, GLint border,
                 GLenum format, GLenum type, const GLvoid *pixels,
                 const struct gl_pixelstore_attrib *packing,
                 struct gl_texture_object *texObj,
                 struct gl_texture_image *texImage)
{
}
   
static void
vboxDDTexImage3D(GLcontext *ctx, GLenum target, GLint level,
                 GLint internalFormat,
                 GLint width, GLint height, GLint depth, GLint border,
                 GLenum format, GLenum type, const GLvoid *pixels,
                 const struct gl_pixelstore_attrib *packing,
                 struct gl_texture_object *texObj,
                 struct gl_texture_image *texImage)
{
}

static void
vboxDDTexSubImage1D(GLcontext *ctx, GLenum target, GLint level,
                    GLint xoffset, GLsizei width,
                    GLenum format, GLenum type,
                    const GLvoid *pixels,
                    const struct gl_pixelstore_attrib *packing,
                    struct gl_texture_object *texObj,
                    struct gl_texture_image *texImage)
{
}
   
static void
vboxDDTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
                    GLint xoffset, GLint yoffset,
                    GLsizei width, GLsizei height,
                    GLenum format, GLenum type,
                    const GLvoid *pixels,
                    const struct gl_pixelstore_attrib *packing,
                    struct gl_texture_object *texObj,
                    struct gl_texture_image *texImage)
{
}

   
static void
vboxDDTexSubImage3D(GLcontext *ctx, GLenum target, GLint level,
                    GLint xoffset, GLint yoffset, GLint zoffset,
                    GLsizei width, GLsizei height, GLint depth,
                    GLenum format, GLenum type,
                    const GLvoid *pixels,
                    const struct gl_pixelstore_attrib *packing,
                    struct gl_texture_object *texObj,
                    struct gl_texture_image *texImage)
{
}


static void
vboxDDGetTexImage(GLcontext *ctx, GLenum target, GLint level,
                  GLenum format, GLenum type, GLvoid *pixels,
                  struct gl_texture_object *texObj,
                  struct gl_texture_image *texImage)
{
}

static void
vboxDDBindTexture(GLcontext *ctx, GLenum target,
            struct gl_texture_object *tObj)
{
}

static GLboolean
vboxDDIsTextureResident(GLcontext *ctx, struct gl_texture_object *t)
{
}

static void
vboxDDPrioritizeTexture(GLcontext *ctx, struct gl_texture_object *t,
                        GLclampf priority)
{
}

static void
vboxDDBlendColor(GLcontext *ctx, const GLfloat color[4])
{
}

static void
vboxDDClearColor(GLcontext *ctx, const GLfloat color[4])
{
}

static void
vboxDDClearIndex(GLcontext *ctx, GLuint index)
{
}

static void
vboxDDClipPlane(GLcontext *ctx, GLenum plane, const GLfloat *equation)
{
}

/*@todo Enable or disable server-side gl capabilities, not related to glEnable? */
static void
vboxDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
{
    if (state) 
        cr_glEnable(cap);
    else 
        cr_glDisable(cap);
}

static void
vboxDDRenderMode(GLcontext *ctx, GLenum mode)
{
    cr_glRenderMode(mode);
}

static void
vboxDDTexParameter(GLcontext *ctx, GLenum target,
                     struct gl_texture_object *texObj,
                     GLenum pname, const GLfloat *params)
{
}

/*Note, checking glGetError before and after those calls is the only way 
 *to return if we succeeded to get value or not, but it will add 2 sync calls and
 *will reset glGetError value returned in case application calls it explicitly
 */
static GLboolean 
vboxDDGetBooleanv(GLcontext *ctx, GLenum pname, GLboolean *result)
{
    cr_glGetBooleanv(pname, result);
    return GL_TRUE;
}

static GLboolean 
vboxDDGetDoublev(GLcontext *ctx, GLenum pname, GLdouble *result)
{
    cr_glGetDoublev(pname, result);
    return GL_TRUE;
}

static GLboolean 
vboxDDGetFloatv(GLcontext *ctx, GLenum pname, GLfloat *result)
{
    cr_glGetFloatv(pname, result);
    return GL_TRUE;
}

static GLboolean 
vboxDDGetIntegerv(GLcontext *ctx, GLenum pname, GLint *result)
{
    cr_glGetIntegerv(pname, result);
    return GL_TRUE;
}

static GLboolean 
vboxDDGetPointerv(GLcontext *ctx, GLenum pname, GLvoid **result)
{
    cr_glGetPointerv(pname, result);
    return GL_TRUE;
}

/** @todo 
 * change stub's createcontext to reuse driver private part of mesa's ctx to store stub ctx info.
 */
#define VBOX_GL_FUNC(func) vboxDD_gl##func
static void
vboxdriInitFuncs(struct dd_function_table *driver)
{
   driver->GetString = VBOX_GL_FUNC(GetString);
   driver->UpdateState = vboxDDUpdateState;
#if 0
   /* I assume that we don't need to change these.  In that case, prefer the
    * default implementation over a stub. */
   driver->GetBufferSize = vboxDDGetBufferSize;
   driver->ResizeBuffers = vboxDDResizeBuffer;
   driver->Error = vboxDDError;
#endif

   driver->Finish = VBOX_GL_FUNC(Finish);
   driver->Flush = VBOX_GL_FUNC(Flush);

   /* framebuffer/image functions */
   driver->Clear = VBOX_GL_FUNC(Clear);
   driver->Accum = VBOX_GL_FUNC(Accum);
   // driver->RasterPos = VBOX_GL_FUNC(RasterPos);  /* No such element in *driver */
   driver->DrawPixels = vboxDDDrawPixels;
   driver->ReadPixels = vboxDDReadPixels;
   driver->CopyPixels = vboxDDCopyPixels;
   driver->Bitmap = vboxDDBitmap;

   /* Texture functions */
    /** @todo deal with texnames and gl_texture_object pointers which are passed here*/
   driver->ChooseTextureFormat = NULL;
   driver->TexImage1D = vboxDDTexImage1D;
   driver->TexImage2D = vboxDDTexImage2D;
   driver->TexImage3D = vboxDDTexImage3D;
   driver->TexSubImage1D = vboxDDTexSubImage1D;
   driver->TexSubImage2D = vboxDDTexSubImage2D;
   driver->TexSubImage3D = vboxDDTexSubImage3D;
   driver->GetTexImage = vboxDDGetTexImage;
   driver->CopyTexImage1D = VBOX_GL_FUNC(CopyTexImage1D);
   driver->CopyTexImage2D = VBOX_GL_FUNC(CopyTexImage2D);
   driver->CopyTexSubImage1D = VBOX_GL_FUNC(CopyTexSubImage1D);
   driver->CopyTexSubImage2D = VBOX_GL_FUNC(CopyTexSubImage2D);
   driver->CopyTexSubImage3D = VBOX_GL_FUNC(CopyTexSubImage3D);
   // driver->GenerateMipmap = VBOX_GL_FUNC(GenerateMipmap); /** @todo or NULL */
   // driver->TestProxyTexImage = vboxDDTestProxyTexImage; /** @todo just pass to glTexImage as we take  care or proxy textures there */
   // driver->CompressedTexImage1D = VBOX_GL_FUNC(CompressedTexImage1D);
   // driver->CompressedTexImage2D = VBOX_GL_FUNC(CompressedTexImage2D);
   // driver->CompressedTexImage3D = VBOX_GL_FUNC(CompressedTexImage3D);
   // driver->CompressedTexSubImage1D = VBOX_GL_FUNC(CompressedTexSubImage1D);
   // driver->CompressedTexSubImage2D = VBOX_GL_FUNC(CompressedTexSubImage2D);
   // driver->CompressedTexSubImage3D = VBOX_GL_FUNC(CompressedTexSubImage3D);
   // driver->GetCompressedTexImage = VBOX_GL_FUNC(GetCompressedTexImage);
   // driver->CompressedTextureSize = NULL; /** @todo */
   driver->BindTexture = vboxDDBindTexture;
   // driver->NewTextureObject = vboxDDNewTextureObject; /** @todo */
   // driver->DeleteTexture = vboxDDDeleteTexture; /** @todo */
   // driver->NewTextureImage = vboxDDNewTextureImage; /** @todo */
   // driver->FreeTexImageData = vboxDDFreeTexImageData; /** @todo */
   // driver->MapTexture = vboxDDMapTexture; /** @todo */
   // driver->UnmapTexture = vboxDDUnmapTexture; /** @todo */
   // driver->TextureMemCpy = vboxDDTextureMemCpy; /** @todo */
   driver->IsTextureResident = vboxDDIsTextureResident;
   driver->PrioritizeTexture = vboxDDPrioritizeTexture;
   driver->ActiveTexture = VBOX_GL_FUNC(ActiveTextureARB);
   // driver->UpdateTexturePalette = vboxDDUpdateTexturePalette; /** @todo */

   /* imaging */
   /*driver->CopyColorTable = _swrast_CopyColorTable;
   driver->CopyColorSubTable = _swrast_CopyColorSubTable;
   driver->CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
   driver->CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;*/

   /* Vertex/fragment programs */
   driver->BindProgram = NULL;
   // driver->NewProgram = _mesa_new_program;  /** @todo */
   // driver->DeleteProgram = _mesa_delete_program;  /** @todo */
   driver->ProgramStringNotify = NULL;
#if FEATURE_MESA_program_debug
   // driver->GetProgramRegister = _mesa_get_program_register;  /** @todo */
#endif /* FEATURE_MESA_program_debug */
   driver->IsProgramNative = NULL;

   /* simple state commands */
   driver->AlphaFunc = VBOX_GL_FUNC(AlphaFunc);
   driver->BlendColor = vboxDDBlendColor;
   // driver->BlendEquationSeparate = VBOX_GL_FUNC(BlendEquationSeparate);  /** @todo */
   driver->BlendFuncSeparate = VBOX_GL_FUNC(BlendFuncSeparateEXT);
   driver->ClearColor = vboxDDClearColor;
   driver->ClearDepth = VBOX_GL_FUNC(ClearDepth);
   driver->ClearIndex = vboxDDClearIndex;
   driver->ClearStencil = VBOX_GL_FUNC(ClearStencil);
   driver->ClipPlane = vboxDDClipPlane;
   driver->ColorMask = VBOX_GL_FUNC(ColorMask);
   driver->ColorMaterial = VBOX_GL_FUNC(ColorMaterial);
   driver->CullFace = VBOX_GL_FUNC(CullFace);
   driver->DrawBuffer = VBOX_GL_FUNC(DrawBuffer);  /** @todo */
   // driver->DrawBuffers = VBOX_GL_FUNC(DrawBuffers);   /** @todo */
   driver->FrontFace = VBOX_GL_FUNC(FrontFace);
   driver->DepthFunc = VBOX_GL_FUNC(DepthFunc);
   driver->DepthMask = VBOX_GL_FUNC(DepthMask);
   driver->DepthRange = VBOX_GL_FUNC(DepthRange);
   driver->Enable = vboxDDEnable;
   driver->Fogfv = VBOX_GL_FUNC(Fogfv);
   driver->Hint = VBOX_GL_FUNC(Hint);
   driver->IndexMask = VBOX_GL_FUNC(IndexMask);
   driver->Lightfv = VBOX_GL_FUNC(Lightfv);
   driver->LightModelfv = VBOX_GL_FUNC(LightModelfv);
   driver->LineStipple = VBOX_GL_FUNC(LineStipple);
   driver->LineWidth = VBOX_GL_FUNC(LineWidth);
   // driver->LogicOpcode = VBOX_GL_FUNC(LogicOpcode);   /** @todo */
   driver->PointParameterfv = VBOX_GL_FUNC(PointParameterfvARB);
   driver->PointSize = VBOX_GL_FUNC(PointSize);
   driver->PolygonMode = VBOX_GL_FUNC(PolygonMode);
   driver->PolygonOffset = VBOX_GL_FUNC(PolygonOffset);
   driver->PolygonStipple = VBOX_GL_FUNC(PolygonStipple);
   driver->ReadBuffer = VBOX_GL_FUNC(ReadBuffer);
   driver->RenderMode = vboxDDRenderMode;
   driver->Scissor = VBOX_GL_FUNC(Scissor);
   driver->ShadeModel = VBOX_GL_FUNC(ShadeModel);
   // driver->StencilFuncSeparate = VBOX_GL_FUNC(StencilFuncSeparate);   /** @todo */
   // driver->StencilOpSeparate = VBOX_GL_FUNC(StencilOpSeparate);   /** @todo */
   // driver->StencilMaskSeparate = VBOX_GL_FUNC(StencilMaskSeparate);   /** @todo */
   driver->TexGen = VBOX_GL_FUNC(TexGenfv);
   driver->TexEnv = VBOX_GL_FUNC(TexEnvfv);
   driver->TexParameter = vboxDDTexParameter;
   // driver->TextureMatrix = VBOX_GL_FUNC(TextureMatrix);   /** @todo */
   driver->Viewport = VBOX_GL_FUNC(Viewport);

   /* vertex arrays */
   driver->VertexPointer = VBOX_GL_FUNC(VertexPointer);
   driver->NormalPointer = VBOX_GL_FUNC(NormalPointer);
   driver->ColorPointer = VBOX_GL_FUNC(ColorPointer);
   driver->FogCoordPointer = VBOX_GL_FUNC(FogCoordPointerEXT);
   driver->IndexPointer = VBOX_GL_FUNC(IndexPointer);
   driver->SecondaryColorPointer = VBOX_GL_FUNC(SecondaryColorPointerEXT);
   driver->TexCoordPointer = VBOX_GL_FUNC(TexCoordPointer);
   driver->EdgeFlagPointer = VBOX_GL_FUNC(EdgeFlagPointer);
   // driver->VertexAttribPointer = VBOX_GL_FUNC(VertexAttribPointer);   /** @todo */
   // driver->LockArraysEXT = VBOX_GL_FUNC(LockArraysEXT);   /** @todo */
   // driver->UnlockArraysEXT = VBOX_GL_FUNC(UnlockArraysEXT);   /** @todo */

   /* state queries */
   driver->GetBooleanv = vboxDDGetBooleanv;
   driver->GetDoublev = vboxDDGetDoublev;
   driver->GetFloatv = vboxDDGetFloatv;
   driver->GetIntegerv = vboxDDGetIntegerv;
   driver->GetPointerv = vboxDDGetPointerv;

/** @todo */   
#if FEATURE_ARB_vertex_buffer_object
   // driver->NewBufferObject = _mesa_new_buffer_object;
   // driver->DeleteBuffer = _mesa_delete_buffer_object;
   // driver->BindBuffer = NULL;
   // driver->BufferData = _mesa_buffer_data;
   // driver->BufferSubData = _mesa_buffer_subdata;
   // driver->GetBufferSubData = _mesa_buffer_get_subdata;
   // driver->MapBuffer = _mesa_buffer_map;
   // driver->UnmapBuffer = _mesa_buffer_unmap;
#endif

/** @todo */
#if FEATURE_EXT_framebuffer_object
   // driver->NewFramebuffer = _mesa_new_framebuffer;
   // driver->NewRenderbuffer = _mesa_new_soft_renderbuffer;
   // driver->RenderTexture = _mesa_render_texture;
   // driver->FinishRenderTexture = _mesa_finish_render_texture;
   // driver->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer;
#endif

/** @todo */
#if FEATURE_EXT_framebuffer_blit
   // driver->BlitFramebuffer = _swrast_BlitFramebuffer;
#endif

   /* query objects */
   // driver->NewQueryObject = VBOX_GL_FUNC(NewQueryObject);   /** @todo */
   // driver->DeleteQuery = VBOX_GL_FUNC(DeleteQuery);   /** @todo */
   // driver->BeginQuery = VBOX_GL_FUNC(BeginQuery);   /** @todo */
   // driver->EndQuery = VBOX_GL_FUNC(EndQuery);   /** @todo */
   // driver->WaitQuery = VBOX_GL_FUNC(WaitQuery);   /** @todo */

   /* APPLE_vertex_array_object */
/*
   driver->NewArrayObject = _mesa_new_array_object;
   driver->DeleteArrayObject = _mesa_delete_array_object;
   driver->BindArrayObject = NULL;
*/

   /* T&L stuff */
   driver->NeedValidate = GL_FALSE;
   driver->ValidateTnlModule = NULL;
   driver->CurrentExecPrimitive = 0;
   driver->CurrentSavePrimitive = 0;
   driver->NeedFlush = 0;
   driver->SaveNeedFlush = 0;

   // driver->ProgramStringNotify = _tnl_program_string;   /** @todo */
   driver->FlushVertices = NULL;
   driver->SaveFlushVertices = NULL;
   driver->NotifySaveBegin = NULL;
   driver->LightingSpaceChange = NULL;

   /* display list */
   driver->NewList = VBOX_GL_FUNC(NewList);
   driver->EndList = VBOX_GL_FUNC(EndList);
   // driver->BeginCallList = VBOX_GL_FUNC(BeginCallList);   /** @todo */
   // driver->EndCallList = VBOX_GL_FUNC(EndCallList);   /** @todo */


   /* shaders */
   /*
   driver->AttachShader = _mesa_attach_shader;
   driver->BindAttribLocation = _mesa_bind_attrib_location;
   driver->CompileShader = _mesa_compile_shader;
   driver->CreateProgram = _mesa_create_program;
   driver->CreateShader = _mesa_create_shader;
   driver->DeleteProgram2 = _mesa_delete_program2;
   driver->DeleteShader = _mesa_delete_shader;
   driver->DetachShader = _mesa_detach_shader;
   driver->GetActiveAttrib = _mesa_get_active_attrib;
   driver->GetActiveUniform = _mesa_get_active_uniform;
   driver->GetAttachedShaders = _mesa_get_attached_shaders;
   driver->GetAttribLocation = _mesa_get_attrib_location;
   driver->GetHandle = _mesa_get_handle;
   driver->GetProgramiv = _mesa_get_programiv;
   driver->GetProgramInfoLog = _mesa_get_program_info_log;
   driver->GetShaderiv = _mesa_get_shaderiv;
   driver->GetShaderInfoLog = _mesa_get_shader_info_log;
   driver->GetShaderSource = _mesa_get_shader_source;
   driver->GetUniformfv = _mesa_get_uniformfv;
   driver->GetUniformiv = _mesa_get_uniformiv;
   driver->GetUniformLocation = _mesa_get_uniform_location;
   driver->IsProgram = _mesa_is_program;
   driver->IsShader = _mesa_is_shader;
   driver->LinkProgram = _mesa_link_program;
   driver->ShaderSource = _mesa_shader_source;
   driver->Uniform = _mesa_uniform;
   driver->UniformMatrix = _mesa_uniform_matrix;
   driver->UseProgram = _mesa_use_program;
   driver->ValidateProgram = _mesa_validate_program;
   */
}

static void
vboxdriInitTnlVtxFmt(GLvertexformat *pVtxFmt)
{
   pVtxFmt->ArrayElement = VBOX_GL_FUNC(ArrayElement);
   pVtxFmt->Begin = VBOX_GL_FUNC(Begin);
   pVtxFmt->CallList = VBOX_GL_FUNC(CallList);
   pVtxFmt->CallLists = VBOX_GL_FUNC(CallLists);
   pVtxFmt->Color3f = VBOX_GL_FUNC(Color3f);
   pVtxFmt->Color3fv = VBOX_GL_FUNC(Color3fv);
   pVtxFmt->Color4f = VBOX_GL_FUNC(Color4f);
   pVtxFmt->Color4fv = VBOX_GL_FUNC(Color4fv);
   pVtxFmt->EdgeFlag = VBOX_GL_FUNC(EdgeFlag);
   pVtxFmt->End = VBOX_GL_FUNC(End);
   pVtxFmt->EvalCoord1f = VBOX_GL_FUNC(EvalCoord1f);
   pVtxFmt->EvalCoord1fv = VBOX_GL_FUNC(EvalCoord1fv);
   pVtxFmt->EvalCoord2f = VBOX_GL_FUNC(EvalCoord2f);
   pVtxFmt->EvalCoord2fv = VBOX_GL_FUNC(EvalCoord2fv);
   pVtxFmt->EvalPoint1 = VBOX_GL_FUNC(EvalPoint1);
   pVtxFmt->EvalPoint2 = VBOX_GL_FUNC(EvalPoint2);
   pVtxFmt->FogCoordfEXT = VBOX_GL_FUNC(FogCoordfEXT);
   pVtxFmt->FogCoordfvEXT = VBOX_GL_FUNC(FogCoordfvEXT);
   pVtxFmt->Indexf = VBOX_GL_FUNC(Indexf);
   pVtxFmt->Indexfv = VBOX_GL_FUNC(Indexfv);
   pVtxFmt->Materialfv = VBOX_GL_FUNC(Materialfv);
   pVtxFmt->MultiTexCoord1fARB = VBOX_GL_FUNC(MultiTexCoord1fARB);
   pVtxFmt->MultiTexCoord1fvARB = VBOX_GL_FUNC(MultiTexCoord1fvARB);
   pVtxFmt->MultiTexCoord2fARB = VBOX_GL_FUNC(MultiTexCoord2fARB);
   pVtxFmt->MultiTexCoord2fvARB = VBOX_GL_FUNC(MultiTexCoord2fvARB);
   pVtxFmt->MultiTexCoord3fARB = VBOX_GL_FUNC(MultiTexCoord3fARB);
   pVtxFmt->MultiTexCoord3fvARB = VBOX_GL_FUNC(MultiTexCoord3fvARB);
   pVtxFmt->MultiTexCoord4fARB = VBOX_GL_FUNC(MultiTexCoord4fARB);
   pVtxFmt->MultiTexCoord4fvARB = VBOX_GL_FUNC(MultiTexCoord4fvARB);
   pVtxFmt->Normal3f = VBOX_GL_FUNC(Normal3f);
   pVtxFmt->Normal3fv = VBOX_GL_FUNC(Normal3fv);
   pVtxFmt->SecondaryColor3fEXT = VBOX_GL_FUNC(SecondaryColor3fEXT);
   pVtxFmt->SecondaryColor3fvEXT = VBOX_GL_FUNC(SecondaryColor3fvEXT);
   pVtxFmt->TexCoord1f = VBOX_GL_FUNC(TexCoord1f);
   pVtxFmt->TexCoord1fv = VBOX_GL_FUNC(TexCoord1fv);
   pVtxFmt->TexCoord2f = VBOX_GL_FUNC(TexCoord2f);
   pVtxFmt->TexCoord2fv = VBOX_GL_FUNC(TexCoord2fv);
   pVtxFmt->TexCoord3f = VBOX_GL_FUNC(TexCoord3f);
   pVtxFmt->TexCoord3fv = VBOX_GL_FUNC(TexCoord3fv);
   pVtxFmt->TexCoord4f = VBOX_GL_FUNC(TexCoord4f);
   pVtxFmt->TexCoord4fv = VBOX_GL_FUNC(TexCoord4fv);
   pVtxFmt->Vertex2f = VBOX_GL_FUNC(Vertex2f);
   pVtxFmt->Vertex2fv = VBOX_GL_FUNC(Vertex2fv);
   pVtxFmt->Vertex3f = VBOX_GL_FUNC(Vertex3f);
   pVtxFmt->Vertex3fv = VBOX_GL_FUNC(Vertex3fv);
   pVtxFmt->Vertex4f = VBOX_GL_FUNC(Vertex4f);
   pVtxFmt->Vertex4fv = VBOX_GL_FUNC(Vertex4fv);
   pVtxFmt->VertexAttrib1fNV = VBOX_GL_FUNC(VertexAttrib1fARB);
   pVtxFmt->VertexAttrib1fvNV = VBOX_GL_FUNC(VertexAttrib1fvARB);
   pVtxFmt->VertexAttrib2fNV = VBOX_GL_FUNC(VertexAttrib2fARB);
   pVtxFmt->VertexAttrib2fvNV = VBOX_GL_FUNC(VertexAttrib2fvARB);
   pVtxFmt->VertexAttrib3fNV = VBOX_GL_FUNC(VertexAttrib3fARB);
   pVtxFmt->VertexAttrib3fvNV = VBOX_GL_FUNC(VertexAttrib3fvARB);
   pVtxFmt->VertexAttrib4fNV = VBOX_GL_FUNC(VertexAttrib4fARB);
   pVtxFmt->VertexAttrib4fvNV = VBOX_GL_FUNC(VertexAttrib4fvARB);
   pVtxFmt->VertexAttrib1fARB = VBOX_GL_FUNC(VertexAttrib1fARB);
   pVtxFmt->VertexAttrib1fvARB = VBOX_GL_FUNC(VertexAttrib1fvARB);
   pVtxFmt->VertexAttrib2fARB = VBOX_GL_FUNC(VertexAttrib2fARB);
   pVtxFmt->VertexAttrib2fvARB = VBOX_GL_FUNC(VertexAttrib2fvARB);
   pVtxFmt->VertexAttrib3fARB = VBOX_GL_FUNC(VertexAttrib3fARB);
   pVtxFmt->VertexAttrib3fvARB = VBOX_GL_FUNC(VertexAttrib3fvARB);
   pVtxFmt->VertexAttrib4fARB = VBOX_GL_FUNC(VertexAttrib4fARB);
   pVtxFmt->VertexAttrib4fvARB = VBOX_GL_FUNC(VertexAttrib4fvARB);

   pVtxFmt->EvalMesh1 = VBOX_GL_FUNC(EvalMesh1);
   pVtxFmt->EvalMesh2 = VBOX_GL_FUNC(EvalMesh2);
   pVtxFmt->Rectf = VBOX_GL_FUNC(Rectf);

   pVtxFmt->DrawArrays = VBOX_GL_FUNC(DrawArrays);
   pVtxFmt->DrawElements = VBOX_GL_FUNC(DrawElements);
   pVtxFmt->DrawRangeElements = VBOX_GL_FUNC(DrawRangeElements);
}
#undef VBOX_GL_FUNC

static void
vboxdriExtSetTexOffset(__DRIcontext *pDRICtx, GLint texname,
                       unsigned long long offset, GLint depth, GLuint pitch)
{
}


static void
vboxdriExtSetTexBuffer(__DRIcontext *pDRICtx, GLint target, __DRIdrawable *dPriv)
{
}

/** @todo not sure we need it from start*/
static const __DRItexOffsetExtension vboxdriTexOffsetExtension = {
    { __DRI_TEX_OFFSET },
    vboxdriExtSetTexOffset,
};

/* This DRI extension is required to support EXT_texture_from_pixmap,
 * which in turn is required by compiz.
 */
static const __DRItexBufferExtension vboxdriTexBufferExtension = {
    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
    vboxdriExtSetTexBuffer,
};

/* List of DRI extensions supported by VBox DRI driver */
static const __DRIextension *vboxdriExtensions[] = {
    &vboxdriTexOffsetExtension.base,
    &vboxdriTexBufferExtension.base,
    NULL
};

static __GLcontextModes *vboxdriFillInModes(unsigned pixel_bits,
                                            unsigned depth_bits,
                                            unsigned stencil_bits,
                                            GLboolean have_back_buffer)
{
        unsigned deep = (depth_bits > 17);

        /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
         * enough to add support.  Basically, if a context is created with an
         * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
         * will never be used.
         */

        static const GLenum db_modes[2] = { GLX_NONE, GLX_SWAP_UNDEFINED_OML };
        uint8_t depth_bits_array[4];
        uint8_t stencil_bits_array[4];
        if(deep) {
                depth_bits_array[0] = 0;
                depth_bits_array[1] = 24;
                stencil_bits_array[0] = 0;
                stencil_bits_array[1] = 8;
        } else {
                depth_bits_array[0] = depth_bits;
                depth_bits_array[1] = 0;
                depth_bits_array[2] = depth_bits;
                depth_bits_array[3] = 0;
                stencil_bits_array[0] = 0;
                stencil_bits_array[1] = 0;
                stencil_bits_array[2] = 8;
                stencil_bits_array[3] = 8;
        }

        return driCreateConfigs(
                deep ? GL_RGBA : GL_RGB,
                deep ? GL_UNSIGNED_INT_8_8_8_8 : GL_UNSIGNED_SHORT_5_6_5,
                depth_bits_array,
                stencil_bits_array,
                deep ? 2 : 4,
                db_modes, 2);
}

/**
 * This is the driver specific part of the createNewScreen entry point.
 * Called when using legacy DRI.
 * 
 * return the __GLcontextModes supported by this driver
 */
static const __DRIconfig **vboxdriInitScreen(__DRIscreenPrivate *psp)
{
    static const __DRIversion ddx_expected = { 1, 1, 0 };
    static const __DRIversion dri_expected = { 4, 0, 0 };
    static const __DRIversion drm_expected = { 1, 0, 0 };
    //PVBoxDRI = (PVBoxDRI) psp->pDevPrivate;

    /* Initialise our call table in chromium. */
    if (!stubInit())
    {
        crDebug("vboxdriInitScreen: stubInit failed");
        return NULL;
    }

    if ( ! driCheckDriDdxDrmVersions2( "tdfx",
                                       &psp->dri_version, & dri_expected,
                                       &psp->ddx_version, & ddx_expected,
                                       &psp->drm_version, & drm_expected ) )
        return NULL;

    /* Calling driInitExtensions here, with a NULL context pointer,
     * does not actually enable the extensions.  It just makes sure
     * that all the dispatch offsets for all the extensions that
     * *might* be enables are known.  This is needed because the
     * dispatch offsets need to be known when _mesa_context_create is
     * called, but we can't enable the extensions until we have a
     * context pointer.
     *
     * Hello chicken.  Hello egg.  How are you two today?
     */
    vboxdriInitExtensions(NULL);

    /** @todo check size of DRIRec (passed from X.Org driver), allocate private
     * structure if necessary, parse options if necessary, map VRAM if
     * necessary. */
    psp->extensions = vboxdriExtensions;

    /* Initialise VtxFmt call table. */
    vboxdriInitTnlVtxFmt(&vboxdriTnlVtxFmt);

    /*return (const __DRIconfig **)
           vboxdriFillInModes(psp, dri_priv->cpp * 8,
                              (dri_priv->cpp == 2) ? 16 : 24,
                              (dri_priv->cpp == 2) ? 0  : 8, 1);*/

    /** @todo This should depend on what the host can do, not the guest.
     *  However, we will probably want to discover that in the X.Org driver,
     *  not here. */
    return (const __DRIconfig **) vboxdriFillInModes(psp, 24, 24, 8, 1);
}

static void
vboxdriDestroyScreen(__DRIscreenPrivate * sPriv)
{
    crDebug("vboxdriDestroyScreen");
#if 0  /* From the tdfx driver */
   /* free all option information */
   driDestroyOptionInfo (&sPriv->private->optionCache);
   FREE(sPriv->private);
   sPriv->private = NULL;
#endif
}

static GLboolean
vboxdriCreateContext(const __GLcontextModes * mesaVis,
                     __DRIcontextPrivate * driContextPriv,
                     void *sharedContextPrivate)
{
    //__DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
    struct dd_function_table functions;
    GLcontext *ctx, *shareCtx;

#if 0  /* We shouldn't need this sort of thing. */
    XVisualInfo *vis;
    vis->visual->visualid;
    context->dpy = dpy;
    context->visual = vis;

    GLXContext vboxctx = glXCreateContext(dpy, mesaVis->visualID, GL_TRUE);
#endif
    /* We should be allocating a private context structure, where we will
     * remember the Mesa context (ctx) among other things.  The TDFX driver
     * also saves importand information in driContextPriv in there - is this
     * not always available to us? */
    //driContextPriv->driverPrivate = vboxctx;

    /* Initialise the default driver functions then plug in our vbox ones,
     * which will actually replace most of the defaults. */
    /** @todo we should also pass some information from the visual back to the
     * host. */
    _mesa_init_driver_functions(&functions);
    vboxdriInitFuncs(&functions);

    /* Allocate context information for Mesa. */
    if (sharedContextPrivate)
      shareCtx = ((tdfxContextPtr) sharedContextPrivate)->glCtx;
   else 
      shareCtx = NULL;
    /** @todo save ctx, or be more confident that we can don't need to. */
    ctx = _mesa_create_context(mesaVis, shareCtx, &functions,
                               driContextPriv->driverPrivate);
    if (!ctx)
    {
        crDebug("vboxdriCreateContext: _mesa_create_context failed");
        return GL_FALSE;
    }

    /* The TDFX driver parses its configuration files here, via
     * driParseConfigFiles.  We will probably get any information via guest
     * properties. */

   /* Set various context configuration.  We take these values from the 
    * TDFX driver. */
   /** @r=Leonid, stub.spu->dispatch_table.GetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&value) etc.
    * Those would be cached where possible, see include/state/cr_limits.h, VBoxOGLgen/packspu_get.c
    * Note, that ctx->Const.MaxTextureImageUnits is *not* related to GL_MAX_TEXTURE_UNITS_ARB,
    * use GL_MAX_TEXTURE_IMAGE_UNITS_ARB instead.
    * Also, those could fail if we haven't made ctx in our stub yet.
    */
   ctx->Const.MaxTextureLevels = 9;
   ctx->Const.MaxTextureUnits = 1;
   ctx->Const.MaxTextureImageUnits = ctx->Const.MaxTextureUnits;
   ctx->Const.MaxTextureCoordUnits = ctx->Const.MaxTextureUnits;

   /* No wide points.
    */
   ctx->Const.MinPointSize = 1.0;
   ctx->Const.MinPointSizeAA = 1.0;
   ctx->Const.MaxPointSize = 1.0;
   ctx->Const.MaxPointSizeAA = 1.0;

   /* Disable wide lines as we can't antialias them correctly in
    * hardware.
    */
   /** @note That applies to the TDFX, not to us, but as I don't yet know
    * what to use instead I am leaving the values for now. */
   ctx->Const.MinLineWidth = 1.0;
   ctx->Const.MinLineWidthAA = 1.0;
   ctx->Const.MaxLineWidth = 1.0;
   ctx->Const.MaxLineWidthAA = 1.0;
   ctx->Const.LineWidthGranularity = 1.0;

   /* Initialize the software rasterizer and helper modules - again, TDFX */
   _swrast_CreateContext( ctx );
   _vbo_CreateContext( ctx );
   _tnl_CreateContext( ctx );
   _swsetup_CreateContext( ctx );

   /* Install the customized pipeline, TDFX */
   _tnl_destroy_pipeline( ctx );
   _tnl_install_pipeline( ctx, tdfx_pipeline );

   /* Configure swrast and T&L to match hardware characteristics, TDFX */
   _swrast_allow_pixel_fog( ctx, GL_TRUE );
   _swrast_allow_vertex_fog( ctx, GL_FALSE );
   _tnl_allow_pixel_fog( ctx, GL_TRUE );
   _tnl_allow_vertex_fog( ctx, GL_FALSE );
    /*ctx->DriverCtx = ;*/

    /* This was *not* in the TDFX driver. */
    _mesa_install_exec_vtxfmt(ctx, &vboxdriTnlVtxFmt);

    vboxdriInitExtensions(ctx);

    return GL_TRUE;
}


static void
vboxdriDestroyContext(__DRIcontextPrivate *driContextPriv)
{
    // glXDestroyContext(driContextPriv->driverPrivate);
    //_mesa_destroy_context ?
}

/**
 * This is called when we need to set up GL rendering to a new X window.
 */
static GLboolean
vboxdriCreateBuffer(__DRIscreenPrivate * driScrnPriv,
                    __DRIdrawablePrivate * driDrawPriv,
                    const __GLcontextModes * mesaVis, GLboolean isPixmap)
{
    return GL_FALSE;
}

static void
vboxdriDestroyBuffer(__DRIdrawablePrivate * driDrawPriv)
{
}

static void
vboxdriSwapBuffers(__DRIdrawablePrivate * dPriv)
{
}


GLboolean
vboxdriMakeCurrent(__DRIcontextPrivate * driContextPriv,
                   __DRIdrawablePrivate * driDrawPriv,
                   __DRIdrawablePrivate * driReadPriv)
{
    return GL_FALSE;
}

GLboolean
vboxdriUnbindContext(__DRIcontextPrivate * driContextPriv)
{
    return GL_TRUE;
}


/* This structure is used by dri_util from mesa, don't rename it! */
DECLEXPORT(const struct __DriverAPIRec) driDriverAPI = {
    .InitScreen       = vboxdriInitScreen,
    .DestroyScreen    = vboxdriDestroyScreen,
    .CreateContext    = vboxdriCreateContext,
    .DestroyContext   = vboxdriDestroyContext,
    .CreateBuffer     = vboxdriCreateBuffer,
    .DestroyBuffer    = vboxdriDestroyBuffer,
    .SwapBuffers      = vboxdriSwapBuffers,
    .MakeCurrent      = vboxdriMakeCurrent,
    .UnbindContext    = vboxdriUnbindContext,
    .GetSwapInfo      = NULL,
    .WaitForMSC       = NULL,
    .WaitForSBC       = NULL,
    .SwapBuffersMSC   = NULL,
    .CopySubBuffer    = NULL,
    .GetDrawableMSC   = NULL,
    .InitScreen2      = NULL
};
