XIL Device Porting and Extensibility Guide
只搜尋這本書
以 PDF 格式下載這本書

I/O Devices

3

This chapter introduces I/O devices and identifies the basic functions required to create them. In addition, the chapter provides a step-by-step procedure for adding an I/O device.
About I/O Devicespage 79
I/O Device Capabilitiespage 80
Implementing an I/O Devicepage 81
Adding an I/O Devicepage 91

About I/O Devices

In the XIL Imaging Library, I/O devices include any devices that can generate or receive images, such as frame grabbers, image files, and displays. The XIL library supports these types of devices by allowing them to appear as device images to an application. When a device image is used as a source in an operation, an image is captured from the device. When a device image is used as a destination in an operation, an image is written to the device.
The I/O device handler provides an implementation for an image captured from a device and for an image written to a device. The first time a device image is created using the xil_create_from_device() API call, the software module containing the handler is loaded. Once the I/O handler is loaded, any compute devices that have only the I/O handler as a dependence
are loaded. The I/O handler information is cached so that subsequent creations of new device images from the same device do not require reloading the I/O handler.
The character string representing the name of the device, passed as the second argument to xil_create_from_device(), is used to select the appropriate loadable library. Currently, the following API call attempts to load an I/O handler named /etc/openwin/lib/xil/devhandlers/ xilIO_my_device.so.2 and fails with an error if this loadable library does not exist:
device_image = xil_create_from_device(systemState, "my_device",
NULL);

I/O Device Capabilities

The current version of the XIL library has added several new capabilities that affect I/O devices:
  • Tiling
  • Molecules
  • Multithread safe (MT-safe)
  • Double buffering
  • Push devices
Tiling, a feature common to all of XIL as of the current library version, has certain implications for I/O devices. First, an I/O device must be able to provide or process portions of an image as the GPI requests. Second, the I/O device is responsible for constructing the controlling image for the device, which is returned to the user.
The library has the ability to implement molecules without a compute routine.
I/O devices are expected to be MT-safe. This means a framebuffer may have to lock its registers so their contents are accessed by one thread at a time when multiple threads are running.
XIL supports devices that use double-buffering. (See "Functions for Double Buffering Devices" on page 90 for more information.)
Finally, a new type of device called a push device controls data flow by providing data to the core as it is ready. By contrast, pull devices provide data when the core requests it. While a pull device is the more common
implementation, the two methods are not mutually exclusive. When the core requests the data from a push device, the device is expected to fill in the requested area at its own pace and to notify the core when processing of the data is complete. This can be useful for sequential access devices such as scanners. The core guarantees that the area requested is the entire area needed and that no asynchronous requests will be made.

Implementing an I/O Device

To implement an I/O device, it is necessary to implement a device manager as well as a device.

Implementing an I/O Device Manager

The device manager exists from the time the I/O device is created by an API call such as xil_create_from_device() until xil_close() is called. Only one device manager exists for any single device. Even if you have two GX framebuffers on the system, there is only one device manager. However, that device manager is responsible for creating GX I/O devices on multiple devices
The complete code to the I/O device manager example can be found in the TBD directory.

Creating a Device Manager

To create a device manager, you derive a class from XilDeviceManagerIO as shown below. Your device manager is where you might store persistent data that is not instance specific.

  class XilDeviceManagerIOcg6 : public XilDeviceManagerIO {  
  public:  
  ...  
  // class definitions go here  
  ...  
  }  

Required Device Manager Functions

You must overload certain functions must be overloaded in your device manager class:
  • static create()
  • one device constructor function
  • getDeviceName()
  • describeMembers()
create() The first function you must overload is a static XilDeviceManagerIO::create(). This is the entry point for the XIL library.

  static XilDeviceManagerIO* create(unsigned int libxil_gpi_major,  
                                   unsigned int  libxil_gpi_minor,  
                                   unsigned int* devhandler_gpi_major,  
                                   unsigned int* devhandler_gpi_minor);  

The create() function lives in every I/O pipeline and constructs a class derived from XilDeviceManagerIO. XIL provides the pipeline with the highest major and minor version numbers of the GPI it supports. At the same time, the compute pipeline is expected to provide XIL with the highest version of the GPI it supports. The compute pipeline is expected to fail if the version is not one that is supported by the pipeline, for example, if there is a mismatch in the major version numbers or the minor version is lower than the one required by the pipeline. XIL may decide not to load the pipeline, or it may decide to alter its behavior to support an older version of the interface.
You can use the macro XIL_BASIC_GPI_VERSION_TEST shown below to test the version number. It is defined in _XilGPIDefines.hh.

  #define  
  XIL_BASIC_GPI_VERSION_TEST(lib_major,lib_minor,ptr_major,ptr_mi  
  nor) \  
      {                                              \  
          if(lib_major != XIL_GPI_MAJOR_VERSION ||   \  
             lib_minor <  XIL_GPI_MINOR_VERSION) {   \  
              return NULL;                           \  
          } else {                                   \  
              *ptr_major = XIL_GPI_MAJOR_VERSION;    \  
              *ptr_minor = XIL_GPI_MAJOR_VERSION;    \  
          }                                          \  
      }  

The code below shows how to use XIL_BASIC_GPI_VERSION_TEST.

  XilDeviceManagerCompute*  
  XilDeviceManagerCompute::create(unsigned int  libxil_gpi_major,  
                                  unsigned int  libxil_gpi_minor,  
                                  unsigned int* devhandler_gpi_major,  
                                  unsigned int* devhandler_gpi_minor)  
  {  
      XIL_BASIC_GPI_VERSION_TEST(libxil_gpi_major,  
                                 libxil_gpi_minor,  
                                 devhandler_gpi_major,  
                                 devhandler_gpi_minor);  
  
      XilDeviceManagerComputeBYTE* device;  
  
      device = new XilDeviceManagerComputeBYTE;  
  
      if(device == NULL) {  
          XIL_ERROR(NULL, XIL_ERROR_RESOURCE, "di-1", TRUE);  
          return NULL;  
      }  
  
      return device;  
  }  

Device Constructor Your derived I/O device manager should overload one or more of the three device construct*Device() functions shown here.

  //  
  //  Creates a new XilDeviceIO object for a particular device.  
  //  This construct call is made through  
  //  xil_create_from_device()  
  //  
  virtual XilDeviceIO*   constructFromDevice(XilSystemState state,  
                                           XilDevice*      device);  
  //  
  //  Creates a new XilDeviceIO object from a display pointer  
  //  and window.  
  //  This construct call is made through  
  //  xil_create_from_window()  
  //  
  virtual XilDeviceIO*  constructDisplayDevice(  
                                          XilSystemState* state,  
                                          Display*        display,  
                                          Window          window);  
  
  //  
  //  Creates a new XilDeviceIO object which supports double  
  //  buffering froma display pointer and window. At construction  
  //  the device is expected to be referencing the BACK buffer  
  //  of the two buffers.  
  //  This construct call is made through  
  //  xil_create_from_double_buffered_window()  
  //  
  virtual XilDeviceIO*  
  
  constructDoubleBufferedDisplayDevice(XilSystemState* state,  
                                                       Display*        display,  
                                                       Window          window)  

getDeviceName() and describeMembers()

You are required to implement two other functions for the device manager class: getDeviceName() and describeMembers().
The prototype of each function is shown here. For information on describeMembers(), see "Registering Operations With the XIL Library" on page 73.

  //  
  //  Required function that returns the name of this device.  
  //  
      const char*            getDeviceName();  
  
  //  
  // Describe the functions we implement to the XIL core  
  //  
      XilStatus              describeMembers();  

