Beginnings of IGL split-up, make Texture2d into an interface and make classes for each IGL implementation for this interface, do cleanups from this
This commit is contained in:
parent
ea068cf70d
commit
25f62c6620
|
@ -0,0 +1,132 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Vortice.Direct3D;
|
||||
using Vortice.Direct3D11;
|
||||
using Vortice.DXGI;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsules all D3D11 resources
|
||||
/// This is mainly needed as we need to be able to recreate these resources
|
||||
/// Due to possibly getting a device reset/lost (e.g. from hibernation)
|
||||
/// </summary>
|
||||
internal sealed class D3D11Resources : IDisposable
|
||||
{
|
||||
public IDXGIFactory1 Factory1;
|
||||
public IDXGIFactory2 Factory2;
|
||||
public ID3D11Device Device;
|
||||
public ID3D11DeviceContext Context;
|
||||
public ID3D11BlendState BlendEnableState;
|
||||
public ID3D11BlendState BlendDisableState;
|
||||
public ID3D11SamplerState PointSamplerState;
|
||||
public ID3D11SamplerState LinearSamplerState;
|
||||
public ID3D11RasterizerState RasterizerState;
|
||||
|
||||
public FeatureLevel DeviceFeatureLevel;
|
||||
|
||||
public readonly HashSet<RenderTarget> RenderTargets = new();
|
||||
public readonly HashSet<D3D11Texture2D> ShaderTextures = new();
|
||||
public readonly HashSet<Shader> VertexShaders = new();
|
||||
public readonly HashSet<Shader> PixelShaders = new();
|
||||
public readonly HashSet<Pipeline> Pipelines = new();
|
||||
|
||||
public void CreateResources()
|
||||
{
|
||||
try
|
||||
{
|
||||
Factory1 = DXGI.CreateDXGIFactory1<IDXGIFactory1>();
|
||||
// we want IDXGIFactory2 for CreateSwapChainForHwnd
|
||||
// however, it's not guaranteed to be available (only available in Win8+ or Win7 with the Platform Update)
|
||||
Factory2 = Factory1.QueryInterfaceOrNull<IDXGIFactory2>();
|
||||
#if false
|
||||
// use this to debug D3D11 calls
|
||||
// note debug layer requires extra steps to use: https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer
|
||||
// also debug output will only be present with a "native debugger" attached (pure managed debugger can't see this output)
|
||||
const DeviceCreationFlags creationFlags = DeviceCreationFlags.Singlethreaded | DeviceCreationFlags.BgraSupport | DeviceCreationFlags.Debug;
|
||||
#else
|
||||
// IGL is not thread safe, so let's not bother making this implementation thread safe
|
||||
const DeviceCreationFlags creationFlags = DeviceCreationFlags.Singlethreaded | DeviceCreationFlags.BgraSupport;
|
||||
#endif
|
||||
D3D11.D3D11CreateDevice(
|
||||
adapter: null,
|
||||
DriverType.Hardware,
|
||||
creationFlags,
|
||||
null!, // this is safe to be null
|
||||
out Device,
|
||||
out Context).CheckError();
|
||||
|
||||
using var dxgiDevice = Device.QueryInterface<IDXGIDevice1>();
|
||||
dxgiDevice.MaximumFrameLatency = 1;
|
||||
|
||||
var bd = default(BlendDescription);
|
||||
bd.AlphaToCoverageEnable = false;
|
||||
bd.IndependentBlendEnable = false;
|
||||
bd.RenderTarget[0].BlendEnable = true;
|
||||
bd.RenderTarget[0].SourceBlend = Blend.SourceAlpha;
|
||||
bd.RenderTarget[0].DestinationBlend = Blend.InverseSourceAlpha;
|
||||
bd.RenderTarget[0].BlendOperation = BlendOperation.Add;
|
||||
bd.RenderTarget[0].SourceBlendAlpha = Blend.One;
|
||||
bd.RenderTarget[0].DestinationBlendAlpha = Blend.Zero;
|
||||
bd.RenderTarget[0].BlendOperationAlpha = BlendOperation.Add;
|
||||
bd.RenderTarget[0].RenderTargetWriteMask = ColorWriteEnable.All;
|
||||
BlendEnableState = Device.CreateBlendState(bd);
|
||||
|
||||
bd.RenderTarget[0].BlendEnable = false;
|
||||
bd.RenderTarget[0].SourceBlend = Blend.One;
|
||||
bd.RenderTarget[0].DestinationBlend = Blend.Zero;
|
||||
BlendDisableState = Device.CreateBlendState(bd);
|
||||
|
||||
PointSamplerState = Device.CreateSamplerState(SamplerDescription.PointClamp);
|
||||
LinearSamplerState = Device.CreateSamplerState(SamplerDescription.LinearClamp);
|
||||
|
||||
DeviceFeatureLevel = Device.FeatureLevel;
|
||||
|
||||
var rd = new RasterizerDescription
|
||||
{
|
||||
CullMode = CullMode.None,
|
||||
FillMode = FillMode.Solid,
|
||||
ScissorEnable = true,
|
||||
DepthClipEnable = DeviceFeatureLevel is FeatureLevel.Level_9_1 or FeatureLevel.Level_9_2 or FeatureLevel.Level_9_3,
|
||||
};
|
||||
|
||||
RasterizerState = Device.CreateRasterizerState(rd);
|
||||
|
||||
Context.IASetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LinearSamplerState?.Dispose();
|
||||
LinearSamplerState = null;
|
||||
PointSamplerState?.Dispose();
|
||||
PointSamplerState = null;
|
||||
|
||||
RasterizerState?.Dispose();
|
||||
RasterizerState = null;
|
||||
|
||||
BlendEnableState?.Dispose();
|
||||
BlendEnableState = null;
|
||||
BlendDisableState?.Dispose();
|
||||
BlendDisableState = null;
|
||||
|
||||
Context?.Dispose();
|
||||
Context = null;
|
||||
Device?.Dispose();
|
||||
Device = null;
|
||||
|
||||
Factory2?.Dispose();
|
||||
Factory2 = null;
|
||||
|
||||
Factory1?.Dispose();
|
||||
Factory1 = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Vortice.Direct3D;
|
||||
using Vortice.Direct3D11;
|
||||
using Vortice.DXGI;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
internal class D3D11Texture2D : ITexture2D
|
||||
{
|
||||
private readonly D3D11Resources _resources;
|
||||
private readonly BindFlags _bindFlags;
|
||||
private readonly ResourceUsage _usage;
|
||||
private readonly CpuAccessFlags _cpuAccessFlags;
|
||||
|
||||
private ID3D11Device Device => _resources.Device;
|
||||
private ID3D11DeviceContext Context => _resources.Context;
|
||||
private HashSet<D3D11Texture2D> ShaderTextures => _resources.ShaderTextures;
|
||||
|
||||
private ID3D11Texture2D StagingTexture;
|
||||
|
||||
public ID3D11Texture2D Texture;
|
||||
public ID3D11ShaderResourceView SRV;
|
||||
public bool LinearFiltering;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public bool IsUpsideDown => false;
|
||||
|
||||
public D3D11Texture2D(D3D11Resources resources, BindFlags bindFlags, ResourceUsage usage, CpuAccessFlags cpuAccessFlags, int width, int height)
|
||||
{
|
||||
_resources = resources;
|
||||
_bindFlags = bindFlags;
|
||||
_usage = usage;
|
||||
_cpuAccessFlags = cpuAccessFlags;
|
||||
Width = width;
|
||||
Height = height;
|
||||
CreateTexture();
|
||||
ShaderTextures.Add(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DestroyTexture();
|
||||
ShaderTextures.Remove(this);
|
||||
}
|
||||
|
||||
public void CreateTexture()
|
||||
{
|
||||
Texture = Device.CreateTexture2D(
|
||||
Format.B8G8R8A8_UNorm,
|
||||
Width,
|
||||
Height,
|
||||
mipLevels: 1,
|
||||
bindFlags: _bindFlags,
|
||||
usage: _usage,
|
||||
cpuAccessFlags: _cpuAccessFlags);
|
||||
|
||||
var srvd = new ShaderResourceViewDescription(ShaderResourceViewDimension.Texture2D, Format.B8G8R8A8_UNorm, mostDetailedMip: 0, mipLevels: 1);
|
||||
SRV = Device.CreateShaderResourceView(Texture, srvd);
|
||||
}
|
||||
|
||||
public void DestroyTexture()
|
||||
{
|
||||
SRV?.Dispose();
|
||||
SRV = null;
|
||||
Texture?.Dispose();
|
||||
Texture = null;
|
||||
StagingTexture?.Dispose();
|
||||
StagingTexture = null;
|
||||
}
|
||||
|
||||
public BitmapBuffer Resolve()
|
||||
{
|
||||
StagingTexture ??= Device.CreateTexture2D(
|
||||
Format.B8G8R8A8_UNorm,
|
||||
Width,
|
||||
Height,
|
||||
mipLevels: 1,
|
||||
bindFlags: BindFlags.None,
|
||||
usage: ResourceUsage.Staging,
|
||||
cpuAccessFlags: CpuAccessFlags.Read);
|
||||
|
||||
Context.CopyResource(StagingTexture, Texture);
|
||||
|
||||
try
|
||||
{
|
||||
var srcSpan = Context.MapReadOnly<byte>(StagingTexture);
|
||||
var pixels = new int[Width * Height];
|
||||
var dstSpan = MemoryMarshal.AsBytes(pixels.AsSpan());
|
||||
|
||||
if (srcSpan.Length == dstSpan.Length)
|
||||
{
|
||||
srcSpan.CopyTo(dstSpan);
|
||||
}
|
||||
else
|
||||
{
|
||||
int srcStart = 0, dstStart = 0;
|
||||
int srcStride = srcSpan.Length / Height, dstStride = Width * sizeof(int);
|
||||
for (var i = 0; i < Height; i++)
|
||||
{
|
||||
srcSpan.Slice(srcStart, dstStride)
|
||||
.CopyTo(dstSpan.Slice(dstStart, dstStride));
|
||||
srcStart += srcStride;
|
||||
dstStart += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
return new(Width, Height, pixels);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.Unmap(StagingTexture, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void LoadFrom(BitmapBuffer buffer)
|
||||
{
|
||||
if (buffer.Width != Width || buffer.Height != Height)
|
||||
{
|
||||
throw new InvalidOperationException("BitmapBuffer dimensions do not match texture dimensions");
|
||||
}
|
||||
|
||||
if ((_cpuAccessFlags & CpuAccessFlags.Write) == 0)
|
||||
{
|
||||
throw new InvalidOperationException("This texture cannot be written by the CPU");
|
||||
}
|
||||
|
||||
var bmpData = buffer.LockBits();
|
||||
try
|
||||
{
|
||||
var srcSpan = new ReadOnlySpan<byte>(bmpData.Scan0.ToPointer(), bmpData.Stride * buffer.Height);
|
||||
var mappedTex = Context.Map<byte>(Texture, 0, 0, MapMode.WriteDiscard);
|
||||
|
||||
if (srcSpan.Length == mappedTex.Length)
|
||||
{
|
||||
srcSpan.CopyTo(mappedTex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// D3D11 sometimes has weird pitches (seen with 3DS)
|
||||
int srcStart = 0, dstStart = 0;
|
||||
int srcStride = bmpData.Stride, dstStride = mappedTex.Length / buffer.Height;
|
||||
var height = buffer.Height;
|
||||
for (var i = 0; i < height; i++)
|
||||
{
|
||||
srcSpan.Slice(srcStart, srcStride)
|
||||
.CopyTo(mappedTex.Slice(dstStart, dstStride));
|
||||
srcStart += srcStride;
|
||||
dstStart += dstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.Unmap(Texture, 0);
|
||||
buffer.UnlockBits(bmpData);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFilterLinear()
|
||||
=> LinearFiltering = true;
|
||||
|
||||
public void SetFilterNearest()
|
||||
=> LinearFiltering = false;
|
||||
|
||||
public override string ToString()
|
||||
=> $"D3D11 Texture2D: {Width}x{Height}";
|
||||
}
|
||||
}
|
|
@ -23,121 +23,9 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
public EDispMethod DispMethodEnum => EDispMethod.D3D11;
|
||||
|
||||
private struct D3D11Resources : IDisposable
|
||||
{
|
||||
public IDXGIFactory1 Factory1;
|
||||
public IDXGIFactory2 Factory2;
|
||||
public ID3D11Device Device;
|
||||
public ID3D11DeviceContext Context;
|
||||
public ID3D11BlendState BlendEnableState;
|
||||
public ID3D11BlendState BlendDisableState;
|
||||
public ID3D11SamplerState PointSamplerState;
|
||||
public ID3D11SamplerState LinearSamplerState;
|
||||
public ID3D11RasterizerState RasterizerState;
|
||||
|
||||
public FeatureLevel DeviceFeatureLevel;
|
||||
|
||||
public void CreateResources()
|
||||
{
|
||||
try
|
||||
{
|
||||
Factory1 = DXGI.CreateDXGIFactory1<IDXGIFactory1>();
|
||||
// we want IDXGIFactory2 for CreateSwapChainForHwnd
|
||||
// however, it's not guaranteed to be available (only available in Win8+ or Win7 with the Platform Update)
|
||||
Factory2 = Factory1.QueryInterfaceOrNull<IDXGIFactory2>();
|
||||
#if false
|
||||
// use this to debug D3D11 calls
|
||||
// note debug layer requires extra steps to use: https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer
|
||||
// also debug output will only be present with a "native debugger" attached (pure managed debugger can't see this output)
|
||||
const DeviceCreationFlags creationFlags = DeviceCreationFlags.Singlethreaded | DeviceCreationFlags.BgraSupport | DeviceCreationFlags.Debug;
|
||||
#else
|
||||
// IGL is not thread safe, so let's not bother making this implementation thread safe
|
||||
const DeviceCreationFlags creationFlags = DeviceCreationFlags.Singlethreaded | DeviceCreationFlags.BgraSupport;
|
||||
#endif
|
||||
D3D11.D3D11CreateDevice(
|
||||
adapter: null,
|
||||
DriverType.Hardware,
|
||||
creationFlags,
|
||||
null!, // this is safe to be null
|
||||
out Device,
|
||||
out Context).CheckError();
|
||||
|
||||
using var dxgiDevice = Device.QueryInterface<IDXGIDevice1>();
|
||||
dxgiDevice.MaximumFrameLatency = 1;
|
||||
|
||||
var bd = default(BlendDescription);
|
||||
bd.AlphaToCoverageEnable = false;
|
||||
bd.IndependentBlendEnable = false;
|
||||
bd.RenderTarget[0].BlendEnable = true;
|
||||
bd.RenderTarget[0].SourceBlend = Blend.SourceAlpha;
|
||||
bd.RenderTarget[0].DestinationBlend = Blend.InverseSourceAlpha;
|
||||
bd.RenderTarget[0].BlendOperation = BlendOperation.Add;
|
||||
bd.RenderTarget[0].SourceBlendAlpha = Blend.One;
|
||||
bd.RenderTarget[0].DestinationBlendAlpha = Blend.Zero;
|
||||
bd.RenderTarget[0].BlendOperationAlpha = BlendOperation.Add;
|
||||
bd.RenderTarget[0].RenderTargetWriteMask = ColorWriteEnable.All;
|
||||
BlendEnableState = Device.CreateBlendState(bd);
|
||||
|
||||
bd.RenderTarget[0].BlendEnable = false;
|
||||
bd.RenderTarget[0].SourceBlend = Blend.One;
|
||||
bd.RenderTarget[0].DestinationBlend = Blend.Zero;
|
||||
BlendDisableState = Device.CreateBlendState(bd);
|
||||
|
||||
PointSamplerState = Device.CreateSamplerState(SamplerDescription.PointClamp);
|
||||
LinearSamplerState = Device.CreateSamplerState(SamplerDescription.LinearClamp);
|
||||
|
||||
DeviceFeatureLevel = Device.FeatureLevel;
|
||||
|
||||
var rd = new RasterizerDescription
|
||||
{
|
||||
CullMode = CullMode.None,
|
||||
FillMode = FillMode.Solid,
|
||||
ScissorEnable = true,
|
||||
DepthClipEnable = DeviceFeatureLevel is FeatureLevel.Level_9_1 or FeatureLevel.Level_9_2 or FeatureLevel.Level_9_3,
|
||||
};
|
||||
|
||||
RasterizerState = Device.CreateRasterizerState(rd);
|
||||
|
||||
Context.IASetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LinearSamplerState?.Dispose();
|
||||
LinearSamplerState = null;
|
||||
PointSamplerState?.Dispose();
|
||||
PointSamplerState = null;
|
||||
|
||||
RasterizerState?.Dispose();
|
||||
RasterizerState = null;
|
||||
|
||||
BlendEnableState?.Dispose();
|
||||
BlendEnableState = null;
|
||||
BlendDisableState?.Dispose();
|
||||
BlendDisableState = null;
|
||||
|
||||
Context?.Dispose();
|
||||
Context = null;
|
||||
Device?.Dispose();
|
||||
Device = null;
|
||||
|
||||
Factory2?.Dispose();
|
||||
Factory2 = null;
|
||||
|
||||
Factory1?.Dispose();
|
||||
Factory1 = null;
|
||||
}
|
||||
}
|
||||
|
||||
// D3D11 resources
|
||||
// these might need to be thrown out and recreated if the device is lost
|
||||
private D3D11Resources _resources;
|
||||
private readonly D3D11Resources _resources;
|
||||
|
||||
private IDXGIFactory1 Factory1 => _resources.Factory1;
|
||||
private IDXGIFactory2 Factory2 => _resources.Factory2;
|
||||
|
@ -156,13 +44,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
private RenderTarget _curRenderTarget;
|
||||
private D3D11SwapChain.SwapChainResources _controlSwapChain;
|
||||
|
||||
// misc state
|
||||
private readonly HashSet<RenderTarget> _renderTargets = new();
|
||||
private readonly HashSet<Texture2d> _shaderTextures = new();
|
||||
private readonly HashSet<Shader> _vertexShaders = new();
|
||||
private readonly HashSet<Shader> _pixelShaders = new();
|
||||
private readonly HashSet<Pipeline> _pipelines = new();
|
||||
|
||||
public IGL_D3D11()
|
||||
{
|
||||
if (OSTailoredCode.IsUnixHost)
|
||||
|
@ -170,6 +51,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
throw new NotSupportedException("D3D11 is Windows only");
|
||||
}
|
||||
|
||||
_resources = new();
|
||||
_resources.CreateResources();
|
||||
}
|
||||
|
||||
|
@ -237,7 +119,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
_controlSwapChain.Dispose();
|
||||
Context.Flush(); // important to properly dispose of the swapchain
|
||||
|
||||
foreach (var pipeline in _pipelines)
|
||||
foreach (var pipeline in _resources.Pipelines)
|
||||
{
|
||||
var pw = (PipelineWrapper)pipeline.Opaque;
|
||||
|
||||
|
@ -257,75 +139,55 @@ namespace BizHawk.Bizware.Graphics
|
|||
vlw.VertexBufferCount = 0;
|
||||
}
|
||||
|
||||
foreach (var sw in _vertexShaders.Select(vertexShader => (ShaderWrapper)vertexShader.Opaque))
|
||||
foreach (var sw in _resources.VertexShaders.Select(vertexShader => (ShaderWrapper)vertexShader.Opaque))
|
||||
{
|
||||
sw.VS.Dispose();
|
||||
sw.VS = null;
|
||||
}
|
||||
|
||||
foreach (var sw in _pixelShaders.Select(pixelShader => (ShaderWrapper)pixelShader.Opaque))
|
||||
foreach (var sw in _resources.PixelShaders.Select(pixelShader => (ShaderWrapper)pixelShader.Opaque))
|
||||
{
|
||||
sw.PS.Dispose();
|
||||
sw.PS = null;
|
||||
}
|
||||
|
||||
foreach (var rt in _renderTargets)
|
||||
foreach (var rw in _resources.RenderTargets.Select(rt => (RenderTargetWrapper)rt.Opaque))
|
||||
{
|
||||
var rw = (RenderTargetWrapper)rt.Opaque;
|
||||
rw.RTV.Dispose();
|
||||
rw.RTV = null;
|
||||
|
||||
var tw = (TextureWrapper)rt.Texture2d.Opaque;
|
||||
tw.SRV.Dispose();
|
||||
tw.SRV = null;
|
||||
tw.Texture.Dispose();
|
||||
tw.Texture = null;
|
||||
}
|
||||
|
||||
foreach (var tw in _shaderTextures.Select(tex2d => (TextureWrapper)tex2d.Opaque))
|
||||
foreach (var tex2d in _resources.ShaderTextures)
|
||||
{
|
||||
tw.SRV.Dispose();
|
||||
tw.SRV = null;
|
||||
tw.Texture.Dispose();
|
||||
tw.Texture = null;
|
||||
tex2d.DestroyTexture();
|
||||
}
|
||||
|
||||
_resources.Dispose();
|
||||
_resources.CreateResources();
|
||||
|
||||
foreach (var tex2d in _shaderTextures)
|
||||
foreach (var tex2d in _resources.ShaderTextures)
|
||||
{
|
||||
var tw = (TextureWrapper)tex2d.Opaque;
|
||||
tw.Texture = CreateTextureForShader(tex2d.IntWidth, tex2d.IntHeight);
|
||||
|
||||
var srvd = new ShaderResourceViewDescription(ShaderResourceViewDimension.Texture2D, Format.B8G8R8A8_UNorm, mostDetailedMip: 0, mipLevels: 1);
|
||||
tw.SRV = Device.CreateShaderResourceView(tw.Texture, srvd);
|
||||
tex2d.CreateTexture();
|
||||
}
|
||||
|
||||
foreach (var rt in _renderTargets)
|
||||
foreach (var rt in _resources.RenderTargets)
|
||||
{
|
||||
var tw = (TextureWrapper)rt.Texture2d.Opaque;
|
||||
tw.Texture = CreateTextureForRenderTarget(rt.Texture2d.IntWidth, rt.Texture2d.IntHeight);
|
||||
|
||||
var srvd = new ShaderResourceViewDescription(ShaderResourceViewDimension.Texture2D, Format.B8G8R8A8_UNorm, mostDetailedMip: 0, mipLevels: 1);
|
||||
tw.SRV = Device.CreateShaderResourceView(tw.Texture, srvd);
|
||||
|
||||
var rw = (RenderTargetWrapper)rt.Opaque;
|
||||
var rtvd = new RenderTargetViewDescription(RenderTargetViewDimension.Texture2D, Format.B8G8R8A8_UNorm);
|
||||
rw.RTV = Device.CreateRenderTargetView(tw.Texture, rtvd);
|
||||
rw.RTV = Device.CreateRenderTargetView(((D3D11Texture2D)rt.Texture2D).Texture, rtvd);
|
||||
}
|
||||
|
||||
foreach (var sw in _vertexShaders.Select(vertexShader => (ShaderWrapper)vertexShader.Opaque))
|
||||
foreach (var sw in _resources.VertexShaders.Select(vertexShader => (ShaderWrapper)vertexShader.Opaque))
|
||||
{
|
||||
sw.VS = Device.CreateVertexShader(sw.Bytecode.Span);
|
||||
}
|
||||
|
||||
foreach (var sw in _pixelShaders.Select(pixelShader => (ShaderWrapper)pixelShader.Opaque))
|
||||
foreach (var sw in _resources.PixelShaders.Select(pixelShader => (ShaderWrapper)pixelShader.Opaque))
|
||||
{
|
||||
sw.PS = Device.CreatePixelShader(sw.Bytecode.Span);
|
||||
}
|
||||
|
||||
foreach (var pipeline in _pipelines)
|
||||
foreach (var pipeline in _resources.Pipelines)
|
||||
{
|
||||
var pw = (PipelineWrapper)pipeline.Opaque;
|
||||
for (var i = 0; i < ID3D11DeviceContext.CommonShaderConstantBufferSlotCount; i++)
|
||||
|
@ -414,14 +276,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
var tw = (TextureWrapper)tex.Opaque;
|
||||
tw.SRV.Dispose();
|
||||
tw.Texture.Dispose();
|
||||
_shaderTextures.Remove(tex);
|
||||
}
|
||||
|
||||
private class ShaderWrapper // Disposable fields cleaned up by Internal_FreeShader
|
||||
{
|
||||
public ReadOnlyMemory<byte> Bytecode;
|
||||
|
@ -460,7 +314,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
var s = new Shader(this, sw, true);
|
||||
sw.IGLShader = s;
|
||||
_vertexShaders.Add(s);
|
||||
_resources.VertexShaders.Add(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -504,7 +358,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
var s = new Shader(this, sw, true);
|
||||
sw.IGLShader = s;
|
||||
_pixelShaders.Add(s);
|
||||
_resources.PixelShaders.Add(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -676,7 +530,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
var ret = new Pipeline(this, pw, true, vertexLayout, uniforms, memo);
|
||||
_pipelines.Add(ret);
|
||||
_resources.Pipelines.Add(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -706,7 +560,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
pw.VertexShader.IGLShader.Release();
|
||||
pw.FragmentShader.IGLShader.Release();
|
||||
|
||||
_pipelines.Remove(pipeline);
|
||||
_resources.Pipelines.Remove(pipeline);
|
||||
}
|
||||
|
||||
public void Internal_FreeShader(Shader shader)
|
||||
|
@ -719,14 +573,14 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
sw.VS.Dispose();
|
||||
sw.VS = null;
|
||||
_vertexShaders.Remove(shader);
|
||||
_resources.VertexShaders.Remove(shader);
|
||||
}
|
||||
|
||||
if (sw.PS != null)
|
||||
{
|
||||
sw.PS.Dispose();
|
||||
sw.PS = null;
|
||||
_pixelShaders.Remove(shader);
|
||||
_resources.PixelShaders.Remove(shader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -753,13 +607,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
public ShaderWrapper VertexShader, FragmentShader;
|
||||
}
|
||||
|
||||
private class TextureWrapper
|
||||
{
|
||||
public ID3D11Texture2D Texture;
|
||||
public ID3D11ShaderResourceView SRV;
|
||||
public bool LinearFiltering;
|
||||
}
|
||||
|
||||
private class RenderTargetWrapper
|
||||
{
|
||||
public ID3D11RenderTargetView RTV;
|
||||
|
@ -960,15 +807,15 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, ITexture2D tex)
|
||||
{
|
||||
if (uniform.Owner == null)
|
||||
{
|
||||
return; // uniform was optimized out
|
||||
}
|
||||
|
||||
var tw = (TextureWrapper)tex.Opaque;
|
||||
var sampler = tw.LinearFiltering ? LinearSamplerState : PointSamplerState;
|
||||
var d3d11Tex = (D3D11Texture2D)tex;
|
||||
var sampler = d3d11Tex.LinearFiltering ? LinearSamplerState : PointSamplerState;
|
||||
|
||||
foreach (var ui in uniform.UniformInfos)
|
||||
{
|
||||
|
@ -985,139 +832,23 @@ namespace BizHawk.Bizware.Graphics
|
|||
throw new InvalidOperationException("Feature level 9.1 does not support setting a shader resource in a vertex shader");
|
||||
}
|
||||
|
||||
Context.VSSetShaderResource(ui.SamplerIndex, tw.SRV);
|
||||
Context.VSSetShaderResource(ui.SamplerIndex, d3d11Tex.SRV);
|
||||
Context.VSSetSampler(ui.SamplerIndex, sampler);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.PSSetShaderResource(ui.SamplerIndex, tw.SRV);
|
||||
Context.PSSetShaderResource(ui.SamplerIndex, d3d11Tex.SRV);
|
||||
Context.PSSetSampler(ui.SamplerIndex, sampler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTextureFilter(Texture2d texture, bool linear)
|
||||
{
|
||||
var tw = (TextureWrapper)texture.Opaque;
|
||||
tw.LinearFiltering = linear;
|
||||
}
|
||||
public ITexture2D CreateTexture(int width, int height)
|
||||
=> new D3D11Texture2D(_resources, BindFlags.ShaderResource, ResourceUsage.Dynamic, CpuAccessFlags.Write, width, height);
|
||||
|
||||
private ID3D11Texture2D CreateTextureForShader(int width, int height)
|
||||
{
|
||||
return Device.CreateTexture2D(
|
||||
Format.B8G8R8A8_UNorm,
|
||||
width,
|
||||
height,
|
||||
mipLevels: 1,
|
||||
bindFlags: BindFlags.ShaderResource,
|
||||
usage: ResourceUsage.Dynamic,
|
||||
cpuAccessFlags: CpuAccessFlags.Write);
|
||||
}
|
||||
|
||||
public Texture2d CreateTexture(int width, int height)
|
||||
{
|
||||
var tex = CreateTextureForShader(width, height);
|
||||
var srvd = new ShaderResourceViewDescription(ShaderResourceViewDimension.Texture2D, Format.B8G8R8A8_UNorm, mostDetailedMip: 0, mipLevels: 1);
|
||||
var srv = Device.CreateShaderResourceView(tex, srvd);
|
||||
var tw = new TextureWrapper { Texture = tex, SRV = srv };
|
||||
var ret = new Texture2d(this, tw, width, height);
|
||||
_shaderTextures.Add(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
|
||||
{
|
||||
// not used for non-GL backends
|
||||
return null;
|
||||
}
|
||||
|
||||
public unsafe void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
|
||||
{
|
||||
if (bmp.Width != tex.IntWidth || bmp.Height != tex.IntHeight)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var tw = (TextureWrapper)tex.Opaque;
|
||||
var bmpData = bmp.LockBits();
|
||||
|
||||
try
|
||||
{
|
||||
var srcSpan = new ReadOnlySpan<byte>(bmpData.Scan0.ToPointer(), bmpData.Stride * bmp.Height);
|
||||
var mappedTex = Context.Map<byte>(tw.Texture, 0, 0, MapMode.WriteDiscard);
|
||||
|
||||
if (srcSpan.Length == mappedTex.Length)
|
||||
{
|
||||
srcSpan.CopyTo(mappedTex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// D3D11 sometimes has weird pitches (seen with 3DS)
|
||||
int srcStart = 0, dstStart = 0;
|
||||
int srcStride = bmpData.Stride, dstStride = mappedTex.Length / bmp.Height;
|
||||
var height = bmp.Height;
|
||||
for (var i = 0; i < height; i++)
|
||||
{
|
||||
srcSpan.Slice(srcStart, srcStride)
|
||||
.CopyTo(mappedTex.Slice(dstStart, dstStride));
|
||||
srcStart += srcStride;
|
||||
dstStart += dstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.Unmap(tw.Texture, 0);
|
||||
bmp.UnlockBits(bmpData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="InvalidOperationException">Vortice call returned unexpected data</exception>
|
||||
public BitmapBuffer ResolveTexture2d(Texture2d tex)
|
||||
{
|
||||
using var target = Device.CreateTexture2D(
|
||||
Format.B8G8R8A8_UNorm,
|
||||
tex.IntWidth,
|
||||
tex.IntHeight,
|
||||
mipLevels: 1,
|
||||
bindFlags: BindFlags.None,
|
||||
usage: ResourceUsage.Staging,
|
||||
cpuAccessFlags: CpuAccessFlags.Read);
|
||||
|
||||
var tw = (TextureWrapper)tex.Opaque;
|
||||
Context.CopyResource(target, tw.Texture);
|
||||
|
||||
try
|
||||
{
|
||||
var srcSpan = Context.MapReadOnly<byte>(target);
|
||||
var pixels = new int[tex.IntWidth * tex.IntHeight];
|
||||
var dstSpan = MemoryMarshal.AsBytes(pixels.AsSpan());
|
||||
|
||||
if (srcSpan.Length == dstSpan.Length)
|
||||
{
|
||||
srcSpan.CopyTo(dstSpan);
|
||||
}
|
||||
else
|
||||
{
|
||||
int srcStart = 0, dstStart = 0;
|
||||
int srcStride = srcSpan.Length / tex.IntHeight, dstStride = tex.IntWidth * sizeof(int);
|
||||
var height = tex.IntHeight;
|
||||
for (var i = 0; i < height; i++)
|
||||
{
|
||||
srcSpan.Slice(srcStart, dstStride)
|
||||
.CopyTo(dstSpan.Slice(dstStart, dstStride));
|
||||
srcStart += srcStride;
|
||||
dstStart += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
return new(tex.IntWidth, tex.IntHeight, pixels);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.Unmap(target, 0);
|
||||
}
|
||||
}
|
||||
// not used for non-GL backends
|
||||
public ITexture2D WrapGLTexture2D(int glTexId, int width, int height)
|
||||
=> null;
|
||||
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int width, int height)
|
||||
{
|
||||
|
@ -1148,36 +879,17 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
var rw = (RenderTargetWrapper)rt.Opaque;
|
||||
rw.RTV.Dispose();
|
||||
_renderTargets.Remove(rt);
|
||||
var tw = (TextureWrapper)rt.Texture2d.Opaque;
|
||||
tw.SRV.Dispose();
|
||||
tw.Texture.Dispose();
|
||||
}
|
||||
|
||||
private ID3D11Texture2D CreateTextureForRenderTarget(int width, int height)
|
||||
{
|
||||
return Device.CreateTexture2D(
|
||||
Format.B8G8R8A8_UNorm,
|
||||
width,
|
||||
height,
|
||||
mipLevels: 1,
|
||||
bindFlags: BindFlags.RenderTarget | BindFlags.ShaderResource, // ack! need to also let this be bound to shaders
|
||||
usage: ResourceUsage.Default,
|
||||
cpuAccessFlags: CpuAccessFlags.None);
|
||||
_resources.RenderTargets.Remove(rt);
|
||||
rt.Texture2D.Dispose();
|
||||
}
|
||||
|
||||
public RenderTarget CreateRenderTarget(int width, int height)
|
||||
{
|
||||
var tex = CreateTextureForRenderTarget(width, height);
|
||||
var srvd = new ShaderResourceViewDescription(ShaderResourceViewDimension.Texture2D, Format.B8G8R8A8_UNorm, mostDetailedMip: 0, mipLevels: 1);
|
||||
var srv = Device.CreateShaderResourceView(tex, srvd);
|
||||
var tw = new TextureWrapper { Texture = tex, SRV = srv };
|
||||
var tex2d = new Texture2d(this, tw, width, height);
|
||||
|
||||
var tex = new D3D11Texture2D(_resources, BindFlags.ShaderResource | BindFlags.RenderTarget, ResourceUsage.Default, CpuAccessFlags.None, width, height);
|
||||
var rtvd = new RenderTargetViewDescription(RenderTargetViewDimension.Texture2D, Format.B8G8R8A8_UNorm);
|
||||
var rw = new RenderTargetWrapper { RTV = Device.CreateRenderTargetView(tw.Texture, rtvd) };
|
||||
var rt = new RenderTarget(this, rw, tex2d);
|
||||
_renderTargets.Add(rt);
|
||||
var rw = new RenderTargetWrapper { RTV = Device.CreateRenderTargetView(tex.Texture, rtvd) };
|
||||
var rt = new RenderTarget(this, rw, tex);
|
||||
_resources.RenderTargets.Add(rt);
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
public static class IGLExtensions
|
||||
{
|
||||
public static IGuiRenderer CreateRenderer(this IGL gl)
|
||||
public static IGuiRenderer CreateGuiRenderer(this IGL gl)
|
||||
=> gl is IGL_GDIPlus gdipImpl
|
||||
? new GDIPlusGuiRenderer(gdipImpl)
|
||||
: new GuiRenderer(gl);
|
||||
|
@ -14,7 +14,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Loads a texture from disk
|
||||
/// </summary>
|
||||
public static Texture2d LoadTexture(this IGL igl, string path)
|
||||
public static ITexture2D LoadTexture(this IGL igl, string path)
|
||||
{
|
||||
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
return igl.LoadTexture(fs);
|
||||
|
@ -23,7 +23,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Loads a texture from the stream
|
||||
/// </summary>
|
||||
public static Texture2d LoadTexture(this IGL igl, Stream stream)
|
||||
public static ITexture2D LoadTexture(this IGL igl, Stream stream)
|
||||
{
|
||||
using var bmp = new BitmapBuffer(stream, new());
|
||||
return igl.LoadTexture(bmp);
|
||||
|
@ -32,7 +32,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Loads a texture from the System.Drawing.Bitmap
|
||||
/// </summary>
|
||||
public static Texture2d LoadTexture(this IGL igl, Bitmap bitmap)
|
||||
public static ITexture2D LoadTexture(this IGL igl, Bitmap bitmap)
|
||||
{
|
||||
using var bmp = new BitmapBuffer(bitmap, new());
|
||||
return igl.LoadTexture(bmp);
|
||||
|
@ -41,10 +41,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Loads a texture from the BitmapBuffer
|
||||
/// </summary>
|
||||
public static Texture2d LoadTexture(this IGL igl, BitmapBuffer buffer)
|
||||
public static ITexture2D LoadTexture(this IGL igl, BitmapBuffer buffer)
|
||||
{
|
||||
var ret = igl.CreateTexture(buffer.Width, buffer.Height);
|
||||
igl.LoadTextureData(ret, buffer);
|
||||
ret.LoadFrom(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,19 +13,19 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Draws the specified texture2d resource.
|
||||
/// </summary>
|
||||
public static void Draw(this IGuiRenderer guiRenderer, Texture2d tex)
|
||||
public static void Draw(this IGuiRenderer guiRenderer, ITexture2D tex)
|
||||
=> guiRenderer.Draw(tex, 0, 0, tex.Width, tex.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the specified texture2d resource with the specified offset.
|
||||
/// </summary>
|
||||
public static void Draw(this IGuiRenderer guiRenderer, Texture2d tex, float x, float y)
|
||||
public static void Draw(this IGuiRenderer guiRenderer, ITexture2D tex, float x, float y)
|
||||
=> guiRenderer.Draw(tex, x, y, tex.Width, tex.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the specified Texture with the specified offset and the specified size. This could be tricky if youve applied other rotate or scale transforms first.
|
||||
/// </summary>
|
||||
public static void Draw(this IGuiRenderer guiRenderer, Texture2d tex, float x, float y, float width, float height)
|
||||
public static void Draw(this IGuiRenderer guiRenderer, ITexture2D tex, float x, float y, float width, float height)
|
||||
{
|
||||
const float u0 = 0, u1 = 1;
|
||||
float v0, v1;
|
|
@ -0,0 +1,13 @@
|
|||
using System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public static class ITexture2DExtensions
|
||||
{
|
||||
public static Rectangle GetRectangle(this ITexture2D texture2D)
|
||||
=> new(0, 0, texture2D.Width, texture2D.Height);
|
||||
|
||||
public static Size GetSize(this ITexture2D texture2D)
|
||||
=> new(texture2D.Width, texture2D.Height);
|
||||
}
|
||||
}
|
|
@ -50,10 +50,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
else
|
||||
{
|
||||
var gtex = (GDIPlusTexture)Target.Texture2d.Opaque;
|
||||
var gtex = (GDIPlusTexture2D)Target.Texture2D;
|
||||
CurGraphics?.Dispose();
|
||||
CurGraphics = SDGraphics.FromImage(gtex.SDBitmap);
|
||||
r = Target.Texture2d.Rectangle;
|
||||
r = gtex.GetRectangle();
|
||||
}
|
||||
|
||||
BufferedGraphics?.Dispose();
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class GDIPlusTexture : IDisposable
|
||||
{
|
||||
public Bitmap SDBitmap;
|
||||
public bool LinearFiltering;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SDBitmap?.Dispose();
|
||||
SDBitmap = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
public class GDIPlusTexture2D : ITexture2D
|
||||
{
|
||||
public Bitmap SDBitmap;
|
||||
public bool LinearFiltering;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public bool IsUpsideDown => false;
|
||||
|
||||
public GDIPlusTexture2D(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
SDBitmap = new(width, height, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SDBitmap?.Dispose();
|
||||
SDBitmap = null;
|
||||
}
|
||||
|
||||
public BitmapBuffer Resolve()
|
||||
{
|
||||
var blo = new BitmapLoadOptions
|
||||
{
|
||||
AllowWrap = false // must be an independent resource
|
||||
};
|
||||
|
||||
return new(SDBitmap, blo);
|
||||
}
|
||||
|
||||
public void LoadFrom(BitmapBuffer buffer)
|
||||
=> buffer.ToSysdrawingBitmap(SDBitmap);
|
||||
|
||||
public void SetFilterLinear()
|
||||
=> LinearFiltering = true;
|
||||
|
||||
public void SetFilterNearest()
|
||||
=> LinearFiltering = false;
|
||||
|
||||
public override string ToString()
|
||||
=> $"GDI+ Texture2D: {Width}x{Height}";
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Numerics;
|
||||
|
||||
using SDGraphics = System.Drawing.Graphics;
|
||||
|
@ -14,19 +13,11 @@ namespace BizHawk.Bizware.Graphics
|
|||
public EDispMethod DispMethodEnum => EDispMethod.GdiPlus;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BufferedGraphicsContext.Dispose();
|
||||
}
|
||||
=> BufferedGraphicsContext.Dispose();
|
||||
|
||||
public void ClearColor(Color color)
|
||||
=> GetCurrentGraphics().Clear(color);
|
||||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
gtex.Dispose();
|
||||
}
|
||||
|
||||
public Shader CreateFragmentShader(string source, string entry, bool required)
|
||||
=> null;
|
||||
|
||||
|
@ -48,9 +39,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
public Pipeline CreatePipeline(VertexLayout vertexLayout, Shader vertexShader, Shader fragmentShader, bool required, string memo)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
=> null;
|
||||
|
||||
public void FreePipeline(Pipeline pipeline)
|
||||
{
|
||||
|
@ -104,57 +93,26 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
}
|
||||
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, ITexture2D tex)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetTextureFilter(Texture2d texture, bool linear)
|
||||
=> ((GDIPlusTexture) texture.Opaque).LinearFiltering = linear;
|
||||
public ITexture2D CreateTexture(int width, int height)
|
||||
=> new GDIPlusTexture2D(width, height);
|
||||
|
||||
public Texture2d CreateTexture(int width, int height)
|
||||
{
|
||||
var sdBitmap = new Bitmap(width, height);
|
||||
var gtex = new GDIPlusTexture { SDBitmap = sdBitmap };
|
||||
return new(this, gtex, width, height);
|
||||
}
|
||||
|
||||
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
|
||||
{
|
||||
// only used for OpenGL
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
|
||||
{
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
bmp.ToSysdrawingBitmap(gtex.SDBitmap);
|
||||
}
|
||||
|
||||
public BitmapBuffer ResolveTexture2d(Texture2d tex)
|
||||
{
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
var blow = new BitmapLoadOptions
|
||||
{
|
||||
AllowWrap = false // must be an independent resource
|
||||
};
|
||||
|
||||
var bb = new BitmapBuffer(gtex.SDBitmap, blow);
|
||||
return bb;
|
||||
}
|
||||
// only used for OpenGL
|
||||
public ITexture2D WrapGLTexture2D(int glTexId, int width, int height)
|
||||
=> null;
|
||||
|
||||
// see CreateGuiViewMatrix for more
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int width, int height)
|
||||
{
|
||||
// see CreateGuiViewMatrix for more
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
=> Matrix4x4.Identity;
|
||||
|
||||
// on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
|
||||
// furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
|
||||
// this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
|
||||
public Matrix4x4 CreateGuiViewMatrix(int width, int height, bool autoFlip)
|
||||
{
|
||||
// on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here
|
||||
// furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it
|
||||
// this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
=> Matrix4x4.Identity;
|
||||
|
||||
public void SetViewport(int x, int y, int width, int height)
|
||||
{
|
||||
|
@ -168,14 +126,9 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
public RenderTarget CreateRenderTarget(int width, int height)
|
||||
{
|
||||
var gtex = new GDIPlusTexture
|
||||
{
|
||||
SDBitmap = new(width, height, PixelFormat.Format32bppArgb)
|
||||
};
|
||||
var tex = new Texture2d(this, gtex, width, height);
|
||||
|
||||
var tex2d = new GDIPlusTexture2D(width, height);
|
||||
var grt = new GDIPlusRenderTarget(() => BufferedGraphicsContext);
|
||||
var rt = new RenderTarget(this, grt, tex);
|
||||
var rt = new RenderTarget(this, grt, tex2d);
|
||||
grt.Target = rt;
|
||||
return rt;
|
||||
}
|
||||
|
@ -195,7 +148,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
else
|
||||
{
|
||||
var gtex = (GDIPlusTexture)rt.Texture2d.Opaque;
|
||||
var gtex = (GDIPlusTexture2D)rt.Texture2D;
|
||||
CurrentRenderTarget = (GDIPlusRenderTarget)rt.Opaque;
|
||||
_currOffscreenGraphics = SDGraphics.FromImage(gtex.SDBitmap);
|
||||
}
|
||||
|
@ -217,9 +170,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
private SDGraphics _currOffscreenGraphics;
|
||||
|
||||
public SDGraphics GetCurrentGraphics()
|
||||
{
|
||||
return _currOffscreenGraphics ?? CurrentRenderTarget.BufferedGraphics.Graphics;
|
||||
}
|
||||
=> _currOffscreenGraphics ?? CurrentRenderTarget.BufferedGraphics.Graphics;
|
||||
|
||||
public GDIPlusRenderTarget CurrentRenderTarget;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Sets a uniform sampler to use use the provided texture
|
||||
/// </summary>
|
||||
void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex);
|
||||
void SetPipelineUniformSampler(PipelineUniform uniform, ITexture2D tex);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a uniform value
|
||||
|
@ -91,11 +91,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// </summary>
|
||||
void Draw(IntPtr data, int count);
|
||||
|
||||
/// <summary>
|
||||
/// resolves the texture into a new BitmapBuffer
|
||||
/// </summary>
|
||||
BitmapBuffer ResolveTexture2d(Texture2d texture);
|
||||
|
||||
/// <summary>
|
||||
/// creates a vertex layout resource
|
||||
/// </summary>
|
||||
|
@ -113,26 +108,15 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
/// <summary>
|
||||
/// Creates a texture with the specified dimensions
|
||||
/// The texture will use a clamping address mode
|
||||
/// The texture will use a clamping address mode and nearest neighbor filtering by default
|
||||
/// </summary>
|
||||
Texture2d CreateTexture(int width, int height);
|
||||
ITexture2D CreateTexture(int width, int height);
|
||||
|
||||
/// <summary>
|
||||
/// In case you already have the texture ID (from an opengl emulator gpu core) you can get a Texture2d with it this way.
|
||||
/// In case you already have the texture ID (from an OpenGL emulator gpu core) you can get an ITexture2D with it this way.
|
||||
/// Otherwise, if this isn't an OpenGL frontend implementation, the core is expected to readback the texture for GetVideoBuffer()
|
||||
/// </summary>
|
||||
Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture's filtering mode
|
||||
/// The default is linear = false (i.e. nearest neighbor)
|
||||
/// </summary>
|
||||
public void SetTextureFilter(Texture2d texture, bool linear);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the texture with new data. This isn't supposed to be especially versatile, it just blasts a bitmap buffer into the texture
|
||||
/// </summary>
|
||||
void LoadTextureData(Texture2d tex, BitmapBuffer bmp);
|
||||
ITexture2D WrapGLTexture2D(int glTexId, int width, int height);
|
||||
|
||||
/// <summary>
|
||||
/// sets the viewport (and scissor) according to the provided specifications
|
||||
|
@ -165,11 +149,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// </summary>
|
||||
void FreeRenderTarget(RenderTarget rt);
|
||||
|
||||
/// <summary>
|
||||
/// Frees the provided texture. Same as disposing the resource.
|
||||
/// </summary>
|
||||
void FreeTexture(Texture2d tex);
|
||||
|
||||
/// <summary>
|
||||
/// Frees the provided pipeline. Same as disposing the resource.
|
||||
/// </summary>
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A full-scale 2D texture, with mip levels and everything.
|
||||
/// In OpenGL tradition, this encapsulates the sampler state, as well, which is equal parts annoying and convenient
|
||||
/// </summary>
|
||||
public interface ITexture2D : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// OpenGL wrapped textures from IGLTextureProvider will be upside down
|
||||
/// </summary>
|
||||
bool IsUpsideDown { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the texture into a new BitmapBuffer
|
||||
/// </summary>
|
||||
BitmapBuffer Resolve();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the texture with new data. This isn't supposed to be especially versatile, it just blasts a bitmap buffer into the texture
|
||||
/// </summary>
|
||||
void LoadFrom(BitmapBuffer buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture's filtering mode to linear
|
||||
/// </summary>
|
||||
void SetFilterLinear();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture's filtering mode to nearest neighbor
|
||||
/// </summary>
|
||||
void SetFilterNearest();
|
||||
}
|
||||
}
|
|
@ -50,9 +50,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GL.Dispose();
|
||||
}
|
||||
=> GL.Dispose();
|
||||
|
||||
public void ClearColor(Color color)
|
||||
{
|
||||
|
@ -60,20 +58,11 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
}
|
||||
|
||||
public void FreeTexture(Texture2d tex)
|
||||
{
|
||||
GL.DeleteTexture((uint)tex.Opaque);
|
||||
}
|
||||
public BizShader CreateVertexShader(string source, string entry, bool required)
|
||||
=> CreateShader(ShaderType.VertexShader, source, required);
|
||||
|
||||
public BizShader CreateFragmentShader(string source, string entry, bool required)
|
||||
{
|
||||
return CreateShader(ShaderType.FragmentShader, source, required);
|
||||
}
|
||||
|
||||
public BizShader CreateVertexShader(string source, string entry, bool required)
|
||||
{
|
||||
return CreateShader(ShaderType.VertexShader, source, required);
|
||||
}
|
||||
=> CreateShader(ShaderType.FragmentShader, source, required);
|
||||
|
||||
public void EnableBlending()
|
||||
{
|
||||
|
@ -285,11 +274,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL.DeleteBuffer(vlw.VBO);
|
||||
}
|
||||
|
||||
private void BindTexture2d(Texture2d tex)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, (uint)tex.Opaque);
|
||||
}
|
||||
|
||||
private void LegacyBindArrayData(VertexLayout vertexLayout, IntPtr pData)
|
||||
{
|
||||
// DEPRECATED CRAP USED, NEEDED FOR ANCIENT SHADERS
|
||||
|
@ -450,7 +434,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
|
||||
public void SetPipelineUniformSampler(PipelineUniform uniform, ITexture2D tex)
|
||||
{
|
||||
var n = (int)uniform.Sole.Opaque >> 24;
|
||||
|
||||
|
@ -458,54 +442,18 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL.ActiveTexture(TextureUnit.Texture0 + n);
|
||||
|
||||
// now bind the texture
|
||||
GL.BindTexture(TextureTarget.Texture2D, (uint)tex.Opaque);
|
||||
GL.BindTexture(TextureTarget.Texture2D, ((OpenGLTexture2D)tex).TexID);
|
||||
}
|
||||
|
||||
public void SetTextureFilter(Texture2d texture, bool linear)
|
||||
{
|
||||
BindTexture2d(texture);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(linear ? TextureMinFilter.Linear : TextureMinFilter.Nearest));
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)(linear ? TextureMagFilter.Linear : TextureMagFilter.Nearest));
|
||||
}
|
||||
public ITexture2D CreateTexture(int width, int height)
|
||||
=> new OpenGLTexture2D(GL, width, height);
|
||||
|
||||
public Texture2d CreateTexture(int width, int height)
|
||||
{
|
||||
var texId = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, texId);
|
||||
unsafe
|
||||
{
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint)width, (uint)height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, null);
|
||||
}
|
||||
|
||||
// sensible defaults
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
|
||||
|
||||
return new(this, texId, width, height);
|
||||
}
|
||||
|
||||
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
|
||||
=> new(this, (uint)glTexId.ToInt32(), width, height) { IsUpsideDown = true };
|
||||
|
||||
public unsafe void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
|
||||
{
|
||||
var bmpData = bmp.LockBits();
|
||||
try
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, (uint)tex.Opaque);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, (uint)bmp.Width, (uint)bmp.Height, PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0.ToPointer());
|
||||
}
|
||||
finally
|
||||
{
|
||||
bmp.UnlockBits(bmpData);
|
||||
}
|
||||
}
|
||||
public ITexture2D WrapGLTexture2D(int glTexId, int width, int height)
|
||||
=> new OpenGLTexture2D(GL, (uint)glTexId, width, height);
|
||||
|
||||
public void FreeRenderTarget(RenderTarget rt)
|
||||
{
|
||||
rt.Texture2d.Dispose();
|
||||
rt.Texture2D.Dispose();
|
||||
GL.DeleteFramebuffer((uint)rt.Opaque);
|
||||
}
|
||||
|
||||
|
@ -513,15 +461,14 @@ namespace BizHawk.Bizware.Graphics
|
|||
public RenderTarget CreateRenderTarget(int width, int height)
|
||||
{
|
||||
// create a texture for it
|
||||
var tex = CreateTexture(width, height);
|
||||
var texId = (uint)tex.Opaque;
|
||||
var tex2d = new OpenGLTexture2D(GL, width, height);
|
||||
|
||||
// create the FBO
|
||||
var fbId = GL.GenFramebuffer();
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbId);
|
||||
|
||||
// bind the tex to the FBO
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, texId, 0);
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, tex2d.TexID, 0);
|
||||
|
||||
// do something, I guess say which color buffers are used by the framebuffer
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
@ -534,7 +481,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
// since we're done configuring unbind this framebuffer, to return to the default
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
return new(this, fbId, tex);
|
||||
return new(this, fbId, tex2d);
|
||||
}
|
||||
|
||||
public void BindRenderTarget(RenderTarget rt)
|
||||
|
@ -550,17 +497,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public unsafe BitmapBuffer ResolveTexture2d(Texture2d tex)
|
||||
{
|
||||
// note - this is dangerous since it changes the bound texture. could we save it?
|
||||
BindTexture2d(tex);
|
||||
var bb = new BitmapBuffer(tex.IntWidth, tex.IntHeight);
|
||||
var bmpdata = bb.LockBits();
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Bgra, PixelType.UnsignedByte, bmpdata.Scan0.ToPointer());
|
||||
bb.UnlockBits(bmpdata);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public Matrix4x4 CreateGuiProjectionMatrix(int width, int height)
|
||||
{
|
||||
var ret = Matrix4x4.Identity;
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
|
||||
using Silk.NET.OpenGL.Legacy;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
internal class OpenGLTexture2D : ITexture2D
|
||||
{
|
||||
private readonly GL GL;
|
||||
public readonly uint TexID;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public bool IsUpsideDown { get; }
|
||||
|
||||
public OpenGLTexture2D(GL gl, int width, int height)
|
||||
{
|
||||
GL = gl;
|
||||
TexID = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexID);
|
||||
unsafe
|
||||
{
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint)width, (uint)height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, null);
|
||||
}
|
||||
|
||||
// sensible defaults
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
IsUpsideDown = false;
|
||||
}
|
||||
|
||||
public OpenGLTexture2D(GL gl, uint texID, int width, int height)
|
||||
{
|
||||
GL = gl;
|
||||
TexID = texID;
|
||||
Width = width;
|
||||
Height = height;
|
||||
IsUpsideDown = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> GL.DeleteTexture(TexID);
|
||||
|
||||
public unsafe BitmapBuffer Resolve()
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexID);
|
||||
|
||||
var pixels = new int[Width * Height];
|
||||
fixed (int* p = pixels)
|
||||
{
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Bgra, PixelType.UnsignedByte, p);
|
||||
}
|
||||
|
||||
return new(Width, Height, pixels);
|
||||
}
|
||||
|
||||
public unsafe void LoadFrom(BitmapBuffer buffer)
|
||||
{
|
||||
if (buffer.Width != Width || buffer.Height != Height)
|
||||
{
|
||||
throw new InvalidOperationException("BitmapBuffer dimensions do not match texture dimensions");
|
||||
}
|
||||
|
||||
var bmpData = buffer.LockBits();
|
||||
try
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexID);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, (uint)buffer.Width, (uint)buffer.Height, PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0.ToPointer());
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.UnlockBits(bmpData);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFilterLinear()
|
||||
{
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
}
|
||||
|
||||
public void SetFilterNearest()
|
||||
{
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"OpenGL Texture2D: {Width}x{Height}";
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
Owner?.Owner.SetPipelineUniform(this, value);
|
||||
}
|
||||
|
||||
public void Set(Texture2d tex)
|
||||
public void Set(ITexture2D tex)
|
||||
{
|
||||
Owner?.Owner.SetPipelineUniformSampler(this, tex);
|
||||
}
|
||||
|
|
|
@ -4,21 +4,21 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
public class RenderTarget : IDisposable
|
||||
{
|
||||
public RenderTarget(IGL owner, object opaque, Texture2d tex)
|
||||
public RenderTarget(IGL owner, object opaque, ITexture2D tex)
|
||||
{
|
||||
Owner = owner;
|
||||
Opaque = opaque;
|
||||
Texture2d = tex;
|
||||
Texture2D = tex;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"GL RT: {Texture2d.Width}x{Texture2d.Height}";
|
||||
return $"GL RT: {Texture2D.Width}x{Texture2D.Height}";
|
||||
}
|
||||
|
||||
public object Opaque { get; }
|
||||
public IGL Owner { get; }
|
||||
public Texture2d Texture2d { get; }
|
||||
public ITexture2D Texture2D { get; }
|
||||
|
||||
public void Unbind()
|
||||
{
|
||||
|
|
|
@ -26,9 +26,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
};
|
||||
|
||||
public void SetCornerColor(int which, Vector4 color)
|
||||
{
|
||||
CornerColors[which] = color;
|
||||
}
|
||||
=> CornerColors[which] = color;
|
||||
|
||||
/// <exception cref="ArgumentException"><paramref name="colors"/> does not have exactly <c>4</c> elements</exception>
|
||||
public void SetCornerColors(Vector4[] colors)
|
||||
|
@ -47,9 +45,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CurrentImageAttributes?.Dispose();
|
||||
}
|
||||
=> CurrentImageAttributes?.Dispose();
|
||||
|
||||
public void SetPipeline(Pipeline pipeline)
|
||||
{
|
||||
|
@ -60,9 +56,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
public void SetModulateColorWhite()
|
||||
{
|
||||
SetModulateColor(Color.White);
|
||||
}
|
||||
=> SetModulateColor(Color.White);
|
||||
|
||||
private ImageAttributes CurrentImageAttributes;
|
||||
|
||||
|
@ -94,14 +88,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
public void EnableBlending()
|
||||
{
|
||||
Owner.EnableBlending();
|
||||
}
|
||||
=> Owner.EnableBlending();
|
||||
|
||||
public void DisableBlending()
|
||||
{
|
||||
Owner.DisableBlending();
|
||||
}
|
||||
=> Owner.DisableBlending();
|
||||
|
||||
private MatrixStack _projection, _modelView;
|
||||
|
||||
|
@ -158,13 +148,13 @@ namespace BizHawk.Bizware.Graphics
|
|||
CurrentImageAttributes = null;
|
||||
}
|
||||
|
||||
public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
public void DrawSubrect(ITexture2D tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
{
|
||||
var g = _gdi.GetCurrentGraphics();
|
||||
|
||||
var tw = (GDIPlusTexture)tex.Opaque;
|
||||
var tex2d = (GDIPlusTexture2D)tex;
|
||||
// TODO - we can support bicubic for the final presentation...
|
||||
g.InterpolationMode = tw.LinearFiltering ? InterpolationMode.Bilinear : InterpolationMode.NearestNeighbor;
|
||||
g.InterpolationMode = tex2d.LinearFiltering ? InterpolationMode.Bilinear : InterpolationMode.NearestNeighbor;
|
||||
|
||||
SetupMatrix(g);
|
||||
|
||||
|
@ -180,9 +170,8 @@ namespace BizHawk.Bizware.Graphics
|
|||
var x1 = u1 * tex.Width;
|
||||
var y1 = v1 * tex.Height;
|
||||
|
||||
var gtex = (GDIPlusTexture)tex.Opaque;
|
||||
g.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
g.DrawImage(gtex.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.DrawImage(tex2d.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes);
|
||||
g.Transform = new(); // .Reset() doesnt work?
|
||||
}
|
||||
|
||||
|
|
|
@ -195,13 +195,13 @@ namespace BizHawk.Bizware.Graphics
|
|||
IsActive = false;
|
||||
}
|
||||
|
||||
public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
public void DrawSubrect(ITexture2D tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1)
|
||||
{
|
||||
PrepDrawSubrectInternal(tex);
|
||||
EmitRectangleInternal(x, y, w, h, u0, v0, u1, v1);
|
||||
}
|
||||
|
||||
private void PrepDrawSubrectInternal(Texture2d tex)
|
||||
private void PrepDrawSubrectInternal(ITexture2D tex)
|
||||
{
|
||||
if (sTexture != tex)
|
||||
{
|
||||
|
@ -271,7 +271,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
private readonly Pipeline DefaultPipeline;
|
||||
|
||||
// state cache
|
||||
private Texture2d sTexture;
|
||||
private ITexture2D sTexture;
|
||||
|
||||
// shaders are hand-coded for each platform to make sure they stay as fast as possible
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
/// <summary>
|
||||
/// Draws a subrectangle from the provided texture. For advanced users only
|
||||
/// </summary>
|
||||
void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1);
|
||||
void DrawSubrect(ITexture2D tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1);
|
||||
|
||||
/// <summary>
|
||||
/// Ends rendering
|
||||
|
|
|
@ -116,8 +116,8 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
// calculate texcoords (we shouldve already had this cached, but im speedcoding now)
|
||||
var tex = TexturePages[bfc.TexturePage];
|
||||
var w = tex.Width;
|
||||
var h = tex.Height;
|
||||
var w = (float)tex.Width;
|
||||
var h = (float)tex.Height;
|
||||
var bounds = new Rectangle(bfc.X, bfc.Y, bfc.Width, bfc.Height);
|
||||
var u0 = bounds.Left / w;
|
||||
var v0 = bounds.Top / h;
|
||||
|
@ -135,6 +135,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
public IGL Owner { get; }
|
||||
|
||||
private readonly BitmapFont FontInfo;
|
||||
private List<Texture2d> TexturePages = new();
|
||||
private List<ITexture2D> TexturePages = new();
|
||||
}
|
||||
}
|
|
@ -16,9 +16,9 @@ namespace BizHawk.Bizware.Graphics
|
|||
Owner = owner;
|
||||
|
||||
VertexLayout = owner.CreateVertexLayout();
|
||||
VertexLayout.DefineVertexAttribute("position", 0, 4, VertexAttribPointerType.Float, AttribUsage.Position, false, 40, 0);
|
||||
VertexLayout.DefineVertexAttribute("color", 1, 4, VertexAttribPointerType.Float, AttribUsage.Color0, false, 40, 16); //just dead weight, i have no idea why this is here. but some old HLSL compilers (used in bizhawk for various reasons) will want it to exist here since it exists in the vertex shader
|
||||
VertexLayout.DefineVertexAttribute("tex", 2, 2, VertexAttribPointerType.Float, AttribUsage.Texcoord0, false, 40, 32);
|
||||
VertexLayout.DefineVertexAttribute("position", 0, 4, VertexAttribPointerType.Float, AttribUsage.Position, normalized: false, stride: 40, offset: 0);
|
||||
VertexLayout.DefineVertexAttribute("color", 1, 4, VertexAttribPointerType.Float, AttribUsage.Color0, normalized: false, stride: 40, offset: 16); // just dead weight, i have no idea why this is here. but some old HLSL compilers (used in bizhawk for various reasons) will want it to exist here since it exists in the vertex shader
|
||||
VertexLayout.DefineVertexAttribute("tex", 2, 2, VertexAttribPointerType.Float, AttribUsage.Texcoord0, normalized: false, stride: 40, offset: 32);
|
||||
VertexLayout.Close();
|
||||
|
||||
var vsSource = $"#define VERTEX\r\n{source}";
|
||||
|
@ -77,7 +77,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
Owner.BindPipeline(Pipeline);
|
||||
}
|
||||
|
||||
public unsafe void Run(Texture2d tex, Size InputSize, Size OutputSize, bool flip)
|
||||
public unsafe void Run(ITexture2D tex, Size InputSize, Size OutputSize, bool flip)
|
||||
{
|
||||
// ack! make sure to set the pipeline before setting uniforms
|
||||
Bind();
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A full-scale 2D texture, with mip levels and everything.
|
||||
/// In OpenGL tradition, this encapsulates the sampler state, as well, which is equal parts annoying and convenient
|
||||
/// </summary>
|
||||
public class Texture2d : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// resolves the texture into a new BitmapBuffer
|
||||
/// </summary>
|
||||
public BitmapBuffer Resolve()
|
||||
{
|
||||
return Owner.ResolveTexture2d(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Owner.FreeTexture(this);
|
||||
Opaque = null;
|
||||
}
|
||||
|
||||
public Texture2d(IGL owner, object opaque, int width, int height)
|
||||
{
|
||||
Owner = owner;
|
||||
Opaque = opaque;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"GL Tex: {Width}x{Height}";
|
||||
}
|
||||
|
||||
public void LoadFrom(BitmapBuffer buffer)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetFilterLinear() => Owner.SetTextureFilter(this, true);
|
||||
|
||||
public void SetFilterNearest() => Owner.SetTextureFilter(this, false);
|
||||
|
||||
public IGL Owner { get; }
|
||||
public object Opaque { get; private set; }
|
||||
|
||||
// note.. this was a lame idea. convenient, but weird. lets just change this back to ints.
|
||||
public float Width { get; }
|
||||
public float Height { get; }
|
||||
|
||||
public int IntWidth => (int)Width;
|
||||
public int IntHeight => (int)Height;
|
||||
public Rectangle Rectangle => new(0, 0, IntWidth, IntHeight);
|
||||
public Size Size => new(IntWidth, IntHeight);
|
||||
|
||||
/// <summary>
|
||||
/// opengl sucks, man. seriously, screw this (textures from render targets are upside down)
|
||||
/// (couldn't we fix it up in the matrices somewhere?)
|
||||
/// </summary>
|
||||
public bool IsUpsideDown;
|
||||
}
|
||||
}
|
|
@ -795,13 +795,13 @@ namespace BizHawk.Client.Common
|
|||
if (vh < 1) vh = 1;
|
||||
|
||||
BitmapBuffer bb = null;
|
||||
Texture2d videoTexture = null;
|
||||
ITexture2D videoTexture = null;
|
||||
if (!simulate)
|
||||
{
|
||||
if (videoProvider is IGLTextureProvider glTextureProvider && _gl.DispMethodEnum == EDispMethod.OpenGL)
|
||||
{
|
||||
// FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code
|
||||
videoTexture = _gl.WrapGLTexture2d(new(glTextureProvider.GetGLTexture()), bufferWidth, bufferHeight);
|
||||
videoTexture = _gl.WrapGLTexture2D(glTextureProvider.GetGLTexture(), bufferWidth, bufferHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -880,13 +880,13 @@ namespace BizHawk.Client.Common
|
|||
|
||||
RunFilterChainSteps(ref rtCounter, out var rtCurr, out _);
|
||||
|
||||
job.OffscreenBb = rtCurr.Texture2d.Resolve();
|
||||
job.OffscreenBb = rtCurr.Texture2D.Resolve();
|
||||
job.OffscreenBb.DiscardAlpha();
|
||||
}
|
||||
|
||||
protected void RunFilterChainSteps(ref int rtCounter, out RenderTarget rtCurr, out bool inFinalTarget)
|
||||
{
|
||||
Texture2d texCurr = null;
|
||||
ITexture2D texCurr = null;
|
||||
rtCurr = null;
|
||||
inFinalTarget = false;
|
||||
foreach (var step in _currentFilterProgram.Program) switch (step.Type)
|
||||
|
@ -921,7 +921,7 @@ namespace BizHawk.Client.Common
|
|||
try
|
||||
{
|
||||
var fontData = new byte[fontStream.Length];
|
||||
fontStream.Read(fontData, 0, (int)fontStream.Length);
|
||||
_ = fontStream.Read(fontData, 0, (int)fontStream.Length);
|
||||
Marshal.Copy(fontData, 0, data, (int)fontStream.Length);
|
||||
CustomFonts.AddMemoryFont(data, fontData.Length);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
return point;
|
||||
}
|
||||
|
||||
public void SetInput(Texture2d tex)
|
||||
public void SetInput(ITexture2D tex)
|
||||
{
|
||||
InputTexture = tex;
|
||||
}
|
||||
|
@ -83,18 +83,18 @@ namespace BizHawk.Client.Common.Filters
|
|||
{
|
||||
}
|
||||
|
||||
public Texture2d GetOutput()
|
||||
public ITexture2D GetOutput()
|
||||
=> _outputTexture;
|
||||
|
||||
// filter actions
|
||||
protected void YieldOutput(Texture2d tex)
|
||||
protected void YieldOutput(ITexture2D tex)
|
||||
{
|
||||
_outputTexture = tex;
|
||||
}
|
||||
|
||||
protected FilterProgram FilterProgram;
|
||||
protected Texture2d InputTexture;
|
||||
private Texture2d _outputTexture;
|
||||
protected ITexture2D InputTexture;
|
||||
private ITexture2D _outputTexture;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate a 'RenderTarget' disposition if you want to draw directly to the input
|
||||
|
|
|
@ -538,9 +538,9 @@ namespace BizHawk.Client.Common.Filters
|
|||
DeclareOutput(state);
|
||||
}
|
||||
|
||||
private Texture2d _texture;
|
||||
private ITexture2D _texture;
|
||||
|
||||
public void SetTexture(Texture2d tex)
|
||||
public void SetTexture(ITexture2D tex)
|
||||
{
|
||||
_texture = tex;
|
||||
}
|
||||
|
|
|
@ -366,7 +366,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
InputTexture.SetFilterNearest();
|
||||
}
|
||||
|
||||
_rsc.Shaders[_rsi].Run(input, input.Size, _outputSize, InputTexture.IsUpsideDown);
|
||||
_rsc.Shaders[_rsi].Run(input, input.GetSize(), _outputSize, InputTexture.IsUpsideDown);
|
||||
|
||||
// maintain invariant.. i think.
|
||||
InputTexture.SetFilterNearest();
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
private readonly Size _size;
|
||||
|
||||
public Texture2d Texture { get; set; }
|
||||
public ITexture2D Texture { get; set; }
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace BizHawk.Client.Common.Filters
|
|||
|
||||
public override void Run()
|
||||
{
|
||||
YieldOutput(FilterProgram.CurrRenderTarget.Texture2d);
|
||||
YieldOutput(FilterProgram.CurrRenderTarget.Texture2D);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,12 +44,12 @@ namespace BizHawk.Client.Common
|
|||
public RenderTarget Get(int width, int height)
|
||||
{
|
||||
//get the current entry
|
||||
RenderTarget currentRenderTarget = _currentRenderTargets[0];
|
||||
var currentRenderTarget = _currentRenderTargets[0];
|
||||
|
||||
//check if its rotten and needs recreating
|
||||
if (currentRenderTarget == null
|
||||
|| currentRenderTarget.Texture2d.IntWidth != width
|
||||
|| currentRenderTarget.Texture2d.IntHeight != height)
|
||||
|| currentRenderTarget.Texture2D.Width != width
|
||||
|| currentRenderTarget.Texture2D.Height != height)
|
||||
{
|
||||
// needs recreating. be sure to kill the old one...
|
||||
currentRenderTarget?.Dispose();
|
||||
|
|
|
@ -29,27 +29,28 @@ namespace BizHawk.Client.Common
|
|||
|
||||
private void ResetList()
|
||||
{
|
||||
_currentTextures = new List<Texture2d> { null, null };
|
||||
_currentTextures = new List<ITexture2D> { null, null };
|
||||
}
|
||||
|
||||
private readonly IGL _gl;
|
||||
private List<Texture2d> _currentTextures;
|
||||
private List<ITexture2D> _currentTextures;
|
||||
|
||||
public Texture2d Get(IDisplaySurface ds)
|
||||
public ITexture2D Get(IDisplaySurface ds)
|
||||
{
|
||||
using var bb = new BitmapBuffer(ds.PeekBitmap(), new BitmapLoadOptions());
|
||||
using var bb = new BitmapBuffer(ds.PeekBitmap(), new());
|
||||
return Get(bb);
|
||||
}
|
||||
public Texture2d Get(BitmapBuffer bb)
|
||||
|
||||
public ITexture2D Get(BitmapBuffer bb)
|
||||
{
|
||||
//get the current entry
|
||||
Texture2d currentTexture = _currentTextures[0];
|
||||
var currentTexture = _currentTextures[0];
|
||||
|
||||
// TODO - its a bit cruddy here that we don't respect the current texture HasAlpha condition (in fact, there's no such concept)
|
||||
// we might need to deal with that in the future to fix some bugs.
|
||||
|
||||
//check if its rotten and needs recreating
|
||||
if (currentTexture == null || currentTexture.IntWidth != bb.Width || currentTexture.IntHeight != bb.Height)
|
||||
if (currentTexture == null || currentTexture.Width != bb.Width || currentTexture.Height != bb.Height)
|
||||
{
|
||||
//needs recreating. be sure to kill the old one...
|
||||
currentTexture?.Dispose();
|
||||
|
@ -59,7 +60,7 @@ namespace BizHawk.Client.Common
|
|||
else
|
||||
{
|
||||
//its good! just load in the data
|
||||
_gl.LoadTextureData(currentTexture, bb);
|
||||
currentTexture.LoadFrom(bb);
|
||||
}
|
||||
|
||||
//now shuffle the buffers
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
IGL gl,
|
||||
PresentationPanel presentationPanel,
|
||||
Func<bool> getIsSecondaryThrottlingDisabled)
|
||||
: base(config, emulator, inputManager, movieSession, gl.DispMethodEnum, gl, gl.CreateRenderer())
|
||||
: base(config, emulator, inputManager, movieSession, gl.DispMethodEnum, gl, gl.CreateGuiRenderer())
|
||||
{
|
||||
_presentationPanel = presentationPanel;
|
||||
_getIsSecondaryThrottlingDisabled = getIsSecondaryThrottlingDisabled;
|
||||
|
@ -99,7 +99,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if (job.Offscreen)
|
||||
{
|
||||
job.OffscreenBb = rtCurr.Texture2d.Resolve();
|
||||
job.OffscreenBb = rtCurr.Texture2D.Resolve();
|
||||
job.OffscreenBb.DiscardAlpha();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
_guiRenderer.Begin(Width, Height);
|
||||
_guiRenderer.DisableBlending();
|
||||
_guiRenderer.Draw(_rt.Texture2d);
|
||||
_guiRenderer.Draw(_rt.Texture2D);
|
||||
_guiRenderer.End();
|
||||
_graphicsControl.SwapBuffers();
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
try
|
||||
{
|
||||
using (gl.CreateRenderer()) return gl;
|
||||
using (gl.CreateGuiRenderer()) return gl;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue