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

Added SupportedTextureFormats setting

This commit is contained in:
narzoul 2022-12-17 20:37:14 +01:00
parent 25f325ec17
commit bb0f5c53e9
12 changed files with 302 additions and 11 deletions

View File

@ -16,6 +16,16 @@ namespace
namespace Compat
{
std::string getTrimmedTypeName(const std::string& typeName)
{
std::string prefix("struct ");
if (prefix == typeName.substr(0, prefix.length()))
{
return typeName.substr(prefix.length());
}
return typeName;
}
LogStream operator<<(LogStream os, const void* ptr)
{
if (ptr)

View File

@ -4,6 +4,7 @@
#include <fstream>
#include <functional>
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
@ -178,6 +179,14 @@ namespace Compat
return val.elem;
}
std::string getTrimmedTypeName(const std::string& typeName);
template <typename T>
std::string getTypeName()
{
return getTrimmedTypeName(typeid(T).name());
}
template <typename T>
Hex<T> hex(T val)
{

View File

@ -68,16 +68,6 @@ public:
}
private:
static std::string getVtableTypeName()
{
std::string name = typeid(Vtable).name();
if (0 == name.find("struct "))
{
name = name.substr(name.find(" ") + 1);
}
return name;
}
template <auto memberPtr, typename Result, typename FirstParam, typename... Params>
static Result STDMETHODCALLTYPE hookFunc(FirstParam firstParam, Params... params)
{
@ -107,4 +97,4 @@ template <auto memberPtr>
std::string VtableHookVisitor<Vtable, Lock>::s_funcName;
template <typename Vtable, typename Lock>
std::string VtableHookVisitor<Vtable, Lock>::s_vtableTypeName(getVtableTypeName());
std::string VtableHookVisitor<Vtable, Lock>::s_vtableTypeName(Compat::getTypeName<Vtable>());

View File

@ -27,6 +27,7 @@
#include <Config/Settings/SpriteTexCoord.h>
#include <Config/Settings/StatsHotKey.h>
#include <Config/Settings/SupportedResolutions.h>
#include <Config/Settings/SupportedTextureFormats.h>
#include <Config/Settings/TerminateHotKey.h>
#include <Config/Settings/TextureFilter.h>
#include <Config/Settings/ThreadPriorityBoost.h>
@ -64,6 +65,7 @@ namespace Config
Settings::SpriteTexCoord spriteTexCoord;
Settings::StatsHotKey statsHotKey;
Settings::SupportedResolutions supportedResolutions;
Settings::SupportedTextureFormats supportedTextureFormats;
Settings::TerminateHotKey terminateHotKey;
Settings::TextureFilter textureFilter;
Settings::ThreadPriorityBoost threadPriorityBoost;

View File

@ -209,6 +209,16 @@ namespace Config
return result;
}
std::string toupper(const std::string& str)
{
std::string result(str);
for (auto& c : result)
{
c = std::toupper(c, std::locale());
}
return result;
}
std::string trim(const std::string& str)
{
auto result(str);

View File

@ -25,6 +25,7 @@ namespace Config
void registerSetting(Setting& setting);
std::string removeParam(const std::string& value);
std::string tolower(const std::string& str);
std::string toupper(const std::string& str);
std::string trim(const std::string& str);
}
}

View File

@ -59,6 +59,10 @@ namespace Config
unsigned result = 0;
for (const auto& value : values)
{
if ("app" == value || "all" == value)
{
throw ParsingError("'" + value + "' cannot be combined with other values");
}
auto num = Parser::parseInt(value, 1, 32);
result |= 1U << (num - 1);
}

View File

