Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
References:
File last commit:
Show/Diff file:
Action:
FNA/src/Graphics/PipelineCache.cs
748 lines | 19.6 KiB | text/x-csharp | CSharpLexer
748 lines | 19.6 KiB | text/x-csharp | CSharpLexer
r0 | #region License | |||
/* FNA - XNA4 Reimplementation for Desktop Platforms | ||||
* Copyright 2009-2020 Ethan Lee and the MonoGame Team | ||||
* | ||||
* Released under the Microsoft Public License. | ||||
* See LICENSE for details. | ||||
*/ | ||||
#endregion | ||||
#region VERBOSE_PIPELINECACHE Option | ||||
// #define VERBOSE_PIPELINECACHE | ||||
/* If you want to debug the PipelineCache to make sure it's interpreting your | ||||
* Effects' render state changes properly, you can enable this and get a bunch | ||||
* of messages logged to FNALoggerEXT. | ||||
* -flibit | ||||
*/ | ||||
#endregion | ||||
#region Using Statements | ||||
using System; | ||||
using System.Collections.Generic; | ||||
using System.Runtime.InteropServices; | ||||
#endregion | ||||
namespace Microsoft.Xna.Framework.Graphics | ||||
{ | ||||
#region Internal PSO Hash Struct | ||||
[StructLayout(LayoutKind.Sequential)] | ||||
internal struct StateHash : IEquatable<StateHash> | ||||
{ | ||||
readonly ulong a; | ||||
readonly ulong b; | ||||
public StateHash(ulong a, ulong b) | ||||
{ | ||||
this.a = a; | ||||
this.b = b; | ||||
} | ||||
public override string ToString() | ||||
{ | ||||
return Convert.ToString((long) a, 2).PadLeft(64, '0') + "|" + | ||||
Convert.ToString((long) b, 2).PadLeft(64, '0'); | ||||
} | ||||
bool IEquatable<StateHash>.Equals(StateHash hash) | ||||
{ | ||||
return a == hash.a && b == hash.b; | ||||
} | ||||
public override bool Equals(object obj) | ||||
{ | ||||
if (obj == null || obj.GetType() != GetType()) | ||||
{ | ||||
return false; | ||||
} | ||||
StateHash hash = (StateHash) obj; | ||||
return a == hash.a && b == hash.b; | ||||
} | ||||
public override int GetHashCode() | ||||
{ | ||||
unchecked | ||||
{ | ||||
int i1 = (int) (a ^ (a >> 32)); | ||||
int i2 = (int) (b ^ (b >> 32)); | ||||
return i1 + i2; | ||||
} | ||||
} | ||||
} | ||||
#endregion | ||||
internal class PipelineCache | ||||
{ | ||||
#region Private Variables | ||||
private GraphicsDevice device; | ||||
#endregion | ||||
#region Public Constructor | ||||
public PipelineCache(GraphicsDevice graphicsDevice) | ||||
{ | ||||
device = graphicsDevice; | ||||
} | ||||
#endregion | ||||
#region BlendState Cache | ||||
/* Public Variables */ | ||||
public BlendFunction AlphaBlendFunction; | ||||
public Blend AlphaDestinationBlend; | ||||
public Blend AlphaSourceBlend; | ||||
public BlendFunction ColorBlendFunction; | ||||
public Blend ColorDestinationBlend; | ||||
public Blend ColorSourceBlend; | ||||
public ColorWriteChannels ColorWriteChannels; | ||||
public ColorWriteChannels ColorWriteChannels1; | ||||
public ColorWriteChannels ColorWriteChannels2; | ||||
public ColorWriteChannels ColorWriteChannels3; | ||||
public Color BlendFactor; | ||||
public int MultiSampleMask; | ||||
/* FIXME: Do we actually care about this calculation, or do we | ||||
* just assume false each time? | ||||
* -flibit | ||||
*/ | ||||
public bool SeparateAlphaBlend; | ||||
/* Private Cache Storage */ | ||||
private Dictionary<StateHash, BlendState> blendCache = | ||||
new Dictionary<StateHash, BlendState>(); | ||||
/* Private Hashing Functions */ | ||||
private static StateHash GetBlendHash( | ||||
BlendFunction alphaBlendFunc, | ||||
Blend alphaDestBlend, | ||||
Blend alphaSrcBlend, | ||||
BlendFunction colorBlendFunc, | ||||
Blend colorDestBlend, | ||||
Blend colorSrcBlend, | ||||
ColorWriteChannels channels, | ||||
ColorWriteChannels channels1, | ||||
ColorWriteChannels channels2, | ||||
ColorWriteChannels channels3, | ||||
Color blendFactor, | ||||
int multisampleMask | ||||
) { | ||||
int funcs = ((int) alphaBlendFunc << 4) | ((int) colorBlendFunc); | ||||
int blendsAndColorWriteChannels = | ||||
((int) alphaDestBlend << 28) | ||||
| ((int) alphaSrcBlend << 24) | ||||
| ((int) colorDestBlend << 20) | ||||
| ((int) colorSrcBlend << 16) | ||||
| ((int) channels << 12) | ||||
| ((int) channels1 << 8) | ||||
| ((int) channels2 << 4) | ||||
| ((int) channels3); | ||||
unchecked | ||||
{ | ||||
return new StateHash( | ||||
((ulong) funcs << 32) | ((ulong) blendsAndColorWriteChannels << 0), | ||||
((ulong) multisampleMask << 32) | ((ulong) blendFactor.PackedValue << 0) | ||||
); | ||||
} | ||||
} | ||||
/* Public Functions */ | ||||
public static StateHash GetBlendHash(BlendState state) | ||||
{ | ||||
return GetBlendHash( | ||||
state.AlphaBlendFunction, | ||||
state.AlphaDestinationBlend, | ||||
state.AlphaSourceBlend, | ||||
state.ColorBlendFunction, | ||||
state.ColorDestinationBlend, | ||||
state.ColorSourceBlend, | ||||
state.ColorWriteChannels, | ||||
state.ColorWriteChannels1, | ||||
state.ColorWriteChannels2, | ||||
state.ColorWriteChannels3, | ||||
state.BlendFactor, | ||||
state.MultiSampleMask | ||||
); | ||||
} | ||||
public void BeginApplyBlend() | ||||
{ | ||||
BlendState oldBlendState = device.BlendState; | ||||
AlphaBlendFunction = oldBlendState.AlphaBlendFunction; | ||||
AlphaDestinationBlend = oldBlendState.AlphaDestinationBlend; | ||||
AlphaSourceBlend = oldBlendState.AlphaSourceBlend; | ||||
ColorBlendFunction = oldBlendState.ColorBlendFunction; | ||||
ColorDestinationBlend = oldBlendState.ColorDestinationBlend; | ||||
ColorSourceBlend = oldBlendState.ColorSourceBlend; | ||||
ColorWriteChannels = oldBlendState.ColorWriteChannels; | ||||
ColorWriteChannels1 = oldBlendState.ColorWriteChannels1; | ||||
ColorWriteChannels2 = oldBlendState.ColorWriteChannels2; | ||||
ColorWriteChannels3 = oldBlendState.ColorWriteChannels3; | ||||
BlendFactor = oldBlendState.BlendFactor; | ||||
MultiSampleMask = oldBlendState.MultiSampleMask; | ||||
SeparateAlphaBlend = ( | ||||
ColorBlendFunction != AlphaBlendFunction || | ||||
ColorDestinationBlend != AlphaDestinationBlend | ||||
); | ||||
} | ||||
public void EndApplyBlend() | ||||
{ | ||||
StateHash hash = GetBlendHash( | ||||
AlphaBlendFunction, | ||||
AlphaDestinationBlend, | ||||
AlphaSourceBlend, | ||||
ColorBlendFunction, | ||||
ColorDestinationBlend, | ||||
ColorSourceBlend, | ||||
ColorWriteChannels, | ||||
ColorWriteChannels1, | ||||
ColorWriteChannels2, | ||||
ColorWriteChannels3, | ||||
BlendFactor, | ||||
MultiSampleMask | ||||
); | ||||
BlendState newBlend; | ||||
if (!blendCache.TryGetValue(hash, out newBlend)) | ||||
{ | ||||
newBlend = new BlendState(); | ||||
newBlend.AlphaBlendFunction = AlphaBlendFunction; | ||||
newBlend.AlphaDestinationBlend = AlphaDestinationBlend; | ||||
newBlend.AlphaSourceBlend = AlphaSourceBlend; | ||||
newBlend.ColorBlendFunction = ColorBlendFunction; | ||||
newBlend.ColorDestinationBlend = ColorDestinationBlend; | ||||
newBlend.ColorSourceBlend = ColorSourceBlend; | ||||
newBlend.ColorWriteChannels = ColorWriteChannels; | ||||
newBlend.ColorWriteChannels1 = ColorWriteChannels1; | ||||
newBlend.ColorWriteChannels2 = ColorWriteChannels2; | ||||
newBlend.ColorWriteChannels3 = ColorWriteChannels3; | ||||
newBlend.BlendFactor = BlendFactor; | ||||
newBlend.MultiSampleMask = MultiSampleMask; | ||||
blendCache.Add(hash, newBlend); | ||||
#if VERBOSE_PIPELINECACHE | ||||
FNALoggerEXT.LogInfo( | ||||
"New BlendState added to pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
FNALoggerEXT.LogInfo( | ||||
"Updated size of BlendState cache: " + | ||||
blendCache.Count | ||||
); | ||||
} | ||||
else | ||||
{ | ||||
FNALoggerEXT.LogInfo( | ||||
"Retrieved BlendState from pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
#endif | ||||
} | ||||
device.BlendState = newBlend; | ||||
} | ||||
#endregion | ||||
#region DepthStencilState Cache | ||||
/* Public Variables */ | ||||
public bool DepthBufferEnable; | ||||
public bool DepthBufferWriteEnable; | ||||
public CompareFunction DepthBufferFunction; | ||||
public bool StencilEnable; | ||||
public CompareFunction StencilFunction; | ||||
public StencilOperation StencilPass; | ||||
public StencilOperation StencilFail; | ||||
public StencilOperation StencilDepthBufferFail; | ||||
public bool TwoSidedStencilMode; | ||||
public CompareFunction CCWStencilFunction; | ||||
public StencilOperation CCWStencilFail; | ||||
public StencilOperation CCWStencilPass; | ||||
public StencilOperation CCWStencilDepthBufferFail; | ||||
public int StencilMask; | ||||
public int StencilWriteMask; | ||||
public int ReferenceStencil; | ||||
/* Private Cache Storage */ | ||||
private Dictionary<StateHash, DepthStencilState> depthStencilCache = | ||||
new Dictionary<StateHash, DepthStencilState>(); | ||||
/* Private Hashing Functions */ | ||||
private static StateHash GetDepthStencilHash( | ||||
bool depthBufferEnable, | ||||
bool depthWriteEnable, | ||||
CompareFunction depthFunc, | ||||
bool stencilEnable, | ||||
CompareFunction stencilFunc, | ||||
StencilOperation stencilPass, | ||||
StencilOperation stencilFail, | ||||
StencilOperation stencilDepthFail, | ||||
bool twoSidedStencil, | ||||
CompareFunction ccwStencilFunc, | ||||
StencilOperation ccwStencilPass, | ||||
StencilOperation ccwStencilFail, | ||||
StencilOperation ccwStencilDepthFail, | ||||
int stencilMask, | ||||
int stencilWriteMask, | ||||
int referenceStencil | ||||
) { | ||||
// Bool -> Int32 conversion | ||||
int zEnable = depthBufferEnable ? 1 : 0; | ||||
int zWriteEnable = depthWriteEnable ? 1 : 0; | ||||
int sEnable = stencilEnable ? 1 : 0; | ||||
int twoSided = twoSidedStencil ? 1 : 0; | ||||
int packedProperties = | ||||
((int) zEnable << 30) | ||||
| ((int) zWriteEnable << 29) | ||||
| ((int) sEnable << 28) | ||||
| ((int) twoSided << 27) | ||||
| ((int) depthFunc << 24) | ||||
| ((int) stencilFunc << 21) | ||||
| ((int) ccwStencilFunc << 18) | ||||
| ((int) stencilPass << 15) | ||||
| ((int) stencilFail << 12) | ||||
| ((int) stencilDepthFail << 9) | ||||
| ((int) ccwStencilFail << 6) | ||||
| ((int) ccwStencilPass << 3) | ||||
| ((int) ccwStencilDepthFail); | ||||
unchecked | ||||
{ | ||||
return new StateHash( | ||||
((ulong) stencilMask << 32) | ((ulong) packedProperties << 0), | ||||
((ulong) referenceStencil << 32) | ((ulong) stencilWriteMask << 0) | ||||
); | ||||
} | ||||
} | ||||
/* Public Functions */ | ||||
public static StateHash GetDepthStencilHash(DepthStencilState state) | ||||
{ | ||||
return GetDepthStencilHash( | ||||
state.DepthBufferEnable, | ||||
state.DepthBufferWriteEnable, | ||||
state.DepthBufferFunction, | ||||
state.StencilEnable, | ||||
state.StencilFunction, | ||||
state.StencilPass, | ||||
state.StencilFail, | ||||
state.StencilDepthBufferFail, | ||||
state.TwoSidedStencilMode, | ||||
state.CounterClockwiseStencilFunction, | ||||
state.CounterClockwiseStencilPass, | ||||
state.CounterClockwiseStencilFail, | ||||
state.CounterClockwiseStencilDepthBufferFail, | ||||
state.StencilMask, | ||||
state.StencilWriteMask, | ||||
state.ReferenceStencil | ||||
); | ||||
} | ||||
public void BeginApplyDepthStencil() | ||||
{ | ||||
DepthStencilState oldDepthStencilState = device.DepthStencilState; | ||||
DepthBufferEnable = oldDepthStencilState.DepthBufferEnable; | ||||
DepthBufferWriteEnable = oldDepthStencilState.DepthBufferWriteEnable; | ||||
DepthBufferFunction = oldDepthStencilState.DepthBufferFunction; | ||||
StencilEnable = oldDepthStencilState.StencilEnable; | ||||
StencilFunction = oldDepthStencilState.StencilFunction; | ||||
StencilPass = oldDepthStencilState.StencilPass; | ||||
StencilFail = oldDepthStencilState.StencilFail; | ||||
StencilDepthBufferFail = oldDepthStencilState.StencilDepthBufferFail; | ||||
TwoSidedStencilMode = oldDepthStencilState.TwoSidedStencilMode; | ||||
CCWStencilFunction = oldDepthStencilState.CounterClockwiseStencilFunction; | ||||
CCWStencilFail = oldDepthStencilState.CounterClockwiseStencilFail; | ||||
CCWStencilPass = oldDepthStencilState.CounterClockwiseStencilPass; | ||||
CCWStencilDepthBufferFail = oldDepthStencilState.CounterClockwiseStencilDepthBufferFail; | ||||
StencilMask = oldDepthStencilState.StencilMask; | ||||
StencilWriteMask = oldDepthStencilState.StencilWriteMask; | ||||
ReferenceStencil = oldDepthStencilState.ReferenceStencil; | ||||
} | ||||
public void EndApplyDepthStencil() | ||||
{ | ||||
StateHash hash = GetDepthStencilHash( | ||||
DepthBufferEnable, | ||||
DepthBufferWriteEnable, | ||||
DepthBufferFunction, | ||||
StencilEnable, | ||||
StencilFunction, | ||||
StencilPass, | ||||
StencilFail, | ||||
StencilDepthBufferFail, | ||||
TwoSidedStencilMode, | ||||
CCWStencilFunction, | ||||
CCWStencilPass, | ||||
CCWStencilFail, | ||||
CCWStencilDepthBufferFail, | ||||
StencilMask, | ||||
StencilWriteMask, | ||||
ReferenceStencil | ||||
); | ||||
DepthStencilState newDepthStencil; | ||||
if (!depthStencilCache.TryGetValue(hash, out newDepthStencil)) | ||||
{ | ||||
newDepthStencil = new DepthStencilState(); | ||||
newDepthStencil.DepthBufferEnable = DepthBufferEnable; | ||||
newDepthStencil.DepthBufferWriteEnable = DepthBufferWriteEnable; | ||||
newDepthStencil.DepthBufferFunction = DepthBufferFunction; | ||||
newDepthStencil.StencilEnable = StencilEnable; | ||||
newDepthStencil.StencilFunction = StencilFunction; | ||||
newDepthStencil.StencilPass = StencilPass; | ||||
newDepthStencil.StencilFail = StencilFail; | ||||
newDepthStencil.StencilDepthBufferFail = StencilDepthBufferFail; | ||||
newDepthStencil.TwoSidedStencilMode = TwoSidedStencilMode; | ||||
newDepthStencil.CounterClockwiseStencilFunction = CCWStencilFunction; | ||||
newDepthStencil.CounterClockwiseStencilFail = CCWStencilFail; | ||||
newDepthStencil.CounterClockwiseStencilPass = CCWStencilPass; | ||||
newDepthStencil.CounterClockwiseStencilDepthBufferFail = CCWStencilDepthBufferFail; | ||||
newDepthStencil.StencilMask = StencilMask; | ||||
newDepthStencil.StencilWriteMask = StencilWriteMask; | ||||
newDepthStencil.ReferenceStencil = ReferenceStencil; | ||||
depthStencilCache.Add(hash, newDepthStencil); | ||||
#if VERBOSE_PIPELINECACHE | ||||
FNALoggerEXT.LogInfo( | ||||
"New DepthStencilState added to pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
FNALoggerEXT.LogInfo( | ||||
"Updated size of DepthStencilState cache: " + | ||||
depthStencilCache.Count | ||||
); | ||||
} | ||||
else | ||||
{ | ||||
FNALoggerEXT.LogInfo( | ||||
"Retrieved DepthStencilState from pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
#endif | ||||
} | ||||
device.DepthStencilState = newDepthStencil; | ||||
} | ||||
#endregion | ||||
#region RasterizerState Cache | ||||
/* Public Variables */ | ||||
public CullMode CullMode; | ||||
public FillMode FillMode; | ||||
public float DepthBias; | ||||
public bool MultiSampleAntiAlias; | ||||
public bool ScissorTestEnable; | ||||
public float SlopeScaleDepthBias; | ||||
/* Private Cache Storage */ | ||||
private Dictionary<StateHash, RasterizerState> rasterizerCache = | ||||
new Dictionary<StateHash, RasterizerState>(); | ||||
/* Private Hashing Functions */ | ||||
private static StateHash GetRasterizerHash( | ||||
CullMode cullMode, | ||||
FillMode fillMode, | ||||
float depthBias, | ||||
bool msaa, | ||||
bool scissor, | ||||
float slopeScaleDepthBias | ||||
) { | ||||
// Bool -> Int32 conversion | ||||
int multiSampleAntiAlias = (msaa ? 1 : 0); | ||||
int scissorTestEnable = (scissor ? 1 : 0); | ||||
int packedProperties = | ||||
((int) multiSampleAntiAlias << 4) | ||||
| ((int) scissorTestEnable << 3) | ||||
| ((int) cullMode << 1) | ||||
| ((int) fillMode); | ||||
unchecked | ||||
{ | ||||
return new StateHash( | ||||
(ulong) packedProperties, | ||||
(FloatToULong(slopeScaleDepthBias) << 32) | FloatToULong(depthBias) | ||||
); | ||||
} | ||||
} | ||||
/* Public Functions */ | ||||
public static StateHash GetRasterizerHash(RasterizerState state) | ||||
{ | ||||
return GetRasterizerHash( | ||||
state.CullMode, | ||||
state.FillMode, | ||||
state.DepthBias, | ||||
state.MultiSampleAntiAlias, | ||||
state.ScissorTestEnable, | ||||
state.SlopeScaleDepthBias | ||||
); | ||||
} | ||||
public void BeginApplyRasterizer() | ||||
{ | ||||
RasterizerState oldRasterizerState = device.RasterizerState; | ||||
CullMode = oldRasterizerState.CullMode; | ||||
FillMode = oldRasterizerState.FillMode; | ||||
DepthBias = oldRasterizerState.DepthBias; | ||||
MultiSampleAntiAlias = oldRasterizerState.MultiSampleAntiAlias; | ||||
ScissorTestEnable = oldRasterizerState.ScissorTestEnable; | ||||
SlopeScaleDepthBias = oldRasterizerState.SlopeScaleDepthBias; | ||||
} | ||||
public void EndApplyRasterizer() | ||||
{ | ||||
StateHash hash = GetRasterizerHash( | ||||
CullMode, | ||||
FillMode, | ||||
DepthBias, | ||||
MultiSampleAntiAlias, | ||||
ScissorTestEnable, | ||||
SlopeScaleDepthBias | ||||
); | ||||
RasterizerState newRasterizer; | ||||
if (!rasterizerCache.TryGetValue(hash, out newRasterizer)) | ||||
{ | ||||
newRasterizer = new RasterizerState(); | ||||
newRasterizer.CullMode = CullMode; | ||||
newRasterizer.FillMode = FillMode; | ||||
newRasterizer.DepthBias = DepthBias; | ||||
newRasterizer.MultiSampleAntiAlias = MultiSampleAntiAlias; | ||||
newRasterizer.ScissorTestEnable = ScissorTestEnable; | ||||
newRasterizer.SlopeScaleDepthBias = SlopeScaleDepthBias; | ||||
rasterizerCache.Add(hash, newRasterizer); | ||||
#if VERBOSE_PIPELINECACHE | ||||
FNALoggerEXT.LogInfo( | ||||
"New RasterizerState added to pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
FNALoggerEXT.LogInfo( | ||||
"Updated size of RasterizerState cache: " + | ||||
rasterizerCache.Count | ||||
); | ||||
} | ||||
else | ||||
{ | ||||
FNALoggerEXT.LogInfo( | ||||
"Retrieved RasterizerState from pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
#endif | ||||
} | ||||
device.RasterizerState = newRasterizer; | ||||
} | ||||
#endregion | ||||
#region SamplerState Cache | ||||
/* Public Variables */ | ||||
public TextureAddressMode AddressU; | ||||
public TextureAddressMode AddressV; | ||||
public TextureAddressMode AddressW; | ||||
public int MaxAnisotropy; | ||||
public int MaxMipLevel; | ||||
public float MipMapLODBias; | ||||
public TextureFilter Filter; | ||||
/* Private Cache Storage */ | ||||
private Dictionary<StateHash, SamplerState> samplerCache = | ||||
new Dictionary<StateHash, SamplerState>(); | ||||
/* Private Hashing Functions */ | ||||
private static StateHash GetSamplerHash( | ||||
TextureAddressMode addressU, | ||||
TextureAddressMode addressV, | ||||
TextureAddressMode addressW, | ||||
int maxAnisotropy, | ||||
int maxMipLevel, | ||||
float mipLODBias, | ||||
TextureFilter filter | ||||
) { | ||||
int filterAndAddresses = | ||||
((int) filter << 6) | ||||
| ((int) addressU << 4) | ||||
| ((int) addressV << 2) | ||||
| ((int) addressW); | ||||
unchecked | ||||
{ | ||||
return new StateHash( | ||||
((ulong) maxAnisotropy << 32) | ((ulong) filterAndAddresses << 0), | ||||
(FloatToULong(mipLODBias) << 32) | ((ulong) maxMipLevel << 0) | ||||
); | ||||
} | ||||
} | ||||
/* Public Functions */ | ||||
public static StateHash GetSamplerHash(SamplerState state) | ||||
{ | ||||
return GetSamplerHash( | ||||
state.AddressU, | ||||
state.AddressV, | ||||
state.AddressW, | ||||
state.MaxAnisotropy, | ||||
state.MaxMipLevel, | ||||
state.MipMapLevelOfDetailBias, | ||||
state.Filter | ||||
); | ||||
} | ||||
public void BeginApplySampler(SamplerStateCollection samplers, int register) | ||||
{ | ||||
SamplerState oldSampler = samplers[register]; | ||||
AddressU = oldSampler.AddressU; | ||||
AddressV = oldSampler.AddressV; | ||||
AddressW = oldSampler.AddressW; | ||||
MaxAnisotropy = oldSampler.MaxAnisotropy; | ||||
MaxMipLevel = oldSampler.MaxMipLevel; | ||||
MipMapLODBias = oldSampler.MipMapLevelOfDetailBias; | ||||
Filter = oldSampler.Filter; | ||||
} | ||||
public void EndApplySampler(SamplerStateCollection samplers, int register) | ||||
{ | ||||
StateHash hash = GetSamplerHash( | ||||
AddressU, | ||||
AddressV, | ||||
AddressW, | ||||
MaxAnisotropy, | ||||
MaxMipLevel, | ||||
MipMapLODBias, | ||||
Filter | ||||
); | ||||
SamplerState newSampler; | ||||
if (!samplerCache.TryGetValue(hash, out newSampler)) | ||||
{ | ||||
newSampler = new SamplerState(); | ||||
newSampler.Filter = Filter; | ||||
newSampler.AddressU = AddressU; | ||||
newSampler.AddressV = AddressV; | ||||
newSampler.AddressW = AddressW; | ||||
newSampler.MaxAnisotropy = MaxAnisotropy; | ||||
newSampler.MaxMipLevel = MaxMipLevel; | ||||
newSampler.MipMapLevelOfDetailBias = MipMapLODBias; | ||||
samplerCache.Add(hash, newSampler); | ||||
#if VERBOSE_PIPELINECACHE | ||||
FNALoggerEXT.LogInfo( | ||||
"New SamplerState added to pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
FNALoggerEXT.LogInfo( | ||||
"Updated size of SamplerState cache: " + | ||||
samplerCache.Count | ||||
); | ||||
} | ||||
else | ||||
{ | ||||
FNALoggerEXT.LogInfo( | ||||
"Retrieved SamplerState from pipeline cache with hash:\n" + | ||||
hash.ToString() | ||||
); | ||||
#endif | ||||
} | ||||
samplers[register] = newSampler; | ||||
} | ||||
#endregion | ||||
#region Vertex Declaration Hashing Methods | ||||
/* The algorithm for these hashing methods | ||||
* is taken from Josh Bloch's "Effective Java". | ||||
* (https://stackoverflow.com/a/113600/12492383) | ||||
* | ||||
* FIXME: Is there a better way to hash this? | ||||
* -caleb | ||||
*/ | ||||
private const ulong HASH_FACTOR = 39; | ||||
public static ulong GetVertexDeclarationHash( | ||||
VertexDeclaration declaration, | ||||
ulong vertexShader | ||||
) { | ||||
ulong hash = vertexShader; | ||||
unchecked | ||||
{ | ||||
for (int i = 0; i < declaration.elements.Length; i += 1) | ||||
{ | ||||
hash = hash * HASH_FACTOR + ( | ||||
(ulong) declaration.elements[i].GetHashCode() | ||||
); | ||||
} | ||||
hash = hash * HASH_FACTOR + (ulong) declaration.VertexStride; | ||||
} | ||||
return hash; | ||||
} | ||||
public static ulong GetVertexBindingHash( | ||||
VertexBufferBinding[] bindings, | ||||
int numBindings, | ||||
ulong vertexShader | ||||
) { | ||||
ulong hash = vertexShader; | ||||
unchecked | ||||
{ | ||||
for (int i = 0; i < numBindings; i += 1) | ||||
{ | ||||
VertexBufferBinding binding = bindings[i]; | ||||
hash = hash * HASH_FACTOR + (ulong) binding.InstanceFrequency; | ||||
hash = hash * HASH_FACTOR + GetVertexDeclarationHash( | ||||
binding.VertexBuffer.VertexDeclaration, | ||||
vertexShader | ||||
); | ||||
} | ||||
} | ||||
return hash; | ||||
} | ||||
#endregion | ||||
#region Private Helper Methods | ||||
private static unsafe ulong FloatToULong(float f) | ||||
{ | ||||
uint uintRep = *((uint *) &f); | ||||
return unchecked((ulong) uintRep); | ||||
} | ||||
#endregion | ||||
} | ||||
} | ||||