XGL Device Pipeline Porting Guide
  Sök endast i den här boken
Ladda ner denna bok i PDF

Pipeline Framework

3

This chapter presents information on the classes and objects that connect XGL device-independent code with the device pipeline. The following topics are covered:
  • Creating the required device pipeline classes
  • Providing renderers optimized for performance-critical primitives
  • Description of required and optional device-dependent functions
  • Pipeline naming conventions and versioning
  • Using the XGL core for backing store support
Note that in XGL the term device refers to both the physical hardware device and the XGL API Device object. The API Device object is an abstraction of the graphics display device. Internally, it consists of two objects: a device-independent object and a device-dependent object. For more information on the internal components of the API Device object, see the XGL Architecture Guide.

Imported image(30x36)

As you read this chapter, you will find it helpful to have access to the header files for the device pipeline classes. These files are:
  • PipeLib.h and DpLib.h
  • DpMgr.h
  • DpDev.h, DpDevRaster.h, DpDevWinRas.h, and DpDevMemRas.h
  • DpCtx2d.h and DpCtx3d.h

Overview of the Pipeline Framework

The XGL architecture has a device-independent component (XGL core) and a device-dependent component. The device-dependent component consists of interfaces to the pipeline code. Because the device-independent component of XGL must interact smoothly with the device pipeline, XGL provides a set of classes that, when subclassed by the device pipeline, creates a framework that allows XGL to pass information to and from the device pipeline. Setting up the basic pipeline framework is one of the primary tasks in writing a device pipeline.
A pipeline implementation needs to derive classes from four different class hierarchies. This means that for your pipeline, you must subclass at least one pipeline class from each of the pipeline class hierarchies. Objects instantiated from the pipeline subclasses provide the functionality that the XGL device-independent code requires. The four pipeline class hierarchies are:
  • Device pipeline library (DpLib)
  • Device pipeline manager (DpMgr)
  • Device pipeline device (DpDev)
  • Pipeline-context (DpCtx2d and DpCtx3d)
At a minimum, your implementation must define five derived classes (one each from the device pipeline library, the device pipeline manager, and the device pipeline device hierarchies, and two from the device pipeline-context hierarchy) that form the basic framework of a device pipeline. Figure 3-1 on page 31 shows the XGL-supplied class header files, header files subclassed by the pipeline implementation, and the objects that are instantiated.
Each of the device pipeline derived classes contains functions that you must implement. In some cases, the functions simply create the next level of the hierarchy; in other cases, there are API-level functions or attributes that you must support. Several classes also include optional functions for operations that depend on the hardware.

Grafik

Figure 3-1

In addition to providing the required classes and functionality, you must include in your library a function called xgl_create_PipeLib(), which creates an object that represents the pipeline library. You must also name your pipeline appropriately so that XGL can load the pipeline object.
To summarize, this is what you must do to set up the framework for your pipeline:
  1. Define the xgl_create_PipeLib() routine.

  2. Define an XglDpLib class for your pipeline and implement the required functions.

  3. Define an XglDpMgr class for your pipeline and implement the required functions.

  4. Define an XglDpDev class for your pipeline and implement the required functions. Implement any of the optional functions that you need for your hardware.

  5. Define two XglDpCtx classes for your pipeline, one for 3D and another for 2D. These classes contain an array of function pointers to primitives.

  6. Name your pipeline according to the conventions noted on page 51.

These steps are discussed in the following sections. For information on how the XGL core instantiates the pipeline objects and loads the pipeline during device creation, and for illustrations showing how these classes are associated at runtime, see the XGL Architecture Guide.
Note that this chapter contains a number of source code examples. You can copy or modify these examples as long as the resulting code is used to create a loadable pipeline for XGL.

Setting Up the Pipeline Framework

Defining xgl_create_PipeLib()

As a first step in writing a device pipeline, you must write a routine that creates an instance of the XGL device pipeline object corresponding to your device pipeline. This routine is named xgl_create_PipeLib(), and it must be included with each pipeline. The routine is called by the XGL core through dlsym() (an interface routine in the Solaris dynamic linking mechanism) after the device pipeline is loaded. This function is declared as follows:
extern "C" XglPipeLib* xgl_create_PipeLib()

Below is a basic implementation of this function, where XglDpLibSampDp represents the name of the XglPipeLib subclass that the device pipeline creates.

  XglPipeLib* xgl_create_PipeLib()  
  {  
     return new XglDpLibSampDp;  
  }  

Note that the extern "C" declaration is needed to disable the C++ name mangling on the function name.

Defining the Device Pipeline Library Class

Next, you must subclass from the device pipeline library class hierarchy to create your device pipeline library (XglDpLib) class. An object from this class does the following:
  • Represents a loaded device pipeline and maps to the .so shared object for that pipeline. For each pipeline that is loaded into the XGL environment, there is an XglDpLib object created by the pipeline function xgl_create_PipeLib().
  • Provides for the creation, management, and destruction of device pipeline manager objects and allows more than one device pipeline manager object to share hardware or software resources.
  • Provides a location for you to place for data relevant to your pipeline library as a whole.
The base class of the device pipeline library hierarchy is XglPipeLib. This class derives to the more specific device pipeline library and software pipeline library classes XglDpLib and XglSwpLib. Your individual device pipeline implementation will derive from XglDpLib. See the files PipeLib.h and DpLib.h for the definition of these classes. A minimal definition of a pipeline library class is shown here. You can copy or modify the source code samples in this chapter as long as the resulting code is used to create a loadable pipeline for XGL.

  #include "xgl/xgl.h"  
  #include "xgli/DpLib.h"  
  #include "DpMgrSampDp.h"  
  
  class XglDrawable;  
  
  extern "C" XglPipeLib* xgl_create_PipeLib();  
  
  class XglDpLibSampDp : public XglDpLib {  
      friend XglPipeLib* xgl_create_PipeLib();  
  private:  
      XglDpLibSampDp()  { dpMgr = NULL; }  
      ~XglDpLibSampDp();  
    //  
    // Device-pipelines Dependent Functions -  
    // Redefine in Device Pipelines  


       virtual XglDpMgr* getDpMgr(Xgl_obj_type,  
                                      XglDrawable* drawable=NULL);  
  
       XglDpMgrSampDp* dpMgr;// I only have one dpMgr  
  };  

Note that if there are two frame buffers on a system and both are of the same type, such as GX, there is one XglDpLib object. If the two frame buffers are different types, such as one GX and one IHV-provided frame buffer, there are two XglDpLib objects, one for each device pipeline. The Global State object in the XGL core keeps a list of XglDpLib objects so that it can destroy them when XGL is closed. See the XGL Architecture Guide for information on the Global State object.

Note - If the device pipeline needs to establish exclusive control of any device-dependent behavior for client applications, this control is handled by the device pipeline objects, as the XGL core does not handle device-specific control of applications. If the control is needed for all clients of the same type of frame buffer (regardless of the number of frame buffers), then the XglDpLib object should maintain the control. If the control is required for each frame buffer (if there is more than one), then the XglDpMgr object should handle the control.

XglDpLib Functions That You Must Override

The XglDpLib class contains one virtual function that you must override for your pipeline implementation:
getDpMgr(Xgl_obj_type, XglDrawable* drawable)

