text: /* -*- mode: c; c-basic-offset: 3 -*- */
  /*
   * Copyright 2000 Gareth Hughes
   * 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
   * GARETH HUGHES 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.
   */
  
  /*
   * Authors:
   *	Gareth Hughes <gareth@valinux.com>
   *	Leif Delgass <ldelgass@retinalburn.net>
   *	Jos�Fonseca <j_r_fonseca@yahoo.co.uk>
   */
  
  #include "main/glheader.h"
  #include "main/context.h"
  #include "main/simple_list.h"
  #include "main/imports.h"
  
  #include "swrast/swrast.h"
  #include "swrast_setup/swrast_setup.h"
  #include "vbo/vbo.h"
  
  #include "tnl/tnl.h"
  #include "tnl/t_pipeline.h"
  
  #include "drivers/common/driverfuncs.h"
  
  #include "mach64_context.h"
  #include "mach64_ioctl.h"
  #include "mach64_dd.h"
  #include "mach64_span.h"
  #include "mach64_state.h"
  #include "mach64_tex.h"
  #include "mach64_tris.h"
  #include "mach64_vb.h"
  
  #include "utils.h"
  #include "vblank.h"
  
  #ifndef MACH64_DEBUG
  int MACH64_DEBUG = (0);
  #endif
  
  static const struct dri_debug_control debug_control[] =
  {
      { "sync",   DEBUG_ALWAYS_SYNC },
      { "api",    DEBUG_VERBOSE_API },
      { "msg",    DEBUG_VERBOSE_MSG },
      { "lru",    DEBUG_VERBOSE_LRU },
      { "dri",    DEBUG_VERBOSE_DRI },
      { "ioctl",  DEBUG_VERBOSE_IOCTL },
      { "prims",  DEBUG_VERBOSE_PRIMS },
      { "count",  DEBUG_VERBOSE_COUNT },
      { "nowait", DEBUG_NOWAIT },
      { "fall",   DEBUG_VERBOSE_FALLBACK },
      { NULL,    0 }
  };
  
  static const struct dri_extension card_extensions[] =
  {
      { "GL_ARB_multitexture",               NULL },
      { "GL_EXT_texture_edge_clamp",         NULL },
      { "GL_MESA_ycbcr_texture",             NULL },
      { NULL,                                NULL }
  };
  
  
  /* Create the device specific context.
    */
  GLboolean mach64CreateContext( gl_api api,
  			       const struct gl_config *glVisual,
  			       __DRIcontext *driContextPriv,
                                 void *sharedContextPrivate )
  {
     struct gl_context *ctx, *shareCtx;
     __DRIscreen *driScreen = driContextPriv->driScreenPriv;
     struct dd_function_table functions;
     mach64ContextPtr mmesa;
     mach64ScreenPtr mach64Screen;
     int i, heap;
     GLuint *c_textureSwapsPtr = NULL;
  
  #if DO_DEBUG
     MACH64_DEBUG = driParseDebugString(getenv("MACH64_DEBUG"), debug_control);
  #endif
  
     /* Allocate the mach64 context */
     mmesa = (mach64ContextPtr) CALLOC( sizeof(*mmesa) );
     if ( !mmesa ) 
        return GL_FALSE;
  
     /* Init default driver functions then plug in our Mach64-specific functions
      * (the texture functions are especially important)
      */
     _mesa_init_driver_functions( &functions );
     mach64InitDriverFuncs( &functions );
     mach64InitIoctlFuncs( &functions );
     mach64InitTextureFuncs( &functions );
  
     /* Allocate the Mesa context */
     if (sharedContextPrivate)
        shareCtx = ((mach64ContextPtr) sharedContextPrivate)->glCtx;
     else 
        shareCtx = NULL;
     mmesa->glCtx = _mesa_create_context(API_OPENGL, glVisual, shareCtx, 
  					&functions, (void *)mmesa);
     if (!mmesa->glCtx) {
        FREE(mmesa);
        return GL_FALSE;
     }
     driContextPriv->driverPrivate = mmesa;
     ctx = mmesa->glCtx;
  
     mmesa->driContext = driContextPriv;
     mmesa->driScreen = driScreen;
     mmesa->driDrawable = NULL;
     mmesa->hHWContext = driContextPriv->hHWContext;
     mmesa->driHwLock = &driScreen->pSAREA->lock;
     mmesa->driFd = driScreen->fd;
  
     mach64Screen = mmesa->mach64Screen = (mach64ScreenPtr)driScreen->private;
  
     /* Parse configuration files */
     driParseConfigFiles (&mmesa->optionCache, &mach64Screen->optionCache,
                          mach64Screen->driScreen->myNum, "mach64");
  
     mmesa->sarea = (drm_mach64_sarea_t *)((char *)driScreen->pSAREA +
  				    sizeof(drm_sarea_t));
  
     mmesa->CurrentTexObj[0] = NULL;
     mmesa->CurrentTexObj[1] = NULL;
  
     (void) memset( mmesa->texture_heaps, 0, sizeof( mmesa->texture_heaps ) );
     make_empty_list( &mmesa->swapped );
  
     mmesa->firstTexHeap = mach64Screen->firstTexHeap;
     mmesa->lastTexHeap = mach64Screen->firstTexHeap + mach64Screen->numTexHeaps;
  
     for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) {
        mmesa->texture_heaps[i] = driCreateTextureHeap( i, mmesa,
  	    mach64Screen->texSize[i],
  	    6, /* align to 64-byte boundary, use 12 for page-size boundary */
  	    MACH64_NR_TEX_REGIONS,
  	    (drmTextureRegionPtr)mmesa->sarea->tex_list[i],
  	    &mmesa->sarea->tex_age[i],
  	    &mmesa->swapped,
  	    sizeof( mach64TexObj ),
  	    (destroy_texture_object_t *) mach64DestroyTexObj );
  
  #if ENABLE_PERF_BOXES
        c_textureSwapsPtr = & mmesa->c_textureSwaps;
  #endif
        driSetTextureSwapCounterLocation( mmesa->texture_heaps[i],
  					c_textureSwapsPtr );
     }
  
     mmesa->RenderIndex = -1;		/* Impossible value */
     mmesa->vert_buf = NULL;
     mmesa->num_verts = 0;
     mmesa->new_state = MACH64_NEW_ALL;
     mmesa->dirty = MACH64_UPLOAD_ALL;
  
     /* Set the maximum texture size small enough that we can
      * guarentee that both texture units can bind a maximal texture
      * and have them both in memory (on-card or AGP) at once.
      * Test for 2 textures * bytes/texel * size * size.  There's no
      * need to account for mipmaps since we only upload one level.
      */
  
     ctx->Const.MaxTextureUnits = 2;
     ctx->Const.MaxTextureImageUnits = 2;
     ctx->Const.MaxTextureCoordUnits = 2;
     ctx->Const.MaxDrawBuffers = 1;
  
     heap = mach64Screen->IsPCI ? MACH64_CARD_HEAP : MACH64_AGP_HEAP;
  
     driCalculateMaxTextureLevels( & mmesa->texture_heaps[heap],
  				 1,
  				 & ctx->Const,
  				 mach64Screen->cpp,
  				 10, /* max 2D texture size is 1024x1024 */
  				 0,  /* 3D textures unsupported. */
  				 0,  /* cube textures unsupported. */
  				 0,  /* texture rectangles unsupported. */
  				 1,  /* mipmapping unsupported. */
  				 GL_TRUE, /* need to have both textures in
  					     either local or AGP memory */
  				 0 );
  
  #if ENABLE_PERF_BOXES
     mmesa->boxes = ( getenv( "LIBGL_PERFORMANCE_BOXES" ) != NULL );
  #endif
  
     /* Allocate the vertex buffer
      */
     mmesa->vert_buf = _mesa_align_malloc(MACH64_BUFFER_SIZE, 32);
     if ( !mmesa->vert_buf )
        return GL_FALSE;
     mmesa->vert_used = 0;
     mmesa->vert_total = MACH64_BUFFER_SIZE;
     
     /* Initialize the software rasterizer and helper modules.
      */
     _swrast_CreateContext( ctx );
     _vbo_CreateContext( ctx );
     _tnl_CreateContext( ctx );
     _swsetup_CreateContext( ctx );
  
     /* Install the customized pipeline:
      */
  /*     _tnl_destroy_pipeline( ctx ); */
  /*     _tnl_install_pipeline( ctx, mach64_pipeline ); */
  
     /* Configure swrast and T&L to match hardware characteristics:
      */
     _swrast_allow_pixel_fog( ctx, GL_FALSE );
     _swrast_allow_vertex_fog( ctx, GL_TRUE );
     _tnl_allow_pixel_fog( ctx, GL_FALSE );
     _tnl_allow_vertex_fog( ctx, GL_TRUE );
  
     driInitExtensions( ctx, card_extensions, GL_TRUE );
  
     mach64InitVB( ctx );
     mach64InitTriFuncs( ctx );
     mach64DDInitStateFuncs( ctx );
     mach64DDInitSpanFuncs( ctx );
     mach64DDInitState( mmesa );
  
     mmesa->do_irqs = (mmesa->mach64Screen->irq && !getenv("MACH64_NO_IRQS"));
  
     driContextPriv->driverPrivate = (void *)mmesa;
  
     if (driQueryOptionb(&mmesa->optionCache, "no_rast")) {
        fprintf(stderr, "disabling 3D acceleration\n");
        FALLBACK(mmesa, MACH64_FALLBACK_DISABLE, 1);
     }
  
     return GL_TRUE;
  }
  
  /* Destroy the device specific context.
   */
  void mach64DestroyContext( __DRIcontext *driContextPriv  )
  {
     mach64ContextPtr mmesa = (mach64ContextPtr) driContextPriv->driverPrivate;
  
     assert(mmesa);  /* should never be null */
     if ( mmesa ) {
        GLboolean   release_texture_heaps;
  
        release_texture_heaps = (mmesa->glCtx->Shared->RefCount == 1);
  
        _swsetup_DestroyContext( mmesa->glCtx );
        _tnl_DestroyContext( mmesa->glCtx );
        _vbo_DestroyContext( mmesa->glCtx );
        _swrast_DestroyContext( mmesa->glCtx );
  
        if (release_texture_heaps) {
           /* This share group is about to go away, free our private
            * texture object data.
            */
           int i;
  
           for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) {
  	    driDestroyTextureHeap( mmesa->texture_heaps[i] );
  	    mmesa->texture_heaps[i] = NULL;
           }
  
  	 assert( is_empty_list( & mmesa->swapped ) );
        }
  
        mach64FreeVB( mmesa->glCtx );
  
        /* Free the vertex buffer */
        if ( mmesa->vert_buf )
  	 _mesa_align_free( mmesa->vert_buf );
        
        /* free the Mesa context */
        mmesa->glCtx->DriverCtx = NULL;
        _mesa_destroy_context(mmesa->glCtx);
  
        FREE( mmesa );
     }
  }
  
  /* Force the context `c' to be the current context and associate with it
   * buffer `b'.
   */
  GLboolean
  mach64MakeCurrent( __DRIcontext *driContextPriv,
                   __DRIdrawable *driDrawPriv,
                   __DRIdrawable *driReadPriv )
  {
     if ( driContextPriv ) {
        GET_CURRENT_CONTEXT(ctx);
        mach64ContextPtr oldMach64Ctx = ctx ? MACH64_CONTEXT(ctx) : NULL;
        mach64ContextPtr newMach64Ctx = (mach64ContextPtr) driContextPriv->driverPrivate;
  
        if ( newMach64Ctx != oldMach64Ctx ) {
  	 newMach64Ctx->new_state |= MACH64_NEW_CONTEXT;
  	 newMach64Ctx->dirty = MACH64_UPLOAD_ALL;
        }
  
        
        if ( newMach64Ctx->driDrawable != driDrawPriv ) {
  	 if (driDrawPriv->swap_interval == (unsigned)-1) {
  	    driDrawPriv->vblFlags = (newMach64Ctx->do_irqs)
  	       ? driGetDefaultVBlankFlags(&newMach64Ctx->optionCache)
  	       : VBLANK_FLAG_NO_IRQ;
  
  	    driDrawableInitVBlank( driDrawPriv );
  	 }
  
  	 newMach64Ctx->driDrawable = driDrawPriv;
  	 mach64CalcViewport( newMach64Ctx->glCtx );
        }
  
        _mesa_make_current( newMach64Ctx->glCtx,
                            (struct gl_framebuffer *) driDrawPriv->driverPrivate,
                            (struct gl_framebuffer *) driReadPriv->driverPrivate );
  
  
        newMach64Ctx->new_state |=  MACH64_NEW_CLIP;
     } else {
        _mesa_make_current( NULL, NULL, NULL );
     }
  
     return GL_TRUE;
  }
  
  
  /* Force the context `c' to be unbound from its buffer.
   */
  GLboolean
  mach64UnbindContext( __DRIcontext *driContextPriv )
  {
     return GL_TRUE;
  }
  