1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Added DisplayFilter setting

This commit is contained in:
narzoul 2021-07-04 17:32:01 +02:00
parent ffc8e04a35
commit 00a78097d2
14 changed files with 259 additions and 15 deletions

View File

@ -4,6 +4,7 @@ namespace Config
{
Settings::CpuAffinity cpuAffinity;
Settings::DesktopColorDepth desktopColorDepth;
Settings::DisplayFilter displayFilter;
Settings::DisplayResolution displayResolution;
Settings::SupportedResolutions supportedResolutions;
Settings::ThreadPriorityBoost threadPriorityBoost;

View File

@ -2,6 +2,7 @@
#include <Config/Settings/CpuAffinity.h>
#include <Config/Settings/DesktopColorDepth.h>
#include <Config/Settings/DisplayFilter.h>
#include <Config/Settings/DisplayResolution.h>
#include <Config/Settings/SupportedResolutions.h>
#include <Config/Settings/ThreadPriorityBoost.h>
@ -14,6 +15,7 @@ namespace Config
extern Settings::CpuAffinity cpuAffinity;
extern Settings::DesktopColorDepth desktopColorDepth;
extern Settings::DisplayFilter displayFilter;
extern Settings::DisplayResolution displayResolution;
extern Settings::SupportedResolutions supportedResolutions;
extern Settings::ThreadPriorityBoost threadPriorityBoost;

View File

@ -21,26 +21,68 @@ namespace Config
{
}
std::string getValueStr() const override
virtual std::string getParamStr() const
{
return {};
}
virtual std::string getValueStr() const override
{
for (const auto& pair : m_valueMapping)
{
if (pair.second == m_value)
{
return pair.first;
std::string param(getParamStr());
if (!param.empty())
{
param = '(' + param + ')';
}
return pair.first + param;
}
}
throw ParsingError("MappedSetting::getValueStr(): value not found in mapping");
}
void setValue(const std::string& value) override
virtual void setDefaultParam(const Value& /*value*/)
{
auto it = m_valueMapping.find(value);
}
virtual void setValue(const std::string& value) override
{
std::string val(value);
std::string param;
auto parenPos = value.find('(');
if (std::string::npos != parenPos)
{
val = value.substr(0, parenPos);
param = value.substr(parenPos + 1);
if (param.length() < 2 || param.back() != ')')
{
throw ParsingError("invalid value: '" + value + "'");
}
param = param.substr(0, param.length() - 1);
}
auto it = m_valueMapping.find(val);
if (it == m_valueMapping.end())
{
throw ParsingError("invalid value: '" + value + "'");
}
m_value = it->second;
if (param.empty())
{
m_value = it->second;
setDefaultParam(it->second);
}
else
{
setValue(it->second, param);
}
}
virtual void setValue(const Value& /*value*/, const std::string& param)
{
throw ParsingError("invalid parameter: '" + param + "'");
}
Value m_value;

View File

@ -0,0 +1,38 @@
#include <Config/Settings/DisplayFilter.h>
namespace Config
{
namespace Settings
{
DisplayFilter::DisplayFilter()
: MappedSetting("DisplayFilter", "bilinear(0)", { {"point", POINT}, {"bilinear", BILINEAR} })
, m_param(0)
{
}
std::string DisplayFilter::getParamStr() const
{
return BILINEAR == m_value ? std::to_string(m_param) : std::string();
}
void DisplayFilter::setDefaultParam(const UINT& value)
{
m_param = BILINEAR == value ? 100 : 0;
}
void DisplayFilter::setValue(const UINT& value, const std::string& param)
{
if (BILINEAR == value)
{
const UINT p = Config::Parser::parseUnsigned(param);
if (p <= 100)
{
m_value = BILINEAR;
m_param = p;
return;
}
}
throw ParsingError("invalid parameter: '" + param + "'");
}
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Config/MappedSetting.h>
namespace Config
{
namespace Settings
{
class DisplayFilter : public MappedSetting<UINT>
{
public:
static const UINT POINT = 0;
static const UINT BILINEAR = 1;
DisplayFilter();
UINT getParam() const { return m_param; }
protected:
virtual std::string getParamStr() const override;
virtual void setDefaultParam(const UINT& value) override;
virtual void setValue(const UINT& value, const std::string& param) override;
UINT m_param;
};
}
}

View File

@ -91,6 +91,7 @@ namespace D3dDdi
m_renderState[D3DDDIRS_PATCHSEGMENTS] = 0x3F800000;
m_renderState[D3DDDIRS_COLORWRITEENABLE] = 0xF;
m_renderState[D3DDDIRS_BLENDOP] = D3DBLENDOP_ADD;
m_renderState[D3DDDIRS_SRGBWRITEENABLE] = FALSE;
for (UINT i = 0; i < m_renderState.size(); i++)
{
@ -122,6 +123,7 @@ namespace D3dDdi
m_textureStageState[i][D3DDDITSS_MAXMIPLEVEL] = 0;
m_textureStageState[i][D3DDDITSS_MAXANISOTROPY] = 1;
m_textureStageState[i][D3DDDITSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE;
m_textureStageState[i][D3DDDITSS_SRGBTEXTURE] = FALSE;
m_textureStageState[i][D3DDDITSS_ADDRESSW] = D3DTADDRESS_WRAP;
m_textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY] = TRUE;

View File

@ -15,6 +15,9 @@ namespace D3dDdi
class DeviceState
{
public:
typedef std::array<FLOAT, 4> ShaderConstF;
typedef std::array<INT, 4> ShaderConstI;
DeviceState(Device& device);
HRESULT pfnCreateVertexShaderDecl(D3DDDIARG_CREATEVERTEXSHADERDECL* data, const D3DDDIVERTEXELEMENT* vertexElements);
@ -44,9 +47,6 @@ namespace D3dDdi
void onDestroyResource(HANDLE resource);
private:
typedef std::tuple<FLOAT, FLOAT, FLOAT, FLOAT> ShaderConstF;
typedef std::tuple<INT, INT, INT, INT> ShaderConstI;
HRESULT deleteShader(HANDLE shader, HANDLE& currentShader,
HRESULT(APIENTRY* origDeleteShaderFunc)(HANDLE, HANDLE));
HRESULT setShader(HANDLE shader, HANDLE& currentShader,
@ -148,6 +148,38 @@ namespace D3dDdi
using ScopedHandle::ScopedHandle;
};
class ScopedPixelShaderConst
{
public:
ScopedPixelShaderConst(
DeviceState& deviceState, const D3DDDIARG_SETPIXELSHADERCONST& data, const ShaderConstF* registers)
: m_deviceState(deviceState)
, m_register(data.Register)
{
if (data.Register + data.Count > m_deviceState.m_pixelShaderConst.size())
{
m_deviceState.m_pixelShaderConst.resize(data.Register + data.Count);
}
auto it = deviceState.m_pixelShaderConst.begin() + data.Register;
m_prevRegisters.assign(it, it + data.Count);
m_deviceState.pfnSetPixelShaderConst(&data, reinterpret_cast<const FLOAT*>(registers));
}
~ScopedPixelShaderConst()
{
D3DDDIARG_SETPIXELSHADERCONST data = {};
data.Register = m_register;
data.Count = m_prevRegisters.size();
m_deviceState.pfnSetPixelShaderConst(&data, reinterpret_cast<const FLOAT*>(m_prevRegisters.data()));
}
private:
DeviceState& m_deviceState;
UINT m_register;
std::vector<ShaderConstF> m_prevRegisters;
};
class ScopedRenderState
{
public:
@ -244,6 +276,7 @@ namespace D3dDdi
, m_scopedMagFilter(deviceState, { stage, D3DDDITSS_MAGFILTER, filter })
, m_scopedMinFilter(deviceState, { stage, D3DDDITSS_MINFILTER, filter })
, m_scopedMipFilter(deviceState, { stage, D3DDDITSS_MIPFILTER, D3DTEXF_NONE })
, m_scopedSrgbTexture(deviceState, { stage, D3DDDITSS_SRGBTEXTURE, D3DTEXF_LINEAR == filter })
, m_scopedWrap(deviceState, { static_cast<D3DDDIRENDERSTATETYPE>(D3DDDIRS_WRAP0 + stage), 0 })
, m_prevTextureColorKeyVal(deviceState.m_textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL])
, m_prevDisableTextureColorKey(deviceState.m_textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY])
@ -285,6 +318,7 @@ namespace D3dDdi
ScopedTextureStageState m_scopedMagFilter;
ScopedTextureStageState m_scopedMinFilter;
ScopedTextureStageState m_scopedMipFilter;
ScopedTextureStageState m_scopedSrgbTexture;
ScopedRenderState m_scopedWrap;
UINT m_prevTextureColorKeyVal;
UINT m_prevDisableTextureColorKey;

View File

@ -24,6 +24,8 @@ namespace
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
RECT g_presentationRect = {};
UINT g_presentationFilter = Config::Settings::DisplayFilter::POINT;
UINT g_presentationFilterParam = 0;
RECT calculatePresentationRect()
{
@ -124,6 +126,25 @@ namespace D3dDdi
Gdi::Cursor::setEmulated(true);
}
Gdi::VirtualScreen::setFullscreenMode(true);
if (g_presentationRect.right - g_presentationRect.left != rect.right ||
g_presentationRect.bottom - g_presentationRect.top != rect.bottom)
{
g_presentationFilter = Config::displayFilter.get();
g_presentationFilterParam = Config::displayFilter.getParam();
if (Config::Settings::DisplayFilter::BILINEAR == g_presentationFilter &&
0 == g_presentationFilterParam &&
0 == (g_presentationRect.right - g_presentationRect.left) % rect.right &&
0 == (g_presentationRect.bottom - g_presentationRect.top) % rect.bottom)
{
g_presentationFilter = Config::Settings::DisplayFilter::POINT;
}
}
else
{
g_presentationFilter = Config::Settings::DisplayFilter::POINT;
}
}
fixResourceData();
@ -548,7 +569,8 @@ namespace D3dDdi
const RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
const bool isLayeredPresentNeeded = Gdi::Window::presentLayered(nullptr, monitorRect);
if (isPalettized || isCursorEmulated || isLayeredPresentNeeded)
if (isPalettized || isCursorEmulated || isLayeredPresentNeeded ||
Config::Settings::DisplayFilter::POINT != g_presentationFilter)
{
const auto& si = srcResource->m_fixedData.pSurfList[0];
const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height));
@ -580,9 +602,6 @@ namespace D3dDdi
m_device.getOrigVtable().pfnBlt(m_device, &blt);
}
srcResource = dst.resource;
data.hSrcResource = *dst.resource;
if (isLayeredPresentNeeded)
{
Gdi::Window::presentLayered(dst.surface, monitorRect);
@ -591,13 +610,22 @@ namespace D3dDdi
if (isCursorEmulated)
{
POINT pos = { cursorInfo.ptScreenPos.x - monitorRect.left, cursorInfo.ptScreenPos.y - monitorRect.top };
m_device.getShaderBlitter().cursorBlt(*srcResource, 0, cursorInfo.hCursor, pos);
m_device.getShaderBlitter().cursorBlt(*dst.resource, 0, cursorInfo.hCursor, pos);
}
if (Config::Settings::DisplayFilter::BILINEAR == g_presentationFilter)
{
m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, g_presentationRect,
*dst.resource, data.SrcRect, g_presentationFilterParam);
return S_OK;
}
data.hSrcResource = *dst.resource;
}
data.DstRect = g_presentationRect;
data.Flags.Linear = 1;
data.Flags.Point = 0;
data.Flags.Linear = 0;
data.Flags.Point = 1;
return m_device.getOrigVtable().pfnBlt(m_device, &data);
}