This function is called by the XGL core's device creation routine when it creates a new XglDpMgr object. The drawable parameter enables the device pipeline to distinguish between different physical frame buffers of the same type. Note that this pointer is transient and should not be cached. The Xgl_obj_type parameter is currently ignored; in future releases, it may be used to allow a pipeline to create more than one type of Device object.
For implementations that handle multiple frame buffers, the XglDpLib object may keep a list of previously created XglDpMgr objects. In this case, the getDpMgr() function should check the list for an existing XglDpMgr object associated with the Device type and Drawable object and retrieve the XglDpMgr object if it exists.
Since the number of device pipeline manager objects your pipeline needs depends on the capabilities of your hardware, the creation, managment, and destruction of XglDpMgr objects is left to your individual device pipeline implementation. Depending on the functions performed by an XglDpMgr object, one XglDpMgr can be created for each frame buffer, or one XglDpMgr can be created for all frame buffers of the same type. Typically, the device pipeline provides one XglDpMgr object for each frame buffer, but the pipeline can manage XglDpMgr objects in other ways as well. Note that the destruction of the XglDpMgr objects should be handled in the XglDpLib destructor function, which the XGL core invokes during xgl_close().
Systems with multiple frame buffers can have frame buffers of either the same type or different types. If the frame buffers are of the same type, the XglDpMgr objects are created by the unique XglDpLib object for that pipeline. If the frame buffers are different types, each XglDpMgr object is created by the XglDpLib object corresponding to the device pipeline for that frame buffer.
For device pipelines that only need one XglDpMgr, such as a memory raster pipeline, the getDpMgr() function will return the same XglDpMgr object every time it is needed. A sample implementation of getDpMgr() is shown below.

  XglDpMgr* XglDpLibSampDp::getDpMgr(Xgl_obj_type,  
                         XglDrawable* drawable)  
  {  
       XglDpMgr*   dpMgr;  
  
       dpMgr = dpMgrList.getDpMgr(drawable->getDevFd());  
       if (dpMgr == NULL) {  
       dpMgr = new XglDpMgrSampDp(drawable->getDevFd());  
       dpMgrList.addDpMgr(dpMgr);  
       }  
       return dpMgr;  
  }  


Note - Although you can initialize your hardware in any of the framework classes, a good place to initialize the hardware is in your XglDpMgr constructor, since this is where the frame buffer is first notified that XGL is going to use it.

Defining the Device Pipeline Manager Class

The next step in setting up the pipeline framework is to define the device pipeline manager (XglDpMgr) class. An object from this class does the following:
  • Provides for the creation of the device pipeline device objects. This class allows multiple device pipeline device objects to share the physical resources of a device.
  • Maintains information about the physical hardware device. If there are multiple frame buffers of the same type on a system, there are either multiple XglDpMgr objects, or the XglDpLib object handles the multiplicity in some other way. If the frame buffers are of different types, for example, one GX and one Cg3 (color frame buffer), there are two XglDpMgr objects: one XglDpMgrGx object and one XglDpMgrCfb object.
See the file DpMgr.h for the definition of this class. A minimal definition of a device pipeline manager class is shown here as XglDpMgrSampDp.

  class XglDevice;  
  class XglDpDev;  
  class XglDrawable;  
  
  class XglDpMgrSampDp : public XglDbgObject {  
  public:  
    virtual ~XglDpMgr();  
  private:  
    //  
    // Device-pipelines Functions - Redefine in Device Pipelines  
    //  
    virtual XglDpDev* createDpDev(XglDevice*,  
                                 Xgl_obj_desc* bkstore_desc = NULL);  
    virtual void  inquire(XglDrawable*, Xgl_inquire*);  
  };  

To limit the number of XglDpMgr objects, you can deny the creation of new XglDpMgr objects by returning NULL from XglDpLibYourFb::getDpMgr(). You can also limit the creation of a new XglDpDev object by returning NULL from XglDpMgrYourFb::createDpDev(). Recoverable errors from the XGL core result in those situations.

XglDpMgr Functions That You Must Override

XglDpMgr includes the following virtual functions that you must override:
XglDpDev* createDpDev(XglDevice*, Xgl_obj_desc*)

Invokes the creation of the device-dependent part of the XGL Device object. The XglDevice argument is cast to a pointer to the type of Device being created, such as XglRasterWin or XglRasterMem. The Xgl_obj_desc argument is a pointer to a structure containing additional information about the XGL Device object. The XGL core uses the information in this structure, and the device pipeline normally does not need it. However, when backing store is enabled, this argument provides information about the parent device that the backing-store device can use or ignore.
A sample implementation of the createDpDev() function to create a window raster device is shown below. Note that:
  • XglDpMgrSampDp represents the name of the device type, for example XglDpMgrGx.
  • XglDpDevSampDp represents the name of the XglDpDev subclass that this device pipeline creates, for example XglDpDevGx.

  XglDpDev* XglDpMgrSampDp::createDpDev (XglDevice* device,  
                                               Xgl_obj_desc*)  
  {  
   return new XglDpDevSampDp(this,(XglRasterWin*)device);  
  }  

void inquire(XglDrawable*, Xgl_inquire*)

An API-level function that returns information on the acceleration features of your device.
For an implementation of the inquire() function, see the sample LI-1 port provided as part of this product. Note that inquire() might be called before the XglDpDev object is created. The inquire() function should use its XglDrawable* parameter to fill the contents of the Xgl_inquire structure whose address is passed. Note also that the XglDrawable pointer passed into the inquire() function is transient and is destroyed afterward. For more information on the inquire() function, see the xgl_inquire() reference page in the XGL Reference Manual.

Defining the Device Pipeline Device Class

Next, you must subclass from the device pipeline device hierarchy. An object from this hierarchy contains the device-dependent elements of an XGL Device object and is linked to the device-independent part of the Device object. An object instantiated from the XglDpDev class does the following:
  • Creates the device pipeline-context objects
  • Provides a device pipeline with the opportunity to exchange device information with XGL core via get() and set() functions
  • Provides a storage location for data relevant to the window
In the case of a single XGL application with multiple windows, each XglDpDev object maps to a single window on the screen. If the application has multiple windows using the same underlying frame buffer, the XglDpMgr object for that frame buffer creates all the XglDpDev objects that the application needs. If the application runs on a system with more than one physical frame buffer, and the application creates multiple windows on each frame buffer, each XglDpDev object is created by the XglDpMgr object that corresponds to the frame buffer.
Although the XglDpMgr object creates multiple XglDpDev objects, it is not designed to keep track of these objects. Instead, for each XGL API-level Device object that is created, a pointer to the XglDpDev object is returned to the device-independent XglRasterWin object, and a pointer to the XglRasterWin object is stored in the XglSysState object list of existing Device objects. For more information on how pipeline objects are instantiated, see the XGL Architecture Guide.
The base class of the device-dependent device hierarchy is XglDpDev, which derives to XglDpDevRaster and then to XglDpDevWinRas, XglDpDevMemRas, or XglDpDevStream. Depending on the type of the device you are porting, your device pipeline will subclass from either XglDpDevWinRas (for window rasters), XglDpDevMemRas (for memory rasters), or XglDpDevStream (for stream devices). See the header files DpDev.h, DpDevRaster.h, DpDevWinRas.h, DpDevMemRas.h., and DpDevStream.h for the device-dependent hierarchy. Sample code for a minimal definition of a device pipeline device class for a window raster is shown below.

  class XglDpDevSampDp : public XglDpDevWinRas {  
           friend XglDpMgrSampDp;  
  private:  
     XglDpDevSampDp(XglDevice* device) : XglDpDevWinRas(device) {}  
        //  
        // Device-pipelines Dependent Functions -  
        // Redefine in Device Pipelines  
        //  
     virtual XglDpCtx3d* createDpCtx(XglContext3d*);  
     virtual XglDpCtx2d* createDpCtx(XglContext2d*);  
  
     virtual int copyBuffer(  
        XglContext3d*,    //3D Context associated with dst mem_ras  
        Xgl_bounds_i2d*,  //Rectangle  
        Xgl_pt_i2d*);     //Position  
  
     virtual int copyBuffer(  
        XglContext2d*,    //2D Context associated with dst mem_ras  
        Xgl_bounds_i2d*,  //Rectangle  
        Xgl_pt_i2d*);     //Position  
  };  


Note - When XglDpDevWinRas is created, a device pipeline should call XglRasterWin:setDgaCmapPutFunc() to register the callback function that updates the hardware color map. See page 135 for information on setDgaCmapPutFunc().

