DrawListTextureWrap: use two textures (#2285)

Making premultiplied pixel data into straight alpha in-place using UAV
seems to be not working on older graphics cards. Now every instance of
DrawListTextureWrap keeps two GPU textures, where one keeps a
premultiplied data which will be written to using ImGui draw data and
read from to calculate straight alpha pixel data.
This commit is contained in:
srkizer 2025-05-30 00:06:48 +09:00 committed by GitHub
parent d80202a755
commit e415699bb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 47 additions and 30 deletions

View file

@ -26,7 +26,10 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
private ComPtr<ID3D11Texture2D> tex;
private ComPtr<ID3D11ShaderResourceView> srv;
private ComPtr<ID3D11RenderTargetView> rtv;
private ComPtr<ID3D11UnorderedAccessView> uav;
private ComPtr<ID3D11Texture2D> texPremultiplied;
private ComPtr<ID3D11ShaderResourceView> srvPremultiplied;
private ComPtr<ID3D11RenderTargetView> rtvPremultiplied;
private int width;
private int height;
@ -138,7 +141,9 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
this.srv.Reset();
this.tex.Reset();
this.rtv.Reset();
this.uav.Reset();
this.srvPremultiplied.Reset();
this.texPremultiplied.Reset();
this.rtvPremultiplied.Reset();
this.device.Reset();
this.deviceContext.Reset();
@ -180,7 +185,7 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
// Clear the texture first, as the texture exists.
var clearColor = this.ClearColor;
this.deviceContext.Get()->ClearRenderTargetView(this.rtv.Get(), (float*)&clearColor);
this.deviceContext.Get()->ClearRenderTargetView(this.rtvPremultiplied.Get(), (float*)&clearColor);
// If there is nothing to draw, then stop.
if (!drawData.Valid
@ -196,8 +201,8 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
using (new DeviceContextStateBackup(this.device.Get()->GetFeatureLevel(), this.deviceContext))
{
Service<Renderer>.Get().RenderDrawData(this.rtv.Get(), drawData);
Service<Renderer>.Get().MakeStraight(this.uav.Get());
Service<Renderer>.Get().RenderDrawData(this.rtvPremultiplied.Get(), drawData);
Service<Renderer>.Get().MakeStraight(this.srvPremultiplied.Get(), this.rtv.Get());
}
}
@ -217,7 +222,9 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
this.tex.Reset();
this.srv.Reset();
this.rtv.Reset();
this.uav.Reset();
this.texPremultiplied.Reset();
this.srvPremultiplied.Reset();
this.rtvPremultiplied.Reset();
this.width = newWidth;
this.Height = newHeight;
this.srv = new((ID3D11ShaderResourceView*)this.emptyTexture.ImGuiHandle);
@ -231,7 +238,9 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
using var tmptex = default(ComPtr<ID3D11Texture2D>);
using var tmpsrv = default(ComPtr<ID3D11ShaderResourceView>);
using var tmprtv = default(ComPtr<ID3D11RenderTargetView>);
using var tmpuav = default(ComPtr<ID3D11UnorderedAccessView>);
using var tmptexPremultiplied = default(ComPtr<ID3D11Texture2D>);
using var tmpsrvPremultiplied = default(ComPtr<ID3D11ShaderResourceView>);
using var tmprtvPremultiplied = default(ComPtr<ID3D11RenderTargetView>);
var tmpTexDesc = new D3D11_TEXTURE2D_DESC
{
@ -243,8 +252,7 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
SampleDesc = new(1, 0),
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
BindFlags = (uint)(D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE |
D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET |
D3D11_BIND_FLAG.D3D11_BIND_UNORDERED_ACCESS),
D3D11_BIND_FLAG.D3D11_BIND_RENDER_TARGET),
CPUAccessFlags = 0u,
MiscFlags = 0u,
};
@ -263,15 +271,27 @@ internal sealed unsafe partial class DrawListTextureWrap : IDrawListTextureWrap,
if (hr.FAILED)
return hr;
var uavDesc = new D3D11_UNORDERED_ACCESS_VIEW_DESC(tmptex, D3D11_UAV_DIMENSION.D3D11_UAV_DIMENSION_TEXTURE2D);
hr = this.device.Get()->CreateUnorderedAccessView(tmpres, &uavDesc, tmpuav.GetAddressOf());
hr = this.device.Get()->CreateTexture2D(&tmpTexDesc, null, tmptexPremultiplied.GetAddressOf());
if (hr.FAILED)
return hr;
tmpres = (ID3D11Resource*)tmptexPremultiplied.Get();
srvDesc = new(tmptexPremultiplied, D3D_SRV_DIMENSION.D3D11_SRV_DIMENSION_TEXTURE2D);
hr = this.device.Get()->CreateShaderResourceView(tmpres, &srvDesc, tmpsrvPremultiplied.GetAddressOf());
if (hr.FAILED)
return hr;
rtvDesc = new(tmptexPremultiplied, D3D11_RTV_DIMENSION.D3D11_RTV_DIMENSION_TEXTURE2D);
hr = this.device.Get()->CreateRenderTargetView(tmpres, &rtvDesc, tmprtvPremultiplied.GetAddressOf());
if (hr.FAILED)
return hr;
tmptex.Swap(ref this.tex);
tmpsrv.Swap(ref this.srv);
tmprtv.Swap(ref this.rtv);
tmpuav.Swap(ref this.uav);
tmptexPremultiplied.Swap(ref this.texPremultiplied);
tmpsrvPremultiplied.Swap(ref this.srvPremultiplied);
tmprtvPremultiplied.Swap(ref this.rtvPremultiplied);
this.width = newWidth;
this.height = newHeight;
this.format = newFormat;

