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

Support gamma ramps in borderless fullscreen mode

This commit is contained in:
narzoul 2022-04-18 21:23:08 +02:00
parent 9813e8b1b7
commit 31444c364a
15 changed files with 228 additions and 30 deletions

View File

@ -28,6 +28,7 @@ namespace
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
Compat::SrwLock g_adapterInfoSrwLock;
std::string g_lastDDrawDeviceName;
bool g_isExclusiveFullscreen = false;
decltype(&D3DKMTSubmitPresentBltToHwQueue) g_origSubmitPresentBltToHwQueue = nullptr;
decltype(&D3DKMTSubmitPresentToHwQueue) g_origSubmitPresentToHwQueue = nullptr;
@ -249,13 +250,34 @@ namespace
return LOG_RESULT(result);
}
NTSTATUS APIENTRY releaseProcessVidPnSourceOwners(HANDLE hProcess)
{
LOG_FUNC("D3DKMTReleaseProcessVidPnSourceOwners", hProcess);
NTSTATUS result = D3DKMTReleaseProcessVidPnSourceOwners(hProcess);
if (SUCCEEDED(result))
{
g_isExclusiveFullscreen = false;
}
return LOG_RESULT(result);
}
NTSTATUS APIENTRY setGammaRamp(const D3DKMT_SETGAMMARAMP* pData)
{
LOG_FUNC("D3DKMTSetGammaRamp", pData);
NTSTATUS result = 0;
UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter();
DDraw::RealPrimarySurface::setUpdateReady();
DDraw::RealPrimarySurface::flush();
HRESULT result = D3DKMTSetGammaRamp(pData);
if (g_isExclusiveFullscreen || D3DDDI_GAMMARAMP_RGB256x3x16 != pData->Type || !pData->pGammaRampRgb256x3x16)
{
D3dDdi::ShaderBlitter::resetGammaRamp();
result = D3DKMTSetGammaRamp(pData);
}
else
{
D3dDdi::ShaderBlitter::setGammaRamp(*pData->pGammaRampRgb256x3x16);
DDraw::RealPrimarySurface::scheduleUpdate();
}
if (SUCCEEDED(result))
{
D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCounter + 1);
@ -263,6 +285,17 @@ namespace
return LOG_RESULT(result);
}
NTSTATUS APIENTRY setVidPnSourceOwner(const D3DKMT_SETVIDPNSOURCEOWNER* pData)
{
LOG_FUNC("D3DKMTSetVidPnSourceOwner", pData);
NTSTATUS result = D3DKMTSetVidPnSourceOwner(pData);
if (SUCCEEDED(result))
{
g_isExclusiveFullscreen = 0 != pData->VidPnSourceCount;
}
return LOG_RESULT(result);
}
NTSTATUS APIENTRY submitPresentToHwQueue(D3DKMT_SUBMITPRESENTTOHWQUEUE* pData)
{
LOG_FUNC("D3DKMTSubmitPresentToHwQueue", pData);
@ -412,7 +445,9 @@ namespace D3dDdi
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTPresent", present);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTReleaseProcessVidPnSourceOwners", releaseProcessVidPnSourceOwners);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetGammaRamp", setGammaRamp);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetVidPnSourceOwner", setVidPnSourceOwner);
Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSubmitPresentToHwQueue", submitPresentToHwQueue);
Dll::createThread(&vsyncThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);

View File

@ -10,6 +10,14 @@ std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data)
<< Compat::hex(data.Value);
}
std::ostream& operator<<(std::ostream& os, const D3DDDI_GAMMA_RAMP_RGB256x3x16& data)
{
return Compat::LogStruct(os)
<< Compat::array(data.Red, 256)
<< Compat::array(data.Green, 256)
<< Compat::array(data.Blue, 256);
}
std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data)
{
return Compat::LogStruct(os)

View File

@ -6,6 +6,7 @@
#include <d3dumddi.h>
std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data);
std::ostream& operator<<(std::ostream& os, const D3DDDI_GAMMA_RAMP_RGB256x3x16& data);
std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data);
std::ostream& operator<<(std::ostream& os, const D3DDDI_RATIONAL& val);
std::ostream& operator<<(std::ostream& os, D3DDDIFORMAT val);

View File

@ -135,7 +135,7 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_SETGAMMARAMP& data)
<< Compat::hex(data.hDevice)
<< data.VidPnSourceId
<< data.Type
<< static_cast<const void*>(data.pGammaRampRgb256x3x16)
<< data.pGammaRampRgb256x3x16
<< data.Size;
}

View File

@ -465,20 +465,15 @@ namespace D3dDdi
return false;
}
auto& repo = SurfaceRepository::get(m_device.getAdapter());
auto newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 1);
if (newRt->resource == rt)
{
newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 0);
}
if (!newRt->resource)
auto& nextRt = getNextRenderTarget(rt, newSrcWidth, newSrcHeight);
if (!nextRt.resource)
{
return false;
}
m_device.getShaderBlitter().textureBlt(*newRt->resource, 0, { 0, 0, newSrcWidth, newSrcHeight },
m_device.getShaderBlitter().textureBlt(*nextRt.resource, 0, { 0, 0, newSrcWidth, newSrcHeight },
*rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR);
rt = newRt->resource;
rt = nextRt.resource;
srcWidth = newSrcWidth;
srcHeight = newSrcHeight;
return true;
@ -531,11 +526,6 @@ namespace D3dDdi
}
}
void* Resource::getLockPtr(UINT subResourceIndex)
{
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
}
D3DDDIFORMAT Resource::getFormatConfig()
{
if (m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.MatchGdiPrimary && D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool &&
@ -550,6 +540,11 @@ namespace D3dDdi
return m_fixedData.Format;
}
void* Resource::getLockPtr(UINT subResourceIndex)
{
return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data;
}
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> Resource::getMultisampleConfig()
{
if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.MatchGdiPrimary ||
@ -561,6 +556,17 @@ namespace D3dDdi
return { D3DDDIMULTISAMPLE_NONE, 0 };
}
const SurfaceRepository::Surface& Resource::getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height)
{
auto& repo = SurfaceRepository::get(m_device.getAdapter());
auto nextRt = &repo.getTempRenderTarget(width, height, 1);
if (nextRt->resource == currentRt)
{
nextRt = &repo.getTempRenderTarget(width, height, 0);
}
return *nextRt;
}
RECT Resource::getRect(UINT subResourceIndex)
{
const auto& si = m_fixedData.pSurfList[subResourceIndex];
@ -873,23 +879,46 @@ namespace D3dDdi
return S_OK;
}
if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get())
const LONG dstWidth = data.DstRect.right - data.DstRect.left;
const LONG dstHeight = data.DstRect.bottom - data.DstRect.top;
while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight))
{
const LONG dstWidth = data.DstRect.right - data.DstRect.left;
const LONG dstHeight = data.DstRect.bottom - data.DstRect.top;
while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight))
{
}
m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, data.DstRect,
*rt, data.SrcRect, Config::displayFilter.getParam());
return S_OK;
}
data.hSrcResource = *rt;
data.SrcSubResourceIndex = 0;
data.Flags.Point = 1;
return m_device.getOrigVtable().pfnBlt(m_device, &data);
const SurfaceRepository::Surface* rtGamma = nullptr;
if (!ShaderBlitter::isGammaRampDefault() &&
SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture())
{
rtGamma = &getNextRenderTarget(rt, dstWidth, dstHeight);
}
const bool useGamma = rtGamma && rtGamma->resource;
auto& rtNext = useGamma ? *rtGamma->resource : *this;
auto rtNextIndex = useGamma ? 0 : data.DstSubResourceIndex;
auto rtNextRect = useGamma ? RECT{ 0, 0, dstWidth, dstHeight } : data.DstRect;
if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get())
{
m_device.getShaderBlitter().genBilinearBlt(rtNext, rtNextIndex, rtNextRect,
*rt, data.SrcRect, Config::displayFilter.getParam());
}
else
{
D3DDDIARG_BLT blt = {};
blt.hSrcResource = *rt;
blt.SrcSubResourceIndex = 0;
blt.SrcRect = data.SrcRect;
blt.hDstResource = rtNext;
blt.DstSubResourceIndex = rtNextIndex;
blt.DstRect = rtNextRect;
blt.Flags.Point = 1;
m_device.getOrigVtable().pfnBlt(m_device, &blt);
}
if (useGamma)
{
m_device.getShaderBlitter().gammaBlt(*this, data.DstSubResourceIndex, data.DstRect, rtNext, rtNextRect);
}
return S_OK;
}
void Resource::presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect)

