private RenderSystemCapabilities UpdateRenderSystemCapabilities(D3DRenderWindow renderWindow)
{
var rsc = realCapabilities ?? new RenderSystemCapabilities();
rsc.SetCategoryRelevant(CapabilitiesCategory.D3D9, true);
rsc.DriverVersion = driverVersion;
rsc.DeviceName = _activeD3DDriver.DriverDescription;
rsc.RendersystemName = Name;
// Init caps to maximum.
rsc.TextureUnitCount = 1024;
rsc.SetCapability(Graphics.Capabilities.AnisotropicFiltering);
rsc.SetCapability(Graphics.Capabilities.HardwareMipMaps);
rsc.SetCapability(Graphics.Capabilities.Dot3);
rsc.SetCapability(Graphics.Capabilities.CubeMapping);
rsc.SetCapability(Graphics.Capabilities.ScissorTest);
rsc.SetCapability(Graphics.Capabilities.TwoSidedStencil);
rsc.SetCapability(Graphics.Capabilities.StencilWrap);
rsc.SetCapability(Graphics.Capabilities.HardwareOcculusion);
rsc.SetCapability(Graphics.Capabilities.UserClipPlanes);
rsc.SetCapability(Graphics.Capabilities.VertexFormatUByte4);
rsc.SetCapability(Graphics.Capabilities.Texture3D);
rsc.SetCapability(Graphics.Capabilities.NonPowerOf2Textures);
rsc.NonPOW2TexturesLimited = false;
rsc.MultiRenderTargetCount = Config.MaxMultipleRenderTargets;
rsc.SetCapability(Graphics.Capabilities.MRTDifferentBitDepths);
rsc.SetCapability(Graphics.Capabilities.PointSprites);
rsc.SetCapability(Graphics.Capabilities.PointExtendedParameters);
rsc.MaxPointSize = 2.19902e+012f;
rsc.SetCapability(Graphics.Capabilities.MipmapLODBias);
rsc.SetCapability(Graphics.Capabilities.PerStageConstant);
rsc.SetCapability(Graphics.Capabilities.StencilBuffer);
rsc.StencilBufferBitCount = 8;
rsc.SetCapability(Graphics.Capabilities.AdvancedBlendOperations);
rsc.SetCapability(Graphics.Capabilities.RTTSerperateDepthBuffer);
rsc.SetCapability(Graphics.Capabilities.RTTMainDepthbufferAttachable);
rsc.SetCapability(Graphics.Capabilities.RTTDepthbufferResolutionLessEqual);
rsc.SetCapability(Graphics.Capabilities.VertexBufferInstanceData);
rsc.SetCapability(Graphics.Capabilities.CanGetCompiledShaderBuffer);
foreach (var dev in _deviceManager)
{
var d3D9Device = dev.D3DDevice;
// Check for hardware stencil support
var pSurf = d3D9Device.DepthStencilSurface;
if (pSurf != null)
{
var surfDesc = pSurf.Description;
if (surfDesc.Format != Format.D15S1 &&
surfDesc.Format != Format.D24S8 &&
surfDesc.Format != Format.D24X4S4 &&
surfDesc.Format != Format.D24SingleS8)
rsc.UnsetCapability( Graphics.Capabilities.StencilBuffer );
}
// Check for hardware occlusion support
//HRESULT hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
try
{
new Query(d3D9Device, QueryType.Occlusion);
}
catch (Direct3D9Exception)
{
rsc.UnsetCapability( Graphics.Capabilities.HardwareOcculusion );
}
}
// Update RS caps using the minimum value found in adapter list.
foreach (var pCurDriver in _driverList)
{
var rkCurCaps = pCurDriver.D3D9DeviceCaps;
if (rkCurCaps.MaxSimultaneousTextures < rsc.TextureUnitCount)
{
rsc.TextureUnitCount = rkCurCaps.MaxSimultaneousTextures;
}
// Check for Anisotropy.
if (rkCurCaps.MaxAnisotropy <= 1)
rsc.UnsetCapability( Graphics.Capabilities.AnisotropicFiltering );
// Check automatic mipmap generation.
if ((rkCurCaps.Caps2 & Caps2.CanAutoGenerateMipMap) == 0)
rsc.UnsetCapability( Graphics.Capabilities.HardwareMipMaps );
// Check Dot product 3.
if ((rkCurCaps.TextureOperationCaps & TextureOperationCaps.DotProduct3) == 0)
rsc.UnsetCapability( Graphics.Capabilities.Dot3 );
// Check cube map support.
if ((rkCurCaps.TextureCaps & TextureCaps.CubeMap) == 0)
rsc.UnsetCapability(Graphics.Capabilities.CubeMapping);
// Scissor test
if ((rkCurCaps.RasterCaps & RasterCaps.ScissorTest) == 0)
rsc.UnsetCapability(Graphics.Capabilities.ScissorTest);
// Two-sided stencil
if ((rkCurCaps.StencilCaps & StencilCaps.TwoSided) == 0)
rsc.UnsetCapability(Graphics.Capabilities.TwoSidedStencil);
// stencil wrap
if ((rkCurCaps.StencilCaps & StencilCaps.Increment) == 0 ||
(rkCurCaps.StencilCaps & StencilCaps.Decrement) == 0)
rsc.UnsetCapability(Graphics.Capabilities.StencilWrap);
// User clip planes
if (rkCurCaps.MaxUserClipPlanes == 0)
rsc.UnsetCapability(Graphics.Capabilities.UserClipPlanes);
// UBYTE4 type?
if ((rkCurCaps.DeclarationTypes & DeclarationTypeCaps.UByte4) == 0)
rsc.UnsetCapability(Graphics.Capabilities.VertexFormatUByte4);
// 3D textures?
if ((rkCurCaps.TextureCaps & TextureCaps.VolumeMap) == 0)
rsc.UnsetCapability(Graphics.Capabilities.Texture3D);
if ((rkCurCaps.TextureCaps & TextureCaps.Pow2) != 0)
{
// Conditional support for non POW2
if ((rkCurCaps.TextureCaps & TextureCaps.NonPow2Conditional) != 0)
rsc.NonPOW2TexturesLimited = true;
// Only power of 2 supported.
else
rsc.UnsetCapability(Graphics.Capabilities.NonPowerOf2Textures);
}
// Number of render targets
if (rkCurCaps.SimultaneousRTCount < rsc.MultiRenderTargetCount)
{
rsc.MultiRenderTargetCount = Utility.Min( rkCurCaps.SimultaneousRTCount, Config.MaxMultipleRenderTargets );
}
if((rkCurCaps.PrimitiveMiscCaps & PrimitiveMiscCaps.MrtIndependentBitDepths) == 0)
{
rsc.UnsetCapability(Graphics.Capabilities.MRTDifferentBitDepths);
}
// Point sprites
if (rkCurCaps.MaxPointSize <= 1.0f)
{
rsc.UnsetCapability(Graphics.Capabilities.PointSprites);
// sprites and extended parameters go together in D3D
rsc.UnsetCapability(Graphics.Capabilities.PointExtendedParameters);
}
// Take the minimum point size.
if (rkCurCaps.MaxPointSize < rsc.MaxPointSize)
rsc.MaxPointSize = rkCurCaps.MaxPointSize;
// Mipmap LOD biasing?
if ((rkCurCaps.RasterCaps & RasterCaps.MipMapLodBias) == 0)
rsc.UnsetCapability(Graphics.Capabilities.MipmapLODBias);
// Do we support per-stage src_manual constants?
// HACK - ATI drivers seem to be buggy and don't support per-stage constants properly?
// TODO: move this to RSC
if((rkCurCaps.PrimitiveMiscCaps & PrimitiveMiscCaps.PerStageConstant) == 0)
rsc.UnsetCapability(Graphics.Capabilities.PerStageConstant);
// Advanced blend operations? min max subtract rev
if ((rkCurCaps.PrimitiveMiscCaps & PrimitiveMiscCaps.BlendOperation) == 0)
rsc.UnsetCapability(Graphics.Capabilities.AdvancedBlendOperations);
}
// Blending between stages supported
rsc.SetCapability(Graphics.Capabilities.Blending);
// We always support compression, D3DX will decompress if device does not support
rsc.SetCapability(Graphics.Capabilities.TextureCompression);
rsc.SetCapability(Graphics.Capabilities.TextureCompressionDXT);
// We always support VBOs
rsc.SetCapability(Graphics.Capabilities.VertexBuffer);
ConvertVertexShaderCaps(rsc);
ConvertPixelShaderCaps(rsc);
// Adapter details
var adapterId = _activeD3DDriver.AdapterIdentifier;
// determine vendor
// Full list of vendors here: http://www.pcidatabase.com/vendors.php?sort=id
switch (adapterId.VendorId)
{
case 0x10DE:
rsc.Vendor = GPUVendor.Nvidia;
break;
case 0x1002:
rsc.Vendor = GPUVendor.Ati;
break;
case 0x163C:
case 0x8086:
rsc.Vendor = GPUVendor.Intel;
break;
case 0x5333:
rsc.Vendor = GPUVendor.S3;
break;
case 0x3D3D:
rsc.Vendor = GPUVendor._3DLabs;
break;
case 0x102B:
rsc.Vendor = GPUVendor.Matrox;
break;
case 0x1039:
rsc.Vendor = GPUVendor.Sis;
break;
default:
rsc.Vendor = GPUVendor.Unknown;
break;
}
// Infinite projection?
// We have no capability for this, so we have to base this on our
// experience and reports from users
// Non-vertex program capable hardware does not appear to support it
if (rsc.HasCapability(Graphics.Capabilities.VertexPrograms))
{
// GeForce4 Ti (and presumably GeForce3) does not
// render infinite projection properly, even though it does in GL
// So exclude all cards prior to the FX range from doing infinite
if (rsc.Vendor != GPUVendor.Nvidia || // not nVidia
!((adapterId.DeviceId >= 0x200 && adapterId.DeviceId <= 0x20F) || //gf3
(adapterId.DeviceId >= 0x250 && adapterId.DeviceId <= 0x25F) || //gf4ti
(adapterId.DeviceId >= 0x280 && adapterId.DeviceId <= 0x28F) || //gf4ti
(adapterId.DeviceId >= 0x170 && adapterId.DeviceId <= 0x18F) || //gf4 go
(adapterId.DeviceId >= 0x280 && adapterId.DeviceId <= 0x28F))) //gf4ti go
{
rsc.SetCapability( Graphics.Capabilities.InfiniteFarPlane );
}
}
// We always support rendertextures bigger than the frame buffer
rsc.SetCapability( Graphics.Capabilities.HardwareRenderToTexture );
// Determine if any floating point texture format is supported
var floatFormats = new[] {Format.R16F, Format.G16R16F,
Format.A16B16G16R16F, Format.R32F, Format.G32R32F,
Format.A32B32G32R32F};
var bbSurf = (Surface[])renderWindow[ "DDBACKBUFFER" ];
var bbSurfDesc = bbSurf[0].Description;
for (var i = 0; i < 6; ++i)
{
if (!_pD3D.CheckDeviceFormat(_activeD3DDriver.AdapterNumber,
DeviceType.Hardware, bbSurfDesc.Format, 0, ResourceType.Texture, floatFormats[i]))
continue;
rsc.SetCapability( Graphics.Capabilities.TextureFloat );
break;
}
// TODO: make convertVertex/Fragment fill in rsc
// TODO: update the below line to use rsc
// Vertex textures
if (rsc.IsShaderProfileSupported("vs_3_0"))
{
// Run through all the texture formats looking for any which support
// vertex texture fetching. Must have at least one!
// All ATI Radeon up to X1n00 say they support vs_3_0,
// but they support no texture formats for vertex texture fetch (cheaters!)
if (CheckVertexTextureFormats(renderWindow))
{
rsc.SetCapability( Graphics.Capabilities.VertexTextureFetch );
// always 4 vertex texture units in vs_3_0, and never shared
rsc.TextureUnitCount = 4;
rsc.VertexTextureUnitsShared = false;
}
}
else
{
//True HW Instancing is supported since Shader model 3.0 ATI has a nasty
//hack for enabling it in their SM 2.0 cards, but we don't (and won't) support it
rsc.UnsetCapability( Graphics.Capabilities.VertexBufferInstanceData );
}
// Check alpha to coverage support
// this varies per vendor! But at least SM3 is required
if (rsc.IsShaderProfileSupported("ps_3_0"))
{
// NVIDIA needs a separate check
switch ( rsc.Vendor )
{
case GPUVendor.Nvidia:
if (_pD3D.CheckDeviceFormat(0, DeviceType.Hardware, Format.X8R8G8B8, 0, ResourceType.Surface,
(Format)( 'A' | ( 'T' ) << 8 | ( 'O' ) << 16 | ( 'C' ) << 24 ) ))
{
rsc.SetCapability( Graphics.Capabilities.AlphaToCoverage );
}
break;
case GPUVendor.Ati:
rsc.SetCapability( Graphics.Capabilities.AlphaToCoverage );
break;
}
// no other cards have Dx9 hacks for alpha to coverage, as far as I know
}
if (realCapabilities == null)
{
realCapabilities = rsc;
realCapabilities.AddShaderProfile("hlsl");
// if we are using custom capabilities, then
// mCurrentCapabilities has already been loaded
if(!useCustomCapabilities)
currentCapabilities = realCapabilities;
FireEvent("RenderSystemCapabilitiesCreated");
InitializeFromRenderSystemCapabilities(currentCapabilities, renderWindow);
}
return rsc;
}