Show More
Commit Description:
Add timers for Simulation and various engines...
Commit Description:
Add timers for Simulation and various engines Starting to add additional timers for different stages of the process of updating in order to get more insight into what is slowing it down. The update takes 9ms, which is much longer than it used to. Engine-specific timers are coming later.
File last commit:
Show/Diff file:
Action:
FNA/src/FNAPlatform/ThreadedGLDevice.cs
1203 lines | 21.5 KiB | text/x-csharp | CSharpLexer
#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 Using Statements
using System;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
#endregion
namespace Microsoft.Xna.Framework.Graphics
{
internal class ThreadedGLDevice : IGLDevice
{
#region Public Properties
public Color BlendFactor
{
get
{
Color result = Color.Black;
ForceToMainThread(() =>
{
result = GLDevice.BlendFactor;
}); // End ForceToMainThread
return result;
}
set
{
ForceToMainThread(() =>
{
GLDevice.BlendFactor = value;
}); // End ForceToMainThread
}
}
public int MultiSampleMask
{
get
{
int result = 0;
ForceToMainThread(() =>
{
result = GLDevice.MultiSampleMask;
}); // End ForceToMainThread
return result;
}
set
{
ForceToMainThread(() =>
{
GLDevice.MultiSampleMask = value;
}); // End ForceToMainThread
}
}
public int ReferenceStencil
{
get
{
int result = 0;
ForceToMainThread(() =>
{
result = GLDevice.ReferenceStencil;
}); // End ForceToMainThread
return result;
}
set
{
ForceToMainThread(() =>
{
GLDevice.ReferenceStencil = value;
}); // End ForceToMainThread
}
}
public bool SupportsDxt1
{
get
{
bool result = false;
ForceToMainThread(() =>
{
result = GLDevice.SupportsDxt1;
}); // End ForceToMainThread
return result;
}
}
public bool SupportsS3tc
{
get
{
bool result = false;
ForceToMainThread(() =>
{
result = GLDevice.SupportsS3tc;
}); // End ForceToMainThread
return result;
}
}
public bool SupportsHardwareInstancing
{
get
{
bool result = false;
ForceToMainThread(() =>
{
result = GLDevice.SupportsHardwareInstancing;
}); // End ForceToMainThread
return result;
}
}
public bool SupportsNoOverwrite
{
get
{
bool result = false;
ForceToMainThread(() =>
{
result = GLDevice.SupportsNoOverwrite;
}); // End ForceToMainThread
return result;
}
}
public int MaxTextureSlots
{
get
{
int result = 0;
ForceToMainThread(() =>
{
result = GLDevice.MaxTextureSlots;
}); // End ForceToMainThread
return result;
}
}
public int MaxMultiSampleCount
{
get
{
int result = 0;
ForceToMainThread(() =>
{
result = GLDevice.MaxMultiSampleCount;
}); // End ForceToMainThread
return result;
}
}
public IGLBackbuffer Backbuffer
{
get
{
IGLBackbuffer result = null;
ForceToMainThread(() =>
{
result = GLDevice.Backbuffer;
}); // End ForceToMainThread
return result;
}
}
#endregion
#region Private Variables
private IGLDevice GLDevice;
private Thread csThread;
private bool csDone = false;
private AutoResetEvent csEvent = new AutoResetEvent(false);
private List<Action> actions = new List<Action>();
#endregion
#region Private Graphics Object Disposal Queues
private ConcurrentQueue<IGLTexture> GCTextures = new ConcurrentQueue<IGLTexture>();
private ConcurrentQueue<IGLRenderbuffer> GCRenderbuffers = new ConcurrentQueue<IGLRenderbuffer>();
private ConcurrentQueue<IGLBuffer> GCVertexBuffers = new ConcurrentQueue<IGLBuffer>();
private ConcurrentQueue<IGLBuffer> GCIndexBuffers = new ConcurrentQueue<IGLBuffer>();
private ConcurrentQueue<IGLEffect> GCEffects = new ConcurrentQueue<IGLEffect>();
private ConcurrentQueue<IGLQuery> GCQueries = new ConcurrentQueue<IGLQuery>();
#endregion
#region Thread Functions
private void csThreadProc()
{
while (!csDone)
{
csEvent.WaitOne();
lock (actions)
{
foreach (Action action in actions)
{
action();
}
actions.Clear();
}
}
GLDevice.Dispose();
}
private void ForceToMainThread(Action action)
{
ManualResetEventSlim resetEvent = new ManualResetEventSlim(false);
lock (actions)
{
actions.Add(() =>
{
action();
resetEvent.Set();
});
}
csEvent.Set();
resetEvent.Wait();
}
#endregion
#region Constructor/Disposal
public ThreadedGLDevice(PresentationParameters presentationParameters)
{
csThread = new Thread(new ThreadStart(csThreadProc));
csThread.Start();
FNALoggerEXT.LogInfo("Running with ThreadedGLDevice!");
ForceToMainThread(() =>
{
if (Environment.GetEnvironmentVariable(
"FNA_THREADEDGLDEVICE_GLDEVICE"
) == "OpenGLDevice") {
GLDevice = new OpenGLDevice(
presentationParameters
);
}
else
{
GLDevice = new ModernGLDevice(
presentationParameters
);
}
}); // End ForceToMainThread
}
public void Dispose()
{
ForceToMainThread(() =>
{
csDone = true;
}); // End ForceToMainThread
csThread.Join();
}
#endregion
#region BeginFrame Operations
public void BeginFrame()
{
ForceToMainThread(() =>
{
GLDevice.BeginFrame();
}); // End ForceToMainThread
}
#endregion
#region Backbuffer Operations
public void ResetBackbuffer(PresentationParameters presentationParameters)
{
ForceToMainThread(() =>
{
GLDevice.ResetBackbuffer(
presentationParameters
);
}); // End ForceToMainThread
}
public void SwapBuffers(
Rectangle? sourceRectangle,
Rectangle? destinationRectangle,
IntPtr overrideWindowHandle
) {
ForceToMainThread(() =>
{
GLDevice.SwapBuffers(
sourceRectangle,
destinationRectangle,
overrideWindowHandle
);
IGLTexture gcTexture;
while (GCTextures.TryDequeue(out gcTexture))
{
GLDevice.AddDisposeTexture(gcTexture);
}
IGLRenderbuffer gcRenderbuffer;
while (GCRenderbuffers.TryDequeue(out gcRenderbuffer))
{
GLDevice.AddDisposeRenderbuffer(gcRenderbuffer);
}
IGLBuffer gcBuffer;
while (GCVertexBuffers.TryDequeue(out gcBuffer))
{
GLDevice.AddDisposeVertexBuffer(gcBuffer);
}
while (GCIndexBuffers.TryDequeue(out gcBuffer))
{
GLDevice.AddDisposeIndexBuffer(gcBuffer);
}
IGLEffect gcEffect;
while (GCEffects.TryDequeue(out gcEffect))
{
GLDevice.AddDisposeEffect(gcEffect);
}
IGLQuery gcQuery;
while (GCQueries.TryDequeue(out gcQuery))
{
GLDevice.AddDisposeQuery(gcQuery);
}
}); // End ForceToMainThread
}
#endregion
#region SetStringMarkerEXT
public void SetStringMarker(string text)
{
ForceToMainThread(() =>
{
GLDevice.SetStringMarker(text);
}); // End ForceToMainThread
}
#endregion
#region Draw Calls
public void DrawIndexedPrimitives(
PrimitiveType primitiveType,
int baseVertex,
int minVertexIndex,
int numVertices,
int startIndex,
int primitiveCount,
IGLBuffer indices,
IndexElementSize indexElementSize
) {
ForceToMainThread(() =>
{
GLDevice.DrawIndexedPrimitives(
primitiveType,
baseVertex,
minVertexIndex,
numVertices,
startIndex,
primitiveCount,
indices,
indexElementSize
);
}); // End ForceToMainThread
}
public void DrawInstancedPrimitives(
PrimitiveType primitiveType,
int baseVertex,
int minVertexIndex,
int numVertices,
int startIndex,
int primitiveCount,
int instanceCount,
IGLBuffer indices,
IndexElementSize indexElementSize
) {
ForceToMainThread(() =>
{
GLDevice.DrawInstancedPrimitives(
primitiveType,
baseVertex,
minVertexIndex,
numVertices,
startIndex,
primitiveCount,
instanceCount,
indices,
indexElementSize
);
}); // End ForceToMainThread
}
public void DrawPrimitives(
PrimitiveType primitiveType,
int vertexStart,
int primitiveCount
) {
ForceToMainThread(() =>
{
GLDevice.DrawPrimitives(
primitiveType,
vertexStart,
primitiveCount
);
}); // End ForceToMainThread
}
public void DrawUserIndexedPrimitives(
PrimitiveType primitiveType,
IntPtr vertexData,
int vertexOffset,
int numVertices,
IntPtr indexData,
int indexOffset,
IndexElementSize indexElementSize,
int primitiveCount
) {
ForceToMainThread(() =>
{
GLDevice.DrawUserIndexedPrimitives(
primitiveType,
vertexData,
vertexOffset,
numVertices,
indexData,
indexOffset,
indexElementSize,
primitiveCount
);
}); // End ForceToMainThread
}
public void DrawUserPrimitives(
PrimitiveType primitiveType,
IntPtr vertexData,
int vertexOffset,
int primitiveCount
) {
ForceToMainThread(() =>
{
GLDevice.DrawUserPrimitives(
primitiveType,
vertexData,
vertexOffset,
primitiveCount
);
}); // End ForceToMainThread
}
#endregion
#region Render States
public void SetPresentationInterval(PresentInterval presentInterval)
{
ForceToMainThread(() =>
{
GLDevice.SetPresentationInterval(presentInterval);
}); // End ForceToMainThread
}
public void SetViewport(Viewport vp)
{
ForceToMainThread(() =>
{
GLDevice.SetViewport(vp);
}); // End ForceToMainThread
}
public void SetScissorRect(Rectangle scissorRect)
{
ForceToMainThread(() =>
{
GLDevice.SetScissorRect(scissorRect);
}); // End ForceToMainThread
}
public void SetBlendState(BlendState blendState)
{
ForceToMainThread(() =>
{
GLDevice.SetBlendState(blendState);
}); // End ForceToMainThread
}
public void SetDepthStencilState(DepthStencilState depthStencilState)
{
ForceToMainThread(() =>
{
GLDevice.SetDepthStencilState(
depthStencilState
);
}); // End ForceToMainThread
}
public void ApplyRasterizerState(RasterizerState rasterizerState)
{
ForceToMainThread(() =>
{
GLDevice.ApplyRasterizerState(rasterizerState);
}); // End ForceToMainThread
}
public void VerifySampler(
int index,
Texture texture,
SamplerState sampler
) {
ForceToMainThread(() =>
{
GLDevice.VerifySampler(index, texture, sampler);
}); // End ForceToMainThread
}
#endregion
#region Target Reads/Writes
public void Clear(
ClearOptions options,
Vector4 color,
float depth,
int stencil
) {
ForceToMainThread(() =>
{
GLDevice.Clear(options, color, depth, stencil);
}); // End ForceToMainThread
}
public void SetRenderTargets(
RenderTargetBinding[] renderTargets,
IGLRenderbuffer renderbuffer,
DepthFormat depthFormat
) {
ForceToMainThread(() =>
{
GLDevice.SetRenderTargets(
renderTargets,
renderbuffer,
depthFormat
);
}); // End ForceToMainThread
}
public void ResolveTarget(RenderTargetBinding target)
{
ForceToMainThread(() =>
{
GLDevice.ResolveTarget(target);
}); // End ForceToMainThread
}
public void ReadBackbuffer(
IntPtr data,
int dataLen,
int startIndex,
int elementCount,
int elementSizeInBytes,
int subX,
int subY,
int subW,
int subH
) {
ForceToMainThread(() =>
{
GLDevice.ReadBackbuffer(
data,
dataLen,
startIndex,
elementCount,
elementSizeInBytes,
subX,
subY,
subW,
subH
);
}); // End ForceToMainThread
}
#endregion
#region Textures
public IGLTexture CreateTexture2D(
SurfaceFormat format,
int width,
int height,
int levelCount,
bool isRenderTarget
) {
IGLTexture result = null;
ForceToMainThread(() =>
{
result = GLDevice.CreateTexture2D(
format,
width,
height,
levelCount,
isRenderTarget
);
}); // End ForceToMainThread
return result;
}
public IGLTexture CreateTexture3D(
SurfaceFormat format,
int width,
int height,
int depth,
int levelCount
) {
IGLTexture result = null;
ForceToMainThread(() =>
{
result = GLDevice.CreateTexture3D(
format,
width,
height,
depth,
levelCount
);
}); // End ForceToMainThread
return result;
}
public IGLTexture CreateTextureCube(
SurfaceFormat format,
int size,
int levelCount,
bool isRenderTarget
) {
IGLTexture result = null;
ForceToMainThread(() =>
{
result = GLDevice.CreateTextureCube(
format,
size,
levelCount,
isRenderTarget
);
}); // End ForceToMainThread
return result;
}
public void AddDisposeTexture(IGLTexture texture)
{
GCTextures.Enqueue(texture);
}
public void SetTextureData2D(
IGLTexture texture,
SurfaceFormat format,
int x,
int y,
int w,
int h,
int level,
IntPtr data,
int dataLength
) {
ForceToMainThread(() =>
{
GLDevice.SetTextureData2D(
texture,
format,
x,
y,
w,
h,
level,
data,
dataLength
);
}); // End ForceToMainThread
}
public void SetTextureData3D(
IGLTexture texture,
SurfaceFormat format,
int level,
int left,
int top,
int right,
int bottom,
int front,
int back,
IntPtr data,
int dataLength
) {
ForceToMainThread(() =>
{
GLDevice.SetTextureData3D(
texture,
format,
level,
left,
top,
right,
bottom,
front,
back,
data,
dataLength
);
}); // End ForceToMainThread
}
public void SetTextureDataCube(
IGLTexture texture,
SurfaceFormat format,
int xOffset,
int yOffset,
int width,
int height,
CubeMapFace cubeMapFace,
int level,
IntPtr data,
int dataLength
) {
ForceToMainThread(() =>
{
GLDevice.SetTextureDataCube(
texture,
format,
xOffset,
yOffset,
width,
height,
cubeMapFace,
level,
data,
dataLength
);
}); // End ForceToMainThread
}
public void SetTextureDataYUV(Texture2D[] textures, IntPtr ptr)
{
ForceToMainThread(() =>
{
GLDevice.SetTextureDataYUV(textures, ptr);
}); // End ForceToMainThread
}
public void GetTextureData2D(
IGLTexture texture,
SurfaceFormat format,
int width,
int height,
int level,
int subX,
int subY,
int subW,
int subH,
IntPtr data,
int startIndex,
int elementCount,
int elementSizeInBytes
) {
ForceToMainThread(() =>
{
GLDevice.GetTextureData2D(
texture,
format,
width,
height,
level,
subX,
subY,
subW,
subH,
data,
startIndex,
elementCount,
elementSizeInBytes
);
}); // End ForceToMainThread
}
public void GetTextureData3D(
IGLTexture texture,
SurfaceFormat format,
int left,
int top,
int front,
int right,
int bottom,
int back,
int level,
IntPtr data,
int startIndex,
int elementCount,
int elementSizeInBytes
) {
ForceToMainThread(() =>
{
GLDevice.GetTextureData3D(
texture,
format,
left,
top,
front,
right,
bottom,
back,
level,
data,
startIndex,
elementCount,
elementSizeInBytes
);
}); // End ForceToMainThread
}
public void GetTextureDataCube(
IGLTexture texture,
SurfaceFormat format,
int size,
CubeMapFace cubeMapFace,
int level,
int subX,
int subY,
int subW,
int subH,
IntPtr data,
int startIndex,
int elementCount,
int elementSizeInBytes
) {
ForceToMainThread(() =>
{
GLDevice.GetTextureDataCube(
texture,
format,
size,
cubeMapFace,
level,
subX,
subY,
subW,
subH,
data,
startIndex,
elementCount,
elementSizeInBytes
);
}); // End ForceToMainThread
}
#endregion
#region Renderbuffers
public IGLRenderbuffer GenRenderbuffer(
int width,
int height,
SurfaceFormat format,
int multiSampleCount,
IGLTexture texture
) {
IGLRenderbuffer result = null;
ForceToMainThread(() =>
{
result = GLDevice.GenRenderbuffer(
width,
height,
format,
multiSampleCount,
texture
);
}); // End ForceToMainThread
return result;
}
public IGLRenderbuffer GenRenderbuffer(
int width,
int height,
DepthFormat format,
int multiSampleCount
) {
IGLRenderbuffer result = null;
ForceToMainThread(() =>
{
result = GLDevice.GenRenderbuffer(
width,
height,
format,
multiSampleCount
);
}); // End ForceToMainThread
return result;
}
public void AddDisposeRenderbuffer(IGLRenderbuffer renderbuffer)
{
GCRenderbuffers.Enqueue(renderbuffer);
}
#endregion
#region Vertex/Index Buffers
public IGLBuffer GenVertexBuffer(
bool dynamic,
BufferUsage usage,
int vertexCount,
int vertexStride
) {
IGLBuffer result = null;
ForceToMainThread(() =>
{
result = GLDevice.GenVertexBuffer(
dynamic,
usage,
vertexCount,
vertexStride
);
}); // End ForceToMainThread
return result;
}
public void AddDisposeVertexBuffer(IGLBuffer buffer)
{
GCVertexBuffers.Enqueue(buffer);
}
public void SetVertexBufferData(
IGLBuffer buffer,
int offsetInBytes,
IntPtr data,
int dataLength,
SetDataOptions options
) {
ForceToMainThread(() =>
{
GLDevice.SetVertexBufferData(
buffer,
offsetInBytes,
data,
dataLength,
options
);
}); // End ForceToMainThread
}
public void GetVertexBufferData(
IGLBuffer buffer,
int offsetInBytes,
IntPtr data,
int startIndex,
int elementCount,
int elementSizeInBytes,
int vertexStride
) {
ForceToMainThread(() =>
{
GLDevice.GetVertexBufferData(
buffer,
offsetInBytes,
data,
startIndex,
elementCount,
elementSizeInBytes,
vertexStride
);
}); // End ForceToMainThread
}
public IGLBuffer GenIndexBuffer(
bool dynamic,
BufferUsage usage,
int indexCount,
IndexElementSize indexElementSize
) {
IGLBuffer result = null;
ForceToMainThread(() =>
{
result = GLDevice.GenIndexBuffer(
dynamic,
usage,
indexCount,
indexElementSize
);
}); // End ForceToMainThread
return result;
}
public void AddDisposeIndexBuffer(IGLBuffer buffer)
{
GCIndexBuffers.Enqueue(buffer);
}
public void SetIndexBufferData(
IGLBuffer buffer,
int offsetInBytes,
IntPtr data,
int dataLength,
SetDataOptions options
) {
ForceToMainThread(() =>
{
GLDevice.SetIndexBufferData(
buffer,
offsetInBytes,
data,
dataLength,
options
);
}); // End ForceToMainThread
}
public void GetIndexBufferData(
IGLBuffer buffer,
int offsetInBytes,
IntPtr data,
int startIndex,
int elementCount,
int elementSizeInBytes
) {
ForceToMainThread(() =>
{
GLDevice.GetIndexBufferData(
buffer,
offsetInBytes,
data,
startIndex,
elementCount,
elementSizeInBytes
);
}); // End ForceToMainThread
}
#endregion
#region Effects
public IGLEffect CreateEffect(byte[] effectCode)
{
IGLEffect result = null;
ForceToMainThread(() =>
{
result = GLDevice.CreateEffect(effectCode);
}); // End ForceToMainThread
return result;
}
public IGLEffect CloneEffect(IGLEffect effect)
{
IGLEffect result = null;
ForceToMainThread(() =>
{
result = GLDevice.CloneEffect(effect);
}); // End ForceToMainThread
return result;
}
public void AddDisposeEffect(IGLEffect effect)
{
GCEffects.Enqueue(effect);
}
public void ApplyEffect(
IGLEffect effect,
IntPtr technique,
uint pass,
IntPtr stateChanges
) {
ForceToMainThread(() =>
{
GLDevice.ApplyEffect(
effect,
technique,
pass,
stateChanges
);
}); // End ForceToMainThread
}
public void BeginPassRestore(IGLEffect effect, IntPtr stateChanges)
{
ForceToMainThread(() =>
{
GLDevice.BeginPassRestore(effect, stateChanges);
}); // End ForceToMainThread
}
public void EndPassRestore(IGLEffect effect)
{
ForceToMainThread(() =>
{
GLDevice.EndPassRestore(effect);
}); // End ForceToMainThread
}
#endregion
#region Vertex Attributes
public void ApplyVertexAttributes(
VertexBufferBinding[] bindings,
int numBindings,
bool bindingsUpdated,
int baseVertex
) {
ForceToMainThread(() =>
{
GLDevice.ApplyVertexAttributes(
bindings,
numBindings,
bindingsUpdated,
baseVertex
);
}); // End ForceToMainThread
}
public void ApplyVertexAttributes(
VertexDeclaration vertexDeclaration,
IntPtr ptr,
int vertexOffset
) {
ForceToMainThread(() =>
{
GLDevice.ApplyVertexAttributes(
vertexDeclaration,
ptr,
vertexOffset
);
}); // End ForceToMainThread
}
#endregion
#region Queries
public IGLQuery CreateQuery()
{
IGLQuery result = null;
ForceToMainThread(() =>
{
result = GLDevice.CreateQuery();
}); // End ForceToMainThread
return result;
}
public void AddDisposeQuery(IGLQuery query)
{
GCQueries.Enqueue(query);
}
public void QueryBegin(IGLQuery query)
{
ForceToMainThread(() =>
{
GLDevice.QueryBegin(query);
}); // End ForceToMainThread
}
public void QueryEnd(IGLQuery query)
{
ForceToMainThread(() =>
{
GLDevice.QueryEnd(query);
}); // End ForceToMainThread
}
public bool QueryComplete(IGLQuery query)
{
bool result = false;
ForceToMainThread(() =>
{
result = GLDevice.QueryComplete(query);
}); // End ForceToMainThread
return result;
}
public int QueryPixelCount(IGLQuery query)
{
int result = 0;
ForceToMainThread(() =>
{
result = GLDevice.QueryPixelCount(query);
}); // End ForceToMainThread
return result;
}
#endregion
}
}