XglDpDev Functions That You Must Override

A minimal implementation of the XglDpDev class includes several functions that you must override:
virtual XglDpCtx{2/3}d*
createDpCtx(XglContext{2/3}d*)

A virtual function to create the XglDpCtx objects. Two of these functions must be created, one for 2D and one for 3D. These functions must be implemented in the pipeline, or an error is returned.
virtual int
copyBuffer(XglContext{2/3}d*,Xgl_bounds_i2d*,Xgl_pt_i2d*)

Two virtual functions, one for 2D and one for 3D, where the destination device is the memory raster associated with the Context parameter and the source device is the pipeline XglDpDev object.
A minimal implementation of createDpCtx() that instantiates a pipeline-context object is shown below. In this example, XglDpCtx3dSampDp represents the name of the XglDpCtx3d subclass that the device pipeline creates.

  XglDpCtx3d* XglDpDevSampDp::createDpCtx(XglContext3d* context)  
  {  
     return new XglDpCtx3dSampDp(context);  
  }  

XglDpDev Optionally Overridable Functions

The XglDpDev class and its subclasses include a number of functions that you can override to perform operations specific to your device. These function declarations, along with their default actions, are defined in the header files for the XglDpDev classes and are listed in Table 3-1 on page 41. If the default behavior of your hardware matches the defaults that XGL has defined for these functions, it is not necessary to override these functions.
Note that this may be an incomplete list; for the most current list, check the header files. Information on default and return values is also available in the header files. See the descriptions beginning on page 52 for more detail on these functions.
Table 3-1
ClassFunction Name
XglDpDevXgl_vdc_orientation getDcOrientation() float getMaxZ()

float getGammaValue()

XglDpDevRastervoid setRectList(const Xgl_irect[])
void setRectNum(Xgl_usgn32)
void setSourceBuffer(Xgl_buffer_sel)
void setSwZBuffer(XglPixRectMem*)
void setSwAccumBuffer(XglPixRectMem*)
void syncRtnDevice(XglRasterWin*)
XglDpDevWinRasXgl_accum_depth getAccumBufferDepth() Xgl_usgn32 getDepth()

Xgl_color_type getRealColorType() XglPixRectMem* getSwZBuffer() XglPixRectMem* getSwAccumBuffer() Xgl_boolean needRtnDevice() void resize()

void setBackingStore(Xgl_boolean) void setBufDisplay(Xgl_usgn32) void setBufDraw(Xgl_usgn32) void setBufMinDelay(Xgl_usgn32) Xgl_usgn32 setBuffersRequested(Xgl_usgn32) void setCmap(XglCmap*)

void setPixelMapping(const Xgl_usgn32) void setStereoMode(Xgl_stereo_mode)

XglDpDevMemRasvoid setCmap(XglCmap*)
void setImageBufferAddr(Xgl_usgn32*)
void setZBufferAddr(Xgl_usgn32*)
void setLineBytes(Xgl_usgn32)
Xgl_accum_depth getAccumBufferDepth()
XglPixRectMem* getAccumBufferPixRect()
XglPixRectMem* getImageBufferPixRect()
XglPixRectMem* getZBufferPixRect()

Device Object Initialization

It is important to be aware that XGL's API-level Device object consists of two internal objects: the device-dependent device object that is created by the device pipeline XglDpMgr object, and a device-independent object, such as XglRasterWin, that is created by the XGL core System State object. These two internal Device objects are linked by a pointer from the device-dependent object to the device-independent object. The API Device object was designed with separate device-independent and device-dependent components to isolate the device-dependent operations. This design allows you to define specific operations for your device.
When the XGL core asks the device pipeline to create an XglDpDev object, it passes a handle to the device-independent Device object:
XglDpDev* XglDpMgrYourFb::createDpDev(XglDevice* device)

At creation time, the XglDpDev object gets from the XglDevice object all the information it needs about the device-independent attributes. The device-independent values are valid at this time. Most of the set...() functions are called later when the application changes device-dependent parameters through the API.
After getting the pointer to the XglDpDev object, the XglRasterWin object calls the device-dependent object's get...() functions (which you should override if the default behavior is incorrect for your device) to complete its own initialization. You should not expect these device-dependent attributes, which provide information such as the DC orientation or the device color type, to be meaningful during the XglDpDev object creation. Later in the process of pipeline initialization, XglRasterWin will call set...() functions that allow the XglDpDev object to complete its initialization with the correct device-dependent data.

Defining the Device Pipeline-Context Class

The final step in creating your pipeline framework classes is to subclass from the device pipeline-context hierarchy. There is one device pipeline-context object per Device-Context pair. If your pipeline supports applications that render in 2D and 3D, then two subclasses are needed, one descending from XglDpCtx2d and the other from XglDpCtx3d.
The two XglDpCtx classes contain the interfaces for the 2D and 3D LI-1, LI-2, and LI-3 primitive layers. The LI-1 and LI-2 interfaces are member functions that you can override in your device pipeline if you choose. If the LI-1 and LI-2 primitives are not implemented by the pipeline, the device pipeline-context object automatically uses the software pipeline. Thus, for LI-1 and LI-2 primitives, the device pipeline does not need to override any functions that the hardware does not support. The LI-3 functions are defined in the XglDpCtx classes and must be implemented by the device pipeline.
An XglDpCtx class for a 3D pipeline in which only multipolylines are implemented might look like the following sample code.

  class XglDpCtx3dSampDp : public XglDpCtx3d {  
      friend XglDpDevSampDp;  
  private:  
      XglDpCtx3dSampDp(XglContext3d* context) :  
      XglDpCtx3d(context) {  
           opsVec[XGLI_LI1_MULTIPOLYLINE] =  
            XGLI_OPS(XglDpCtx3dSampDp::li1MultiPolyline);  
           opsVec[XGLI_LI_OBJ_SET] =  
            XGLI_OPS(XglDpCtx3dSampDp::objectSet);  
           opsVec[XGLI_LI_MXG_RCV] =  
            XGLI_OPS(XglDpCtx3dSampDp::messageReceive);  
       }  
      //  
      // Device-pipeline Dependent Functions  
      //  
      void li1MultiPolyline(Xgl_bbox*, Xgl_usgn32, Xgl_pt_list*);  
  
      // Function to handle ctx related changes  
      void  objectSet (const  Xgl_attribute*);  
  
       //Function to draw the line through the hardware  
       void drawLine (Xgl_usgn32, Xgl_pt_list*);  
  };  

The LI functions are described in Chapter 9, "Writing Loadable Interfaces". For more information on switching between the device pipeline and the software pipeline, see page 20.

Rendering through the XglDpCtx Object

When a primitive is called, the XGL core maps the API call to an internal C++ call in a wrapper function. The wrapper passes the primitive call directly to the device pipeline through the opsVec[] array. The opsVec[] is a dynamic array of function pointers to LI functions. It is defined by the XGL core and maintained by the device pipeline. The array is defined as shown below. XGLI_OPS is defined as (void(XglDpCtx::*)()) in DpCtx.h .

  XglDpCtx3d::XglDpCtx3d(XglDevice*    dev,  
                         XglContext3d* context) : XglPipeCtx3d(context)  
  {  
      //  
      // Initialize DI opsVec[]  
      //  
      opsVec[XGLI_LI1_NEW_FRAME] =  
                XGLI_OPS(XglDpCtx3d::li1NewFrame);  
      opsVec[XGLI_LI1_GET_PIXEL] =  
                XGLI_OPS(XglDpCtx3d::li1GetPixel);  
      opsVec[XGLI_LI1_SET_PIXEL] =  
                XGLI_OPS(XglDpCtx3d::li1SetPixel);  
      opsVec[XGLI_LI1_SET_MULTI_PIXEL] =  
                XGLI_OPS(XglDpCtx3d::li1SetMultiPixel);  
      opsVec[XGLI_LI1_SET_PIXEL_ROW] =  
                XGLI_OPS(XglDpCtx3d::li1SetPixelRow);  
      opsVec[XGLI_LI1_COPY_BUFFER] =  
                XGLI_OPS(XglDpCtx3d::li1CopyBuffer);  
      opsVec[XGLI_LI1_ACCUMULATE] =  
                XGLI_OPS(XglDpCtx3d::li1Accumulate);  
      opsVec[XGLI_LI1_CLEAR_ACCUMULATION] =  
                XGLI_OPS(XglDpCtx3d::li1ClearAccumulation);  
      :  
      :  
      :  
  }  