View File

@ -90,6 +90,7 @@ namespace D3dDdi
void fixResourceData();
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);

View File

@ -7,6 +7,7 @@
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Shaders/DrawCursor.h>
#include <Shaders/Gamma.h>
#include <Shaders/GenBilinear.h>
#include <Shaders/PaletteLookup.h>
#include <Shaders/TextureSampler.h>
@ -15,11 +16,27 @@
#define CONCAT(a, b) CONCAT_(a, b)
#define SCOPED_STATE(state, ...) DeviceState::Scoped##state CONCAT(scopedState, __LINE__)(m_device.getState(), __VA_ARGS__)
namespace
{
D3DDDI_GAMMA_RAMP_RGB256x3x16 g_gammaRamp;
bool g_isGammaRampDefault = true;
bool g_isGammaRampInvalidated = false;
void setGammaValues(BYTE* ptr, USHORT* ramp)
{
for (UINT i = 0; i < 256; ++i)
{
ptr[i] = static_cast<BYTE>(ramp[i] * 0xFF / 0xFFFF);
}
}
}
namespace D3dDdi
{
ShaderBlitter::ShaderBlitter(Device& device)
: m_device(device)
, m_psDrawCursor(createPixelShader(g_psDrawCursor))
, m_psGamma(createPixelShader(g_psGamma))
, m_psGenBilinear(createPixelShader(g_psGenBilinear))
, m_psPaletteLookup(createPixelShader(g_psPaletteLookup))
, m_psTextureSampler(createPixelShader(g_psTextureSampler))
@ -206,9 +223,49 @@ namespace D3dDdi
m_device.pfnDrawPrimitive(&dp, nullptr);
}
void ShaderBlitter::gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect)
{
LOG_FUNC("ShaderBlitter::gammaBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcRect);
auto gammaRampTexture(SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture());
if (!gammaRampTexture)
{
return;
}
if (g_isGammaRampInvalidated)
{
D3DDDIARG_LOCK lock = {};
lock.hResource = *gammaRampTexture;
lock.Flags.Discard = 1;
m_device.getOrigVtable().pfnLock(m_device, &lock);
if (!lock.pSurfData)
{
return;
}
auto ptr = static_cast<BYTE*>(lock.pSurfData);
setGammaValues(ptr, g_gammaRamp.Red);
setGammaValues(ptr + lock.Pitch, g_gammaRamp.Green);
setGammaValues(ptr + 2 * lock.Pitch, g_gammaRamp.Blue);
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = *gammaRampTexture;
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
g_isGammaRampInvalidated = false;
}
setTempTextureStage(1, *gammaRampTexture, D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGamma.get(), D3DTEXF_POINT);
}
void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, UINT blurPercent)
{
LOG_FUNC("ShaderBlitter::genBilinearBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcRect, blurPercent);
if (100 == blurPercent)
{
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect,
@ -233,6 +290,11 @@ namespace D3dDdi
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR);
}
bool ShaderBlitter::isGammaRampDefault()
{
return g_isGammaRampDefault;
}
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect, RGBQUAD palette[256])
{
@ -264,6 +326,24 @@ namespace D3dDdi
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT);
}
void ShaderBlitter::resetGammaRamp()
{
g_isGammaRampDefault = true;
g_isGammaRampInvalidated = false;
}
void ShaderBlitter::setGammaRamp(const D3DDDI_GAMMA_RAMP_RGB256x3x16& ramp)
{
g_gammaRamp = ramp;
g_isGammaRampDefault = true;
for (WORD i = 0; i < 256 && g_isGammaRampDefault; ++i)
{
const WORD defaultRamp = i * 0xFFFF / 0xFF;
g_isGammaRampDefault = defaultRamp == ramp.Red[i] && defaultRamp == ramp.Green[i] && defaultRamp == ramp.Blue[i];
}
g_isGammaRampInvalidated = !g_isGammaRampDefault;
}
void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey)
{
auto& state = m_device.getState();

View File

@ -25,6 +25,8 @@ namespace D3dDdi
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
HCURSOR cursor, POINT pt);
void gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, const RECT& srcRect);
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 RECT& dstRect,
@ -34,6 +36,10 @@ namespace D3dDdi
UINT filter, const UINT* srcColorKey = nullptr, const BYTE* alpha = nullptr,
const Gdi::Region& srcRgn = nullptr);
static bool isGammaRampDefault();
static void resetGammaRamp();
static void setGammaRamp(const D3DDDI_GAMMA_RAMP_RGB256x3x16& ramp);
private:
struct Vertex
{
@ -63,6 +69,7 @@ namespace D3dDdi
Device& m_device;
std::unique_ptr<void, ResourceDeleter> m_psDrawCursor;
std::unique_ptr<void, ResourceDeleter> m_psGamma;
std::unique_ptr<void, ResourceDeleter> m_psGenBilinear;
std::unique_ptr<void, ResourceDeleter> m_psPaletteLookup;
std::unique_ptr<void, ResourceDeleter> m_psTextureSampler;

View File

@ -169,6 +169,16 @@ namespace D3dDdi
return result;
}
Resource* SurfaceRepository::getGammaRampTexture()
{
DDPIXELFORMAT pf = {};
pf.dwSize = sizeof(pf);
pf.dwFlags = DDPF_LUMINANCE;
pf.dwLuminanceBitCount = 8;
pf.dwLuminanceBitMask = 0xFF;
return getSurface(m_gammaRampTexture, 256, 3, pf, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource;
}
Resource* SurfaceRepository::getLogicalXorTexture()
{
return getInitializedResource(m_logicalXorTexture, 256, 256, DDraw::DirectDraw::getRgbPixelFormat(8),

View File

@ -38,6 +38,7 @@ namespace D3dDdi
Cursor getCursor(HCURSOR cursor);
Resource* getLogicalXorTexture();
Resource* getPaletteTexture();
Resource* getGammaRampTexture();
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1);
const Surface& getTempRenderTarget(DWORD width, DWORD height, UINT index = 0);
@ -67,6 +68,7 @@ namespace D3dDdi
Surface m_cursorMaskTexture;
Surface m_cursorColorTexture;
Surface m_cursorTempTexture;
Surface m_gammaRampTexture;
Surface m_logicalXorTexture;
Surface m_paletteTexture;
std::vector<Surface> m_renderTargets;

View File

@ -25,6 +25,14 @@ std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck)
<< Compat::hex(ck.dwColorSpaceHighValue);
}
std::ostream& operator<<(std::ostream& os, const DDGAMMARAMP& ramp)
{
return Compat::LogStruct(os)
<< Compat::array(ramp.red, 256)
<< Compat::array(ramp.green, 256)
<< Compat::array(ramp.blue, 256);
}
std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps)
{
return Compat::LogStruct(os)

View File

@ -6,6 +6,7 @@
std::ostream& operator<<(std::ostream& os, const DDBLTFX& fx);
std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck);
std::ostream& operator<<(std::ostream& os, const DDGAMMARAMP& ramp);
std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps);
std::ostream& operator<<(std::ostream& os, const DDSCAPS2& caps);
std::ostream& operator<<(std::ostream& os, const DDPIXELFORMAT& pf);

View File

@ -455,6 +455,7 @@
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\DrawCursor.hlsl" />
<FxCompile Include="Shaders\Gamma.hlsl" />
<FxCompile Include="Shaders\GenBilinear.hlsl" />
<FxCompile Include="Shaders\PaletteLookup.hlsl" />
<FxCompile Include="Shaders\TextureSampler.hlsl" />

View File

@ -890,6 +890,9 @@
<FxCompile Include="Shaders\VertexFixup.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\Gamma.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<Image Include="arrow.bmp">

View File

@ -0,0 +1,12 @@
sampler2D s_texture : register(s0);
sampler2D s_gammaRamp : register(s1);
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
const float4 color = tex2D(s_texture, texCoord);
return float4(
tex2D(s_gammaRamp, float2(color.r, 0.0f)).r,
tex2D(s_gammaRamp, float2(color.g, 0.5f)).r,
tex2D(s_gammaRamp, float2(color.b, 1.0f)).r,
0);
}