View file

@ -1,4 +1,4 @@
#include "DrawListTexture.Renderer.Common.hlsl"
#include "Renderer.Common.hlsl"
struct ImDrawVert {
float2 position : POSITION;
@ -18,7 +18,6 @@ struct PsData {
Texture2D s_texture : register(t0);
SamplerState s_sampler : register(s0);
RWTexture2D<float4> s_output : register(u1);
VsData vs_main(const ImDrawVert idv) {
VsData result;
@ -34,7 +33,7 @@ float4 ps_main(const VsData vd) : SV_TARGET {
/*
fxc /Zi /T vs_5_0 /E vs_main /Fo DrawListTexture.Renderer.DrawToPremul.vs.bin DrawListTexture.Renderer.DrawToPremul.hlsl
fxc /Zi /T ps_5_0 /E ps_main /Fo DrawListTexture.Renderer.DrawToPremul.ps.bin DrawListTexture.Renderer.DrawToPremul.hlsl
fxc /Zi /T vs_5_0 /E vs_main /Fo Renderer.DrawToPremul.vs.bin Renderer.DrawToPremul.hlsl
fxc /Zi /T ps_5_0 /E ps_main /Fo Renderer.DrawToPremul.ps.bin Renderer.DrawToPremul.hlsl
*/

View file

@ -1,22 +1,19 @@
RWTexture2D<unorm float4> s_output : register(u1);
Texture2D s_texture : register(t0);
float4 vs_main(const float2 position : POSITION) : SV_POSITION {
return float4(position, 0, 1);
}
float4 ps_main(const float4 position : SV_POSITION) : SV_TARGET {
const float4 src = s_output[position.xy];
s_output[position.xy] =
src.a > 0
const float4 src = s_texture[position.xy];
return src.a > 0
? float4(src.rgb / src.a, src.a)
: float4(0, 0, 0, 0);
return float4(0, 0, 0, 0); // unused
}
/*
fxc /Zi /T vs_5_0 /E vs_main /Fo DrawListTexture.Renderer.MakeStraight.vs.bin DrawListTexture.Renderer.MakeStraight.hlsl
fxc /Zi /T ps_5_0 /E ps_main /Fo DrawListTexture.Renderer.MakeStraight.ps.bin DrawListTexture.Renderer.MakeStraight.hlsl
fxc /Zi /T vs_5_0 /E vs_main /Fo Renderer.MakeStraight.vs.bin Renderer.MakeStraight.hlsl
fxc /Zi /T ps_5_0 /E ps_main /Fo Renderer.MakeStraight.ps.bin Renderer.MakeStraight.hlsl
*/

View file

@ -259,15 +259,16 @@ internal sealed unsafe partial class DrawListTextureWrap
}
/// <summary>Renders draw data.</summary>
/// <param name="puav">The pointer to a Texture2D UAV to make straight.</param>
public void MakeStraight(ID3D11UnorderedAccessView* puav)
/// <param name="psrv">The pointer to a Texture2D SRV to read premultiplied data from.</param>
/// <param name="prtv">The pointer to a Texture2D RTV to write straightened data.</param>
public void MakeStraight(ID3D11ShaderResourceView* psrv, ID3D11RenderTargetView* prtv)
{
ThreadSafety.AssertMainThread();
D3D11_TEXTURE2D_DESC texDesc;
using (var texRes = default(ComPtr<ID3D11Resource>))
{
puav->GetResource(texRes.GetAddressOf());
prtv->GetResource(texRes.GetAddressOf());
using var tex = default(ComPtr<ID3D11Texture2D>);
texRes.As(&tex).ThrowOnError();
@ -292,10 +293,9 @@ internal sealed unsafe partial class DrawListTextureWrap
var viewport = new D3D11_VIEWPORT(0, 0, texDesc.Width, texDesc.Height);
this.deviceContext.Get()->RSSetViewports(1, &viewport);
this.deviceContext.Get()->OMSetBlendState(null, null, 0xFFFFFFFF);
this.deviceContext.Get()->OMSetBlendState(null, null, 0xffffffff);
this.deviceContext.Get()->OMSetDepthStencilState(this.depthStencilState, 0);
var nullrtv = default(ID3D11RenderTargetView*);
this.deviceContext.Get()->OMSetRenderTargetsAndUnorderedAccessViews(1, &nullrtv, null, 1, 1, &puav, null);
this.deviceContext.Get()->OMSetRenderTargets(1, &prtv, null);
this.deviceContext.Get()->VSSetShader(this.makeStraightVertexShader.Get(), null, 0);
this.deviceContext.Get()->PSSetShader(this.makeStraightPixelShader.Get(), null, 0);
@ -304,6 +304,7 @@ internal sealed unsafe partial class DrawListTextureWrap
this.deviceContext.Get()->DSSetShader(null, null, 0);
this.deviceContext.Get()->CSSetShader(null, null, 0);
this.deviceContext.Get()->PSSetShaderResources(0, 1, &psrv);
this.deviceContext.Get()->DrawIndexed(6, 0, 0);
}