When the application calls a primitive, the wrapper forwards the API function call to the device pipeline, as shown in the following sample wrapper function:

  void xgl_multipolyline(Xgl_ctx      ctx,  
                         Xgl_bbox*    bounding_box,  
                         Xgl_usgn32   num_pt_lists,  
                         Xgl_pt_list* pl)  
  {  
      XglDpCtx* dp = ((XglCtxObject*)ctx)->getDp(); //get dp pointer  
           (dp->*( //call dp function pointed to by mpline array entry  
             (void(XglDpCtx::*)(Xgl_bbox*,Xgl_usgn32,Xgl_pt_list*))  
             (dp->currOpsVec[XGLI_LI1_MULTIPOLYLINE])  
            )  
      )(bounding_box,num_pt_lists,pl); // function called with API  
                                       // args  
  }  


Note - At LI-1, API geometry data is passed to the device pipeline unchanged.

Required Initialization of the opsVec[] Function Array

The XGL core initializes the opsVec[] array to a set of default function pointers that point to the software pipeline LI-1 primitives. It is the device pipeline's responsibility to override the entries in the opsVec[] array to functions that the device pipeline has implemented. This can occur at initialization of the pipeline XglDpCtx object (when the Device is set on the Context) or during program execution. In deciding how to set up your pipeline's opsVec[] array, you have three cases to consider:
  • Primitives that the pipeline does not implement
  • Primitives that are not critical to performance
  • Primitives that are critical to performance
Designing the opsVec[] array to handle these cases is discussed below.
Using the Default Software Pipeline Renderer If your device pipeline has not implemented a particular LI-1 or LI-2 primitive, you can use the default opsVec[] array entry. The opsVec[] entries are loaded with calls to the software pipeline at LI-1 or LI-2 by default. The XglDpCtx3d default call to the software pipeline looks like this:

  void XglDpCtx3d::li1MultiPolyline(Xgl_bbox*    bounding_box,  
                                    Xgl_usgn32   num_pt_lists,  
                                    Xgl_pt_list* pl)  
  {  
      if (error_checking) {  
          do_error_checking()  
      }  
      swp->li1MultiPolyline(bounding_box, num_pt_lists, pl);  
  }  

In this case, you do not need to change the opsVec[] array. Your XglDpCtx object will inherit the default software pipeline calls.
Implementing a Generic Renderer If your pipeline implements a primitive, but the primitive's performance is not critical, the pipeline can load a pointer to its primitive function when the Device is set on the Context and not reset it later. This function will be called whenever the application calls a primitive.
To provide a renderer, declare the function as a member of your pipeline XglDpCtx, and in the XglDpCtx's constructor, put a pointer to the function in the appropriate entry of the opsVec[] array. A list of opsVec[] array indices can be found in DpCtx.h.
An example of initializing the opsVec[] array for a device pipeline LI-1 multipolyline is shown below:

  //  
  // Install multipolyline  
  //  
  opsVec[XGLI_LI1_MULTIPOLYLINE] =  
          XGLI_OPS(XglDpCtx3dExampleDp::li1MultiPolyline);  

Implementing a Performance-Critical Renderer If your device pipeline implements a primitive whose performance is critical, you may want to create a set of renderers for this primitive, including:
  1. A single generic renderer that does error checking and handles point type changes, attribute changes, and transform changes.

  2. A set of fast renderers that do not need to handle point type changes, etc. and that are tuned to specific combinations of attributes.

A generic renderer might look something like this:

  //  
  // Get and return clip changed status.  
  //  
  // Result OR'ed and saved in "clipChanged" since  
  // drawable->clipChanged() does not retain clip status.  
  //  
  #define GX_CLIP_CHANGED(drawable) (clipChanged |=  \  
                         (drawable)->clipChanged())  
  XglDpCtx3dGx::GenericMpline(Xgl_bbox*    bounding_box,  
                              Xgl_usgn32   num_pt_lists,  
                              Xgl_pt_list* pl)  
  {  
      if (error_checking) {  
          do_error_checking()  
      }  
      if (ctx != last_ctx) {  
          // handle context change  
      }  
      if (pt_type != last_pt_type) {  
          // handle point type change  
      }  
      if (prim != last_prim)  {  
          // handle primitive type change  
      }  
      if (GX_CLIP_CHANGED(drawable)) {  
          // handle window type change  
      }  
      if (xforms_changed) {  
          // handle transform changes  
      }  
      // Figure out which fast line renderer to use and set  
      // opsVec[XGLI_LI1_MULTIPOLYLINE] to this line renderer.  


      // window locking  
      // model clipping  
  
       // Draw the multipolyline with the fast renderer you just set.  
      (this->*((void(XglDpCtx3dGx::*)  
                (Xgl_bbox*, Xgl_usgn32, Xgl_pt_list*, Xgl_boolean)  
               )(opsVec[XGLI_LI1_MULTIPOLYLINE])  
              )  
      )(bounding_box, num_pt_lists, pl, FALSE);  
  
     // If nothing changes, this fast renderer will be  
     // called directly the next time.  
  
     // window unlocking  
  }  

A fast renderer might look something like this:

  XglDpCtx3dGx::FastMPline()  
  {  
     //state changes that require re-evaluation before renderering  
     if (ctx!=last_ctx || pt_type!=last_pt_type ||  
         prim!=last_prim || GX_CLIP_CHANGED(drawable)) {  
           GenericMpline();  
     }     return;  
     // send the points to the hardware to render  
  }  

A device pipeline rendering function can override opsVec[] entries at any time. You can design a renderer to support a particular set of attributes and install that renderer during program execution. This frees some renderers from having to test the attributes in each primitive call, and thus provides improved acceleration.
If a device decides to set an opsVec[] entry back to its default value, the opsVecDiDefault[] array can be used:

  //  
  // Set opsVec[] back to default  
  //  
  opsVec[XGLI_LI1_MULTIPOLYLINE] =  
          opsVecDiDefault[XGLI_LI1_MULTIPOLYLINE];  


Note - In order for backing store to work correctly, the device pipeline must pass the parameter gen_punt = FALSE when it calls any XglDpCtx function through the opsVec[] array.

Calling the Software Pipeline

If a device pipeline cannot accelerate the API arguments or the Context state (for example, API attributes, point type, or facet flags), the pipeline can call the software pipeline directly, as shown in this example:

  void XglDpCtx3dSampDp::li1MultiPolyline(  
     Xgl_bbox*     bounding_box,  
     Xgl_usgn32    num_pt_lists,  
     Xgl_pt_list*  pl)  
  
  {  
      const XglStrokeGroup3d* cur_stroke = ctx->getCurrentStroke();  
  
      // Check if I can render with the current attrs  
      // e.g. If dp can handle only line style solid then  
      // dp must call software pipeline  
      if ( cur_stroke->getStyle() != XGL_LINE_SOLID) {  
          swp->li1MultiPolyline(bounding_box, num_pt_lists, pl);  
      }   return;  
  
      // Draw the polyline  
       drawLine(num_pt_lists, pl);  
  }  

