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

Added ColorKeyMethod setting

This commit is contained in:
narzoul 2023-01-22 21:43:47 +01:00
parent 2248a07113
commit bfc5a0be24
21 changed files with 552 additions and 45 deletions

View File

@ -3,6 +3,7 @@
#include <Config/Settings/AltTabFix.h>
#include <Config/Settings/Antialiasing.h>
#include <Config/Settings/BltFilter.h>
#include <Config/Settings/ColorKeyMethod.h>
#include <Config/Settings/ConfigHotKey.h>
#include <Config/Settings/CpuAffinity.h>
#include <Config/Settings/CpuAffinityRotation.h>
@ -46,6 +47,7 @@ namespace Config
Settings::AltTabFix altTabFix;
Settings::Antialiasing antialiasing;
Settings::BltFilter bltFilter;
Settings::ColorKeyMethod colorKeyMethod;
Settings::ConfigHotKey configHotKey;
Settings::CpuAffinity cpuAffinity;
Settings::CpuAffinityRotation cpuAffinityRotation;

View File

@ -0,0 +1,25 @@
#include <Config/Settings/ColorKeyMethod.h>
namespace Config
{
namespace Settings
{
ColorKeyMethod::ColorKeyMethod()
: MappedSetting("ColorKeyMethod", "native", {
{"none", NONE},
{"native", NATIVE},
{"alphatest", ALPHATEST}
})
{
}
Setting::ParamInfo ColorKeyMethod::getParamInfo() const
{
if (ALPHATEST == m_value)
{
return { "AlphaRef", 1, 255, 1, m_param };
}
return {};
}
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <Config/MappedSetting.h>
namespace Config
{
namespace Settings
{
class ColorKeyMethod : public MappedSetting<UINT>
{
public:
static const UINT NONE = 0;
static const UINT NATIVE = 1;
static const UINT ALPHATEST = 2;
ColorKeyMethod();
virtual ParamInfo getParamInfo() const override;
};
}
extern Settings::ColorKeyMethod colorKeyMethod;
}

View File

@ -248,13 +248,6 @@ namespace D3dDdi
return m_origVtable.pfnColorFill(m_device, data);
}
HRESULT Device::pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code)
{
LOG_DEBUG << "Pixel shader bytecode: " << Compat::hexDump(code, data->CodeSize);
LOG_DEBUG << ShaderAssembler(code, data->CodeSize).disassemble();
return m_origVtable.pfnCreatePixelShader(m_device, data, code);
}
HRESULT Device::pfnCreateResource(D3DDDIARG_CREATERESOURCE* data)
{
D3DDDIARG_CREATERESOURCE2 data2 = {};

View File

@ -33,7 +33,6 @@ namespace D3dDdi
HRESULT pfnBlt(const D3DDDIARG_BLT* data);
HRESULT pfnClear(const D3DDDIARG_CLEAR* data, UINT numRect, const RECT* rect);
HRESULT pfnColorFill(const D3DDDIARG_COLORFILL* data);
HRESULT pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code);
HRESULT pfnCreateResource(D3DDDIARG_CREATERESOURCE* data);
HRESULT pfnCreateResource2(D3DDDIARG_CREATERESOURCE2* data);
HRESULT pfnCreateVertexShaderFunc(D3DDDIARG_CREATEVERTEXSHADERFUNC* data, const UINT* code);

View File

@ -54,7 +54,6 @@ namespace
SET_DEVICE_FUNC(pfnColorFill);
SET_DEVICE_FUNC(pfnCreateResource);
SET_DEVICE_FUNC(pfnCreateResource2);
SET_DEVICE_FUNC(pfnCreatePixelShader);
SET_DEVICE_FUNC(pfnCreateVertexShaderFunc);
SET_DEVICE_FUNC(pfnDepthFill);
SET_DEVICE_FUNC(pfnDestroyDevice);
@ -71,6 +70,7 @@ namespace
SET_DEVICE_FUNC(pfnUnlock);
SET_DEVICE_FUNC(pfnUpdatePalette);
SET_DEVICE_STATE_FUNC(pfnCreatePixelShader);
SET_DEVICE_STATE_FUNC(pfnCreateVertexShaderDecl);
SET_DEVICE_STATE_FUNC(pfnDeletePixelShader);
SET_DEVICE_STATE_FUNC(pfnDeleteVertexShaderDecl);

View File