@ -0,0 +1,148 @@
#include <map>
#include <vector>
#include <d3d.h>
#include <d3dumddi.h>
#include <Config/Parser.h>
#include <Config/Settings/SupportedTextureFormats.h>
namespace
{
std::map<D3DDDIFORMAT, std::string> g_formatNames = []()
{
std::map<D3DDDIFORMAT, std::string> names;
#define ADD_FORMAT(format) names[format] = #format
ADD_FORMAT(D3DDDIFMT_R8G8B8);
ADD_FORMAT(D3DDDIFMT_A8R8G8B8);
ADD_FORMAT(D3DDDIFMT_X8R8G8B8);
ADD_FORMAT(D3DDDIFMT_R5G6B5);
ADD_FORMAT(D3DDDIFMT_X1R5G5B5);
ADD_FORMAT(D3DDDIFMT_A1R5G5B5);
ADD_FORMAT(D3DDDIFMT_A4R4G4B4);
ADD_FORMAT(D3DDDIFMT_R3G3B2);
ADD_FORMAT(D3DDDIFMT_A8);
ADD_FORMAT(D3DDDIFMT_A8R3G3B2);
ADD_FORMAT(D3DDDIFMT_X4R4G4B4);
ADD_FORMAT(D3DDDIFMT_A8P8);
ADD_FORMAT(D3DDDIFMT_P8);
ADD_FORMAT(D3DDDIFMT_L8);
ADD_FORMAT(D3DDDIFMT_A8L8);
ADD_FORMAT(D3DDDIFMT_A4L4);
ADD_FORMAT(D3DDDIFMT_V8U8);
ADD_FORMAT(D3DDDIFMT_L6V5U5);
ADD_FORMAT(D3DDDIFMT_X8L8V8U8);
#undef ADD_FORMAT
for (auto& pair : names)
{
pair.second = Config::Parser::tolower(pair.second.substr(10));
}
return names;
}();
#define FOURCC(cc) *reinterpret_cast<D3DDDIFORMAT*>(#cc)
std::map<std::string, std::vector<D3DDDIFORMAT>> g_formatGroups = {
{ "argb", { D3DDDIFMT_A8R8G8B8, D3DDDIFMT_A1R5G5B5, D3DDDIFMT_A4R4G4B4 } },
{ "bump", { D3DDDIFMT_V8U8, D3DDDIFMT_L6V5U5, D3DDDIFMT_X8L8V8U8 } },
{ "dxt", { FOURCC(DXT1), FOURCC(DXT2), FOURCC(DXT3), FOURCC(DXT4),FOURCC(DXT5) } },
{ "lum", { D3DDDIFMT_L8, D3DDDIFMT_A8L8, D3DDDIFMT_A4L4 } },
{ "rgb", { D3DDDIFMT_X8R8G8B8, D3DDDIFMT_R5G6B5, D3DDDIFMT_X1R5G5B5, D3DDDIFMT_X4R4G4B4 } }
};
#undef FOURCC
}
namespace Config
{
namespace Settings
{
SupportedTextureFormats::SupportedTextureFormats()
: ListSetting("SupportedTextureFormats", "all")
{
}
std::string SupportedTextureFormats::getValueStr() const
{
if (m_formats.empty())
{
return "all";
}
std::string result;
for (const auto& format : m_formats)
{
result += ", ";
auto it = g_formatNames.find(static_cast<D3DDDIFORMAT>(format));
if (it != g_formatNames.end())
{
result += Config::Parser::toupper(it->second);
}
else
{
auto p = reinterpret_cast<const char*>(&format);
result += std::string(p, p + 4);
}
}
return result.substr(2);
}
bool SupportedTextureFormats::isSupported(UINT format) const
{
if (m_formats.empty())
{
return true;
}
return m_formats.find(format) != m_formats.end();
}
void SupportedTextureFormats::setValues(const std::vector<std::string>& values)
{
if (values.empty())
{
throw ParsingError("empty list is not allowed");
}
if (1 == values.size() && "all" == values[0])
{
m_formats.clear();
return;
}
std::set<UINT> formats;
for (const auto& fmt : values)
{
if ("all" == fmt)
{
throw ParsingError("'all' cannot be combined with other values");
}
auto group = g_formatGroups.find(fmt);
if (group != g_formatGroups.end())
{
formats.insert(group->second.begin(), group->second.end());
continue;
}
auto name = std::find_if(g_formatNames.begin(), g_formatNames.end(),
[&](const auto& pair) { return pair.second == fmt; });
if (name != g_formatNames.end())
{
formats.insert(name->first);
continue;
}
if (4 == fmt.length() &&
fmt.end() == std::find_if(fmt.begin(), fmt.end(), [](const char c) { return !std::isalnum(c); }))
{
formats.insert(*reinterpret_cast<const UINT*>(Config::Parser::toupper(fmt).c_str()));
continue;
}
throw ParsingError("invalid format name: '" + fmt + "'");
}
m_formats = formats;
}
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <set>
#include <Windows.h>
#include <Config/ListSetting.h>
namespace Config
{
namespace Settings
{
class SupportedTextureFormats : public ListSetting
{
public:
SupportedTextureFormats();
virtual std::string getValueStr() const override;
bool isSupported(UINT format) const;
private:
void setValues(const std::vector<std::string>& values) override;
std::set<UINT> m_formats;
};
}
extern Settings::SupportedTextureFormats supportedTextureFormats;
}

View File

@ -187,6 +187,7 @@
<ClInclude Include="Config\Settings\SpriteTexCoord.h" />
<ClInclude Include="Config\Settings\StatsHotKey.h" />
<ClInclude Include="Config\Settings\SupportedResolutions.h" />
<ClInclude Include="Config\Settings\SupportedTextureFormats.h" />
<ClInclude Include="Config\Settings\TerminateHotKey.h" />
<ClInclude Include="Config\Settings\TextureFilter.h" />
<ClInclude Include="Config\Settings\ThreadPriorityBoost.h" />
@ -333,6 +334,7 @@
<ClCompile Include="Config\Settings\SpriteFilter.cpp" />
<ClCompile Include="Config\Settings\SpriteTexCoord.cpp" />
<ClCompile Include="Config\Settings\SupportedResolutions.cpp" />
<ClCompile Include="Config\Settings\SupportedTextureFormats.cpp" />
<ClCompile Include="Config\Settings\TextureFilter.cpp" />
<ClCompile Include="Config\Settings\VSync.cpp" />
<ClCompile Include="Config\Settings\WinVersionLie.cpp" />

View File

@ -636,6 +636,9 @@
<ClInclude Include="DDraw\LogUsedResourceFormat.h">
<Filter>Header Files\DDraw</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\SupportedTextureFormats.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -1004,6 +1007,9 @@
<ClCompile Include="DDraw\LogUsedResourceFormat.cpp">
<Filter>Source Files\DDraw</Filter>
</ClCompile>
<ClCompile Include="Config\Settings\SupportedTextureFormats.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">

View File

@ -1,7 +1,10 @@
#include <Common/CompatPtr.h>
#include <Common/CompatRef.h>
#include <Common/CompatVtable.h>
#include <Common/Log.h>
#include <Config/Settings/SupportedTextureFormats.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/FormatInfo.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/Surface.h>
@ -10,6 +13,80 @@
namespace
{
struct EnumTextureFormatsArgs
{
void* callback;
void* context;
};
bool isSupported(const DDPIXELFORMAT& pf)
{
if ((pf.dwFlags & DDPF_FOURCC) && pf.dwFourCC < 0x100)
{
// D3DDDIFMT_A8B8G8R8 and D3DDDIFMT_X8B8G8R8 are enumerated like this, but nobody is expected to use them,
// and with proper pixel formats these cannot be created in video memory anyway.
return false;
}
return Config::supportedTextureFormats.isSupported(D3dDdi::getFormat(pf));
}
bool isSupported(const DDSURFACEDESC& desc)
{
return isSupported(desc.ddpfPixelFormat);
}
template <typename Format>
HRESULT CALLBACK enumTextureFormatsCallback(Format* lpFormat, LPVOID lpContext)
{
if (!isSupported(*lpFormat))
{
return D3DENUMRET_OK;
}
auto& args = *static_cast<EnumTextureFormatsArgs*>(lpContext);
auto origCallback = static_cast<decltype(&enumTextureFormatsCallback<Format>)>(args.callback);
return origCallback(lpFormat, args.context);
}
template <typename TDirect3DDevice>
D3DDEVICEDESC getCaps(TDirect3DDevice* This)
{
D3DDEVICEDESC hwDesc = {};
hwDesc.dwSize = sizeof(hwDesc);
D3DDEVICEDESC helDesc = {};
helDesc.dwSize = sizeof(helDesc);
getOrigVtable(This).GetCaps(This, &hwDesc, &helDesc);
return hwDesc;
}
D3DDEVICEDESC7 getCaps(IDirect3DDevice7* This)
{
D3DDEVICEDESC7 desc = {};
getOrigVtable(This).GetCaps(This, &desc);
return desc;
}
template <typename TDirect3DDevice>
bool isHalDevice(TDirect3DDevice* This)
{
return getCaps(This).dwDevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY;
}
template <typename TDirect3DDevice, typename EnumProc>
HRESULT STDMETHODCALLTYPE enumTextureFormats(TDirect3DDevice* This, EnumProc* lpd3dEnumPixelProc, LPVOID lpArg)
{
if (!This || !lpd3dEnumPixelProc || !isHalDevice(This))
{
if (This && lpd3dEnumPixelProc)
{
LOG_ONCE("Using feature: enumerating software texture formats via " << Compat::getTypeName<TDirect3DDevice>());
}
return getOrigVtable(This).EnumTextureFormats(This, lpd3dEnumPixelProc, lpArg);
}
LOG_ONCE("Using feature: enumerating hardware texture formats via " << Compat::getTypeName<TDirect3DDevice>());
EnumTextureFormatsArgs args = { lpd3dEnumPixelProc, lpArg };
return getOrigVtable(This).EnumTextureFormats(This, enumTextureFormatsCallback, &args);
}
HRESULT STDMETHODCALLTYPE execute(IDirect3DDevice* This,
LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags)
{
@ -48,6 +125,8 @@ namespace
{
vtable.SetRenderTarget = &setRenderTarget;
}
vtable.EnumTextureFormats = &enumTextureFormats;
}
}