The getDeviceName() function returns the name of the device (xilIO_return_value.so.2), for example SUNWcg6.
Optional Device Manager Destructor The device manager destructor provides an opportunity to clear any persistent data generated by the constructor. Because a constructor typically is used to open a device, implementation of the destructor is optional.

  //  
  // Constructor Destructor  
  //  
                             XilDeviceManagerIOcg6();  
                             ~XilDeviceManagerIOcg6();  

Implementing a Device

Every device image has an XilDeviceIO class. The XilDeviceIO class is called to implement the display and capture operations. In addition the class may choose to implement certain sequences of operations that involve a display or capture operation as molecules.

Creating a Device

To create a device, you derive a class from XilDeviceIO, which is your device.

  class XilDeviceIOcg6 : public XilDeviceIO {  
  public:  
  ...  
  // class definitions go here  
  ...  
  }  

Required Device Functions

There are several functions in the XilDeviceIO class, some of which must be overloaded and some of which are optional. The following functions must be implemented:
  • constructControllingImage()
  • setAttribute()
  • getAttribute()
  • Functions for readable and/or writable devices
  • Functions for double buffering devices
constructControllingImage()

The controlling image is the image that holds the results of the capture and the source of the display. It is requested by the XIL core through the constructControllingImage() function.

  //  
  // Return the image created by the device to the  
  // core, which can then attach the device to it.  
  //  
      XilImage*            constructControllingImage();  

When a device image is used as a source, the library inserts a device-dependent capture into the current operation sequence and returns the controlling image. When a device image is used as a destination, the library
inserts a copy from the source to the controlling image and then inserts a display operation into the current operation sequence. In the current version of the XIL library, the IO device is responsible for creating the controlling image according to the requirements of the device.
setAttribute() and getAttribute() The setAttribute() and getAttribute() functions provide a way for a device to set and get device-specific attributes from the API.

  //  
  // Set an attribute on the device  
  //  
  XilStatus setAttribute(const char* attribute_name,  
                             void*       value);  
  
  //  
  // Get an attribute from the device  
  //  
  XilStatus getAttribute(const char* attribute_name,  
                             void**      value);  

I/O devices may define attributes that are used to modify or report their behavior. For example, a frame grabber would use attributes to allow the application to select the type of output image or to select which video input to use. A file input device would use attributes to set the path name.

Note - Device image attributes are defined by the port, but some frame-buffer-specific attributes have already been defined for XIL handlers and must be supported.

These attributes are listed in Table 3-1.
Table 3-1
AttributeValue
COLORMAPThe X colormap of the device image (write only)
Table 3-1 (Continued)
AttributeValue
WINDOWThe X window (read only)
DISPLAYThe X display (read only)
COLORSPACEThe color space name
Functions for Readable and/or Writable Devices You must implement two or all four of the following functions depending on whether the device is readable, writable, or both.
  • capture()and getPixel()
  • display() and setPixel()

  //  
  // Is the device readable - if it is readable, then  
  // the capture() and getPixel() functions must be implemented.  
  //  
  Xil_boolean isReadable();  
  
  //  
  // Is the device writable - if it is writable, then the  
  // display() and setPixel() functions must be implemented.  
  //  
  Xil_boolean isWritable();  