When a device pipeline can only render part of a primitive, it can fall back to the software pipeline for partial rendering of the primitive. For example, to handle a complex polygon in an xgl_multi_simple_polygon() call, the device pipeline can do the following:

  //  
  // Second version of a fast renderer.  
  //  
  // Get and return clip changed status.  
  //  
  // Result OR'ed and saved in "clipChanged" since  
  // drawable->clipChanged() does not retain clip status.  
  //  


  #define GX_CLIP_CHANGED(drawable) (clipChanged |=  \  
                         (drawable)->clipChanged())  
  
  XglDpCtx3dGx::li1FastMsp(Xgl_facet_flags api_facet_flags,  
                           Xgl_facet_list  *api_facet_list,  
                           Xgl_bbox        *api_bbox,  
                           Xgl_usgn32      api_num_pt_lists,  
                           Xgl_pt_list     *api_pt_list)  
  {  
      //  
      // API arguments that can't be handled by the device pipeline.  
      //  
      if (api_pt_list->pt_type & XGL__HOM) { // Homogeneous point  
                                             // type  
          swp->li1MultiSimplePolygon(api_facet_flags,  
                                     api_facet_list,  
                                     api_bbox, api_num_pt_lists,  
                                     api_pt_list);  
          return;  
      }  
  
      //  
      // State changes that require re-evaluation before  
      // renderering.  
      //  
      if (ctx != dp_saved_last_ctx_ptr ||  
         api_pt_list->pt_type != dp_saved_last_pt_type ||  
         api_facet_flags != dp_saved_last_facet_flags ||  
         api_facet_list->facet_type != dp_saved_last_facet_type ||  
         dp_saved_prim != dp_saved_last_prim ||  
         GX_CLIP_CHANGED(drawable)) {  
  
         li1MultiSimplePolygon(api_facet_flags, api_facet_list,  
                               api_bbox,api_num_pt_lists, api_pt_list);  
         return;  
      }  
      Xgl_pt_list *pl = api_pt_list;  
      for(Xgl_usgn32 i = 0; i < api_num_pt_lists; pl++) { // for  
                                                           each polygon  
          if (api_facet_flags & XGL_FACET_FLAG_SHAPE_CONVEX)  
              //  
              // if convex  
               // send the points to the hardware  
              //  
          else  


              //  
              // Parts of the primitive that can't be handled  
              //  
           swp->li1Polygon(api_facet_list->facet_type,  
                          api_facet_list->facets,  
                           api_bbox,  
                           1,  
                          pl);  
      }  
  }  

Naming Your Device Pipeline

An XGL device pipeline must be named according to the following convention:
xgl<COMPANY NAME><device name>.so.<major version>

where:
  • <COMPANY NAME> is a 4-letter capitalized abbreviation for the company that implements the device pipeline.
  • <device name> is the abbreviated name of the device, which should be an abbreviated form of the name of the corresponding kernel device driver located in the /dev directory.
  • <major version> is the major release number of the DDK associated with the particular release of XGL that is compatible with this device pipeline. The DDK major version number can be found in the header file xgli/DdkVersion.h.
For example, a Sun Microsystems Cg6 device pipeline with a major version number of 4 is named xglSUNWcg6.so.4. See page 63 for more information on version numbers.
The name of the pipeline is defined in the Makefile located in the device pipeline build area. The Makefile macro LIB_NAME must be set to the pipeline name.
When XGL attempts to load a pipeline, it issues a system call that returns the pipeline name, as defined above, for the active device. See page 58 for more information on how XGL loads a device pipeline.

Optional Functions in Device-Dependent Classes

This section provides a brief description of the optional device-dependent operations provided in the XglDpDev class hierarchy. Many of these functions have a corresponding API attribute; in those cases, you can find more information about the attribute in the XGL Reference Manual.

Overridable Functions in DpDev.h

virtual Xgl_vdc_orientation getDcOrientation()
  Returns a value for the orientation of DC for the hardware device. The
  default value is XGL_Y_DOWN_Z_AWAY. Override this function if your device
  has a different orientation. This function is called by the XGL core as part of
  the Device object initialization.

virtual float getMaxZ() Returns a value for the hardware device's maximum Z coordinate value. The default value is XGLI_DEFAULT_MAX_DEPTH, which is a constant defined as 224-1. Override this function if your device has a different maximum Z value. This function is called by the XGL core as part of the Device object initialization.
virtual float getGammaValue() The default implementation of this function returns a value of 2.22. The function also checks the environment variable XGL_AA_GAMMA_VALUE and returns the value that the environment variable is set to, if it is set. See Appendix B, "Software Rendering Characteristics" in the XGL Programmer's Guide for information on this environment variable.
The value returned by this function is used as the gamma value to build gamma and inverse gamma look-up tables. These tables are built by buildGammaTables(), which is called by the constructors for objects like XglRasterWin and XglRasterMem. The gamma and inverse gamma tables are only used for manipulating the colors of antialiased stroke and dot primitives. If a device implements antialiasing in hardware, then these tables, and hence the getGammaValue() function have no effect. However, if the device expects stroke or dot antialiasing to be done by the software pipeline, there are two possible cases. First, if the device does its own gamma correction, the function needs to return the value 1.0. Otherwise, the device can choose to not implement this function or to implement it to return a gamma value that is more suitable.
Note that this function might not be present in future releases of XGL; check the current header files for the most up-to-date list of optional functions.

Overridable Functions in DpDevRaster.h

virtual void setRectList(const Xgl_irect[]) Sets the list of clip rectangles in the application-specified clip list. The input argument is an Xgl_irect array of rectangles that defines the clip region. This function maps to the API attribute XGL_RAS_RECT_LIST and is used by the XGL core to inform the pipeline when the clip list changes. The default is no operation. See the XGL_RAS_RECT_LIST reference page for more information.
virtual void setRectNum(Xgl_usgn32) Sets the number of clip rectangles in the application-specified clip list. The input argument is an unsigned 32-bit integer. This function maps to the API attribute XGL_RAS_RECT_NUM and is used by the XGL core to inform the pipeline when the clip list changes. The default is no operation. See the XGL_RAS_RECT_NUM reference page for more information.
virtual void setSourceBuffer(Xgl_buffer_sel) Specifies the buffer used as the source buffer during raster operations. The input argument is a macro value from the Xgl_buffer_sel typedef. This function maps to the API attribute XGL_RAS_SOURCE_BUFFER and is used by the XGL core to inform the pipeline when the source buffer for raster operations changes. The default is no operation. See the XGL_RAS_SOURCE_BUFFER reference page for more information.
virtual void setSwZBuffer(XglPixRectMem*) Specifies that if the device uses a software Z-buffer, it should share it with the base device in the backing store device by getting the memory address and linebytes from the Z-buffer and reassigning them as its own. This function is called by the XGL core when the device is a backing store device, so the device pipelines do not need to check for it. The default is no operation.
virtual void setSwAccumBuffer(XglPixRectMem*) Specifies that if the device uses a software accumulation buffer, it should share the same software accumulation buffer with the base device in the backing store device by getting the memory address and linebytes from the
accumulation buffer and reassigning them as its own. The XGL core calls this function when the device is a backing store device, so the device pipelines do not need to check for it. The default is no operation.
virtual void syncRtnDevice(XglRasterWin*) Synchronizes any device-dependent attributes, if needed, for backing store devices. The default is no operation.

Overridable Functions in DpDevWinRas.h

virtual Xgl_usgn32 getDepth()
  Returns the number of bits required to store the color of one pixel in the
  image buffer of this hardware device. The default behavior is to query the
  Drawable object for the depth of the frame buffer image buffer.

virtual Xgl_accum_depth getAccumBufferDepth()
  Returns the accumulation buffer depth supported by the device. Called by
  the XGL core during the creation of the XglDpDev object. This function is
  currently only used by the software pipeline when doing accumulation.

virtual Xgl_color_type getRealColorType()
  Returns the real color type of the device. The default behavior is to query
  the Drawable object for the real color type of the frame buffer.

