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

Emulate unsupported render target formats

Fixes Midtown Madness 2 rendering on NVIDIA. See issue #159.
This commit is contained in:
narzoul 2022-12-23 23:25:05 +01:00
parent b53678bfd4
commit 12c4f87cb6
6 changed files with 66 additions and 15 deletions

View File

@ -266,6 +266,26 @@ namespace D3dDdi
return supportedZBufferBitDepths; return supportedZBufferBitDepths;
} }
bool Adapter::isEmulatedRenderTargetFormat(D3DDDIFORMAT format)
{
const auto& fi = getFormatInfo(format);
if (0 == fi.red.bitCount)
{
return false;
}
const auto& formatOps = getInfo().formatOps;
auto it = formatOps.find(format);
if (it == formatOps.end() || (it->second.Operations & FORMATOP_OFFSCREEN_RENDERTARGET))
{
return false;
}
auto replacementFormat = 0 != fi.alpha.bitCount ? D3DDDIFMT_A8R8G8B8 : D3DDDIFMT_X8R8G8B8;
it = formatOps.find(replacementFormat);
return it != formatOps.end() && (it->second.Operations & FORMATOP_OFFSCREEN_RENDERTARGET);
}
HRESULT Adapter::pfnCloseAdapter() HRESULT Adapter::pfnCloseAdapter()
{ {
auto adapter = m_adapter; auto adapter = m_adapter;
@ -325,10 +345,16 @@ namespace D3dDdi
auto formatOp = static_cast<FORMATOP*>(pData->pData); auto formatOp = static_cast<FORMATOP*>(pData->pData);
for (UINT i = 0; i < count; ++i) for (UINT i = 0; i < count; ++i)
{ {
if (isEmulatedRenderTargetFormat(formatOp[i].Format))
{
formatOp[i].Operations |= FORMATOP_OFFSCREEN_RENDERTARGET;
}
if (D3DDDIFMT_P8 == formatOp[i].Format && Config::palettizedTextures.get()) if (D3DDDIFMT_P8 == formatOp[i].Format && Config::palettizedTextures.get())
{ {
formatOp[i].Operations |= FORMATOP_TEXTURE | FORMATOP_CUBETEXTURE; formatOp[i].Operations |= FORMATOP_TEXTURE | FORMATOP_CUBETEXTURE;
} }
if (D3DDDIFMT_D24X4S4 == formatOp[i].Format || D3DDDIFMT_X4S4D24 == formatOp[i].Format) if (D3DDDIFMT_D24X4S4 == formatOp[i].Format || D3DDDIFMT_X4S4D24 == formatOp[i].Format)
{ {
// If these formats are reported as depth buffers, then EnumZBufferFormats returns only D16 // If these formats are reported as depth buffers, then EnumZBufferFormats returns only D16

View File

@ -40,6 +40,7 @@ namespace D3dDdi
const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; } const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; } CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository; }
SIZE getScaledSize(Int2 size) const; SIZE getScaledSize(Int2 size) const;
bool isEmulatedRenderTargetFormat(D3DDDIFORMAT format);
HRESULT pfnCloseAdapter(); HRESULT pfnCloseAdapter();
HRESULT pfnCreateDevice(D3DDDIARG_CREATEDEVICE* pCreateData); HRESULT pfnCreateDevice(D3DDDIARG_CREATEDEVICE* pCreateData);

View File

@ -587,7 +587,7 @@ namespace D3dDdi
void DeviceState::prepareTextures() void DeviceState::prepareTextures()
{ {
for (UINT stage = 0; stage < m_app.textures.size(); ++stage) for (UINT stage = 0; stage < getVertexDecl().textureStageCount; ++stage)
{ {
auto resource = getTextureResource(stage); auto resource = getTextureResource(stage);
if (resource) if (resource)
@ -1045,7 +1045,13 @@ namespace D3dDdi
{ {
for (UINT stage = 0; stage <= m_maxChangedTextureStage; ++stage) for (UINT stage = 0; stage <= m_maxChangedTextureStage; ++stage)
{ {
if (setTexture(stage, m_app.textures[stage]) || auto resource = getTextureResource(stage);
if (resource)
{
resource = &resource->prepareForGpuRead(0);
}
if (setTexture(stage, resource ? *resource : m_app.textures[stage]) ||
m_changedTextureStageStates[stage].test(D3DDDITSS_DISABLETEXTURECOLORKEY) || m_changedTextureStageStates[stage].test(D3DDDITSS_DISABLETEXTURECOLORKEY) ||
m_changedTextureStageStates[stage].test(D3DDDITSS_TEXTURECOLORKEYVAL)) m_changedTextureStageStates[stage].test(D3DDDITSS_TEXTURECOLORKEYVAL))
{ {

View File

@ -35,6 +35,7 @@ namespace
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
RECT g_presentationRect = {}; RECT g_presentationRect = {};
bool g_enableConfig = true;
D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN; D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN;
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> g_msaaOverride = {}; std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> g_msaaOverride = {};
@ -128,7 +129,7 @@ namespace D3dDdi
, m_paletteHandle(0) , m_paletteHandle(0)
, m_paletteColorKeyIndex(-1) , m_paletteColorKeyIndex(-1)
, m_isOversized(false) , m_isOversized(false)
, m_isSurfaceRepoResource(SurfaceRepository::inCreateSurface()) , m_isSurfaceRepoResource(SurfaceRepository::inCreateSurface() || !g_enableConfig)
, m_isClampable(true) , m_isClampable(true)
, m_isPrimary(false) , m_isPrimary(false)
, m_isPalettizedTextureUpToDate(false) , m_isPalettizedTextureUpToDate(false)
@ -404,7 +405,7 @@ namespace D3dDdi
if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && if (D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool &&
(m_fixedData.Flags.ZBuffer && &dstRes == m_msaaSurface.resource && m_nullSurface.resource || (m_fixedData.Flags.ZBuffer && &dstRes == m_msaaSurface.resource && m_nullSurface.resource ||
m_fixedData.Flags.RenderTarget || dstRes.m_fixedData.Flags.RenderTarget ||
!m_fixedData.Flags.ZBuffer && ( !m_fixedData.Flags.ZBuffer && (
data.Flags.SrcColorKey || data.Flags.SrcColorKey ||
data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown || data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown ||
@ -583,10 +584,12 @@ namespace D3dDdi
D3DDDI_RESOURCEFLAGS flags = {}; D3DDDI_RESOURCEFLAGS flags = {};
flags.Value = g_resourceTypeFlags; flags.Value = g_resourceTypeFlags;
flags.RenderTarget = 0; flags.RenderTarget = 0;
flags.Texture = 0;
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool ||
m_isSurfaceRepoResource || m_isSurfaceRepoResource ||
0 == m_formatInfo.bytesPerPixel || 0 == m_formatInfo.bytesPerPixel ||
0 != (m_fixedData.Flags.Value & flags.Value)) 0 != (m_fixedData.Flags.Value & flags.Value) ||
m_fixedData.Flags.Texture && !m_origData.Flags.RenderTarget)
{ {
return; return;
} }
@ -683,6 +686,11 @@ namespace D3dDdi
} }
} }
void Resource::enableConfig(bool enable)
{
g_enableConfig = enable;
}
void Resource::fixResourceData() void Resource::fixResourceData()
{ {
if (m_fixedData.Flags.MatchGdiPrimary) if (m_fixedData.Flags.MatchGdiPrimary)
@ -698,8 +706,7 @@ namespace D3dDdi
} }
m_fixedData.Format = D3DDDIFMT_X8R8G8B8; m_fixedData.Format = D3DDDIFMT_X8R8G8B8;
} }
else if (D3DDDIFMT_UNKNOWN != g_formatOverride)
if (D3DDDIFMT_UNKNOWN != g_formatOverride)
{ {
m_fixedData.Format = g_formatOverride; m_fixedData.Format = g_formatOverride;
if (FOURCC_INTZ == g_formatOverride) if (FOURCC_INTZ == g_formatOverride)
@ -707,6 +714,10 @@ namespace D3dDdi
m_fixedData.Flags.Texture = 1; m_fixedData.Flags.Texture = 1;
} }
} }
else if (m_fixedData.Flags.RenderTarget && m_device.getAdapter().isEmulatedRenderTargetFormat(m_fixedData.Format))
{
m_fixedData.Flags.RenderTarget = 0;
}
if (D3DDDIMULTISAMPLE_NONE != g_msaaOverride.first) if (D3DDDIMULTISAMPLE_NONE != g_msaaOverride.first)
{ {
@ -736,6 +747,11 @@ namespace D3dDdi
D3DDDIFORMAT Resource::getFormatConfig() D3DDDIFORMAT Resource::getFormatConfig()
{ {
if (m_origData.Flags.RenderTarget && !m_fixedData.Flags.RenderTarget)
{
return 0 != m_formatInfo.alpha.bitCount ? D3DDDIFMT_A8R8G8B8 : D3DDDIFMT_X8R8G8B8;
}
if (D3DDDIFMT_X8R8G8B8 == m_fixedData.Format || D3DDDIFMT_R5G6B5 == m_fixedData.Format) if (D3DDDIFMT_X8R8G8B8 == m_fixedData.Format || D3DDDIFMT_R5G6B5 == m_fixedData.Format)
{ {
switch (Config::renderColorDepth.get()) switch (Config::renderColorDepth.get())
@ -775,8 +791,7 @@ namespace D3dDdi
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> Resource::getMultisampleConfig() std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> Resource::getMultisampleConfig()
{ {
if (!m_fixedData.Flags.Texture && if (!m_isPrimary || m_origData.Flags.RenderTarget)
(!m_isPrimary || m_fixedData.Flags.RenderTarget))
{ {
return m_device.getAdapter().getMultisampleConfig(m_fixedData.Format); return m_device.getAdapter().getMultisampleConfig(m_fixedData.Format);
} }
@ -803,7 +818,7 @@ namespace D3dDdi
SIZE Resource::getScaledSize() SIZE Resource::getScaledSize()
{ {
SIZE size = { static_cast<LONG>(m_fixedData.pSurfList[0].Width), static_cast<LONG>(m_fixedData.pSurfList[0].Height) }; SIZE size = { static_cast<LONG>(m_fixedData.pSurfList[0].Width), static_cast<LONG>(m_fixedData.pSurfList[0].Height) };
if (!m_fixedData.Flags.Texture) if (m_origData.Flags.RenderTarget || m_fixedData.Flags.ZBuffer)
{ {
return m_device.getAdapter().getScaledSize(size); return m_device.getAdapter().getScaledSize(size);
} }
@ -951,7 +966,7 @@ namespace D3dDdi
if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate) if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate)
{ {
loadMsaaResolvedResource(subResourceIndex); loadMsaaResolvedResource(subResourceIndex);
if (!m_fixedData.Flags.RenderTarget || if (!m_origData.Flags.RenderTarget ||
Config::Settings::ResolutionScaleFilter::POINT == Config::resolutionScaleFilter.get()) Config::Settings::ResolutionScaleFilter::POINT == Config::resolutionScaleFilter.get())
{ {
const bool isScaled = static_cast<LONG>(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || const bool isScaled = static_cast<LONG>(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx ||
@ -1199,7 +1214,7 @@ namespace D3dDdi
if (srcResource->m_lockResource) if (srcResource->m_lockResource)
{ {
if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate && if (srcResource->m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate &&
!srcResource->m_fixedData.Flags.RenderTarget) !srcResource->m_origData.Flags.RenderTarget)
{ {
srcResource->m_lockData[data.SrcSubResourceIndex].isVidMemUpToDate = false; srcResource->m_lockData[data.SrcSubResourceIndex].isVidMemUpToDate = false;
srcResource->m_lockData[data.SrcSubResourceIndex].isMsaaResolvedUpToDate = false; srcResource->m_lockData[data.SrcSubResourceIndex].isMsaaResolvedUpToDate = false;
@ -1515,7 +1530,7 @@ namespace D3dDdi
} }
} }
if (!m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer) if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer)
{ {
LONG width = data.DstRect.right - data.DstRect.left; LONG width = data.DstRect.right - data.DstRect.left;
LONG height = data.DstRect.bottom - data.DstRect.top; LONG height = data.DstRect.bottom - data.DstRect.top;
@ -1563,7 +1578,7 @@ namespace D3dDdi
data.Flags.Linear ? D3DTEXF_LINEAR : D3DTEXF_POINT, data.Flags.SrcColorKey ? &ck : nullptr); data.Flags.Linear ? D3DTEXF_LINEAR : D3DTEXF_POINT, data.Flags.SrcColorKey ? &ck : nullptr);
} }
if (!m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer) if (!dstResource.m_fixedData.Flags.RenderTarget && !dstResource.m_fixedData.Flags.ZBuffer)
{ {
HRESULT result = copySubResourceRegion(data.hDstResource, data.DstSubResourceIndex, data.DstRect, HRESULT result = copySubResourceRegion(data.hDstResource, data.DstSubResourceIndex, data.DstRect,
*dstRes, dstIndex, dstRect); *dstRes, dstIndex, dstRect);
@ -1617,7 +1632,7 @@ namespace D3dDdi
{ {
if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format || if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format ||
m_fixedData.Flags.MatchGdiPrimary || m_fixedData.Flags.MatchGdiPrimary ||
!m_isPrimary && !m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer || !m_isPrimary && !m_origData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer ||
!m_fixedData.Flags.ZBuffer && !m_lockResource) !m_fixedData.Flags.ZBuffer && !m_lockResource)
{ {
return; return;

View File

@ -60,6 +60,7 @@ namespace D3dDdi
void updateConfig(); void updateConfig();
void updatePalettizedTexture(UINT stage); void updatePalettizedTexture(UINT stage);
static void enableConfig(bool enable);
static void setFormatOverride(D3DDDIFORMAT format); static void setFormatOverride(D3DDDIFORMAT format);
private: private:

View File

@ -38,7 +38,9 @@ namespace DDraw
auto data = privateData.get(); auto data = privateData.get();
data->m_palettizedSurface = palettizedSurface; data->m_palettizedSurface = palettizedSurface;
D3dDdi::Resource::enableConfig(false);
result = Surface::create(dd, desc, surface, std::move(privateData)); result = Surface::create(dd, desc, surface, std::move(privateData));
D3dDdi::Resource::enableConfig(true);
if (FAILED(result)) if (FAILED(result))
{ {
return LOG_RESULT(result); return LOG_RESULT(result);