// 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> { pub fn 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. //
pub fn 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));
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;
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.