virtual void resize()
  Called by the XGL core when the pipeline's window is resized. The default
  is no operation.

virtual void setBackingStore(Xgl_boolean)
  Requests backing store support from the device. No device pipeline
  operation is needed if the device relies on the XGL core to handle backing
  store manipulation. The input argument is a Boolean that indicates the
  on/off setting for backing store. This function maps to the API attribute
  XGL_WIN_RAS_BACKING_STORE; see the XGL_WIN_RAS_BACKING_STORE
  reference page for more information.

virtual Xgl_usgn32 setBuffersRequested(Xgl_usgn32) Defines the number of buffers requested by the application. This function maps to the API attribute XGL_WIN_RAS_BUFFERS_REQUESTED and is used by the XGL core to request single or double buffering for the device. The default return value is one buffer.
virtual void setBufDraw(Xgl_usgn32)
  Specifies the current draw buffer. This function maps to the API attribute
  XGL_WIN_RAS_BUF_DRAW and is used by the XGL core to set the current
  draw buffer. The default is no operation. See the XGL_WIN_RAS_BUF_DRAW
  reference page for more information.

virtual void setBufDisplay(Xgl_usgn32)
  Specifies the current display buffer. This function maps to the API attribute
  XGL_WIN_RAS_BUF_DISPLAY and is used by the XGL core to set the
  current display buffer for the device. The default is no operation. See the
  XGL_WIN_RAS_BUF_DISPLAY for more information.

virtual void setBufMinDelay(Xgl_usgn32) Defines the minimum time delay between buffer switches for this device. This function maps to the API attribute XGL_WIN_RAS_BUF_MIN_DELAY. The default is no operation. See the XGL_WIN_RAS_BUF_MIN_DELAY reference page for more information.
virtual void setCmap(XglCmap*) Sets the color map. This function maps to the API attribute XGL_DEV_COLOR_MAP and is used by the XGL core to inform the pipeline when the XGL Color Map object changes. The input argument is a pointer to a Color Map object. The default is no operation.
When the contents of the Color Map change, XglDpDevWinRas::setCmap() is called. The device pipeline messageReceive() is called for object type XGL_WIN_RAS with message flag XGLI_MSG_DEV_COLOR. This message tells the device pipeline to handle the appropriate plane mask and color map changes.
virtual void setPixelMapping(conxt Xgl_usgn32[]) Sets the pixel mapping from the application's color indexes to the device color indexes. This function maps to the API attribute XGL_WIN_RAS_PIXEL_MAPPING and is used by the XGL core to inform the device when the pixel mapping changes. The input argument is an array of color values. The default is no operation. See the XGL_WIN_RAS_PIXEL_MAPPING reference page for more information.
virtual void setStereoMode(Xgl_stereo_mode) Requests stereo mode support from the device. The input argument is an Xgl_stereo_mode enumerated value for the stereo setting. This function maps to the API attribute XGL_WIN_RAS_STEREO_MODE and is used by the XGL core to set the stereo mode on the device. The default is no operation. See the XGL_WIN_RAS_STEREO_MODE reference page for more information.
virtual XglPixRectMem* getSwZBuffer() Returns a pointer to the XglPixRectMem object that represents the software Z-buffer. This function should be overridden by all devices that have a software implementation of the Z-buffer. The default return is NULL, meaning that if the device has a hardware Z-buffer, it does not need to override this function.
virtual XglPixRectMem* getSwAccumBuffer() Returns a pointer to the XglPixRectMem object that represents the software accumulation buffer. This function should be overridden by all devices that have a software implementation of the accumulation buffer. The default return is NULL, meaning that if the device has a hardware accumulation buffer, it does not need to override this function.
virtual Xgl_boolean needRtnDevice() Returns TRUE if the base device needs a shadow device for backing store. Device pipelines that provide for backing-store support in hardware will override this function, as will Xlib or PEXlib pipelines that use backing-store support in the server.

Overridable Functions in DpDevMemRas.h


Note - For all practical purposes, there is only one Memory Raster pipeline, which is provided by XGL. The device pipeline does not need to override the functions in DpDevMemRas.h, as they are overridden in XGL's Memory Raster pipeline.

virtual XglPixRectMem* getImageBufferPixRect() Returns a pointer to the XglPixRectMem object that represents the image buffer for the memory raster. The default return is NULL.
virtual XglPixRectMem* getZBufferPixRect()
  Returns a pointer to the XglPixRectMem object that represents the Z-buffer
  for the memory raster. The default return is NULL.

virtual XglPixRectMem* getAccumBufferPixRect()
  Returns a pointer to the XglPixRectMem object that represents the
  accumulation buffer for the Memory Raster.  The default return is NULL.

virtual Xgl_accum_depth getAccumBufferDepth()
  Returns a value for the depth of the accumulation buffer.  The default return
  value is XGL_ACCUM_DEPTH_2X.

virtual void setCmap(XglCmap*)
  Sets the color map. This function maps to the API attribute
  XGL_DEV_COLOR_MAP and is used by the XGL core to inform the pipeline
  when the XGL Color Map object changes. The input argument is a pointer to
  the Color Map object.

virtual void setImageBufferAddr(Xgl_usgn32*)
  Specifies the array of pixels used in an XGL Memory Raster. This function
  maps to the API attribute XGL_MEM_RAS_IMAGE_BUFFER_ADDR. See the
  XGL_MEM_RAS_IMAGE_BUFFER_ADDR reference page for more information.

virtual void setZBufferAddr(Xgl_usgn32*)
  Sets the starting address of the block of memory for the Z-buffer of a
  Memory Raster. This function maps to the API attribute
  XGL_MEM_RAS_Z_BUFFER_ADDR. See the XGL_MEM_RAS_Z_BUFFER_ADDR
  reference page.

virtual void setLineBytes(Xgl_usgn32) Sets the linebytes value when the memory raster is set up to access memory for retained windows. linebytes is the number of bytes that separates one line in a raster, in other words, the number of bytes from (x,y) to (x,y+1).

What Else You Should Know

This section provides additional information about the pipeline framework classes that you might need to know as you set up your device pipeline.

How a Device Pipeline Is Loaded

A device pipeline is loaded when the application calls xgl_inquire() or calls xgl_object_create() to create a Device object for the first time. With the device object creation call, the application passes in the device type and the descriptor containing the X window identifying information. The XGL core then proceeds to create the objects needed for the pipeline. The pipeline loading part of this process is as follows:
  1. When the application requests a Device object with xgl_object_create(), the System State object initiates the creation of the device-independent part of the Device object. In the case of a window raster, XglRasterWin is created.

  2. When XglRasterWin is created, it calls XglDrawable::grabDrawable() to obtain an XglDrawable object of the appropriate type for the XGL device.

  3. During the creation process of XglRasterWin, the Device object asks the XglGlobalState object to create its device-dependent part.

  4. In the process of creating the device-dependent part of the Device object, the XglGlobalState object does the following:

    a. It gets the name of the pipeline shared object file by calling the Window Raster's XglDrawable::getPipeName() routine. This routine issues a system call to the kernel device driver, using the VIS_GETIDENTIFIER ioctl(), to get a string specifying the name of the device when the device is a frame buffer. This string can then be used to create the pipeline name, which is of the form:

xgl<COMPANY NAME><device name>.so.<major version>