View File

@ -5,7 +5,9 @@
#include <D3dDdi/ShaderBlitter.h>
#include <D3dDdi/SurfaceRepository.h>
#include <Shaders/DrawCursor.h>
#include <Shaders/GenBilinear.h>
#include <Shaders/PaletteLookup.h>
#include <Shaders/TextureSampler.h>
#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)
@ -16,7 +18,9 @@ namespace D3dDdi
ShaderBlitter::ShaderBlitter(Device& device)
: m_device(device)
, m_psDrawCursor(createPixelShader(g_psDrawCursor))
, m_psGenBilinear(createPixelShader(g_psGenBilinear))
, m_psPaletteLookup(createPixelShader(g_psPaletteLookup))
, m_psTextureSampler(createPixelShader(g_psTextureSampler))
, m_vertexShaderDecl(createVertexShaderDecl())
{
}
@ -55,6 +59,7 @@ namespace D3dDdi
SCOPED_STATE(RenderState, { D3DDDIRS_CLIPPLANEENABLE, 0 });
SCOPED_STATE(RenderState, { D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE });
SCOPED_STATE(RenderState, { D3DDDIRS_COLORWRITEENABLE, 0xF });
SCOPED_STATE(RenderState, { D3DDDIRS_SRGBWRITEENABLE, D3DTEXF_LINEAR == filter });
SCOPED_STATE(Texture, 0, srcResource, filter);
@ -164,6 +169,33 @@ namespace D3dDdi
blt(dstResource, dstSubResourceIndex, clippedDstRect, *cur.tempTexture, clippedSrcRect, m_psDrawCursor, D3DTEXF_POINT);
}
void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, UINT blurPercent)
{
if (100 == blurPercent)
{
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psTextureSampler, D3DTEXF_LINEAR);
return;
}
const auto& srcDesc = srcResource.getFixedDesc().pSurfList[0];
float scaleX = static_cast<float>(dstRect.right - dstRect.left) / (srcRect.right - srcRect.left);
float scaleY = static_cast<float>(dstRect.bottom - dstRect.top) / (srcRect.bottom - srcRect.top);
const float blur = blurPercent / 100.0f;
scaleX = 1 / ((1 - blur) / scaleX + blur);
scaleY = 1 / ((1 - blur) / scaleY + blur);
const DeviceState::ShaderConstF registers[] = {
{ static_cast<float>(srcDesc.Width), static_cast<float>(srcDesc.Height), 0.0f, 0.0f },
{ scaleX, scaleY, 0.0f, 0.0f }
};
SCOPED_STATE(PixelShaderConst, { 0, sizeof(registers) / sizeof(registers[0]) }, registers);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psGenBilinear, D3DTEXF_LINEAR);
}
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256])
{

View File

@ -17,6 +17,8 @@ namespace D3dDdi
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, HCURSOR cursor, POINT pt);
void genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, UINT blurPercent);
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256]);
@ -35,7 +37,9 @@ namespace D3dDdi
Device& m_device;
HANDLE m_psDrawCursor;
HANDLE m_psGenBilinear;
HANDLE m_psPaletteLookup;
HANDLE m_psTextureSampler;
HANDLE m_vertexShaderDecl;
};
}

