// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information.
// // Description: // Contains HW Vertex Buffer and Builder class implementations // // // Notes: // // +--------------------------------------+ // | | // | Start Stratum | // 1 | | // | | // +--------------------------------------+ // 2 |======================================| // +--------------------------------------+ // | / \ / \ | // | / \ / \ | // | A / B \ C / D \ E | // 3 | / \ / \ | // | / \ / \ | // | / \ / \ | // | / \ / \ | // +--------------------------------------+ // | \ / \ / | // | \ / \ / | // 4 | F \ G / H \ I / J | // | \ / \ / | // +--------------------------------------+ // 5 |======================================| // +--------------------------------------+ // 6 |======================================| // +--------------------------------------+ // | | // | | // 7 | Stop Stratum | // | | // | | // +--------------------------------------+ // // // Strata & complement mode. // // The anti-aliased HW rasterizer produces a series of "strata" where // each strata can be a complex span rendered using lines (#'s 2,5,6) or // a series of trapezoids (#'s 3 & 4.) In normal mode the trapezoid // regions B,D,G,I are filled in. // // Complement mode complicates things. Complex spans are relatively easy // because we get the whole line's worth of data at once. Trapezoids are // more complex because we get B,D,G and I separately. We handle this by // tracking the current stratum and finishing the last incomplete // trapezoid stratum when a new stratum begins. Regions E & J finish // trapezoid strata. We also need to add rectangles at the beginning and // end of the geometry (start and stop) to fill out the complement // region. // // This is implemented like so: // // 1. Strata are generated from top to bottom without gaps. // 2. Before drawing any lines or trapezoids call // PrepareStratum(a, b, fTrapezoid) where a & b are the extent of // the current stratum and fTrapezoid is true if you are drawing // a trapezoid. This will take care of creating the start // stratum and/or finishing a trapezoid stratum if necessary. // 3. When completely done call EndBuildingOutside() which will // close a pending trapezoid and/or produce the stop stratum. // //-----------------------------------------------------------------------------
const FORCE_TRIANGLES: bool = true;
//+---------------------------------------------------------------------------- // // Constants to control when we stop waffling because the tiles are too // small to make a difference. // // Future Consideration: can produce an excessive number of triangles. // How we mitigate or handle this could be improved. Right now we stop // waffling if the waffle size is less than a quarter-pixel. // Two big improvements that could be made are: // - multipacking very small textures (but note that we cannot rely // on prefiltering to ensure that small screen space means small texture // source) // - clipping primitives to approximately the screen size // //----------------------------------------------------------------------------- //const c_rMinWaffleWidthPixels: f32 = 0.25;
//+---------------------------------------------------------------------------- // // Class: CHwVertexBuffer and CHwTVertexBuffer<class TVertex> // // Synopsis: This class accumulates geometry data for a primitive // //-----------------------------------------------------------------------------
//+---------------------------------------------------------------------------- // // Class: CHwVertexBuffer::Builder // // Synopsis: Base vertex builder class // // Responsibilities: // - Given ordered basic vertex information expand/convert/pass-thru // to vertex buffer (Basic vertex information is minimal vertex // information sent from the caller that may or may not have been // passed thru a tessellator.) // - Choosing vertex format from a minimal required vertex format // // Not responsible for: // - Allocating space in vertex buffer // // Inputs required: // - Key and data to translate input basic vertex info to full vertex data // - Vertex info from tessellation (or other Geometry Generator) // - Vertex buffer to send output to //
//+------------------------------------------------------------------------ // // Member: SetConstantMapping // // Synopsis: Use this method to specify that the given color source for // the given vertex destination is constant (won't differ per // vertex) // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: FinalizeMappings // // Synopsis: Use this method to let builder know that all mappings have // been sent // //-------------------------------------------------------------------------
virtualHRESULTFinalizeMappings( )PURE;
//+------------------------------------------------------------------------ // // Member: SetOutsideBounds // // Synopsis: Enables rendering zero-alpha geometry outside of the input // shape but within the given bounding rectangle, if fNeedInside // isn't true then it doesn't render geometry with full alpha. // //------------------------------------------------------------------------- virtualvoidSetOutsideBounds( __in_ecount_opt(1)constCMILSurfaceRect*prcBounds, boolfNeedInside )PURE;
//+------------------------------------------------------------------------ // // Member: HasOutsideBounds // // Synopsis: Returns true if outside bounds have been set. // //------------------------------------------------------------------------- virtualboolHasOutsideBounds()constPURE;
//+------------------------------------------------------------------------ // // Member: BeginBuilding // // Synopsis: This method lets the builder know it should start from a // clean slate // //-------------------------------------------------------------------------
virtualHRESULTBeginBuilding( )PURE;
//+------------------------------------------------------------------------ // // Member: EndBuilding // // Synopsis: Use this method to let the builder know that all of the // vertex data has been sent // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: FlushReset // // Synopsis: Send pending state and geometry to the device and reset // the vertex buffer. // //-------------------------------------------------------------------------
MIL_FORCEINLINEHRESULTFlushReset() { returnFlushInternal(NULL); } // // Currently all CHwVertexBuffer::Builder are supposed to be allocated via // a CBufferDispenser. //
//+------------------------------------------------------------------------ // // Member: FlushInternal // // Synopsis: Send any pending state and geometry to the device. // If the optional argument is NULL then reset the // vertex buffer. // If the optional argument is non-NULL AND we have // not yet flushed the vertex buffer return the vertex // buffer. // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: Reset // // Synopsis: Mark the beginning of a new list of vertices; the existing // list is discarded // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: AddNonIndexedTriListVertices // // Synopsis: Reserve space for consecutive vertices and return start // index // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: AddTriListVertices // // Synopsis: Reserve space for consecutive vertices and return start // index // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: AddTriStripVertices // // Synopsis: Reserve space for consecutive vertices and return start // index // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: AddLineListVertices // // Synopsis: Reserve space for consecutive vertices and return start // index // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: AddLine implements ILineSink<PointXYA> // // Synopsis: Add a line given two points with x, y, & alpha. // //------------------------------------------------------------------------- HRESULTAddLine( __in_ecount(1)constPointXYA&v0, __in_ecount(1)constPointXYA&v1 );
//+------------------------------------------------------------------------ // // Member: AddTriangle implements ITriangleSink<PointXYA> // // Synopsis: Add a triangle given three points with x, y, & alpha. // //-------------------------------------------------------------------------
// Re-introduce parent AddTriangle(WORD,WORD,WORD) into this scope. usingCHwVertexBuffer::AddTriangle; //+------------------------------------------------------------------------ // // Member: AddLineAsTriangleStrip // // Synopsis: Add a horizontal line using a trinagle strip // //------------------------------------------------------------------------- HRESULTAddLineAsTriangleStrip( __in_ecount(1)constTVertex*pBegin,// Begin __in_ecount(1)constTVertex*pEnd// End );
//+------------------------------------------------------------------------ // // Member: SendVertexFormat // // Synopsis: Send contained vertex format to device // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: DrawPrimitive // // Synopsis: Send the geometry data to the device and execute rendering // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetTriListVertices // // Synopsis: Return pointer to beginning of vertex list and their count // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetNumNonIndexedTriListVertices // // Synopsis: Return current number of vertices // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetNonIndexedTriListVertices // // Synopsis: Return pointer to beginning of vertex list and their count // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetNumTriStripVertices // // Synopsis: Return current number of vertices // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetTriStripVertices // // Synopsis: Return pointer to beginning of vertex list and their count // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetNumLineListVertices // // Synopsis: Return current number of vertices // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetLineListVertices // // Synopsis: Return pointer to beginning of vertex list and their count // //-------------------------------------------------------------------------
//+------------------------------------------------------------------------ // // Member: GetLineListVertices // // Synopsis: Return pointer to beginning of vertex list // //-------------------------------------------------------------------------
*/
// Dynamic array of vertices for which all allocations are zeroed. // XXX: the zero has been removed //m_rgVerticesTriList: DynArray<TVertex>, // Indexed triangle list vertices //m_rgVerticesNonIndexedTriList: DynArray<TVertex>, // Non-indexed triangle list vertices
m_rgVerticesTriList: DynArray<TVertex>, // Triangle strip vertices //m_rgVerticesLineList: DynArray<TVertex>, // Linelist vertices
#[cfg(debug_assertions)] // In debug make a note if we add a triangle strip that doesn't have 6 vertices // so that we can ensure that we only waffle 6-vertex tri strips.
m_fDbgNonLineSegmentTriangleStrip: bool,
subpixel_bias: f32,
}
impl<'z, TVertex: Default> CHwTVertexBuffer<'z, TVertex> { pubfn new(rasterization_truncates: bool, output_buffer: Option<&'z mut [TVertex]>) -> Self {
CHwTVertexBuffer::<TVertex> {
subpixel_bias: if rasterization_truncates { // 1/512 is 0.5 of a subpixel when using 8 bits of subpixel precision. 1./512.
} else { 0.
},
m_rgVerticesBuffer: output_buffer,
m_rgVerticesBufferOffset: 0,
..Default::default()
}
}
//+---------------------------------------------------------------------------- // // Class: CHwTVertexMappings<class TVertex> // // Synopsis: Helper class that knows how to populate a vertex from the // incoming basic per vertex data, like just X and Y // //----------------------------------------------------------------------------- #[derive(Default)] struct CHwTVertexMappings<TVertex>
{/* public:
HRESULTAddVertex( __in_ecount(1)constMilPoint2F&ptPosition, // In: Vertex coordinates __out_ecount(1)WORD*pIndex // Out: The index of the new vertex );
HRESULTAddIndexedVertices( UINTcVertices,// In: number of vertices __in_bcount(cVertices*uVertexStride)constvoid*pVertexBuffer,// In: vertex buffer containing the vertices UINTuVertexStride,// In: size of each vertex MilVertexFormatmvfFormat,// In: format of each vertex UINTcIndices,// In: Number of indices __in_ecount(cIndices)constUINT*puIndexBuffer// In: index buffer );
HRESULTAddTriangle( DWORDi1,// In: Index of triangle's first vertex DWORDi2,// In: Index of triangle's second vertex DWORDi3// In: Index of triangle's third vertex );
HRESULTAddComplexScan( INTnPixelY, // In: y coordinate in pixel space __in_ecount(1)constCCoverageInterval*pIntervalSpanStart // In: coverage segments );
HRESULTAddParallelogram( __in_ecount(4)constMilPoint2F*rgPosition ); HRESULTAddTrapezoid( floatrPixelYTop,// In: y coordinate of top of trapezoid floatrPixelXTopLeft,// In: x coordinate for top left floatrPixelXTopRight,// In: x coordinate for top right floatrPixelYBottom,// In: y coordinate of bottom of trapezoid floatrPixelXBottomLeft,// In: x coordinate for bottom left floatrPixelXBottomRight,// In: x coordinate for bottom right floatrPixelXLeftDelta,// In: trapezoid expand radius for left edge floatrPixelXRightDelta// In: trapezoid expand radius for right edge );
// Helpers that do AddTrapezoid. Same parameters HRESULTAddTrapezoidStandard(float,float,float,float,float,float,float,float); HRESULTAddTrapezoidWaffle(float,float,float,float,float,float,float,float);
HRESULTPrepareStratumSlow( floatrStratumTop, floatrStratumBottom, boolfTrapezoid, floatrTrapezoidLeft, floatrTrapezoidRight ); // Wrap up building of outside geometry. HRESULTEndBuildingOutside();
// Expands all vertices in the buffer. voidExpandVertices(); // Has never been successfully used to declare a method or derived type... /* typedef void (CHwTVertexBuffer<TVertex>::Builder::FN_ExpandVertices)( UINTuCount, TVertex*pVertex
);*/
// // Table of vertex expansion routines for common expansion cases: // - There are entries for Z, Diffuse, and one set texture coordinates for // a total of eight combinations. // - Additionally there is a second set of entries for anti-aliasing // falloff applied thru diffuse. //
// This is true if we had to flush the pipeline as we were getting // geometry rather than just filling up a single vertex buffer.
m_fHasFlushed: bool,
// The next two members control the generation of the zero-alpha geometry // outside the input geometry.
m_fNeedOutsideGeometry: bool,
m_fNeedInsideGeometry: bool,
m_rcOutsideBounds: CMILSurfaceRect, // Bounds for creation of outside geometry
/* // Helpful m_rcOutsideBounds casts. floatOutsideLeft()const{returnstatic_cast<float>(m_rcOutsideBounds.left);} floatOutsideRight()const{returnstatic_cast<float>(m_rcOutsideBounds.right);} floatOutsideTop()const{returnstatic_cast<float>(m_rcOutsideBounds.top);} floatOutsideBottom()const{returnstatic_cast<float>(m_rcOutsideBounds.bottom);}
*/ // This interval (if we are doing outside) shows the location // of the current stratum. It is initialized to [FLT_MAX, -FLT_MAX]. // // If the current stratum is a complex span then // m_rCurStratumBottom is set to the bottom of the stratum and // m_rCurStratumTop is set to FLT_MAX. // // If the current stratum is a trapezoidal one, then // m_rCurStratumBottom is its bottom and m_rCurStratumTop is its // top.
m_rCurStratumTop: f32,
m_rCurStratumBottom: f32,
// If the current stratum is a trapezoidal one, following var stores // right boundary of the last trapezoid handled by PrepareStratum. // We need it to cloze the stratus properly.
m_rLastTrapezoidRight: f32,
// These are needed to implement outside geometry using triangle lists
m_rLastTrapezoidTopRight: f32,
m_rLastTrapezoidBottomRight: f32,
}
/* //+---------------------------------------------------------------------------- // // Member: CHwVertexBuffer::AddTriangle // // Synopsis: Add a triangle using the three indices given to the list // implCHwVertexBuffer{
fnAddTriangle( i1:WORD,// In: Index of triangle's first vertex i2:WORD,// In: Index of triangle's second vertex i3:WORD// In: Index of triangle's third vertex )->HRESULT { lethr:HRESULT=S_OK;
// Asserting indices < max vertex requires a debug only pure virtual method // which is too much of a functionality change between retail and debug. // // // Assert(i1 < GetNumTriListVertices()); // Assert(i2 < GetNumTriListVertices()); // Assert(i3 < GetNumTriListVertices());
WORD*pIndices;
IFC(m_rgIndices.AddMultiple(3,&pIndices));
pIndices[0]=i1; pIndices[1]=i2; pIndices[2]=i3;
Cleanup: RRETURN(hr); }
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::AddTriangle // // Synopsis: Add a triangle using given three points to the list // //----------------------------------------------------------------------------- template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::AddTriangle( __in_ecount(1)constPointXYA&v0, __in_ecount(1)constPointXYA&v1, __in_ecount(1)constPointXYA&v2) { lethr:HRESULT=S_OK; TVertex*pVertices; hr=AddNonIndexedTriListVertices(3,&pVertices);
impl CHwVertexBuffer<'_> { //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::AddLine // // Synopsis: Add a nominal width line using given two points to the list // //----------------------------------------------------------------------------- fn AddLine(&mutself,
v0: &PointXYA,
v1: &PointXYA
) -> HRESULT
{ type TVertex = CD3DVertexXYZDUV2; let hr = S_OK;
let pVertices: &mut [TVertex]; letmut rgScratchVertices: [TVertex; 2] = Default::default();
assert!(!(v0.y != v1.y));
let fUseTriangles = /*(v0.y < m_pBuilder->GetViewportTop() + 1) ||*/ FORCE_TRIANGLES;
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::GetOutVertexFormat // // Synopsis: Return MIL vertex format covered by specific builders // //-----------------------------------------------------------------------------
*ppVertexBufferBuilder=pVBB; } else { // NOTE-2004/03/22-chrisra Adding another vertexbuffer type requires updating enum // // If we add another buffer builder type kMaxVertexBuilderSize enum in hwvertexbuffer.h file // needs to be updated to reflect possible changes to the maximum size of buffer builders. // IFC(E_NOTIMPL); }
// Store the pipeline, if any, which this VBB can use to spill the vertex buffer to if it // overflows. (**ppVertexBufferBuilder).m_pPipelineNoRef=pPipeline; (**ppVertexBufferBuilder).m_pDeviceNoRef=pDevice;
//+---------------------------------------------------------------------------- // // Member: THwTVertexMappings<TVertex>::SetPositionTransform // // Synopsis: Sets the position transform that needs to be applied. // //----------------------------------------------------------------------------- template<classTVertex> void CHwTVertexMappings<TVertex>::SetPositionTransform( __in_ecount(1)constMILMatrix3x2&matPositionTransform ) { m_matPos2DTransform=matPositionTransform; }
//+---------------------------------------------------------------------------- // // Member: CHwTVertexMappings<TVertex>::SetConstantMapping // // Synopsis: Remember the static color for the given vertex field //
//+---------------------------------------------------------------------------- // // Member: CHwTVertexMappings<TVertex>::PointToUV // // Synopsis: Helper function to populate the texture coordinates at the given // index using the given point //
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::Create // // Synopsis: Instantiate a specific type of vertex builder //
// These two track the Y extent of the shape this builder is producing.
m_rCurStratumTop: f32::MAX,
m_rCurStratumBottom: -f32::MAX,
m_fNeedOutsideGeometry: false,
m_fNeedInsideGeometry: true,
// // If AA falloff is not going to scale the diffuse color and it is // generated then see if the color is constant such that we can do any // complex conversions just once here instead of in every iteration of the // expansion loop. If AA falloff is going to scale the diffuse color then // we can still optimize for the falloff = 1.0 case by precomputing that // color now and checking for 1.0 during generation. Such a precomputation // has shown significant to performance. //
// Assumes diffuse color is constant m_map.m_vStatic.Diffuse= Convert_MilColorF_scRGB_To_Premultiplied_MilColorB_sRGB(&m_map.m_colorStatic); } else { // Set default Diffuse value: White m_map.m_vStatic.Diffuse=MIL_COLOR(0xFF,0xFF,0xFF,0xFF); } }
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::SetOutsideBounds // // // Synopsis: Enables rendering geometry for areas outside the shape but // within the bounds. These areas will be created with // zero alpha. //
pubfn SetOutsideBounds(&mutself,
prcOutsideBounds: Option<&CMILSurfaceRect>,
fNeedInside: bool,
)
{ // Waffling and outside bounds is not currently implemented. It's // not difficult to do but currently there is no need. //assert!(!(self.AreWaffling() && self.prcOutsideBounds));
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::BeginBuilding // // Synopsis: Prepare for a new primitive by resetting the vertex buffer // pubfn BeginBuilding(&mutself,
) -> HRESULT
{
RRETURN!(hr);
}
} impl IGeometrySink for CHwVertexBufferBuilder<'_, '_> {
fn AddTrapezoid(&mutself,
rPixelYTop: f32, // In: y coordinate of top of trapezoid
rPixelXTopLeft: f32, // In: x coordinate for top left
rPixelXTopRight: f32, // In: x coordinate for top right
rPixelYBottom: f32, // In: y coordinate of bottom of trapezoid
rPixelXBottomLeft: f32, // In: x coordinate for bottom left
rPixelXBottomRight: f32, // In: x coordinate for bottom right
rPixelXLeftDelta: f32, // In: trapezoid expand radius for left edge
rPixelXRightDelta: f32 // In: trapezoid expand radius for right edge
) -> HRESULT
{ let hr = S_OK;
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddVertex // // Synopsis: Add a vertex to the vertex buffer // // Remember just the given vertex information now and convert later // in a single, more optimal pass. //
template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::Builder::AddVertex( __in_ecount(1)constMilPoint2F&ptPosition, // Vertex coordinates __out_ecount(1)WORD*pIndex // The index of the new vertex ) { HRESULThr=S_OK;
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddIndexedVertices, IGeometrySink // // Synopsis: Add a fully computed, indexed vertex to the vertex buffer //
template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::Builder::AddIndexedVertices( UINTcVertices, // In: number of vertices __in_bcount(cVertices*uVertexStride)constvoid*pVertexBufferNoRef, // In: vertex buffer containing the vertices UINTuVertexStride, // In: size of each vertex MilVertexFormatmvfFormat, // In: format of each vertex UINTcIndices, // In: Number of indices __in_ecount(cIndices)constUINT*puIndexBuffer // In: index buffer ) { Assert(m_mvfIn&(MILVFAttrXYZ|MILVFAttrDiffuse|MILVFAttrUV2)); Assert(mvfFormat==(MILVFAttrXYZ|MILVFAttrDiffuse|MILVFAttrUV2));
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddTriangle // // Synopsis: Add a triangle to the vertex buffer //
template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::Builder::AddTriangle( DWORDi1,// In: Index of triangle's first vertex DWORDi2,// In: Index of triangle's second vertex DWORDi3// In: Index of triangle's third vertex ) { HRESULThr=S_OK;
// Use triangles instead of lines, for lines too close to the top of the viewport // because lines are clipped (before rasterization) against a viewport that only // includes half of the top pixel row. Waffling will take care of this separately. if (/*pLineSink.is_none() && rPixelY < self.GetViewportTop() + 1 ||*/ FORCE_TRIANGLES)
{
pLineSink = Some(&mutself.m_pVB);
}
// // Output all segments if creating outside geometry, otherwise only output segments // with non-zero coverage. //
if (pLineSink.is_none())
{ /* UINTnSegmentCount=0;
// // Having allocated space (if not using sink), now let's actually output the vertices. //
while ((*pIntervalSpanStart).m_nPixelX.get() != INT::MAX)
{
assert!(!(*pIntervalSpanStart).m_pNext.get().is_null());
// // Output line list segments // // Note that line segments light pixels by going through the the // "diamond" interior of a pixel. While we could accomplish this // by going from left edge to right edge of pixel, D3D10 uses the // convention that the LASTPIXEL is never lit. We respect that now // by setting D3DRS_LASTPIXEL to FALSE and use line segments that // start in center of first pixel and end in center of one pixel // beyond last. // // Since our top left corner is integer, we add 0.5 to get to the // pixel center. // if (self.NeedCoverageGeometry((*pIntervalSpanStart).m_nCoverage.get()))
{ let rCoverage: f32 = ((*pIntervalSpanStart).m_nCoverage.get() as f32)/(c_nShiftSizeSquared as f32);
letmut iBegin: LONG = (*pIntervalSpanStart).m_nPixelX.get(); letmut iEnd: LONG = (*(*pIntervalSpanStart).m_pNext.get()).m_nPixelX.get(); if (self.NeedOutsideGeometry())
{ // Intersect the interval with the outside bounds to create // start and stop lines. The scan begins (ends) with an // interval starting (ending) at -inf (+inf).
// The given geometry is not guaranteed to be within m_rcOutsideBounds but // the additional inner min and max (in that order) produce empty spans // for intervals not intersecting m_rcOutsideBounds. // // We could cull here but that should really be done by the geometry // generator.
iBegin = iBegin.max(iEnd.min(self.m_rcOutsideBounds.left));
iEnd = iEnd.min(iBegin.max(self.m_rcOutsideBounds.right));
} let rPixelXBegin: f32= (iBegin as f32) + 0.5; let rPixelXEnd: f32 = (iEnd as f32) + 0.5;
// // Output line (linelist or tristrip) for a pixel //
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddLineAsTriangleList // // Synopsis: Adds a horizontal line as a triangle list to work around // issue in D3D9 where horizontal lines with y = 0 may not render. // // Line clipping in D3D9 // This behavior will change in D3D10 and this work-around will no // longer be needed. (Pixel center conventions will also change.) // //----------------------------------------------------------------------------- impl CHwVertexBuffer<'_> { fn AddLineAsTriangleList(&mutself,
pBegin: &CD3DVertexXYZDUV2, // Begin
pEnd: &CD3DVertexXYZDUV2 // End
) -> HRESULT
{ let hr = S_OK;
// Collect pertinent data from vertices.
debug_assert!(pBegin.y == pEnd.y);
debug_assert!(pBegin.coverage == pEnd.coverage);
// Offset begin and end X left by 0.5 because the line starts on the first // pixel center and ends on the center of the pixel after the line segment. let x0 = pBegin.x - 0.5; let x1 = pEnd.x - 0.5; let y = pBegin.y; let dwDiffuse = pBegin.coverage;
// // Add the vertices //
// OpenGL doesn't specify how vertex positions are converted to fixed point prior to rasterization. On macOS, with AMD GPUs, // the GPU appears to truncate to fixed point instead of rounding. This behaviour is controlled by PA_SU_VTX_CNTL // register. To handle this we'll add a 1./512. subpixel bias to the center vertex to cause the coordinates to round instead // of truncate. // // D3D11 requires the fixed point integer result to be within 0.6ULP which implicitly disallows the truncate behaviour above. // This means that D2D doesn't need to deal with this problem. let subpixel_bias = self.subpixel_bias;
// Use a single triangle to cover the entire line self.AddTriVertices(
OutputVertex{ x: x0, y: y - 0.5, coverage: dwDiffuse },
OutputVertex{ x: x0, y: y + 0.5, coverage: dwDiffuse },
OutputVertex{ x: x1, y: y + subpixel_bias, coverage: dwDiffuse },
);
self.AddedNonLineSegment();
//Cleanup:
RRETURN!(hr);
}
}
/* //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddParallelogram // // Synopsis: This function adds the coordinates of a parallelogram to the vertex strip buffer. // // Parameter: rgPosition contains four coordinates of the parallelogram. Coordinates should have // a winding order // //----------------------------------------------------------------------------- template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::Builder::AddParallelogram( __in_ecount(4)constMilPoint2F*rgPosition ) { HRESULThr=S_OK;
// // Duplicate the first vertex. This creates 2 degenerate triangles: one connecting // the previous rect to this one and another between vertices 0 and 1. //
// // Duplicate the last vertex. This creates 2 degenerate triangles: one // between vertices 4 and 5 and one connecting this Rect to the // next one. //
pVertex[5].ptPt=rgPosition[2]; pVertex[5].Diffuse=FLOAT_ONE; } Cleanup: RRETURN(hr); } //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::BuildWafflePipeline<TWaffler> // // Synopsis: Builds a pipeline of wafflers into the provided array of wafflers. // And returns a pointer (not to be deleted) to the input sink // of the waffle pipeline. // the final result is sinked int m_pVB. // //-----------------------------------------------------------------------------
// Each column ([a,b,c] transpose) of this matrix specifies a waffler that // partitions the plane into regions between the lines: // ax + by + c = k // for every integer k. // // If this partition width is substantially less than a pixel we have // serious problems with waffling generating too many triangles for // doubtful visual effect so we don't perform a waffling with width less // than c_rMinWaffleWidthPixels. So we need to know the width of the partition // regions: // // Changing c just translates the partition so let's assume c = 0. // The line ax + by = 0 goes through the origin and the line ax + by // = 1 is adjacent to it in the partition. The distance between // these lines is also the distance from ax + by = 1 to the origin. // Using Lagrange multipliers we can determine that this distance // is // 1/sqrt(a*a+b*b). // We want to avoid waffling if this is less than c_rMinWaffleWidthPixels // or equivalently: // 1/sqrt(a*a+b*b) < c_rMinWaffleWidthPixels // sqrt(a*a+b*b) > 1/c_rMinWaffleWidthPixels // a*a+b*b > 1/(c_rMinWaffleWidthPixels*c_rMinWaffleWidthPixels) //
if(count) { fWafflersUsed=true; // As the last step in the chain we send the triangles to our vertex buffer. wafflers[count-1].SetSink(m_pVB); return&wafflers[0]; } else { fWafflersUsed=false; // If we built no wafflers then sink straight into the vertex buffer. returnm_pVB; } }
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::IsEmpty // // Synopsis: Does our VB have any triangles/lines? // //----------------------------------------------------------------------------- template<classTVertex> BOOL CHwTVertexBuffer<TVertex>::Builder::IsEmpty() { returnm_pVB->IsEmpty(); }
*/ //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddTrapezoid // // Synopsis: Add a trapezoid to the vertex buffer // // // left edge right edge // ___+_________________+___ <<< top edge // / + / \ + \ // / + / \ + \ // / + / \ + \ // /__+__/___________________\__+__\ <<< bottom edge // + ^^ + // delta // impl CHwVertexBufferBuilder<'_, '_> {
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidStandard // // Synopsis: See AddTrapezoid. This doesn't do waffling & uses tri strips. //
fn AddTrapezoidStandard(&mutself,
rPixelYTop: f32, // In: y coordinate of top of trapezoid
rPixelXTopLeft: f32, // In: x coordinate for top left
rPixelXTopRight: f32, // In: x coordinate for top right
rPixelYBottom: f32, // In: y coordinate of bottom of trapezoid
rPixelXBottomLeft: f32, // In: x coordinate for bottom left
rPixelXBottomRight: f32, // In: x coordinate for bottom right
rPixelXLeftDelta: f32, // In: trapezoid expand radius for left edge
rPixelXRightDelta: f32 // In: trapezoid expand radius for right edge
) -> HRESULT
{ type TVertex = CD3DVertexXYZDUV2; let hr = S_OK; //TVertex *pVertex;
if (!fNeedOutsideGeometry)
{ // // Duplicate the last vertex. This creates 2 degenerate triangles: one // between vertices 8 and 9 and one connecting this trapezoid to the // next one. //
//Cleanup:
RRETURN!(hr);
}
} /* //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidWaffle // // Synopsis: See AddTrapezoid. This adds a waffled trapezoid. // //----------------------------------------------------------------------------- template<classTVertex> HRESULT CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidWaffle( floatrPixelYTop,// In: y coordinate of top of trapezoid floatrPixelXTopLeft,// In: x coordinate for top left floatrPixelXTopRight,// In: x coordinate for top right floatrPixelYBottom,// In: y coordinate of bottom of trapezoid floatrPixelXBottomLeft,// In: x coordinate for bottom left floatrPixelXBottomRight,// In: x coordinate for bottom right floatrPixelXLeftDelta,// In: trapezoid expand radius for left edge floatrPixelXRightDelta// In: trapezoid expand radius for right edge ) { HRESULThr=S_OK;
// We have 2 (u & v) wafflers per texture coordinate that need waffling. TriangleWaffler<PointXYA>wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex)*2]; boolfWafflersUsed=false;
// Send the triangles in the strip through the waffle pipeline. for(inti=0;i<6;++i) { IFC(pWaffleSinkNoRef->AddTriangle(vertices[i+1],vertices[i],vertices[i+2])); }
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::NeedCoverageGeometry // // Synopsis: Returns true if the coverage value needs to be rendered // based on NeedInsideGeometry() and NeedOutsideGeometry() // // Two cases where we don't need to generate geometry: // 1. NeedInsideGeometry is false, and coverage is c_nShiftSizeSquared. // 2. NeedOutsideGeometry is false and coverage is 0 // //----------------------------------------------------------------------------- fn NeedCoverageGeometry(&self,
nCoverage: INT
) -> bool
{ return (self.NeedInsideGeometry() || nCoverage != c_nShiftSizeSquared)
&& (self.NeedOutsideGeometry() || nCoverage != 0);
}
//+------------------------------------------------------------------------ // // Member: NeedOutsideGeometry // // Synopsis: True if we should create geometry with zero alpha for // areas outside the input geometry but within a given // bounding box. // //------------------------------------------------------------------------- fn NeedOutsideGeometry(&self) -> bool
{ returnself.m_fNeedOutsideGeometry;
}
//+------------------------------------------------------------------------ // // Member: NeedInsideGeometry // // Synopsis: True if we should create geometry for areas completely // withing the input geometry (i.e. alpha 1.) Should only // be false if NeedOutsideGeometry is true. // //------------------------------------------------------------------------- fn NeedInsideGeometry(&self) -> bool
{
assert!(self.m_fNeedOutsideGeometry || self.m_fNeedInsideGeometry); returnself.m_fNeedInsideGeometry;
}
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::PrepareStratumSlow // // Synopsis: Call before producing a new stratum (complex span or trapezoid.) // Handles several tasks: // 1. Producing between top of complement geometry & the 1st // stratum or when a gap between strata occurs (because // the geometry is not closed and has horizontal gaps.) // Passing in FLT_MAX for rStratumTop and rStratumBottom // Fills the gap between the last stratum and the bottom // of the outside. // 2. Begins and/or ends the triangle strip corresponding to // a trapezoid row. // 3. Updates status vars m_rCurStratumTop & m_rCurStratumBottom // // Note: Call PrepareStratum which inlines the check for NeedOutsideGeometry() // If NeedOutsideGeometry is false PrepareStratum() does nothing. // This (slow) version asserts NeedOutsideGeometry() // //----------------------------------------------------------------------------- fn PrepareStratumSlow(&mutself,
rStratumTop: f32,
rStratumBottom: f32,
fTrapezoid: bool,
rTrapezoidLeft: f32,
rTrapezoidRight: f32,
rTrapezoidTopLeft: f32,
rTrapezoidBottomLeft: f32,
rTrapezoidTopRight: f32,
rTrapezoidBottomRight: f32,
) -> HRESULT
{ type TVertex = OutputVertex; let hr: HRESULT = S_OK;
if ( fEndBuildingOutside == 1.
|| rStratumBottom != self.m_rCurStratumBottom)
{
// New stratum starting now. Two things to do // 1. Close out current trapezoid stratum if necessary. // 2. Begin new trapezoid stratum if necessary.
if (self.m_rCurStratumTop != f32::MAX)
{ // we do not clip trapezoids so RIGHT boundary // of the stratus can be outside of m_rcOutsideBounds.
let rOutsideRight: f32 = self.OutsideRight().max(self.m_rLastTrapezoidRight);
// End current trapezoid stratum.
self.m_pVB.AddTrapezoidVertices(
OutputVertex{
x: self.m_rLastTrapezoidTopRight,
y: self.m_rCurStratumTop,
coverage: FLOAT_ZERO,
},
OutputVertex{
x: self.m_rLastTrapezoidBottomRight,
y: self.m_rCurStratumBottom,
coverage: FLOAT_ZERO,
},
OutputVertex{
x: rOutsideRight,
y: self.m_rCurStratumTop,
coverage: FLOAT_ZERO,
},
OutputVertex{
x: rOutsideRight,
y: self.m_rCurStratumBottom,
coverage: FLOAT_ZERO,
}
);
} // Compute the gap between where the last stratum ended and where // this one begins. let flGap: f32 = rStratumTop - self.m_rCurStratumBottom;
if (flGap > 0.)
{ // The "special" case of a gap at the beginning is caught here // using the sentinel initial value of m_rCurStratumBottom.
let flRectTop: f32 = ifself.m_rCurStratumBottom == -f32::MAX { self.OutsideTop() } else { self.m_rCurStratumBottom }; let flRectBot: f32 = (rStratumTop as f32);
// Produce rectangular for any horizontal intervals in the // outside bounds that have no generated geometry.
assert!(self.m_rCurStratumBottom != -f32::MAX || self.m_rCurStratumTop == f32::MAX);
let outside_left = self.OutsideLeft(); let outside_right = self.OutsideRight();
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::EndBuildingOutside // // Synopsis: Finish creating outside geometry. // 1. If no geometry was created then just fill bounds. // 2. Otherwise: // A. End last trapezoid row // B. Produce stop stratum // //----------------------------------------------------------------------------- fn EndBuildingOutside(&mutself) -> HRESULT
{ returnself.PrepareStratum( self.OutsideBottom(), self.OutsideBottom(), false, /* Not a trapezoid. */ 0., 0., 0., 0., 0., 0.,
);
}
//+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer<TVertex>::Builder::EndBuilding // // Synopsis: Expand all vertices to the full required format and return // vertex buffer. // //----------------------------------------------------------------------------- pubfn EndBuilding(&mutself) -> HRESULT
{ let hr = S_OK;
IFC!(self.EndBuildingOutside());
//Cleanup:
RRETURN!(hr);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.67 Sekunden
(vorverarbeitet am 2026-06-23)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.