@ -1,6 +1,7 @@
#include <algorithm>
#include <Config/Settings/AlternatePixelCenter.h>
#include <Config/Settings/ColorKeyMethod.h>
#include <Config/Settings/SpriteFilter.h>
#include <Config/Settings/SpriteTexCoord.h>
#include <Config/Settings/TextureFilter.h>
@ -10,6 +11,7 @@
#include <D3dDdi/DrawPrimitive.h>
#include <D3dDdi/Log/DeviceFuncsLog.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ShaderAssembler.h>
#include <Shaders/VertexFixup.h>
#define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": "
@ -280,6 +282,58 @@ namespace D3dDdi
return it != m_vertexShaderDecls.end() ? it->second : emptyDecl;
}
bool DeviceState::isColorKeyUsed()
{
if (!m_app.renderState[D3DDDIRS_COLORKEYENABLE])
{
return false;
}
bool used = false;
for (UINT i = 0; i < getVertexDecl().textureStageCount && !used; ++i)
{
used = !m_app.textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY];
}
return used;
}
HANDLE DeviceState::mapPixelShader(HANDLE shader)
{
if (Config::Settings::ColorKeyMethod::ALPHATEST != Config::colorKeyMethod.get())
{
return m_app.pixelShader;
}
auto it = m_pixelShaders.find(shader);
if (it == m_pixelShaders.end())
{
return m_app.pixelShader;
}
if (!it->second.isModified)
{
ShaderAssembler shaderAssembler(it->second.tokens.data(), it->second.tokens.size());
if (shaderAssembler.addAlphaTest(Config::colorKeyMethod.getParam()))
{
const auto& tokens = shaderAssembler.getTokens();
D3DDDIARG_CREATEPIXELSHADER data = {};
data.CodeSize = tokens.size() * 4;
HRESULT result = m_device.getOrigVtable().pfnCreatePixelShader(m_device, &data, tokens.data());
if (SUCCEEDED(result))
{
it->second.modifiedPixelShader.reset(data.ShaderHandle);
}
else
{
LOG_ONCE("ERROR: failed to create modified pixel shader: " << Compat::hex(result));
}
}
it->second.isModified = true;
}
return it->second.modifiedPixelShader ? it->second.modifiedPixelShader.get() : m_app.pixelShader;
}
UINT DeviceState::mapRsValue(D3DDDIRENDERSTATETYPE state, UINT value)
{
if (state >= D3DDDIRS_WRAP0 && state <= D3DDDIRS_WRAP7)
@ -287,14 +341,13 @@ namespace D3dDdi
return value & (D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2 | D3DWRAPCOORD_3);
}
if (D3DDDIRS_COLORKEYENABLE == state && value)
if (D3DDDIRS_COLORKEYENABLE == state)
{
UINT enable = FALSE;
for (UINT i = 0; i < getVertexDecl().textureStageCount && !enable; ++i)
if (Config::Settings::ColorKeyMethod::NATIVE != Config::colorKeyMethod.get())
{
enable = !m_app.textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY];
return FALSE;
}
return enable;
return isColorKeyUsed();
}
if (D3DDDIRS_MULTISAMPLEANTIALIAS == state)
@ -371,6 +424,21 @@ namespace D3dDdi
&DeviceState::pfnSetStreamSource);
}
HRESULT DeviceState::pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code)
{
LOG_DEBUG << "Pixel shader bytecode: " << Compat::hexDump(code, data->CodeSize);
LOG_DEBUG << ShaderAssembler(code, data->CodeSize).disassemble();
HRESULT result = m_device.getOrigVtable().pfnCreatePixelShader(m_device, data, code);
if (SUCCEEDED(result))
{
m_pixelShaders.emplace(data->ShaderHandle,
PixelShader{ std::vector<UINT>(code, code + data->CodeSize / 4),
std::unique_ptr<void, ResourceDeleter>(
nullptr, ResourceDeleter(m_device, m_device.getOrigVtable().pfnDeleteVertexShaderFunc)) });
}
return result;
}
HRESULT DeviceState::pfnCreateVertexShaderDecl(
D3DDDIARG_CREATEVERTEXSHADERDECL* data,
const D3DDDIVERTEXELEMENT* vertexElements)
@ -413,7 +481,21 @@ namespace D3dDdi
HRESULT DeviceState::pfnDeletePixelShader(HANDLE shader)
{
return deleteShader(shader, &State::pixelShader, m_device.getOrigVtable().pfnDeletePixelShader);
HRESULT result = deleteShader(shader, &State::pixelShader, m_device.getOrigVtable().pfnDeletePixelShader);
if (SUCCEEDED(result))
{
auto it = m_pixelShaders.find(shader);
if (it != m_pixelShaders.end())
{
if (it->second.modifiedPixelShader)
{
deleteShader(it->second.modifiedPixelShader.release(), &State::pixelShader,
m_device.getOrigVtable().pfnDeletePixelShader);
}
m_pixelShaders.erase(it);
}
}
return result;
}
HRESULT DeviceState::pfnDeleteVertexShaderDecl(HANDLE shader)
@ -593,6 +675,7 @@ namespace D3dDdi
if (resource)
{
resource->updatePalettizedTexture(stage);
resource->prepareForTextureRead(stage);
}
}
}
@ -918,14 +1001,27 @@ namespace D3dDdi
void DeviceState::updateConfig()
{
m_changedStates |= CS_RENDER_STATE | CS_RENDER_TARGET | CS_TEXTURE_STAGE;
m_changedStates |= CS_RENDER_STATE | CS_RENDER_TARGET | CS_SHADER | CS_TEXTURE_STAGE;
m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE);
m_changedRenderStates.set(D3DDDIRS_MULTISAMPLEANTIALIAS);
for (auto& ps : m_pixelShaders)
{
if (ps.second.modifiedPixelShader.get())
{
deleteShader(ps.second.modifiedPixelShader.release(), &State::pixelShader,
m_device.getOrigVtable().pfnDeletePixelShader);
}
ps.second.isModified = false;
}
for (UINT i = 0; i < m_changedTextureStageStates.size(); ++i)
{
m_changedTextureStageStates[i].set(D3DDDITSS_MINFILTER);
m_changedTextureStageStates[i].set(D3DDDITSS_MAGFILTER);
m_changedTextureStageStates[i].set(D3DDDITSS_MIPFILTER);
m_changedTextureStageStates[i].set(D3DDDITSS_MAXANISOTROPY);
m_changedTextureStageStates[i].set(D3DDDITSS_TEXTURECOLORKEYVAL);
}
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSU);
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSV);
@ -937,7 +1033,7 @@ namespace D3dDdi
m_changedRenderStates.forEach([&](UINT stateIndex)
{
const auto state = static_cast<D3DDDIRENDERSTATETYPE>(stateIndex);
setRenderState({ state, mapRsValue(state, m_app.renderState[state]) });
setRenderState({ state, mapRsValue(state, m_app.renderState[state]) });
});
m_changedRenderStates.reset();
}
@ -979,7 +1075,7 @@ namespace D3dDdi
void DeviceState::updateShaders()
{
setPixelShader(m_app.pixelShader);
setPixelShader(mapPixelShader(m_app.pixelShader));
setVertexShaderDecl(m_app.vertexShaderDecl);
auto it = m_vertexShaderDecls.find(m_app.vertexShaderDecl);
if (it != m_vertexShaderDecls.end() && it->second.isTransformed)
@ -1008,11 +1104,24 @@ namespace D3dDdi
{
m_changedTextureStageStates[stage].reset(D3DDDITSS_DISABLETEXTURECOLORKEY);
m_changedTextureStageStates[stage].reset(D3DDDITSS_TEXTURECOLORKEYVAL);
if (!m_app.textures[stage])
if (!m_app.textures[stage] || Config::Settings::ColorKeyMethod::NONE == Config::colorKeyMethod.get())
{
return;
}
if (Config::Settings::ColorKeyMethod::ALPHATEST == Config::colorKeyMethod.get())
{
const BOOL colorKeyEnabled = !m_app.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY];
if (colorKeyEnabled != m_pixelShaderConstB[stage][0])
{
D3DDDIARG_SETPIXELSHADERCONSTB data = {};
data.Register = stage;
data.Count = 1;
setShaderConst(&data, &colorKeyEnabled, m_pixelShaderConstB, m_device.getOrigVtable().pfnSetPixelShaderConstB);
}
return;
}
D3DDDIARG_TEXTURESTAGESTATE tss = {};
tss.Stage = stage;
@ -1030,7 +1139,7 @@ namespace D3dDdi
if (resource && resource->getPalettizedTexture())
{
tss.Value = reinterpret_cast<DWORD&>(
m_device.getPalette(resource->getPalettizedTexture()->getPaletteHandle())[tss.Value]);
m_device.getPalette(resource->getPalettizedTexture()->getPaletteHandle())[tss.Value]) & 0xFFFFFF;
}
m_current.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] = tss.Value;
m_current.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = FALSE;
@ -1048,7 +1157,7 @@ namespace D3dDdi
auto resource = getTextureResource(stage);
if (resource)
{
resource = &resource->prepareForGpuRead(0);
resource = &resource->prepareForTextureRead(stage);
}
if (setTexture(stage, resource ? *resource : m_app.textures[stage]) ||

View File

@ -86,6 +86,7 @@ namespace D3dDdi
DeviceState(Device& device);
HRESULT pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code);
HRESULT pfnCreateVertexShaderDecl(D3DDDIARG_CREATEVERTEXSHADERDECL* data, const D3DDDIVERTEXELEMENT* vertexElements);
HRESULT pfnDeletePixelShader(HANDLE shader);
HRESULT pfnDeleteVertexShaderDecl(HANDLE shader);
@ -148,6 +149,13 @@ namespace D3dDdi
CS_TEXTURE_STAGE = 1 << 4
};
struct PixelShader
{
std::vector<UINT> tokens;
std::unique_ptr<void, ResourceDeleter> modifiedPixelShader;
bool isModified;
};
template <int N>
std::unique_ptr<void, ResourceDeleter> createVertexShader(const BYTE(&code)[N])
{
@ -158,6 +166,8 @@ namespace D3dDdi
HRESULT deleteShader(HANDLE shader, HANDLE State::* shaderMember,
HRESULT(APIENTRY* origDeleteShaderFunc)(HANDLE, HANDLE));
bool isColorKeyUsed();
HANDLE mapPixelShader(HANDLE shader);
UINT mapRsValue(D3DDDIRENDERSTATETYPE state, UINT value);
UINT mapTssValue(UINT stage, D3DDDITEXTURESTAGESTATETYPE state, UINT value);
void prepareTextures();
@ -214,6 +224,7 @@ namespace D3dDdi
std::array<BitSet<D3DDDITSS_TEXTUREMAP, D3DDDITSS_TEXTURECOLORKEYVAL>, 8> m_changedTextureStageStates;
std::unique_ptr<void, ResourceDeleter> m_vsVertexFixup;
std::array<Resource*, 8> m_textureResource;
std::map<HANDLE, PixelShader> m_pixelShaders;
bool m_isLocked;
bool m_spriteMode;
};

