Contained Within
Find More Documentation
Featured Support Resources
| PDF로 이 문서 다운로드
Getting Started
2
- This chapter presents information that you will need as you write your device handler. The following topics are covered:
-
- A quick look at the XGL architecture as it relates to the device handler
- A brief discussion of issues to consider before you begin porting, such as multiple context support and backing store implementation
- Overview information on the porting task, including a summary of how to write an LI-1 device pipeline
- Information on the XGL DDK directory structure
XGL Architecture From the Pipeline Point of View
- The XGL architecture defines two basic components: the device-independent core component and the device-dependent loadable device pipelines. The XGL core functions as the interface between the application program and the device pipelines. The pipelines turn geometric primitives and their state attributes into pixel data that is displayed on a graphics hardware device or written into memory. Figure 2-1 illustrates these basic components:

Figure 2-1
About Device Pipelines
- A device pipeline is composed of two sets of objects:
-
- A set of device objects that work together to form the abstract XGL Device object
- A set of loadable interfaces that send the application data to the hardware
- The set of device objects serve as a framework connecting the device-independent code with the device pipeline rendering code. The loadable interfaces correspond to API primitives at the top level (LI-1), and provide span and pixel renderers at the lower levels (LI-2 and LI-3).
- Conceptually, the pipeline is the sequence of transformations and operations for a graphics primitive. The actual implementation of a pipeline for a specific device will order geometric operations to enhance performance. However, a device may only be capable of enhancing performance under certain conditions. For other conditions, the device pipeline can call the XGL software pipeline, which can handle any valid combination of conditions.
- For a brief description of the loadable interface layers, see Chapter 1, "Introduction to XGL Loadable Interfaces." The remainder of this book provides details on implementing pipelines at these layers.
Services the XGL Core Provides the Device Pipeline
- The XGL device-independent code provides the device pipeline with some useful services. For example, the device-independent code can perform generic error checking, backing store, and deferral mode handling. The device-independent code also keeps track of XGL context state and provides interfaces that allow the device pipeline to retrieve information on attribute settings. In addition, the device-independent code provides the device pipeline with a quick test to determine whether any view model or coordinate system attributes have changed. The device-independent code also includes utilities that the device pipeline can use for computing normal and color values.
- A simple view of the XGL device-independent code and a graphics handler that has implemented a complete LI-1 loadable interface for the API primitive xgl_multipolyline() looks like Figure 2-2. For more information on the XGL architecture and for illustrations of the architecture of the device pipeline, see the XGL Architecture Guide.

Figure 2-2
Issues to Consider Before You Begin Porting
- Before beginning your XGL graphics handler, you need to consider several important issues:
-
- How your graphics handler will support multiple XGL contexts
- How your handler will support backing store
- Whether you need to port Direct Graphics Access (DGA) for your device
- These issues are briefly discussed below.
Device Support for Multiple XGL Contexts
- The term context refers to a set of state information that controls an executing entity. The use of this term can become confusing at times because it can refer to any one of the following:
-
| Hardware context | State information that defines rendering characteristics on graphics accelerators, such as line color or raster operation register values. |
| Process context | State information that controls a UNIX process, such as the program counter, the signal mask, or file descriptors. This state also includes memory mapping information for devices. |
| XGL context | State information that defines the rendering of XGL primitives, such as line color or transforms. |
- A hardware device can be used by many different graphics rendering processes at once. At a minimum, the device will be used by the display server and one XGL client, and there may be other libraries or additional XGL clients using the device as well. Each task maintains a current state or context, such as line color. Since the device is being shared by multiple users, the state must be current for each user before drawing can take place. Thus, your hardware resources must be able to support multiple contexts.
- Because graphics hardware support for context switching is device dependent, state changes resulting from intraprocess switching of XGL contexts must be managed within the device pipeline. Thus, early in the device pipeline design phase, you should consider how your device pipeline will support multiple XGL contexts within a single process.
- Also, multiple processes can access your hardware simultaneously. It is important to define how your device will allocate and share its resources among different processes and different windows within a process. Efficient sharing of hardware resources will enable your pipeline to make better use of the XGL architecture.
Device Support for Backing Store
- Backing store is a mechanism that saves the obscured portions of a window so that the window can be refreshed quickly when it becomes visible again. A backing store is off-screen memory that reflects the contents of the display buffer. This memory is used by the server to automatically restore previously obscured areas of the display during an expose event. Backing store can be handled by your graphics device or by XGL.
- If you can use your graphics device to implement backing store, the device must be able to render graphics into off-screen memory. In addition, in your implementation of the OpenWindows server, you need to enable the backing store feature. A request for backing store support from the server will then allocate backing store memory from your hardware.
- If your device does not support backing store, you can request that the server and XGL handle backing store instead. To use XGL for backing store support, you must implement a small set of device-dependent functions in the pipeline. If your device has a software Z-buffer or accumulation buffer, then the buffer's contents must be shared with the backing store to keep the buffer and its backing store counterparts synchronized, since the server only repairs damage to the display buffer.
- For more information on using XGL to support backing store, see page 57. For information on the architecture of backing store, see the XGL Architecture Guide.
OpenWindows and XGL
- The OpenWindows(TM) environment includes Sun's DGA technology, which arbitrates access to the display screen between XGL and the window system. DGA defines a protocol between the client application (XGL in this case) and the X11 window server that enables both the application and the server to share the underlying graphics hardware.
- When an application is running on the same machine as the OpenWindows server and the hardware has DGA support, XGL uses DGA to synchronize on-screen drawing with the server. For local rendering, DGA allows XGL to send commands directly to the accelerator or frame buffer, substantially improving performance. When the XGL client program is running remotely, XGL uses Xlib or PEXlib for all rendering.
- Depending on your hardware, you may need to port the device-dependent portions of DGA to your hardware. Your device-specific version of DGA enables XGL to render directly to your device. For information on the DGA interfaces, see the X Server Device Developer's Guide.
iv>
Porting Task
- During the initial design phase for a device pipeline, you may want to choose LI-1, LI-2, or LI-3 as the primary interface level for the port. This section presents some guidelines for choosing an interface level to port to and, as an example, provides a brief overview of the steps in porting at the LI-1 level.
Choosing a Loadable Interface Level
- An important decision when you begin your graphics handler is to determine which loadable interface level to begin implementing first. Depending on your goals and your hardware, you may want to begin with LI-1 functions, LI-2 functions, or LI-3 functions. You can also focus on either 2D rendering or 3D rendering because these are different paths. In some cases, the hardware determines the loadable interface level that you port to, as follows:
-
- Consider an LI-1 port if your hardware provides a high level of graphics rendering capability, such as transforms, clipping, lighting, or accelerated scan conversion. Points are input to an LI-1 pipeline in model coordinates, and it is the device pipeline's responsibility to perform all rendering operations, including transforming the point data to device coordinates.
- Plan on an LI-2 port if your hardware is capable of rendering device coordinate primitives but is not capable of performing higher level operations such as depth cueing, transformations, lighting, or clipping. The LI-2 layer is provided for devices that can draw primitives if the device coordinates and color of the object are given and no further processing is required.
-
- Port to LI-3 if your device is a simple frame buffer that provides pixel-based operations but does not provide graphics acceleration. The input to LI-3 is pixel data, and the frame buffer renders in device coordinates. You might also choose to port to LI-3 if you want to do a minimal amount of work to write a device handler for the device. An LI-3 pipeline relies on the software pipeline geometric and rendering functions to feed the pixel-level interface at the LI-3 level.
- If you are writing a pipeline for a high-level graphics device, you may begin by implementing the basic put-pixel and get-pixel interfaces at the LI-3 level or by implementing one or more accelerated pipelines at the LI-1 level. There is no particular layer that you must begin with, but there are performance trade-offs to consider.
Starting With an LI-3 Level Port
- A good way to begin, even for an LI-1 port, is to start work on the LI-3 level using the LI-3 utility object RefDpCtx (Reference Device Pipeline Context). To implement the LI-3 layer with this object, you simply write functions to store the value of a pixel (set-pixel) and to retrieve the value of a pixel (get-pixel). Then you can call the LI-3 primitives using the interfaces provided with the RefDpCtx utility. XGL will only use your LI-3 device pipeline port at the end of a rendering operation. The XGL software pipeline will handle all other operations required for rendering.
- Using RefDpCtx to implement LI-3 is the simplest, quickest route for porting XGL to your hardware. With the LI-3 level implemented in this way, you can begin working on window system interactions with DGA and on verifying your port using the Denizen test suite. (See the XGL Test Suite User's Guide for information on the Denizen test suite.)
- Porting to the LI-3 level provides breadth of functionality rather than performance. This is the approach to take if your primary goal is to port XGL quickly to see your device running an XGL application. An LI-3 port is advantageous during the early stages of implementing a device pipeline because it produces full XGL functionality with a minimal amount of effort by the porting team. Then to improve performance, you can concentrate on the primitives that you decide are most important and rewrite their implementation at the LI-1 or LI-2 interface level.
Starting With an LI-1 Level Port
- An alternate approach is to focus on accelerated rendering and begin with LI-1 primitives. If you have a graphics device with a high degree of functionality, you may choose to implement a complete primitive at the LI-1 level, in effect bypassing the lower levels. For example, if your hardware is designed to render triangles at high speed, it may be more advantageous to implement triangle renderers and the LI-1 triangle primitives than to implement a pixel interface at LI-3. Your device implements the triangle strip primitive at the LI-1 level by executing all of the operations of the rendering pipeline on the device. When the device is unable to handle a particular situation, for example dithering with a color cube, it can fall back to the software pipeline for the function specific to that situation.
- Writing a set of LI-1 level interfaces is not a simple task and can require significant time and resources. Optimizing the code for maximum performance will require even more development time. One way to organize work at the LI-1 level is to focus on a single area of acceleration, polylines for example, and implement the LI-1 level primitive for that area. With this approach, you can identify design problems early. Once the LI-1 primitive is performing well, you can implement more LI-1 primitives using the design that you have developed for the first primitive.
Starting With an LI-2 Level Port
- If you are writing loadable interfaces for a device that renders in device coordinates only, you will implement LI-2 and LI-3 level interfaces and will not implement interfaces at the LI-1 level. In this case, you can choose whether to begin with the LI-2 layer or the LI-3 layer. As mentioned above, implementing LI-3 through RefDpCtx provides complete functionality in a relatively short time.
A Quick Look at Implementing an XGL Graphics Handler
- Implementing an XGL graphics handler is a large project consisting of the following general steps:
-
- Decide which XGL primitives and attributes your hardware can accelerate.
- Write the xgli_create_PipeLib() routine, which creates a device pipeline library object for your device.
- Derive the set of classes that provide the device pipeline framework.
- Choose a simple primitive to implement.
- Implement software pipeline calls, if necessary.
- Determine how to handle attribute processing.
- Implement primitives not provided by the software pipeline.
- Implement error handling.
- Test your implementation with the Denizen Test Suite.
- These steps are briefly described in this section. While this section may make the task of writing a graphics handler seem simpler than it actually is, it is meant to help you divide the porting task into manageable subtasks or concepts. Each step includes references to later chapters that include the information needed to complete the task.
· Decide which XGL primitives and attributes your hardware can accelerate.
- To determine which of the primitives and attributes your hardware can accelerate, consider the capabilities of your hardware and examine the scope of XGL functionality in the XGL Reference Manual and in Chapter 8, Chapter 9, and Chapter 10 of this book. Most likely you cannot implement all the XGL functionality on your device, so you may want to focus on implementing only those features that your hardware can accelerate.
- For those primitive-attribute combinations that your pipeline cannot handle, you can call the software pipeline for processing. To decide which primitives to implement in your pipeline, consider the kind of applications you are targeting with your device and the features that should be accelerated for those applications. Early identification of what to implement in your device pipeline will facilitate the process of porting XGL to your device.
· Write the xgli_create_PipeLib() routine.
- Each graphics handler must include a routine that creates an instance of the XGL device pipeline library object corresponding to the pipeline. This routine. xgli_create_PipeLib(), is called through dlsym() after the device pipeline is dynamically loaded. See Chapter 3, "Pipeline Interface Classes," for information on this routine and for information on naming your handler so that XGL device initialization functions can load the it at runtime.
· Derive the set of classes that provide the device pipeline framework.
- XGL provides a set of classes that, when derived by the pipeline, provide a framework linking the pipeline to the XGL device-independent code. Briefly, the XGL-provided classes are:
-
- XglDpLib - Maps to the shared library for your device.
- XglDpMgr - Maintains information about the physical device. You may want to put your device initialization routines in this class.
- XglDpDev - Constitutes the device-dependent part of the XGL Device object.
- XglDpCtx2d and XglDpCtx3d - Constitute the device-dependent part of the XGL Context object. These classes contain the loadable interfaces that the device implements.
- These classes have a number of methods that you are required to implement as well as optional methods, such as the LI-1 and LI-2 loadable interfaces. For detailed information on creating the device pipeline derived classes and objects, see Chapter 3, "Pipeline Interface Classes." For a summary of the required and optional methods in the device pipeline classes, see page 66. For information and illustrations on the architecture of the device pipeline, see the XGL Architecture Guide.
- You also need to consider your approach to implementing DGA. When you have implemented DGA and the device pipeline classes, you will be able to create an X window and open an XGL Device object on it.
· Choose a simple primitive to implement.
- Once a window is available to render to, you can implement a primitive, such as xgl_multipolyline(). The goal for this step is to render a simple piece of geometry, such as a line, on your hardware. To do this, you need to process the geometric data, converting it to a format appropriate for your hardware. You may also need to work out a way to initialize your hardware for each primitive.
- Note that some window information, in particular the window clip list, is critical data. This means that it cannot be modified by another process while XGL is using it. The device pipeline must lock critical window data structures before rendering and unlock them when rendering is complete. This prevents the server from making changes to these data structures while an XGL rendering operation is taking place. For more information on XGL's interface to the window system, see Chapter 7, "Window System Interactions."
- Once you have succeeded in rendering geometry on your device, you have completed the important milestone of getting XGL to communicate with your hardware.
· Implement software pipeline calls, if necessary.
- At each LI-1 and LI-2 rendering call, the device pipeline must determine whether it can proceed. If it can render the geometry, in most cases it will take control and render to the hardware at that point. If the device pipeline cannot perform the LI-1 or LI-2 processing, the device pipeline can call the software pipeline to process the primitive. For information and example code on how to call the software pipeline, see "Calling the Software Pipeline" on page 50. For more specific information on the using the software pipeline at the LI-1 or LI-2 levels, see Chapter 9 and Chapter 10.
· Determine how to handle attribute processing.
- Each XGL primitive has a set of attributes that affects it. The pipeline gets the attribute settings from the Context object. A pipeline can improve performance for attribute handling by using the pipeline objectSet() and messageReceive() functions. For information on these functions and on other issues to consider as you implement attribute handling, see Chapter 4, "Handling Changes to Object State."
- When handling attribute changes, be aware that techniques that work for a simple primitive, such as multipolyline, may not work for more complex primitives, such as surface primitives. If you determine that your device cannot handle the current attribute setting for a primitive, you can fall back to the software pipeline for rendering.
- At this time, you will also want to consider how to handle view model changes and coordinate system changes. XGL provides the view model derived data facility to assist you in implementing view model operations. Using derived data, you can set up objects that track the derived items important to your pipeline. For information on the processing of view model and coordinate system changes, see Chapter 6, "View Model Derived Data."
- You may have to map the XGL attributes to attributes specific to your hardware so that the appropriate rendering occurs. Once you have determined what attributes you need to handle and how to handle them, you should think about how to structure the pipeline for performance. How you do this depends on how your hardware saves Context state values.
- Your pipeline must also manage state changes that may result when the application changes the Context it is using to render. Chapter 4, "Handling Changes to Object State" provides a brief discussion on context switching and hardware state updating and also provides information on handling the updating of state when the pipeline switches between interface layers. There are several pitfalls that you may encounter when switching loadable interface layers. Solving these design problems early in the porting process will simplify your overall task.
- When you reach this point, you have worked through most of the porting process for a geometry operator. You should be familiar with problems that you need to resolve. At this point, you can look into implementing other types of functions, including functions that the XGL software pipeline does not provide, such as the xgl_context_new_frame() operator.
· Implement primitives not provided by the software pipeline.
- There is a small subset of device-dependent operators that XGL does not implement in the software pipeline. The xgl_context_new_frame() operator is one of these operators. The new frame operator clears the screen and may be required each time rendering occurs. You may want to implement xgl_context_new_frame() early in your development schedule.
- Another primitive that the device pipeline must provide is xgl_context_copy_buffer(). Implementing a pixel operator after a geometry primitive will help you understand the range of possible functions that you must handle.
· Implement error handling.
- XGL provides an error-reporting mechanism that is used when an error is detected during the execution of an XGL application. If you want an error to be reported to the application, you must explicitly add code to the device pipeline to handle error conditions. For information on adding error processing to a device pipeline, see Chapter 11, "Error Handling."
· Test Your Implementation.
- To verify that your graphics handler produces images that conform to XGL's reference images, run the Denizen Test Suite, which is supplied with the XGL DDK. The Denizen Test Suite is a group of shell scripts and C programs designed to use the XGL library to render objects and evaluate results. Denizen contains approximately 600 test programs that test every XGL function and the major internal components of the XGL library.
- The first time you run the Denizen Test Suite, you will generate a set of reference images for your hardware. Compare your pipeline's reference images with the cg3, cg8, and GX reference images provided with the XGL DDK to ensure that the images generated by your device are generally similar to the cg3, cg8, or GX reference images. Note, however, that reference images may vary across hardware platforms. The images generated for each platform should be similar, but they may not be identical pixel-by-pixel, since different hardware may touch different pixels. It is up to you to determine whether the differences between the XGL-provided reference images and your pipeline references images are acceptable.
- Your device handler should produce Denizen pass rates similar to those measured for Sun's reference frame buffers (8- and 24-bit nonaccelerated frame buffers). The Denizen Test Suite is not intended to be a debugging tool but a verification tool to help you ensure the accuracy of your implementation. For information on using the Denizen Test Suite, see the XGL Test Suite User's Guide.
-
Figure 2-3 summarizes the basic steps in the process of implementing an XGL graphics handler.

Figure 2-3
Device Pipeline Makefiles
- The XGL DDK provides the makefiles for the reference pipelines in the pipeline source directories. To create a makefile for your pipeline, copy the Skeleton pipeline makefile in
-
DDK_DIR/SUNWddk/ddk_2.5.1/xgl/src/dd/skeleton and change the source file names to the names of your pipeline's source files.
- The XGL DDK provides a set of predefined targets that you can use to build your pipeline. For example, the make debug command builds an debuggable pipeline. Table 2-1 lists the XGL DDK make targets.
-
Table 2-1
| Target | Description |
| opt | Builds an optimized pipeline. |
| debug | Builds a source-level debuggable pipeline. You can debug the program with the SPARCworks or ProWorks Debugger or dbx. |
| opt-sb | Builds an optimized pipeline with source browser information. You can analyze the program with the SPARCworks or ProWorks SourceBrowser tool. |
| debug-sb | Builds a debuggable pipeline with additional source browser information. |
| tcov | Builds a pipeline with tcov information. You can run any test or application program to gather test coverage data. |
-
Note - A pipeline cannot be debugged until it is dynamically loaded by an application.
Directory Structure for the XGL DDK
-
Figure 2-4 illustrates the XGL DDK directory structure. The XGL DDK package includes sample source code for the XGL reference loadable device pipelines.

Figure 2-4
-
Note - If you run the Solaris PEX product, PEX expects the XGL library and the XGL pipelines to be in the default runtime location of /opt/SUNWits/Graphics-sw/xgl. Therefore, when you are developing your pipelines, create a symbolic link from the runtime area to your pipeline in the DDK area.
Accessing External Files at Runtime
- The XGL system may require external files during the execution of an XGL application. For example, the device pipelines are dynamically-loaded shared object files that must exist in a directory tree in a location known to XGL so that XGL can load them. The XGL library also requires external files for the error messages and stroke fonts. These external files exist within the directory tree that is created when the XGL files are installed. The top of this directory tree is pointed to by the XGLHOME environment variable. The value of XGLHOME is used internally by XGL when it searches for any of the external files.
- To retrieve the value of XGLHOME from the XGL device-independent code, use the static function XglGlobalState::getXglHome() as shown below.
-
-
const char* xgli_home;
xgli_home = XglGlobalState::getXglHome();
-
Note - If an application is running remotely and the server has loaded the PEX extension, XGLHOME is not used to load device pipelines; however, XGLHOME is used to load font files and error message files.
|
|