mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Material editor: use a SafeHandle for texture swapping
This commit is contained in:
parent
0dbe9b59c2
commit
233a865c78
2 changed files with 59 additions and 26 deletions
|
|
@ -5,6 +5,7 @@ using Dalamud.Plugin.Services;
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.Interop.SafeHandles;
|
||||
|
||||
namespace Penumbra.Interop.MaterialPreview;
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
|||
private readonly Framework _framework;
|
||||
|
||||
private readonly Texture** _colorSetTexture;
|
||||
private readonly Texture* _originalColorSetTexture;
|
||||
private readonly SafeTextureHandle _originalColorSetTexture;
|
||||
|
||||
private Half[] _colorSet;
|
||||
private bool _updatePending;
|
||||
|
|
@ -40,12 +41,10 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
|||
|
||||
_colorSetTexture = colorSetTextures + (MaterialInfo.ModelSlot * 4 + MaterialInfo.MaterialSlot);
|
||||
|
||||
_originalColorSetTexture = *_colorSetTexture;
|
||||
_originalColorSetTexture = new SafeTextureHandle(*_colorSetTexture, true);
|
||||
if (_originalColorSetTexture == null)
|
||||
throw new InvalidOperationException("Material doesn't have a color set");
|
||||
|
||||
Structs.TextureUtility.IncRef(_originalColorSetTexture);
|
||||
|
||||
_colorSet = new Half[TextureLength];
|
||||
_updatePending = true;
|
||||
|
||||
|
|
@ -59,15 +58,9 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
|||
base.Clear(disposing, reset);
|
||||
|
||||
if (reset)
|
||||
{
|
||||
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)_originalColorSetTexture);
|
||||
if (oldTexture != null)
|
||||
Structs.TextureUtility.DecRef(oldTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Structs.TextureUtility.DecRef(_originalColorSetTexture);
|
||||
}
|
||||
_originalColorSetTexture.Exchange(ref *(nint*)_colorSetTexture);
|
||||
|
||||
_originalColorSetTexture.Dispose();
|
||||
}
|
||||
|
||||
public void ScheduleUpdate()
|
||||
|
|
@ -89,8 +82,8 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
|||
textureSize[0] = TextureWidth;
|
||||
textureSize[1] = TextureHeight;
|
||||
|
||||
var newTexture = Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7);
|
||||
if (newTexture == null)
|
||||
using var texture = new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false);
|
||||
if (texture.IsInvalid)
|
||||
return;
|
||||
|
||||
bool success;
|
||||
|
|
@ -98,20 +91,12 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
|||
{
|
||||
fixed (Half* colorSet = _colorSet)
|
||||
{
|
||||
success = Structs.TextureUtility.InitializeContents(newTexture, colorSet);
|
||||
success = Structs.TextureUtility.InitializeContents(texture.Texture, colorSet);
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)newTexture);
|
||||
if (oldTexture != null)
|
||||
Structs.TextureUtility.DecRef(oldTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Structs.TextureUtility.DecRef(newTexture);
|
||||
}
|
||||
texture.Exchange(ref *(nint*)_colorSetTexture);
|
||||
}
|
||||
|
||||
protected override bool IsStillValid()
|
||||
|
|
|
|||
48
Penumbra/Interop/SafeHandles/SafeTextureHandle.cs
Normal file
48
Penumbra/Interop/SafeHandles/SafeTextureHandle.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
||||
namespace Penumbra.Interop.SafeHandles;
|
||||
|
||||
public unsafe class SafeTextureHandle : SafeHandle
|
||||
{
|
||||
public Texture* Texture => (Texture*)handle;
|
||||
|
||||
public override bool IsInvalid => handle == 0;
|
||||
|
||||
public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle)
|
||||
{
|
||||
if (incRef && !ownsHandle)
|
||||
throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported");
|
||||
if (incRef && handle != null)
|
||||
TextureUtility.IncRef(handle);
|
||||
SetHandle((nint)handle);
|
||||
}
|
||||
|
||||
public void Exchange(ref nint ppTexture)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
handle = Interlocked.Exchange(ref ppTexture, handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static SafeTextureHandle CreateInvalid()
|
||||
=> new(null, incRef: false);
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
nint handle;
|
||||
lock (this)
|
||||
{
|
||||
handle = this.handle;
|
||||
this.handle = 0;
|
||||
}
|
||||
if (handle != 0)
|
||||
TextureUtility.DecRef((Texture*)handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue