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.Kernel;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
|
using Penumbra.Interop.SafeHandles;
|
||||||
|
|
||||||
namespace Penumbra.Interop.MaterialPreview;
|
namespace Penumbra.Interop.MaterialPreview;
|
||||||
|
|
||||||
|
|
@ -16,8 +17,8 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
||||||
|
|
||||||
private readonly Framework _framework;
|
private readonly Framework _framework;
|
||||||
|
|
||||||
private readonly Texture** _colorSetTexture;
|
private readonly Texture** _colorSetTexture;
|
||||||
private readonly Texture* _originalColorSetTexture;
|
private readonly SafeTextureHandle _originalColorSetTexture;
|
||||||
|
|
||||||
private Half[] _colorSet;
|
private Half[] _colorSet;
|
||||||
private bool _updatePending;
|
private bool _updatePending;
|
||||||
|
|
@ -40,12 +41,10 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
||||||
|
|
||||||
_colorSetTexture = colorSetTextures + (MaterialInfo.ModelSlot * 4 + MaterialInfo.MaterialSlot);
|
_colorSetTexture = colorSetTextures + (MaterialInfo.ModelSlot * 4 + MaterialInfo.MaterialSlot);
|
||||||
|
|
||||||
_originalColorSetTexture = *_colorSetTexture;
|
_originalColorSetTexture = new SafeTextureHandle(*_colorSetTexture, true);
|
||||||
if (_originalColorSetTexture == null)
|
if (_originalColorSetTexture == null)
|
||||||
throw new InvalidOperationException("Material doesn't have a color set");
|
throw new InvalidOperationException("Material doesn't have a color set");
|
||||||
|
|
||||||
Structs.TextureUtility.IncRef(_originalColorSetTexture);
|
|
||||||
|
|
||||||
_colorSet = new Half[TextureLength];
|
_colorSet = new Half[TextureLength];
|
||||||
_updatePending = true;
|
_updatePending = true;
|
||||||
|
|
||||||
|
|
@ -59,15 +58,9 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
||||||
base.Clear(disposing, reset);
|
base.Clear(disposing, reset);
|
||||||
|
|
||||||
if (reset)
|
if (reset)
|
||||||
{
|
_originalColorSetTexture.Exchange(ref *(nint*)_colorSetTexture);
|
||||||
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)_originalColorSetTexture);
|
|
||||||
if (oldTexture != null)
|
_originalColorSetTexture.Dispose();
|
||||||
Structs.TextureUtility.DecRef(oldTexture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Structs.TextureUtility.DecRef(_originalColorSetTexture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScheduleUpdate()
|
public void ScheduleUpdate()
|
||||||
|
|
@ -89,8 +82,8 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
||||||
textureSize[0] = TextureWidth;
|
textureSize[0] = TextureWidth;
|
||||||
textureSize[1] = TextureHeight;
|
textureSize[1] = TextureHeight;
|
||||||
|
|
||||||
var newTexture = Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7);
|
using var texture = new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false);
|
||||||
if (newTexture == null)
|
if (texture.IsInvalid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
|
|
@ -98,20 +91,12 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase
|
||||||
{
|
{
|
||||||
fixed (Half* colorSet = _colorSet)
|
fixed (Half* colorSet = _colorSet)
|
||||||
{
|
{
|
||||||
success = Structs.TextureUtility.InitializeContents(newTexture, colorSet);
|
success = Structs.TextureUtility.InitializeContents(texture.Texture, colorSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
texture.Exchange(ref *(nint*)_colorSetTexture);
|
||||||
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)newTexture);
|
|
||||||
if (oldTexture != null)
|
|
||||||
Structs.TextureUtility.DecRef(oldTexture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Structs.TextureUtility.DecRef(newTexture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool IsStillValid()
|
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