The traditional model for rasterizing a frame of vector graphics typically involves processing and blending a single graphics instruction (primitive) at a time into a back buffer, and presenting (or blt-ing, sometimes referred to as blit-ing) the back buffer to a display area. However, this model of drawing each primitive one at a time to a back buffer has a number of problems, particularly regarding storage and performance.
For example, when multiple primitives are each directed to writing to the same pixel, that is, when primitives correspond to overlapping pixels, at least some pixels are blended to the back buffer multiple times, sometimes referred to as overdraw, potentially causing performance-related bottlenecks. For example, one primitive may be for drawing a background in one color, another primitive for drawing a differently-colored rectangle that appears in front of that background, yet another primitive for drawing a box such as corresponding to a button within the rectangle, and so forth. Some primitives require reading previous pixel data from the buffer, blending it in some way with corresponding pixel data specified by another primitive, and writing the blend back to the buffer. The blend operations thus often involve read-modify-write operations that are significantly slower than write operations. A typical software application may require three to six passes through the memory, many of which are read-modify-write blends, which are slow. For example, even with simple shapes where memory bandwidth is equal to the speed of the rasterizer, this overdraw factor of three to six is indeed a performance bottleneck, often causing the perceived performance of the application program to be below acceptable levels. For other applications that have more layers and more blending, this overdraw factor can be much larger than three to six times the display area. The blend is even more expensive if the independent objects have complex brushes, materials, or textures.
Another problem results when dealing with format conversion to a destination surface of fewer bits. Doing so requires an extra pass, or results in a loss of precision during blending.
Further, independently drawing primitives while enabling features such as full-scene anti-aliasing often requires a large amount of storage for the back buffer. This extra storage substantially increases the memory usage and the amount of time needed to rasterize. To reduce the amount of memory allocated for the back buffer, tiling techniques may be used, but such an approach increases the number of passes required. For three-dimensional situations, an extra z-buffer is required to store depth information. There is a memory bandwidth cost (and memory cost) to reading and writing to that surface as well.
Other problems with this model result from effects on groups of primitives, such as opacity effects or anti-aliased clipping that typically involve creating temporary surfaces for grouping. For example, consider applying a later-processed opacity-related primitive to pixel data that form a blue rectangle over a red surface. To do this correctly, a rasterizer first needs to treat the blue and red data together as a group, because if handled separately on each piece of data, the opacity would effectively be applied to a purple rectangle. To treat such data as a group, a temporary surface is required, which again takes memory, sometimes substantial memory, and can be extremely slow.
This Summary is provided to introduce a selection of representative concepts in a simplified form that are further described below in the Detailed Description. This Summary is not intended to identify key features or essential features of the claimed subject matter, nor is it intended to be used in any way that would limit the scope of the claimed subject matter.
Briefly, various aspects of the subject matter described herein are directed towards a rasterizer that processes a set of graphics primitives into entries into a vector buffer having an array of entries, with each entry representing a scanline. For each primitive, an entry is made in the vector buffer to point to a data structure associated with that primitive, with a linked-list or the like created when multiple primitives enter on the same scanline. When the vector buffer includes the pointers, the rasterizer walks the entries to determine which primitive or primitives affect a selected scanline, and for the selected scanline, to draw pixels for the scanline by processing drawing information associated with each primitive that affects that scanline.
Thus, by adding data to a vector buffer to represent how one or more graphics-related primitives affect a scanline, the vector buffer may be processed on a per-scanline basis to obtain drawing data corresponding to each primitive, to draw at least a segment of the scanline to a destination surface based on the drawing data, e.g., including brush information and a primitive drawing order. In general, a scanline is selected and drawn, such as by drawing segments determined from where the primitives horizontally start and end on that scanline, and the process repeated for each scanline until an entire image is drawn.
Other advantages may become apparent from the following detailed description when taken in conjunction with the drawings.
The present invention is illustrated by way of example and not limited in the accompanying figures in which like reference numerals indicate similar elements and in which:
Exemplary Operating Environment
The invention is operational with numerous other general purpose or special purpose computing system environments or configurations. Examples of well known computing systems, environments, and/or configurations that may be suitable for use with the invention include, but are not limited to: personal computers, server computers, hand-held or laptop devices, tablet devices, multiprocessor systems, microprocessor-based systems, set top boxes, programmable consumer electronics, network PCs, minicomputers, mainframe computers, distributed computing environments that include any of the above systems or devices, and the like.
The invention may be described in the general context of computer-executable instructions, such as program modules, being executed by a computer. Generally, program modules include routines, programs, objects, components, data structures, and so forth, which perform particular tasks or implement particular abstract data types. The invention may also be practiced in distributed computing environments where tasks are performed by remote processing devices that are linked through a communications network. In a distributed computing environment, program modules may be located in local and/or remote computer storage media including memory storage devices.
With reference to
The computer 110 typically includes a variety of computer-readable media. Computer-readable media can be any available media that can be accessed by the computer 110 and includes both volatile and nonvolatile media, and removable and non-removable media. By way of example, and not limitation, computer-readable media may comprise computer storage media and communication media. Computer storage media includes volatile and nonvolatile, removable and non-removable media implemented in any method or technology for storage of information such as computer-readable instructions, data structures, program modules or other data. Computer storage media includes, but is not limited to, RAM, ROM, EEPROM, flash memory or other memory technology, CD-ROM, digital versatile disks (DVD) or other optical disk storage, magnetic cassettes, magnetic tape, magnetic disk storage or other magnetic storage devices, or any other medium which can be used to store the desired information and which can accessed by the computer 110. Communication media typically embodies computer-readable instructions, data structures, program modules or other data in a modulated data signal such as a carrier wave or other transport mechanism and includes any information delivery media. The term “modulated data signal” means a signal that has one or more of its characteristics set or changed in such a manner as to encode information in the signal. By way of example, and not limitation, communication media includes wired media such as a wired network or direct-wired connection, and wireless media such as acoustic, RF, infrared and other wireless media. Combinations of the any of the above should also be included within the scope of computer-readable media.
The system memory 130 includes computer storage media in the form of volatile and/or nonvolatile memory such as read only memory (ROM) 131 and random access memory (RAM) 132. A basic input/output system 133 (BIOS), containing the basic routines that help to transfer information between elements within computer 110, such as during start-up, is typically stored in ROM 131. RAM 132 typically contains data and/or program modules that are immediately accessible to and/or presently being operated on by processing unit 120. By way of example, and not limitation,
The computer 110 may also include other removable/non-removable, volatile/nonvolatile computer storage media. By way of example only,
The drives and their associated computer storage media, described above and illustrated in
The computer 110 may operate in a networked environment using logical connections to one or more remote computers, such as a remote computer 180. The remote computer 180 may be a personal computer, a server, a router, a network PC, a peer device or other common network node, and typically includes many or all of the elements described above relative to the computer 110, although only a memory storage device 181 has been illustrated in
When used in a LAN networking environment, the computer 110 is connected to the LAN 171 through a network interface or adapter 170. When used in a WAN networking environment, the computer 110 typically includes a modem 172 or other means for establishing communications over the WAN 173, such as the Internet. The modem 172, which may be internal or external, may be connected to the system bus 121 via the user input interface 160 or other appropriate mechanism. In a networked environment, program modules depicted relative to the computer 110, or portions thereof, may be stored in the remote memory storage device. By way of example, and not limitation,
An auxiliary display subsystem 199 may be connected via the user interface 160 to allow data such as program content, system status and event notifications to be provided to the user, even if the main portions of the computer system are in a low power state. The auxiliary display subsystem 199 may be connected to the modem 172 and/or network interface 170 to allow communication between these systems while the main processing unit 120 is in a low power state.
Write-Once Vector and Triangle Rasterization
Various aspects of the technology described herein are directed towards a technology by which a rasterizer combines information from graphics primitives prior to writing any pixel such that each pixel need be written only once to a back buffer, and indeed may instead be written directly to video memory or the like. As a result of combining the primitives' information, many of the existing problems with conventional rasterizing are solved, including requiring no additional storage (or at most a single back buffer), and eliminating overwriting, greatly improving performance. Note that the technology is applicable to sub-pixel output as well.
While significant benefits are achieved in efficient and high-quality display output, the mechanisms described herein can also be used to enable efficient printing of content. As described herein, because the process eliminates overdraw/overlap, it removes the need for excess memory or difficult composition on the printer. Indeed, any technology that processes instructions or the like to write bits (or sets of bits) to an output surface such as a memory may benefit from the concepts described herein.
One solution described herein accomplishes write-once rasterization by building a data structure or structures that enables the rasterizer to determine all paths/triangles (including materials/brushes/textures) that contribute to a particular pixel. With this data structure, the rasterizer can conceptually walk each destination pixel exactly once, independent of the complexity of the scene being rendered. As described below, for each pixel, the rasterizer may compute a destination color by performing the appropriate math on the sources that contribute.
In one example implementation, the computed color is determined and written out, and the rasterizer advances to the next pixel. The process is repeated for each horizontal line (scanline) of pixels to be written out, and the scanlines may be processed in any order, although typically they would be processed from the uppermost scanline to the lowest scanline. Note that because scanlines are processed, (as opposed to writing and possibly blending the result of each primitive), multiple processors can easily be arranged perform these computations in parallel, by simply dividing up the scanlines to be handled by each. For example, this technology may be implemented on multiple-core processing units, by having different cores work on different scanlines.
While the example rasterizer described herein thus outputs pixel data via horizontal scanlines, typically from top to bottom, it is equivalent to have a rasterizer arranged to process pixels in vertically lines, and, for example, move to the next vertical line, such as left to right. This may be valuable, for example, such as by being more efficient in a model where a display is arranged to show its output in a portrait orientation instead of a landscape orientation, or vice-versa. The concepts described herein thus apply to any orientation of a scanline.
Turning to
As described below, the rasterizer 202 includes a mechanism, comprising an algorithm that walks the primitives and builds up one or more data structures 214 in order to obtain the pixel data for each, such that the pixel need only be written once to an output destination surface 216, e.g., to video memory, to AGP memory, and/or to a system memory back buffer. Shown for completeness in
By way of a straightforward example, consider the rendered image 322 represented in
Continuing with the example, a second primitive P2 draws a different, white-colored rectangle (labeled P2 in a circled label which is not part of the image 322) that spans from horizontal (X-coordinates) 100 to 900, and from vertical coordinates (Y-coordinates) 100 to 800. Because the primitives are in order, the rasterizer knows to draw this primitive P2 rectangle over the P1 rectangle. It is alternatively feasible in two-dimensions to have a z-order with each primitive that can be sorted to get them into a desired order. As also represented in
As described above, a conventional rasterizer would separately draw to a buffer for each primitive, overwriting P1 with P2 where they overlap, and then overwriting P2 with pixel data based on primitive P3. Also, P3 would have to overwrite P1's pixels, if, in a modified example to that of
In contrast, the rasterizer 202 described herein processes the primitives in a manner that allows each pixel to be written once and only once to the destination surface 216 (
In general, the rasterizer 202 walks each primitive in the set 204 to be drawn for a frame, and for that primitive, adds an entry to a scanline-indexed data structure (e.g., array) referred to herein as a vector buffer 430 (
In the example of
As multiple primitives may affect a scanline, one suitable mechanism used to track how primitives are ordered with respect to one another is a linked list, where the vector buffer 430 points to the primitive's data structure of the most recent primitive that affected that scanline, with the primitive's data structure pointing to the next most recent primitive data structure, and so forth until no other such primitive exists (NULL pointer). Other mechanisms are feasible, (such as by linking from the next most recent to the most recent, instead of from the most recent the next most recent).
Using the example of
When the primitive P2 is processed, P2 also affects the scanlines starting at scanline entry 100. This is the state represented in
All other primitives are similarly processed in order, until none remain, which in this example is only P1-P3. The result is a set of rasterizer paths, containing at least one primitive's data structure possibly linked to one or more additional primitive's data structures.
Step 604 initializes the data structure of the selected primitive, e.g., including to compute the start and end y-values that correspond to a range of scanlines, based on the drawing data (e.g., the geometry and starting coordinates) associated with the primitives. Other information that may be copied into the primitive data structure includes data such as brush-related information (e.g., solid/gradient and color data), effects data and so forth, although this information may be obtained from the primitive at a later time. Note that a vertical gradient may be treated as a solid color for that scanline, that is, it does not vary horizontally.
Steps 606, 608610 and 612 represent setting the pointer in the vector buffer's entry for the current scanline to point to the selected primitive's data structure, preserving any prior pointer data at step 610, that is, by creating a linked list as necessary. First, step 606 moves to the entry location where the selected primitive enters on a scanline. Step 608 determines if there is a NULL at this entry location; if not, there is a pointer to another primitive's data structure, and step 610 copies this existing pointer into the Next field of the selected primitive's data structure to maintain the linked list. Then at step 612 the process writes the pointer to the selected primitive's data structure over that now-copied entry into the vector buffer 430. Note that if at step 610 the pointer was NULL, step 610 is bypassed to write the pointer to the selected primitive's data structure over the NULL at step 612.
When a given primitive is handled in this manner, steps 614 and 616 select the next primitive as the selected primitive and loop back for similar processing for that primitive's first affected scanline, until all primitives have been handled. Thus, in the example of
Once the primitives are processed, the vector buffer 430 contains the pointers that point to the primitives' respective data structures, that each in turn will include a pointer to another primitive's data structure when necessary, forming a linked list. At this time, the scanlines can be built using the data of any primitive that affects the scanline.
In one implementation, the primitives are merged into a single list, as the rasterizer 202 performs a scanline walk, to make segments as described below. The current scanline has a list of “active primitives” that are kept in draw order.
For example, a vector buffer may be stored as set forth below, forming a structure that is linked and scanline indexed, (where AddPath corresponds to inserting a link in the scanline in which the path begins; this insertion is a fast constant time operation):
As should be understood, the vector buffer 430 allows multiple paths to be added in draw order, one at a time. As described below, once the paths are known, a list of path segments needed for a specific scanline are obtained. The scanline-indexed array of path pointers described via
Assuming four byte pointers, the vector buffer costs four bytes per scanline (i.e., 4 k for 1,000 scanlines) and eight bytes per path object of memory. The flattened edge store is usually retained independently of this algorithm to avoid flattening/widening of paths on every frame, so its cost is not included here. However, if the flattened edge store is not retained in a particular rendering system, it can be generated when a path enters a set of scanlines, and destroyed when it leaves.
When the vector buffer 430 including its paths is prepared, the rasterizer 202 sweeps, e.g., from the top scanline to the bottom scanline, knowing which paths enter on each scanline. With this information, the rasterizer 202 walks from top scanline to bottom, and knows the paths that intersect each scanline by merging the paths from the previous scanline with those from the current scanline. Note that the rasterizer also needs to remove paths that have already completed rasterization in this process.
Steps 706 and 708 remove any primitive that ends on the currently selected scanline from the active list 940. Step 710 and 712 repeat the process for the remaining scanlines to be walked. Thus, in the example of
Once the rasterizer 202 knows the paths for a particular scanline, the rasterizer 202 also knows the edges for that scanline. More particularly, each primitive has an associated edge list 940 (
Edges are kept on the path in y-sorted order, and can be linked during the vertical sweep, so the rasterizer only needs to advance and update edges for the paths as the rasterizer advances a single scanline.
Once the rasterizer knows the edges for a particular scanline, the rasterizer then needs to rasterize. For aliased content, this may be accomplished simply by sorting the edges for a current scanline by x-value, tracking brush data, and walking from left to right writing pixels, as described below via the flow diagram of
Given that the rasterizer 202 knows the sets of edges for each scanline, when returning to the example of
As represented in the combined segments 1050 of
The next segment, from 100 to 199, is a combination of P2's data with P1's data, with P2's data known to be atop P1's data. Any alpha blending will require that the brushes from each be mathematically combined. However, for single color brushes, the computation can be done for only the first pixel with a result that applies to the rest of pixels for that segment, providing efficient computations. Also for efficiency, occluded brush data is not drawn; since the brush stack represents all the brushes for a segment in the frame, the rasterizer simply stops processing brushes when the rasterizer hits a completely solid brush with no alpha data.
Step 806 represents selecting the lowest brush that is solid (has no opacity), based on the draw order, or the selecting of the lowest brush if none are solid. This step essentially selects the lowest brush that need be drawn, because nothing will appear below a solid brush. Steps 810 and 812 blend any higher brush or brushes with the lowest brush that was drawn, until none remain and that segment is drawn. When the segment is complete, steps 814 and 816 repeat the process for any other segments.
In the example of
It should be noted that the blending can occur in various ways. For example, if the destination surface is a back buffer, then the blending can be performed simply by writing the lowest brush to the appropriate location in the back buffer memory, writing the next lowest brush over it and so forth, until no brushes remain to be blended and the process can move to the next segment (or next scanline if completing the last segment). Again, if the brush data corresponds to a single solid color, this blending computation can be done once and the result extended to the rest of the segment. However, two or more transparent gradients will require computing over the various segments' pixels. Note that if the ultimate destination surface is in video memory, a scratch scanline is used for the blending, essentially as a one-line back buffer, so that temporary writes and blends while filling the segment with combined pixels are not temporarily visible. Instead, the scratch scanline's pixel data are copied to video memory when the blending is complete.
The above description was primarily directed towards a single processor handling all of the scanlines with respect to building the vector buffer, although it is understood that as mentioned above, any number of processors can then rasterize the scanlines. However, multiple processors/a multiple-core processor can provide additional efficiency, not just in rendering a subset of the scanlines from its corresponding subset of the vector buffer, but in an alternative implementation by building its own scanline data and/or vector buffer data. By way of example, if a processor processes the primitives to determine which primitive affects a given scanline, (including those that do not necessarily start on the scanline), then that processor may draw as little as a single scanline, without any need to know and merge what was above it. In other words, each processor would just process the set of primitives to determine which primitive or primitives affected (and not just entered) that processor's corresponding scanline or scanlines, and draw as described above. Note that in an implementation where each processor handles a subset of scanlines, (e.g., one processor handled scanlines 100-200), the processor can determine from the primitives which one(s) entered or affected the processor's highest scanline, e.g., entered at 100 or entered above 100 without ending above 100, and then use the “entry-only” technique for primitives that first enter at lines 101-200.
While the above mechanism for aliased content is thus relatively straightforward to implement, for anti-aliased content such as for sharpening diagonal and curved lines, there are several edge-related situations that require additional processing. In general, edges may be present between the pixels of a scanline; edges may end in the middle of scanline, so there is not a unique edge order for a specific scanline, edges may begin in the middle of a scanline and edges may cross and reorder.
To handle anti-aliased content, typically only the edges are drawn anti-aliased, with aliased content drawn between the edges. With the rasterizer described herein, full scene anti-aliasing may be accomplished by use of sub-scanlines, with weighted contributions from the edges of adjacent segments mathematically combined into a single resultant pixel value. For example, with 8×8 anti-aliasing, eight sub-scanlines can be built as in
In an alternative implementation, a coverage buffer is used by the anti-aliased rasterizer, wherein the coverage buffer indicates how much a pixel is covered by an edge. The path edges are thus rasterized at the anti-aliasing resolution into a coverage buffer containing the anti-aliasing information.
As represented in
Note that the rasterizer already has a coverage buffer data structure (used for standard anti-aliased vector rasterization) that can accurately resolve the sub-pixel detail for a single path as well as the other situations mentioned above. As a result, to rasterize a scanline, the rasterizer computes the coverage buffer for each path (for the portion that intersects the current scanline) and adds it to a virtual color buffer that has the instructions needed to rasterize a scanline.
More particularly, an example frame rasterization function comprises:
The color buffer is also a virtual buffer that contains entries on the order of the edge-complexity of the scanline. Conceptually, the color buffer is just a list of instructions indicating how to fill a scanline. As paths are visited, their anti-aliasing information is computed in a virtual coverage buffer which is merged (with brush information) into the virtual color buffer. An example color buffer implementation is set forth in the below linked list of non-overlapping segments representing a scanline of color data:
Note that the color buffer linked list would have increasing x-values and conceptually represent a list of non-overlapping segments to rasterize. By keeping the color buffer as a list of segments, the rasterizer has a number of advantages, including that the blending of solid colors is done on edges of spans rather than per-pixel. Further, as described above, occluded brush data is never drawn, as brush processing halts when the rasterizer hits a completely solid brush with no alpha data.
Moreover, since the color buffer stores the path data for a single scanline for a frame, the rasterizer is guaranteed at most one write to the destination surface 216. The write once rasterizer 202 has a number of advantages over other models, including the elimination of overdraw, as well as being able to write to any destination surface including video memory, AGP memory, or a system memory back buffer. More particularly, because of writing only once to each pixel in surface scanline order, it is reasonably efficient to draw directly to video memory since the rasterizer has no costly read (for read-modify-write type) operations and only one write. The rasterizer can also write directly to the primary display surface without structural tearing. Still further, because the rasterizer knows the full set of primitives that contribute to a pixel, the rasterizer can perform full-scene anti-aliasing without incurring extra surface memory cost and/or without the stitching artifacts in per-primitive anti-aliasing. Still further, because each pixel is only written once (and sources are blended at full precision), the pixel color can be converted to lower bit-depths on-the-fly without having to take an extra format conversion pass.
Turning to a consideration of how the rasterizer may be extended to support three-dimensional triangle rasterization, z-information is added to the color buffer, and this information used when merging the virtual geometry data into the color buffer. For three-dimensional content, since the rasterizer knows the triangles that contribute to a pixel, the rasterizer can resolve occlusion without having to use a z-buffer.
More particularly, the state of a triangle (e.g., pixel shader, Gauraud shaded, texture and so forth) corresponds to a primitive, and instead of using a draw order, the triangles are sorted by Z-order. Thus, the above virtual buffer structure and color buffer can be used for three-dimensional triangles, and for purposes of processing data into one or more pixels of a scanline, a triangle can be considered equivalent to a primitive, where appropriate.
However, a triangle can have its z-order vary, as represented in
Another way in which the write-once rasterizer may have extended functionality is to provide support for effects on groups of primitives, such as opacity effects, anti-aliased clip, or other effects. For example, consider applying fifth-percent opacity to a solid blue rectangle above a red rectangle. If their primitives are not treated as a group, the blue and red rectangles would each be made half-transparent, resulting in the blue rectangle becoming purple because it would show some red through it, when what is actually desired was a single blue over red group, with the group half-transparent.
With conventional rasterization, such effects typically required creating and clearing a temporary surface, drawing the primitives (to which the rasterizer will apply the effect) to that surface, drawing a path with that surface selected as a brush to the back buffer with specified effects applied, and discarding the temporary surface. This resulted in very bad performance and memory usage due to overdraw, which could become unacceptable with certain shapes such as a group of slanted rectangles.
With the write-once rasterizer, the rasterizer performs different steps, on each destination scanline rather than for each primitive. In general, each primitive of a group is given a layer identifier that is associated with an opacity value, as generally represented in
To draw the group, a new primitive is created and introduced with the bounds of the shape for the group, with a brush that corresponds to the layer. Thus, primitive X may have a layer pointer that points to layer 1, as may primitive Y. More particularly, the write-once rasterizer creates a virtual color buffer (Prim Z in
The rasterizer then draws the primitives into the virtual color buffer, and merges the virtual color buffer into the main color buffer (using the path data as a virtual mask if needed). The color buffer is then rasterized. When rasterizing, the lowest layer (e.g., layer 0) is drawn first. In the event that a segment is determined to have a layer for its brush, as in the path that includes Primitive Z, that brush can be rasterized to a temporary scratch scanline, with effects applied to the temporary scanline. Only the scratch scanline needs to be allocated, rather than a block of memory that bounds an entire primitive.
A still more efficient technique merges pointers to the linked list, although this only applies to certain situations. Consider an example with primitive P1 and P2, and primitive 0 below them, where primitives P1 and P2 are to be drawn with a 0.5 alpha transparency. If primitive P1 is known to be occluded, (e.g., the red is occluded by the solid color blue segment which the rasterizer can determine) the stacks can be merged to essentially eliminate this red segment. If P2 needs to be blended with P1, then the merging cannot be accomplished and the temporary scratch scanline needs to be used.
A key advantage for effects is that the rasterizer can work in virtual buffers, which are on the order of the edge-complexity of the scene, and avoid per-pixel operations as would be required with a surface clear and/or intermediate rasterization. Instead, the rasterizer merges virtual color buffers and rasterizes only once to the back buffer. With respect to group behavior, effects may be applied to groups of primitives on the sources, and written once to the destination memory, without temporary surfaces.
Anti-aliased clipping is another concept, where the clipping occurs between pixel boundaries. In general, the same layer concept for opacity effects is used, with the clip used as the primitive with a temporary surface as the texture. That is, the layer still applies, except the shape used is the clip instead of the bounds of the primitives.
While the invention is susceptible to various modifications and alternative constructions, certain illustrated embodiments thereof are shown in the drawings and have been described above in detail. It should be understood, however, that there is no intention to limit the invention to the specific forms disclosed, but on the contrary, the intention is to cover all modifications, alternative constructions, and equivalents falling within the spirit and scope of the invention.