b. The XglGlobalState::getDpLib() routine then traverses the Global State's XglDpLibList object list to determine if an object for the pipeline library already exists. If so, it returns.
If XglGlobalState does not find a match in its XglDpLibList, XglGlobalState::loadPipeLib() loads the pipeline using dlopen(), which is an interface routine in the Solaris dynamic linking mechanism. dlopen() gives XGL runtime access to the device pipeline shared object file and binds it to XGL's process address space.
c. XglGlobalState::loadPipeLib() then creates the XglDpLib object for the pipeline by calling the device pipeline's xgl_create_PipeLib() routine, which is defined in the pipeline and accessed through dlsym(). xgl_create_PipeLib() first checks the DDK major and minor version numbers to ensure that the pipeline is compatible with the core XGL library that is attempting to load it. If this check succeeds, xgl_create_PipeLib() creates an instance of the pipeline-derived XglDpLib class and returns a pointer to the object. This pointer is appended to the XglGlobalState's XglDpLibList object for future reference. The XglDpLib object represents a single pipeline.
At this point, the process of pipeline object creation continues with the instantiation of the pipeline XglDpMgr object and the pipeline XglDpDev object. For detailed information on the complete set of steps that occur during pipeline creation, see the XGL Architecture Guide.

Device Pipeline Objects for Multiple Processes

The device pipeline objects in Figure 3-2 are created when a pipeline is instantiated on a single frame buffer from a single application.

Grafik

Figure 3-2

When a single application opens windows on a two-headed system in which the frame buffers are the same type, there is one XglDpLib object, an XglDpMgr for each frame buffer, and an XglDpDev object for each window. The single application program is one UNIX process. A diagram of a single application opening one window on each of two identical frame buffers would look like Figure 3-3 on page 60.

Grafik

Figure 3-3

When there is more than one application program using XGL, there is a UNIX process for each application. If there are two application programs, there are two UNIX processes. In this case, there is an XglDpLib object for each process, an XglDpMgr object corresponding to each XglDpLib, and an XglDpDev object for each window. Figure 3-4 shows the pipeline objects that are created for two application programs running on one frame buffer. The second application opens two windows.

Grafik

Figure 3-4

The XGL/DGA system does not describe how an accelerator accommodates two or more application processes. DGA is basically a concurrency control mechanism; it will serialize concurrent accesses, but it does not mandate how the accelerator handles state information for different processes. You must coordinate the interaction between the XglDpLib objects for each process.
If the application programs run on a two-headed system with frame buffers of different types, for example, your frame buffer and a GX frame buffer, the pipeline objects that are created might look like Figure 3-5 on page 61.

Grafik

Figure 3-5

Adding Member Data to a Pipeline Class