View File

@ -6,6 +6,7 @@
#include <Common/Rect.h>
#include <Common/Time.h>
#include <Config/Settings/BltFilter.h>
#include <Config/Settings/ColorKeyMethod.h>
#include <Config/Settings/DepthFormat.h>
#include <Config/Settings/DisplayFilter.h>
#include <Config/Settings/RenderColorDepth.h>
@ -122,6 +123,8 @@ namespace D3dDdi
, m_msaaSurface{}
, m_msaaResolvedSurface{}
, m_nullSurface{}
, m_colorKeyedSurface{}
, m_colorKey(0)
, m_formatConfig(D3DDDIFMT_UNKNOWN)
, m_multiSampleConfig{ D3DDDIMULTISAMPLE_NONE, 0 }
, m_scaledSize{}
@ -133,6 +136,7 @@ namespace D3dDdi
, m_isClampable(true)
, m_isPrimary(false)
, m_isPalettizedTextureUpToDate(false)
, m_isColorKeyedSurfaceUpToDate(false)
{
if (m_origData.Flags.VertexBuffer &&
m_origData.Flags.MightDrawFromLocked &&
@ -824,7 +828,7 @@ namespace D3dDdi
return *nextRt;
}
RECT Resource::getRect(UINT subResourceIndex)
RECT Resource::getRect(UINT subResourceIndex) const
{
const auto& si = m_fixedData.pSurfList[subResourceIndex];
return { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
@ -1071,6 +1075,7 @@ namespace D3dDdi
if (!data.Flags.ReadOnly)
{
m_isPalettizedTextureUpToDate = false;
m_isColorKeyedSurfaceUpToDate = false;
}
if (m_fixedData.Flags.ZBuffer && m_msaaResolvedSurface.resource)
@ -1127,6 +1132,7 @@ namespace D3dDdi
Resource& Resource::prepareForBltDst(HANDLE& resource, UINT subResourceIndex, RECT& rect)
{
m_isPalettizedTextureUpToDate = false;
m_isColorKeyedSurfaceUpToDate = false;
if (m_lockResource || m_msaaResolvedSurface.resource)
{
loadFromLockRefResource(subResourceIndex);
@ -1166,6 +1172,8 @@ namespace D3dDdi
void Resource::prepareForCpuWrite(UINT subResourceIndex)
{
m_isPalettizedTextureUpToDate = false;
m_isColorKeyedSurfaceUpToDate = false;
if (m_lockResource)
{
if (m_lockRefSurface.resource &&
@ -1202,6 +1210,7 @@ namespace D3dDdi
void Resource::prepareForGpuWrite(UINT subResourceIndex)
{
m_isColorKeyedSurfaceUpToDate = false;
if (m_lockResource || m_msaaResolvedSurface.resource)
{
if (m_msaaSurface.resource)
@ -1225,6 +1234,55 @@ namespace D3dDdi
}
}
Resource& Resource::prepareForTextureRead(UINT stage)
{
if (m_lockResource)
{
for (UINT i = 0; i < m_lockData.size(); ++i)
{
prepareForGpuRead(i);
}
}
auto& defaultResource = m_msaaResolvedSurface.resource ? *m_msaaResolvedSurface.resource : *this;
const auto& appState = m_device.getState().getAppState();
if (Config::Settings::ColorKeyMethod::ALPHATEST != Config::colorKeyMethod.get() ||
!appState.renderState[D3DDDIRS_COLORKEYENABLE] ||
appState.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY])
{
return defaultResource;
}
if (!m_colorKeyedSurface.surface)
{
auto& repo = SurfaceRepository::get(m_device.getAdapter());
repo.getSurface(m_colorKeyedSurface, m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height,
D3DDDIFMT_A8R8G8B8, DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY |
(m_fixedData.MipLevels > 1 ? DDSCAPS_MIPMAP : 0),
m_fixedData.SurfCount,
m_fixedData.Flags.CubeMap ? DDSCAPS2_CUBEMAP : 0);
if (!m_colorKeyedSurface.surface)
{
return defaultResource;
}
m_colorKey = appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] + 1;
}
if (!m_isColorKeyedSurfaceUpToDate ||
m_colorKey != appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL])
{
m_isColorKeyedSurfaceUpToDate = true;
m_colorKey = appState.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL];
auto ck = convertToShaderConst(m_formatInfo, m_colorKey);
for (UINT i = 0; i < m_fixedData.SurfCount; ++i)
{
m_device.getShaderBlitter().colorKeyBlt(*m_colorKeyedSurface.resource, i, defaultResource, i, ck);
}
}
return *m_colorKeyedSurface.resource;
}
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource)
{
LOG_FUNC("Resource::presentationBlt", data, *srcResource);
@ -1767,7 +1825,11 @@ namespace D3dDdi
memcpy(palette, m_device.getPalette(m_palettizedTexture->m_paletteHandle), sizeof(palette));
for (int i = 0; i < 256; ++i)
{
if (i != paletteColorKeyIndex && palette[i] == palette[paletteColorKeyIndex])
if (i == paletteColorKeyIndex)
{
palette[i].rgbReserved = 0;
}
else if (palette[i] == palette[paletteColorKeyIndex])
{
palette[i].rgbBlue += 0xFF == palette[i].rgbBlue ? -1 : 1;
}

View File

@ -40,6 +40,7 @@ namespace D3dDdi
HRESULT colorFill(D3DDDIARG_COLORFILL data);
void disableClamp();
void* getLockPtr(UINT subResourceIndex);
RECT getRect(UINT subResourceIndex) const;
HRESULT lock(D3DDDIARG_LOCK& data);
void onDestroyResource(HANDLE resource);
Resource& prepareForBltSrc(const D3DDDIARG_BLT& data);
@ -49,6 +50,7 @@ namespace D3dDdi
void prepareForCpuWrite(UINT subResourceIndex);
Resource& prepareForGpuRead(UINT subResourceIndex);
void prepareForGpuWrite(UINT subResourceIndex);
Resource& prepareForTextureRead(UINT stage);
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource* srcResource);
void scaleRect(RECT& rect);
void setAsGdiResource(bool isGdiResource);
@ -111,7 +113,6 @@ namespace D3dDdi
D3DDDIFORMAT getFormatConfig();
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> getMultisampleConfig();
const SurfaceRepository::Surface& getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height);
RECT getRect(UINT subResourceIndex);
SIZE getScaledSize();
bool isValidRect(UINT subResourceIndex, const RECT& rect);
void loadFromLockRefResource(UINT subResourceIndex);
@ -138,6 +139,8 @@ namespace D3dDdi
SurfaceRepository::Surface m_msaaSurface;
SurfaceRepository::Surface m_msaaResolvedSurface;
SurfaceRepository::Surface m_nullSurface;
SurfaceRepository::Surface m_colorKeyedSurface;
UINT m_colorKey;
D3DDDIFORMAT m_formatConfig;
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> m_multiSampleConfig;
SIZE m_scaledSize;
@ -149,5 +152,6 @@ namespace D3dDdi
bool m_isClampable;
bool m_isPrimary;
bool m_isPalettizedTextureUpToDate;
bool m_isColorKeyedSurfaceUpToDate;
};
}

View File

@ -5,12 +5,14 @@
#include <d3d9.h>
#include <Common/Log.h>
#include <D3dDdi/ShaderAssembler.h>
namespace
{
const UINT BEGIN_BLOCK = 1;
const UINT END_BLOCK = 2;
const UINT32 PARAMETER_TOKEN_RESERVED_BIT = 0x80000000;
typedef std::array<const char*, 7> Controls;
@ -50,6 +52,19 @@ namespace
UINT32 type : 16;
};
class RestorePos
{
public:
RestorePos(UINT& pos) : m_pos(pos), m_origPos(pos) { }
~RestorePos() { m_pos = m_origPos; }
private:
UINT& m_pos;
UINT m_origPos;
};
void setRegisterType(UINT32& token, D3DSHADER_PARAM_REGISTER_TYPE registerType);
std::map<UINT16, Instruction> g_instructionMap = {
{ D3DSIO_NOP, { "nop" } },
{ D3DSIO_MOV, { "mov", 1, 1 } },
@ -192,6 +207,68 @@ namespace
{ D3DDECLUSAGE_DEPTH, "depth" },
{ D3DDECLUSAGE_SAMPLE, "sample" }
};
UINT getFreeRegisterNumber(const std::set<UINT>& usedRegisterNumbers)
{
UINT prev = UINT_MAX;
for (UINT num : usedRegisterNumbers)
{
if (num > prev + 1)
{
return prev + 1;
}
}
return usedRegisterNumbers.empty() ? 0 : (*usedRegisterNumbers.rbegin() + 1);
}
D3DSHADER_PARAM_REGISTER_TYPE getRegisterType(UINT32 token)
{
return static_cast<D3DSHADER_PARAM_REGISTER_TYPE>(
((token & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) |
((token & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2));
}
UINT32 makeConstToken(FLOAT value)
{
return *reinterpret_cast<UINT32*>(&value);
}
UINT32 makeDestinationParameterToken(D3DSHADER_PARAM_REGISTER_TYPE registerType, UINT32 registerNumber,
UINT32 writeMask, UINT32 modifiers)
{
UINT32 token = PARAMETER_TOKEN_RESERVED_BIT | registerNumber | writeMask | modifiers;
setRegisterType(token, registerType);
return token;
}
UINT32 makeInstructionToken(D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode)
{
auto& inst = g_instructionMap.at(static_cast<UINT16>(opcode));
auto tokenCount = inst.dstCount + inst.srcCount + inst.extraCount;
return opcode | (tokenCount << D3DSI_INSTLENGTH_SHIFT);
}
UINT32 makeSourceParameterToken(D3DSHADER_PARAM_REGISTER_TYPE registerType, UINT32 registerNumber,
UINT32 swizzle, D3DSHADER_PARAM_SRCMOD_TYPE modifier)
{
UINT32 token = PARAMETER_TOKEN_RESERVED_BIT | registerNumber | swizzle | modifier;
setRegisterType(token, registerType);
return token;
}
UINT reserveRegisterNumber(std::set<UINT>& usedRegisterNumbers)
{
auto num = getFreeRegisterNumber(usedRegisterNumbers);
usedRegisterNumbers.insert(num);
return num;
}
void setRegisterType(UINT32& token, D3DSHADER_PARAM_REGISTER_TYPE registerType)
{
token &= ~(D3DSP_REGTYPE_MASK | D3DSP_REGTYPE_MASK2);
token |= ((registerType << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK) |
((registerType << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2);
}
}
namespace D3dDdi
@ -202,11 +279,95 @@ namespace D3dDdi
{
}
bool ShaderAssembler::addAlphaTest(UINT alphaRef)
{
LOG_FUNC("ShaderAssembler::addAlphaTest", alphaRef);
LOG_DEBUG << "Original bytecode: " << Compat::hexDump(m_tokens.data(), m_tokens.size() * 4);
LOG_DEBUG << disassemble();
RestorePos restorePos(m_pos);
m_pos = 0;
UINT constRegNum = UINT_MAX;
UINT tempRegNum = UINT_MAX;
while (nextInstruction())
{
auto instruction = getToken<InstructionToken>();
if (D3DSIO_TEX != instruction.opcode)
{
continue;
}
const auto dst = getToken<UINT32>(1);
const auto src = getToken<UINT32>(3);
const auto samplerRegNum = src & D3DSP_REGNUM_MASK;
if (UINT_MAX == constRegNum)
{
auto usedConstRegNums = getUsedRegisterNumbers(D3DSPR_CONST);
constRegNum = reserveRegisterNumber(usedConstRegNums);
if (constRegNum >= 32)
{
LOG_ONCE("ERROR: no free PS const register found");
return false;
}
auto usedTempRegNums = getUsedRegisterNumbers(D3DSPR_TEMP);
tempRegNum = reserveRegisterNumber(usedTempRegNums);
if (tempRegNum >= 32)
{
LOG_ONCE("ERROR: no free PS temp register found");
return false;
}
}
nextInstruction();
insertToken(makeInstructionToken(D3DSIO_IF));
insertToken(makeSourceParameterToken(D3DSPR_CONSTBOOL, samplerRegNum, D3DSP_NOSWIZZLE, D3DSPSM_NONE));
insertToken(makeInstructionToken(D3DSIO_SUB));
insertToken(makeDestinationParameterToken(D3DSPR_TEMP, tempRegNum, D3DSP_WRITEMASK_ALL, D3DSPDM_NONE));
insertToken(makeSourceParameterToken(D3DSPR_TEMP, dst & D3DSP_REGNUM_MASK, D3DSP_REPLICATEALPHA, D3DSPSM_NONE));
insertToken(makeSourceParameterToken(D3DSPR_CONST, constRegNum, D3DSP_REPLICATEALPHA, D3DSPSM_NONE));
insertToken(makeInstructionToken(D3DSIO_TEXKILL));
insertToken(makeDestinationParameterToken(D3DSPR_TEMP, tempRegNum, D3DSP_WRITEMASK_ALL, D3DSPDM_NONE));
insertToken(makeInstructionToken(D3DSIO_ENDIF));
--m_pos;
}
if (UINT_MAX == constRegNum)
{
LOG_DEBUG << "No modifications needed";
return false;
}
m_pos = 0;
nextInstruction();
insertToken(makeInstructionToken(D3DSIO_DEF));
insertToken(makeDestinationParameterToken(D3DSPR_CONST, constRegNum, D3DSP_WRITEMASK_ALL, D3DSPSM_NONE));
for (UINT i = 0; i < 3; ++i)
{
insertToken(makeConstToken(0));
}
insertToken(makeConstToken(alphaRef / 255.0f));
LOG_DEBUG << "Modified bytecode: " << Compat::hexDump(m_tokens.data(), m_tokens.size() * 4);
LOG_DEBUG << disassemble();
return true;
}
std::string ShaderAssembler::disassemble()
{
auto origPos = m_pos;
m_pos = 0;
if (Config::Settings::LogLevel::DEBUG != Compat::Log::getLogLevel())
{
return {};
}
RestorePos restorePos(m_pos);
m_pos = 0;
std::ostringstream os;
os << "Disassembled shader code:" << std::endl;
@ -228,7 +389,6 @@ namespace D3dDdi
os << e.what();
}
m_pos = origPos;
return os.str();
}
@ -419,9 +579,7 @@ namespace D3dDdi
void ShaderAssembler::disassembleRegister(std::ostream& os, UINT token)
{
auto registerType = static_cast<D3DSHADER_PARAM_REGISTER_TYPE>(
((token & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) |
((token & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2));
auto registerType = getRegisterType(token);
auto registerNumber = token & D3DSP_REGNUM_MASK;
auto it = g_registerMap.find(registerType);
@ -538,6 +696,66 @@ namespace D3dDdi
return static_cast<ShaderType>(m_tokens.front() >> 16);
}
template <typename Token>
Token ShaderAssembler::getToken(UINT offset) const
{
auto pos = m_pos + offset;
return pos < m_tokens.size() ? *reinterpret_cast<const Token*>(&m_tokens[pos]) : Token{};
}
std::set<UINT> ShaderAssembler::getUsedRegisterNumbers(int registerType)
{
RestorePos restorePos(m_pos);
m_pos = 0;
std::set<UINT> usedRegisterNumbers;
while (nextInstruction())
{
auto it = g_instructionMap.find(getToken<InstructionToken>().opcode);
if (it == g_instructionMap.end())
{
continue;
}
const UINT offset = D3DSIO_DCL == it->first ? 2 : 1;
const auto tokenCount = it->second.dstCount + it->second.srcCount;
for (UINT i = 0; i < tokenCount; ++i)
{
auto token = getToken<UINT32>(offset + i);
if (registerType == getRegisterType(token))
{
usedRegisterNumbers.insert(token & D3DSP_REGNUM_MASK);
}
}
}
return usedRegisterNumbers;
}
void ShaderAssembler::insertToken(UINT32 token)
{
m_tokens.insert(m_tokens.begin() + m_pos, token);
++m_pos;
}
bool ShaderAssembler::nextInstruction()
{
if (0 == m_pos)
{
m_pos = 1;
}
else
{
auto token = readToken<InstructionToken>();
readTokens(token.tokenCount);
}
while (D3DSIO_COMMENT == getToken<InstructionToken>().opcode)
{
auto token = readToken<CommentToken>();
readTokens(token.tokenCount);
}
return m_pos < m_tokens.size() && D3DSIO_END != getToken<InstructionToken>().opcode;
}
UINT ShaderAssembler::readToken()
{
return *readTokens(1);

View File

@ -1,6 +1,7 @@
#pragma once
#include <ostream>
#include <set>
#include <string>
#include <vector>
@ -13,7 +14,9 @@ namespace D3dDdi
public:
ShaderAssembler(const UINT* code, DWORD size);
bool addAlphaTest(UINT alphaRef);
std::string disassemble();
const std::vector<UINT>& getTokens() const { return m_tokens; }
private:
enum ShaderType
@ -33,10 +36,15 @@ namespace D3dDdi
void disassembleSourceSwizzle(std::ostream& os, UINT token);
void disassembleVersion(std::ostream& os);
UINT getRemainingTokenCount() const;
std::set<UINT> getUsedRegisterNumbers(int registerType);
ShaderType getShaderType() const;
void insertToken(UINT32 token);
bool nextInstruction();
UINT readToken();
const UINT* readTokens(UINT count);
template <typename Token>
Token getToken(UINT offset = 0) const;
template <typename Token>
Token readToken();

View File

@ -7,6 +7,7 @@
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Shaders/ColorKey.h>
#include <Shaders/ColorKeyBlend.h>
#include <Shaders/DepthBlt.h>
#include <Shaders/DrawCursor.h>
#include <Shaders/Gamma.h>
@ -55,6 +56,7 @@ namespace D3dDdi
ShaderBlitter::ShaderBlitter(Device& device)
: m_device(device)
, m_psColorKey(createPixelShader(g_psColorKey))
, m_psColorKeyBlend(createPixelShader(g_psColorKeyBlend))
, m_psDepthBlt(createPixelShader(g_psDepthBlt))
, m_psDrawCursor(createPixelShader(g_psDrawCursor))
, m_psGamma(createPixelShader(g_psGamma))
@ -164,6 +166,15 @@ namespace D3dDdi
m_device.flushPrimitives();
}
void ShaderBlitter::colorKeyBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, UINT srcSubResourceIndex, DeviceState::ShaderConstF srcColorKey)
{
DeviceState::TempPixelShaderConst psConst(m_device.getState(), { 31, 1 }, &srcColorKey);
blt(dstResource, dstSubResourceIndex, dstResource.getRect(dstSubResourceIndex),
srcResource, srcSubResourceIndex, srcResource.getRect(srcSubResourceIndex),
m_psColorKeyBlend.get(), D3DTEXF_POINT);
}
std::unique_ptr<void, ResourceDeleter> ShaderBlitter::createPixelShader(const BYTE* code, UINT size)
{
D3DDDIARG_CREATEPIXELSHADER data = {};

View File

@ -24,6 +24,8 @@ namespace D3dDdi
ShaderBlitter& operator=(const ShaderBlitter&) = delete;
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
void colorKeyBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, UINT srcSubResourceIndex, DeviceState::ShaderConstF srcColorKey);
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
HCURSOR cursor, POINT pt);
void depthBlt(const Resource& dstResource, const RECT& dstRect,
@ -75,6 +77,7 @@ namespace D3dDdi
Device& m_device;
std::unique_ptr<void, ResourceDeleter> m_psColorKey;
std::unique_ptr<void, ResourceDeleter> m_psColorKeyBlend;
std::unique_ptr<void, ResourceDeleter> m_psDepthBlt;
std::unique_ptr<void, ResourceDeleter> m_psDrawCursor;
std::unique_ptr<void, ResourceDeleter> m_psGamma;

View File

@ -30,7 +30,7 @@ namespace D3dDdi
}
CompatPtr<IDirectDrawSurface7> SurfaceRepository::createSurface(
DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, UINT surfaceCount)
DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps, DWORD caps2, UINT surfaceCount)
{
if (!m_dd)
{
@ -53,7 +53,21 @@ namespace D3dDdi
desc.dwHeight = height;
desc.ddpfPixelFormat = getPixelFormat(format);
desc.ddsCaps.dwCaps = caps;
if (surfaceCount > 1)
desc.ddsCaps.dwCaps2 = caps2;
if (caps2 & DDSCAPS2_CUBEMAP)
{
desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
surfaceCount /= 6;
}
if (caps & DDSCAPS_MIPMAP)
{
desc.dwFlags |= DDSD_MIPMAPCOUNT;
desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
desc.dwMipMapCount = surfaceCount;
}
else if (surfaceCount > 1)
{
desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
@ -221,7 +235,7 @@ namespace D3dDdi
}
SurfaceRepository::Surface& SurfaceRepository::getSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount)
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount, DWORD caps2)
{
if (!g_enableSurfaceCheck)
{
@ -235,7 +249,7 @@ namespace D3dDdi
if (!surface.surface)
{
surface.surface = createSurface(width, height, format, caps, surfaceCount);
surface.surface = createSurface(width, height, format, caps, caps2, surfaceCount);
if (surface.surface)
{
surface.resource = D3dDdi::Device::findResource(

View File

@ -42,7 +42,7 @@ namespace D3dDdi
Resource* getPaletteTexture();
Resource* getGammaRampTexture();
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1);
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount = 1, DWORD caps2 = 0);
const Surface& getTempRenderTarget(DWORD width, DWORD height, UINT index = 0);
Surface& getTempSysMemSurface(DWORD width, DWORD height);
Surface& getTempSurface(Surface& surface, DWORD width, DWORD height,
@ -57,7 +57,7 @@ namespace D3dDdi
private:
CompatPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height,
D3DDDIFORMAT format, DWORD caps, UINT surfaceCount);
D3DDDIFORMAT format, DWORD caps, DWORD caps2, UINT surfaceCount);
bool getCursorImage(Surface& surface, HCURSOR cursor, DWORD width, DWORD height, UINT flags);
Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, D3DDDIFORMAT format, DWORD caps,
std::function<void(const DDSURFACEDESC2&)> initFunc);

View File

@ -165,6 +165,7 @@
<ClInclude Include="Config\Settings\AltTabFix.h" />
<ClInclude Include="Config\Settings\Antialiasing.h" />
<ClInclude Include="Config\Settings\BltFilter.h" />
<ClInclude Include="Config\Settings\ColorKeyMethod.h" />
<ClInclude Include="Config\Settings\ConfigHotKey.h" />
<ClInclude Include="Config\Settings\CpuAffinity.h" />
<ClInclude Include="Config\Settings\CpuAffinityRotation.h" />
@ -333,6 +334,7 @@
<ClCompile Include="Config\Parser.cpp" />
<ClCompile Include="Config\Setting.cpp" />
<ClCompile Include="Config\Settings\Antialiasing.cpp" />
<ClCompile Include="Config\Settings\ColorKeyMethod.cpp" />
<ClCompile Include="Config\Settings\CpuAffinity.cpp" />
<ClCompile Include="Config\Settings\DesktopResolution.cpp" />
<ClCompile Include="Config\Settings\DisplayAspectRatio.cpp" />
@ -457,12 +459,9 @@
<None Include="genversion.ps1" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\ColorKey.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
</FxCompile>
<FxCompile Include="Shaders\DepthBlt.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
</FxCompile>
<FxCompile Include="Shaders\ColorKey.hlsl" />
<FxCompile Include="Shaders\ColorKeyBlend.hlsl" />
<FxCompile Include="Shaders\DepthBlt.hlsl" />
<FxCompile Include="Shaders\DrawCursor.hlsl" />
<FxCompile Include="Shaders\Gamma.hlsl" />
<FxCompile Include="Shaders\GenBilinear.hlsl" />

View File

@ -663,6 +663,9 @@
<ClInclude Include="D3dDdi\ShaderAssembler.h">
<Filter>Header Files\D3dDdi</Filter>
</ClInclude>
<ClInclude Include="Config\Settings\ColorKeyMethod.h">
<Filter>Header Files\Config\Settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -1049,7 +1052,10 @@
<ClCompile Include="D3dDdi\ShaderAssembler.cpp">
<Filter>Source Files\D3dDdi</Filter>
</ClCompile>
</ItemGroup>
<ClCompile Include="Config\Settings\ColorKeyMethod.cpp">
<Filter>Source Files\Config\Settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DDrawCompat.rc">
<Filter>Resource Files</Filter>
@ -1088,10 +1094,13 @@
<FxCompile Include="Shaders\DepthBlt.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\ColorKeyBlend.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<Image Include="arrow.bmp">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>
</Project>

View File

@ -5,6 +5,7 @@
#include <Config/Settings/AlternatePixelCenter.h>
#include <Config/Settings/Antialiasing.h>
#include <Config/Settings/BltFilter.h>
#include <Config/Settings/ColorKeyMethod.h>
#include <Config/Settings/ConfigHotKey.h>
#include <Config/Settings/DepthFormat.h>
#include <Config/Settings/DisplayFilter.h>
@ -31,7 +32,7 @@ namespace
namespace Overlay
{
ConfigWindow::ConfigWindow()
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 455 }, WS_BORDER, Config::configHotKey.get())
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 480 }, WS_BORDER, Config::configHotKey.get())
, m_buttonCount(0)
, m_focus(nullptr)
{
@ -44,6 +45,7 @@ namespace Overlay
addControl(Config::alternatePixelCenter);
addControl(Config::antialiasing);
addControl(Config::bltFilter);
addControl(Config::colorKeyMethod);
addControl(Config::depthFormat);
addControl(Config::displayFilter);
addControl(Config::fontAntialiasing);

View File

@ -1,4 +1,5 @@
#include <Config/Settings/Antialiasing.h>
#include <Config/Settings/ColorKeyMethod.h>
#include <Config/Settings/DepthFormat.h>
#include <Config/Settings/RenderColorDepth.h>
#include <Config/Settings/ResolutionScale.h>
@ -83,6 +84,7 @@ namespace Overlay
}
if (&Config::antialiasing == &m_setting ||
&Config::colorKeyMethod == &m_setting ||
&Config::depthFormat == &m_setting ||
&Config::renderColorDepth == &m_setting ||
&Config::resolutionScale == &m_setting ||

View File

@ -0,0 +1,13 @@
sampler2D s_texture : register(s0);
float4 g_colorKey : register(c31);
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
float4 color = tex2D(s_texture, texCoord);
float4 diff = abs(color - g_colorKey);
if (all(diff.rgb < 0.5f / 255))
{
color.a = 0;
}
return color;
}