470 likes | 689 Views
Tessellation in a Low Poly World. Nicolas Thibieroz AMD Graphics Products Group nicolas.thibieroz@amd.com Original materials from Bill Bilodeau. GDC Paris 2008. Low. Medium. High. What is Tessellation?. Tessellation is the process of adding new primitives into an existing model
E N D
Tessellation in a Low Poly World Nicolas Thibieroz AMD Graphics Products Group nicolas.thibieroz@amd.com Original materials from Bill Bilodeau GDC Paris 2008
Low Medium High What is Tessellation? • Tessellation is the process of adding new primitives into an existing model • Triangle counts can be “dialed in” by adjusting the tessellation level
Input Assembler Tessellator Vertex Shader Rasterizer Pixel Shader AMD Hardware Tessellator Memory / Resources Memory / Resources Output Merger
Hardware tessellation allows you to render more polygons for better silhouettes Initial concept artwork from Bay Raitt, Valve
Animated Control Cage Pixel Shader Vertex Shader Vertex Shader Pixel Shader Tessellator Surface control cages are easier to work with than individual triangles • Artists prefer to create models this way • Animations are simpler on a control cage • Control cage can be animated on the GPU, then tessellated in a second pass R2VB
Hardware tessellation is a form of compression • Smaller footprint – you only need to store the control cage and possibly a displacement map • Improved bandwidth – less data to transfer from memory to GPU
Three types of primitives, or “superprims”, are supported • Triangles • Quads • Lines
There are two tessellation modes • - Continuous • - Adaptive
Continuous Tessellation • Specify floating point tessellation level per-draw call • Tessellation levels range from 1.0 to 14.99 • Eliminates popping as vertices are added through tessellation Level 2.0 Level 1.0
Level = 1.7 Level = 1.0 Level = 1.1 Level = 1.3 Level = 2.0 Continuous Tessellation • Specify floating point tessellation level per-draw call • Tessellation levels range from 1.0 to 14.99 • Eliminates popping as vertices are added through tessellation Level 2.0 Level 1.0
Edge tessellation factor = 7.x Edge tessellation factor = 3.x Edge tessellation factor = 3.x Edge tessellation factor = 3.x Edge tessellation factor = 3.x Edge tessellation factor = 5.x Edge tessellation factor = 5.x Adaptive allows different levels of tessellation within the same mesh
Transformed Superprim Mesh Pixel Shader Superprim Mesh Vertex Shader Superprim Mesh Vertex Shader Superprim Mesh Vertex Shader Pixel Shader Sampler R2VB Tessellation Factors Stream 1 Pixel Shader Tessellator Stream 0 Adaptive tessellation can be done in real-time using multiple passes
Code Example: Continuous Tessellation // Enable tessellation: TSSetTessellationMode( pd3dDevice, TSMD_ENABLE_CONTINUOUS ); // Set tessellation level: TSSetMaxTessellationLevel( pd3dDevice, sg_fMaxTessellationLevel ); // Select appropriate technique to render our tessellated objects: sg_pEffect->SetTechnique( "RenderTessellatedDisplacedScene" ); // Render all passes with tessellation V( sg_pEffect->Begin( &cPasses, 0 ) ); for ( iPass = 0; iPass < cPasses; iPass++ ) { V( sg_pEffect->BeginPass( iPass ) ); V( TSDrawMeshSubset( sg_pMesh, 0 ) ); V( sg_pEffect->EndPass() ); } V( sg_pEffect->End() ); // Disable tessellation: TSSetTessellationMode( pd3dDevice, TSMD_DISABLE );
(Evaluation Shader) Vertex Shader Tessellator Super-prim Mesh Tessellated Mesh Tessellated and Displaced Mesh Sampler Displacement Map The vertex shader is used as an evaluation shader
Example Code: Evaluation Vertex Shader struct VsInputTessellated { // Barycentric weights for this vertex float3 vBarycentric: BLENDWEIGHT0; // Data from superprim vertex 0: float4 vPositionVert0 : POSITION0; float2 vTexCoordVert0 : TEXCOORD0; float3 vNormalVert0 : NORMAL0; // Data from superprim vertex 1: float4 vPositionVert1 : POSITION4; float2 vTexCoordVert1 : TEXCOORD4; float3 vNormalVert1 : NORMAL4; // Data from superprim vertex 2: float4 vPositionVert2 : POSITION8; float2 vTexCoordVert2 : TEXCOORD8; float3 vNormalVert2 : NORMAL8; };
Example Code: Evaluation Vertex Shader VsOutputTessellated VSRenderTessellatedDisplaced( VsInputTessellated i ) { VsOutputTessellated o; // Compute new position based on the barycentric coordinates: float3 vPosTessOS = i.vPositionVert0.xyz * i.vBarycentric.x + i.vPositionVert1.xyz i.vBarycentric.y + i.vPositionVert2.xyz * i.vBarycentric.z; // Output world-space position: o.vPositionWS = vPosTessOS; // Compute new normal vector for the tessellated vertex: o.vNormalWS = i.vNormalVert0.xyz * i.vBarycentric.x + i.vNormalVert1.xyz * i.vBarycentric.y + i.vNormalVert2.xyz * i.vBarycentric.z; // Compute new texture coordinates based on the barycentric coordinates: o.vTexCoord = i.vTexCoordVert0.xy * i.vBarycentric.x + i.vTexCoordVert1.xy * i.vBarycentric.y + i.vTexCoordVert2.xy * i.vBarycentric.z; // Displace the tessellated vertex (sample the displacement map) o.vPositionWS = DisplaceVertex( vPosTessOS, o.vTexCoord, o.vNormalWS ); // Transform position to screen-space: o.vPosCS =mul( float4( o.vPositionWS, 1.0 ), g_mWorldViewProjection ); return o; } // End of VsOutputTessellated VSRenderTessellatedDisplaced(..)
Bezier Control Points Tessellator Vertex Shader (u,v) P0,0, P0,1 …P3,3 Sampler What if you want to do more? • DirectX 9 has a limit of 15 float4 vertex input components – High order surfaces need more inputs • TSToggleIndicesRetrieval() allows you to fetch the super-prim data from a vertex texture
Other Tessellation Library Functions • TSDrawIndexed(…) • Analogous to DrawIndexedPrimitive(…) • TSDrawNonIndexed(…) • Needed for adaptive tessellation, since every edge needs its own tessellation level • TSSetMinTessellationLevel(…) • Sets the minimum tessellation level for adaptive tessellation • TSComputeNumTessellatedPrimitives(…) • Calculates the number of tessellated primitives that will be generated by the tessellator
Displacement mapping alters tangent space • To do normal mapping we need to rotate tangent space • Alternatively, use model space normal maps • Doesn’t work with animation or tiling
Displacement map lighting • Use the displacement map to calculate the per-pixel normal • Central differencing with neighboring displacements can approximate the derivative • Light with the computed normal • No need to use a normal map
Terrain Rendering: Performance Results Both use the same displacement map (2K x 2K) and identical pixel shaders Rendering with tessellation is > 6X faster and provides memory savings over 44MB! Subtracting the cost of shading
AMD GPU MeshMapper New tool for generate normal, displacement, and ambient occlusion maps from hi-res and low-res mesh pairs
Advantages of the Tessellator • Saves memory bandwidth and reduces memory footprint • Flexible support for displacement mapping and many kinds of high order surfaces • Easier content creation – artists and animators only need to work with low resolution geometry • Continuous LOD avoids unnecessary triangles • The tessellator is available now on the Xbox 360 and the latest ATI Radeon and FireGL graphics cards • Public availability of tessellation SDK very soon
Harnessing the Power of Multiple GPUs Nicolas Thibieroz AMD Graphics Products Group nicolas.thibieroz@amd.com Original materials from Jon Story & Holger Grün GDC Paris 2008
Why MGPU? • MGPUs can be used to dramatically increase performance and visual quality • At higher screen resolutions • Especially with increased use of MSAA • Many applications become GPU limited at higher screen resolutions • High resolution monitors => mainstream affordability • Achieve next generation performance on today‘s HW • Prototype your next engine • Provides an upgrade path for mainstream parts
Multiple Boards • An increasing number of motherboards can accept 2 or more discrete video cards • Connected by high speed crossover cables • Now possible to fit 4 Radeon HD3850 boards to a single motherboard • CrossFireX technology allows you to harness that performance 2x 4x
Multiple GPUs per Board • The Radeon HD3870 X2 is a single-board multi-GPU architecture • AFR is on by default • Heavy peer to peer communication • Bi-directional 16x lane pipe connecting the 2 GPUs • CrossFireX supports 2 HD3870 X2 boards for Quad GPU performance 2x 4x
Hybrid Crossfire • Combination of integrated and discrete graphics • 3D graphics performance boost • Laptops • Mainstream desktop PCs • Use less power during non-taxing graphical tasks
CrossFire Rendering Modes • Split Frame Rendering / Scissor • Screen is divided into number of GPUs • Dynamic load balancing • Alternate Frame Rendering • GPUs take alternate frames • Vertex processing not duplicated • Highest performing mode
How does AFR Work? CPU GPU0 (Frame N) GPU1 (Frame N+1) Command Command Command Command Command Command Command Command Command Command Command Command
Hardware Considerations • Current MGPU setups are not shared memory architectures • Resources placed in local video memory are duplicated for each GPU • Driver initiates peer to peer (P2P) copies to keep resources in sync • On some chipsets this may involve the CPU • Synchronizes all GPUs • Very heavy impact on performance that can even result in negative scaling
Driver Modes • Compatible AFR Mode • Default mode • Driver checks for AFR unfriendly behaviour • Will P2P copy stale resources • Full AFR Mode (Application Profile) • Driver recognises EXE name • Use a unique name and don‘t change it • Behaviour fully guided by profile • Best performance – no checking • Rename EXE to “AFR-FriendlyD3D.exe“ • Use “AFR-FriendlyOGL.exe“ for OpenGL • No checking : Speed & compatibility test
Detecting the Number of GPUs • Visit http://ati.amd.com/developer • Download project called “CrossFire Detect“ • Statically link to: • “atimgpud_s_x86.lib“ 32 bit version • “atimgpud_s_x64.lib“ 64 bit version • Include header file: • “atimgpud.h“ • Call this function: • INT count = AtiMultiGPUAdapters();
Pitfall: Dependencies Between Frames resource A resource A GPU0 (Frame N) GPU1 (Frame N+1) Present (N-1) Draw using A Update resource A Draw using A P2P copy from GPU0 to GPU1 Update resource A Present (N) Present (N+1)
Solution: Resources that Change Every Frame resource A resource A GPU0 (Frame N) GPU1 (Frame N+1) Present (N-1) Update resource A Draw using A Update resource A Draw using A Present (N) Present (N+1)
Solution: Resources that Change Every Few Frames resource A resource A GPU0 (Frame N) GPU1 (Frame N+1) Present (N-1) Update resource A Draw using A Update resource A Draw using A Present (N) Present (N+1) Draw using A Draw using A Present (N+2) Present (N+3) Draw using A Present (N+4)
Pitfalls: In DX10 there are Other Ways to Update Resources... • Drawing to vertex/index buffers • Stream Out • CopyResource() calls • CopySubresourceRegion() calls • GenerateMips() calls • ResolveSubresource() calls
Waiting starves GPU queues Pitfall: Waiting on Queries Waiting limits parallelism CPU Waiting for Query Result!!! Waiting => CPU limitation GPU0 (Frame N) GPU1 (Frame N+1) Command Command Command Command Command Command Command Command Command Command Command Command
Solution: Queries • Avoid using queries whenever possible • - For occlusion queries consider a CPU-based approach • Avoid waiting on query results • - Pick up the result of a query at least N-GPU frames after it was issued • For queries issued every frame • - Create additional query objects for each GPU • - Cycle through them
Pitfall: CPU Access to a Renderable Resource • When the CPU locks a renderable resource it must wait for all GPUs to finish using the resource before acquiring the pointer • All GPUs now have to wait until the CPU unlocks the resource pointer • After the unlock the driver has to update the resource on each GPU via P2P copies • Just don‘t do this – it destroys performance even on a single GPU setup, and is catastrophic for MGPUs
Solutions: Locks / Maps • In DX10 stream to and copy from STAGING textures • In DX9 StretchRect() is always better than Lock() • At resource creation time use the appropriate flags from: • D3D10_USAGE • D3D10_CPU_ACCESS_FLAG • In DX9 never lock static Vertex/Index Buffers because it will cause P2P copies
Concluding Pitfalls & Solutions • Drivers take a conservative approach • Performs checks on resource synchronization • P2P copy if necessary • You know the application best • Determine if a P2P copy is necessary • Talk to us about a profile
AFR-Friendly SDK Sample • Part of the ATI developer SDK • http://ati.amd.com/developer • Detects the number of GPUs • Correctly deals with textures used as render targets • Provides a solution for dealing with mouse cursor lag • Go and take a look!!
Call to Action • MGPUs provide demonstrable performance gains • MGPUs boost visual quality • Plan from day one to make your rendering scale • Detect the number of GPUs • Regularly check for AFR unfriendly behavior • Talk to us...
QUESTIONS? • ? nicolas.thibieroz@amd.com