When creating subclassed pipeline classes, you can add member data whenever needed. The following example illustrates a way to add and initialize a pointer to the device manager as member data in the XglDpDev and XglDpCtx subclasses.
  1. First, add a device pipeline manager pointer as member data and a device pipeline manager parameter to the constructors of XglDpDevSampDp and XglDpCtx[2/3]dSampDp:


  class XglDpDevSampDp : public XglDpDevWinRas {  
      friend XglDpLibSampDp;  
  private:  
      // call base class constructor with device,  
      // assign device manager pointer (dev_mgr)  
      // to member data dpMgr  
      XglDpDevSampDp(XglDevice* device, XglDpMgrSampDp* dev_mgr)  
                  : XglDpDevWinRas(device), dpMgr(dev_mgr) { }  
  
      XglDpMgrSampDp* dpMgr;   // device manager pointer  
      //        .... other declarations  
  };  
  
  class XglDpCtx3dSampDp : public XglDpCtx3d {  
      friend XglDpDevSampDp;  
  private:  
      // call base class constructor with context,  
      // assign device manager pointer (dev_mgr)  


  class XglDpDevSampDp : public XglDpDevWinRas {  
      // to member data dpMgr  
      XglDpCtx3dSampDp(XglContext3d* context, XglDpMgrSampDp*  
                        dev_mgr)  
      : XglDpCtx3d(context), dpMgr(dev_mgr)  
     {  
         opsVec[XGLI_LI1_MULTIPOLYLINE] =  
             XGLI_OPS(XglDpCtx3dSampDp::li1MultiPolyline);  
  
         // Attribute changes  
         opsVec[XGLI_LI_OBJ_SET] =  
             XGLI_OPS(XglDpCtx3dSampDp::objectSet);  
  
         // Message handler  
         opsVec[XGLI_LI_MSG_RCV] =  
             XGLI_OPS(XglDpCtx3dSampDp::messageReceive);  
     }  
      XglDpMgrSampDp* dpMgr;        // device manager pointer  
      //  .... other declarations  
  };  

  1. Modify the object-creation functions to pass the device manager pointer to the constructors:


  XglDpDev* XglDpMgrSampDp::createDpDev(XglDevice* device)  
  {  
      // "this" is the device manager (XglDpMgrSampDp) itself  
      return new XglDpDevSampDp(device,this);  
  }  
  
  XglDpCtx3d* XglDpDevSampDp::createDpCtx(XglContext3d* context)  
  {  
      // here dpMgr is a member data of XglDpDevSampDp  
      return new XglDpCtx3dSampDp(context,dpMgr);  
  }  

Versioning

The XGL core library (libxgl.so) dynamically loads device pipeline modules at runtime; therefore, a versioning scheme is required to ensure that the core library and the pipeline that it loads are compatible. The versioning scheme is implemented both as part of the XGL core library and as part of the Driver Developer Kit (DDK).
The DDK contains header files that define the interfaces between the core XGL library and the dynamically loaded pipeline modules. The core library and the DDK have a version number that is called the DDK version number. This version number, which contains both major and minor parts, is defined by two macro definitions in the file xgli/DdkVersion.h. The macro definitions for the current release are:
#define XGLI_DDK_MAJOR_VERSION  4
#define XGLI_DDK_MINOR_VERSION  0

Every XGL device pipeline must include the DdkVersion.h header file in order to use the versioning information.

Versioning Rules

Each release of XGL is accompanied by a corresponding release of the DDK containing files used to build the core XGL library and the reference device pipelines. Independent Hardware Vendors (IHV's) use the DDK to build a device handler that is compatible with the core XGL library in that release.
The DDK version number is unrelated to the XGL API library version number. For example, the 3 in libxgl.so.3 is the version number of the XGL API release. It is not related to the internal DDK majorVersion number. IHV's supplying XGL device pipelines must conform to the following versioning rules:
  1. The DDK majorVersion (defined in xgli/DdkVersion.h) used to build the device pipeline is stamped in the file name of the device pipeline, such as, xglSUNWcg6.so.4, where the 4 is the same as majorVersion. The convention used to name the device pipelines is:

    xgl<COMPANY NAME><device name>.so.<majorVersion>

  1. The core XGL library is stamped internally with both the DDK major and minor version numbers of the DDK used to build it. The core XGL library will never load a pipeline with a DDK majorVersion greater than its own. For example, libxgl.so with DDK internal version number 3 will not load a pipeline named xglSUNWcg6.so.4.

  2. The core XGL library will load a device pipeline with a DDK majorVersion less than its own DDK majorVersion only if the XGL core library has explicitly decided to emulate that lesser majorVersion interface. Every time a new version of XGL and the XGL DDK are released, this DDK document will specify which, if any, DDK major versions are emulated by the core XGL library.

    For this release of the DDK (major version 4, minor version 0), no prior versions are emulated.

  3. The core XGL library will always attempt to dynamically load a device pipeline that has the same DDK majorVersion as itself. If the device pipeline depends on functionality that was added in a particular minorVersion of the DDK, your pipeline must check for the existence of that functionality by checking the core library's DDK version number.

    A device pipeline can provide its own workaround if the functionality does not exist, or it can fail with an appropriate error message indicating the core library version that is required.

    The functionality differences between minorVersion releases of the DDK will be documented in the DDK documentation. A device pipeline can check the core library's DDK version number by calling the global library function xglGetDdkVersion() from within its xgl_create_PipeLib() function, as declared in xgli/DdkVersion.h.

There is also an XGLI_PIPELINE_CHECK_VERSION() macro in the DdkVersion.h file which shows a sample implementation. A device pipeline is free to use it or implement its handling in the xgl_create_PipeLib() routine as long as it adheres to the versioning rules stated above.

  #include "xgli/DdkVersion.h"  
  
  //  
  // Interface routine called after pipeline loading  
  //  
  
  XglPipeLib* xgl_create_PipeLib()  
  {  
      XGLI_PIPELINE_CHECK_VERSION(XglDpLibSampDp);  
  }  

Backing Store Support in the Pipeline Classes

The XGL core is responsible for handling XGL backing store device creation and use. The device pipeline needs only to implement a small set of device-dependent functions in certain cases. This section summarizes the functions that the device pipeline needs to implement. For more information on how the XGL core handles backing store, see the XGL Architecture Guide.

Backing Store Clipping Status Values

If the device pipeline can determine whether a primitive is clipped, it can notify the device-independent layer with the setPrimClipStatus() function to indicate the current status. The following argument values are defined in DpCtx.h:
XGLI_DP_STATUS_FAIL                         The primitive could not be 
                                            rendered.

XGLI_DP_STATUS_SUCCESS                      The primitive was successfully 
                                            rendered and may or may not have 
                                            been clipped.

XGLI_DP_STATUS_FULLY_RENDERED               The primitive was successfully 
                                            rendered without being clipped.

You can use the value XGLI_DP_STATUS_FULLY_RENDERED for all the primitives at the LI-1 level.
The XGLI_DP_STATUS_FULLY_RENDERED value means that the primitive was successfully rendered, and that the primitive was fully rendered into the window without any clipping. This argument value is optional and applies only to synchronous accelerators (those without queues). If the graphics device cannot determine whether the primitive is clipped, it is not necessary to call setPrimClipStatus().
The XGLI_DP_STATUS_FULLY_RENDERED value is an optimization to improve the performance of applications using backing store when the window is partially covered. If a device pipeline can set this status, performance is increased if there is a backing-store device and if the window is partially covered. This optimization does not apply to accelerators that cannot determine the clip status.

Note - The device pipeline should never set the value XGLI_DP_STATUS_UNCLIPPED (defined in DpCtx.h). This value is for internal use only.

Backing Store in Window Raster Pipelines

The following functions in XglDpDevWinRas.h should be overridden by all devices that provide Z-buffers or accumulation buffers in software. See page 54 for information on these functions.
  • virtual XglPixRectMem* getSwZBuffer()
  • virtual XglPixRectMem* getSwAccumBuffer()
Device pipelines that can handle backing store in hardware or the X11 server (for example, the PEXlib pipeline) will override the following function. A pipeline that returns FALSE can ignore the remainder of the functions in this section.
  • virtual Xgl_boolean needRtnDevice()

Backing Store Support for Backing Store Devices

Devices that provide backing store support, such as Memory Raster devices or a hardware device with a cache for backing-store memory, will override these functions in XglDpDevRaster.h. See page 53 for information.
  • virtual void setSwZBuffer(XglPixRectMem*)
  • virtual void setSwAccumBuffer(XglPixRectMem*)
  • virtual void syncRtnDevice(XglRasterWin*)

Backing Store Support in the Dp Manager

The device pipeline manager object provides an object descriptor for the backing store device:
XglDpDev* XglDpMgrFb::createDpDev(XglDevice*,
                                     Xgl_obj_desc* bkstore_desc=NULL);

When the XGL core creates a backing store device, the descriptor is passed in as follows:
bkstore_desc.win_ras.type = XGL_WIN_RAS_BACKING_STORE;
bkstore_desc.win_ras.desc = (pointer to the parent device);

A device pipeline can ignore this parameter if appropriate.

Note - The XGL API cannot support backing store and double buffering at the same time. Even if your device can support both, there are issues regarding the synchronization of double buffering and backing store with the X11 server that are not resolved in the current release of the server. Therefore, an application backing store request is denied by the XGL core when double buffering is enabled. Thus, even if your pipeline supports both double buffering and backing store, the pipeline will not be called for backing store when double buffering is enabled. See the XGL_WIN_RAS_BACKING_STORE reference page for details.

Quick Reference Chart of Overridable Functions

In the device pipeline classes there are some functions that your device pipeline must override and other functions that are optional. Whenever possible, XGL provided defaults for functions; however, you will probably want to override XGL's version of these functions if your device can accelerate the functionality. Required functions are completely device dependent.
Table 3-2 provides a quick reference summary of all the pipeline functions; those marked "Required" must be overridden by the device pipeline, or an error will be returned. For information on input arguments and return values for the functions in the device pipeline classes, see page 52. For information on the LI-1, LI-2, and LI-3 loadable interfaces, see Chapter 9, "Writing Loadable Interfaces"..
Table 3-2
ClassFunction NameStatus
Device pipeline .so filexgl_create_PipeLib()Required
XglDpLibgetDpMgr()Required
XglDpMgrcreateDpDev()
inquire()
Required
Required
XglDpDevcreateDpCtx() for 2D
createDpCtx() for 3D
copyBuffer() for 2D
copyBuffer() for 3D
Required
Required
Required
Required
getDcOrientation()
getMaxZ()
getGammaValue()
Optional
Optional
Optional
XglDpDevRastersetRectList()
setRectNum()
setSourceBuffer()
setSwZBuffer()
setSwAccumBuffer()
syncRtnDevice()
All
optional
Table 3-2
ClassFunction NameStatus
XglDpDevWinRasgetDepth()
getAccumBufferDepth()
getRealColorType()
resize()
setBackingStore()
setBufDisplay()
setBufDraw()
setBufMinDelay()
setCmap()
setPixelMapping()
setStereoMode()
setBuffersRequested()
getSwZBuffer()
getSwAccumBuffer()
needRtnDevice()
All
optional
XglDpDevMemRasgetImageBufferPixRect() getZBufferPixRect() getAccumBufferPixRect() getAccumBufferDepth() setCmap()

setImageBufferAddr() setZBufferAddr() setLineBytes()

All optional
XglDpCtx2d
LI-1 Primitives

li1AnnotationText()
li1DisplayGcache()
li1MultiArc()
li1MultiCircle()
li1MultiMarker()
li1MultiPolyline()
li1MultiRectangle()
li1MultiSimplePolygon()
li1NurbsCurve()
li1Polygon()
li1StrokeText()

All
optional
Table 3-2
ClassFunction NameStatus
Pixel and Raster
Operators
li1NewFrame
li1CopyBuffer()
li1GetPixel()
li1Image()
li1SetMultiPixel()
li1SetPixel()
li1SetPixelRow()
li1Flush()
li1PickBufferFlush()
Required
Required
Required
Optional
Optional
Required
Optional
Optional
Optional
LI-2 Functionsli2GeneralPolygon
li2MultiDot()
li2MultiEllipse()
li2MultiEllipticalArc()
li2MultiPolyline()
li2MultiRect()
li2MultiSimplePolygon()
All
optional
LI-3 Functionsli3Begin()
li3End()
li3MultiDot()
li3Vector()
li3MultiSpan()
li3CopyFromDpBuffer()
li3CopyToDpBuffer()
All
required
State ChangesobjectSet()Required
Message PassingmessageReceive()Required
XglDpCtx3d LI-1 PrimitivesAll 2D primitives and the following: li1MultiEllipticalArc() li1NurbsSurf()

li1QuadrilateralMesh() li1TriangleList() li1TriangleStrip()

All optional
Pixel and Raster
Operators
All 2D pixel and raster functions and the
following:
li1Accumulate()
li1ClearAccumulation()


Optional
Optional
Table 3-2
ClassFunction NameStatus
LI-2 Functionsli2GeneralPolygon()
li2MultiDot()
li2MultiPolyline()
li2MultiSimplePolygon()
li2TriangleList()
li2TriangleStrip()
All
optional
LI-3 Functionsli3Begin()
li3End()
li3MultiDot()
li3Vector()
li3MultiSpan()
li3CopyFromDpBuffer()
li3CopyToDpBuffer()
All
required
State ChangesobjectSet()Required
Message PassingmessageReceive()Required