If the function isReadable() returns TRUE, the getPixel() and capture() functions must be implemented. If the isWritable() function returns TRUE, the display() and setPixel() functions must be implemented.

  //  
  // Get a pixel from the device  
  //  
  XilStatus getPixel(unsigned int x,  
                     unsigned int y,  
                     float*       data,  
                     unsigned int offset_band,  
                     unsigned int nbands);  
  //  
  // Capture an image from the device  
  //  
  XilStatus capture(XilOp*       op,  
                    unsigned int op_count,  
  //  
  // Display an image on the device  
  //  
  
  XilStatus display(XilOp*       op,  
                    unsigned int op_count,  
                    XilRoi*      roi,  
                    XilBoxList*  bl);  
  //  
  // Set a pixel on the device  
  //  
  XilStatus setPixel(unsigned int x,  
                     unsigned int y,  
                     float*       data,  
                     unsigned int offset_band,  
                     unsigned int nbands);  


Note - capture() would only be implemented if the device is a pull device. For a push device, the class would need to implement startCapture() and stopCapture().

Functions for Double Buffering Devices In addition, for those devices that represent double-buffered devices and whose creation function is constructDoubleBufferedDisplayDevice(), you must implement the functions described in Table 3-2.
Table 3-2
FunctionDescription
getActiveBuffer()Returns the buffer into which data is written
setActiveBuffer()Specifies whether the active buffer is to be set to the front or back
swapBuffers()Moves contents of the back buffer to the front buffer
These functions are shown here.

  //  
  //  Set and get the active buffer state for the device  
  //  and swap back buffer and the front buffer. After a  
  //  swap the contents of the back buffer are UNDEFINED.  
  //  
  //  These are only valid for devices created as a double  
  //  buffering device via the xil_create_double_buffered_window()  
  //  call.  
  //  
  XilStatus       setActiveBuffer(XilBufferId active_buffer);  
  XilBufferId     getActiveBuffer();  
  XilStatus       swapBuffers();  

Optional Device functions

You may choose to overload the hasSubPixelCapture() and hasSubPixelDisplay() functions to implement special functionality with your device. These functions may be implemented as a performance optimization when the device allows less than all bands of a pixel to be updated.
For example, by creating a one-banded child of an RGB image, the user may intend on modifying the 'R' data only of a display image. If the framebuffer allows for sub-pixel updates, XIL uses the following optimal two-step procedure:
  1. It copies the new 'R' band data to the controlling image.

  2. It copies the 'R' band data back to the framebuffer.

If, however, the framebuffer does not allow for sub-pixel updates, XIL uses a three-step procedure:
  1. It captures all bands to the controlling image.

  2. It updates the 'R' data in the controlling image.

  3. It copies all three bands back to the framebuffer.


  //  
  //  Indicate whether the device's capture and display routines  
  //  support sub-pixels.  
  
  //  This means the capture routine supports using the band_offset  
  //  num_bands arguments provided.  The default is that routines  
  //  do not support writing sub portions of pixels to the device.  
  //  
  Xil_boolean     hasSubPixelCapture();  
  Xil_boolean     hasSubPixelDisplay();  

Adding an I/O Device

Adding an I/O device is straightforward in the XIL library. The handler writer must follow these steps:
  1. Choose a name for your device.

    It is recommend that you include your company's stock symbol (if you have one) as part of the name, for example, the Fred framebuffer from the company FRED-FX (FFX) would name the IO device FFXfred.

  2. Create a device manager class, for example, the class name

XilDeviceManagerIOFFXfred.
Implement the static create() function and overload at least one of the
constructors and the two required functions, getDeviceName() and
describeMembers().

  1. Implement the device class for the device, for example, the device class name XilDeviceIOFFXfred.

    Implement the required functions constructControllingImage(), setAttribute(), getAttribute(), isReadable(), and isWritable(). Implement capture(), display(), and get/setPixel() as needed. Implement any of the optional overloaded functions or any molecules as desired.

  2. Identify any new molecules to XIL through use of the xilcompdesc.pl script.

    For pull devices, you must identify display() and capture() in describeMembers(). Push devices do not need to identify capture() but must identify display().

  3. Place the new loadable library file in an application package so that it will be installed in the correct location.

    See the document SunOS Application Packaging and Installation Guide for information on using the package system. Also see Chapter 1, "Overview," for information about packaging handlers.

    The name of the loadable library must be unique; it is strongly suggested that you use xilIO_device_name.so, where device_name is the name that will be used to describe the device in the xil_create_from_device() API call. The xilIO_ portion of this name is required. As an example, for the device name FFXfred, the loadable library name is xilIO_FFXfred.so.