View File

@ -215,6 +215,7 @@
<ClInclude Include="Config\Setting.h" />
<ClInclude Include="Config\Settings\CpuAffinity.h" />
<ClInclude Include="Config\Settings\DesktopColorDepth.h" />
<ClInclude Include="Config\Settings\DisplayFilter.h" />
<ClInclude Include="Config\Settings\DisplayResolution.h" />
<ClInclude Include="Config\Settings\SupportedResolutions.h" />
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
@ -320,6 +321,7 @@
<ClCompile Include="Config\Parser.cpp" />
<ClCompile Include="Config\Setting.cpp" />
<ClCompile Include="Config\Settings\CpuAffinity.cpp" />
<ClCompile Include="Config\Settings\DisplayFilter.cpp" />
<ClCompile Include="Config\Settings\DisplayResolution.cpp" />
<ClCompile Include="Config\Settings\SupportedResolutions.cpp" />
<ClCompile Include="D3dDdi\Adapter.cpp" />
@ -403,7 +405,9 @@
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\DrawCursor.hlsl" />
<FxCompile Include="Shaders\GenBilinear.hlsl" />
<FxCompile Include="Shaders\PaletteLookup.hlsl" />
<FxCompile Include="Shaders\TextureSampler.hlsl" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -444,6 +444,9 @@
<ClInclude Include="Config\Settings\SupportedResolutions.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\DisplayFilter.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -698,6 +701,9 @@
<ClCompile Include="Config\Settings\SupportedResolutions.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
<ClCompile Include="Config\Settings\DisplayFilter.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">
@ -716,5 +722,11 @@
<FxCompile Include="Shaders\DrawCursor.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\GenBilinear.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\TextureSampler.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
sampler2D s_texture : register(s0);
float2 g_textureRes : register(c0);
float2 g_scaleFactor : register(c1);
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
float2 coord = texCoord * g_textureRes - 0.5f;
float2 fracPart = frac(coord);
float2 intPart = coord - fracPart;
coord = (intPart + saturate(g_scaleFactor * (fracPart - 0.5f) + 0.5f) + 0.5f) / g_textureRes;
return tex2D(s_texture, coord);
}

View File

@ -0,0 +1,6 @@
sampler2D s_texture : register(s0);
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(s_texture, texCoord);
}