diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index c974941..538a331 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -164,11 +164,12 @@ namespace D3dDdi HRESULT Device::pfnClear(const D3DDDIARG_CLEAR* data, UINT numRect, const RECT* rect) { flushPrimitives(); - m_state.flush(); if (data->Flags & D3DCLEAR_TARGET) { + setRenderTarget(m_state.getAppState().renderTarget); prepareForGpuWrite(); } + m_state.flush(); if (m_renderTarget && rect) { diff --git a/DDrawCompat/D3dDdi/DrawPrimitive.cpp b/DDrawCompat/D3dDdi/DrawPrimitive.cpp index f7e68d6..5a10e57 100644 --- a/DDrawCompat/D3dDdi/DrawPrimitive.cpp +++ b/DDrawCompat/D3dDdi/DrawPrimitive.cpp @@ -475,6 +475,8 @@ namespace D3dDdi { state.setSpriteMode(false); } + m_device.setRenderTarget(state.getAppState().renderTarget); + m_device.prepareForGpuWrite(); state.flush(); } @@ -531,6 +533,8 @@ namespace D3dDdi { state.setSpriteMode(false); } + m_device.setRenderTarget(state.getAppState().renderTarget); + m_device.prepareForGpuWrite(); state.flush(); } diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index f79357e..0c84f75 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -111,6 +111,7 @@ namespace D3dDdi , m_fixedData(data) , m_lockBuffer(nullptr, &heapFree) , m_lockResource(nullptr, ResourceDeleter(device, device.getOrigVtable().pfnDestroyResource)) + , m_lockRefSurface{} , m_msaaSurface{} , m_msaaResolvedSurface{} , m_formatConfig(D3DDDIFMT_UNKNOWN) @@ -184,11 +185,12 @@ namespace D3dDdi Gdi::Cursor::setMonitorClipRect({}); } - if (m_msaaSurface.surface || m_msaaResolvedSurface.surface) + if (m_msaaSurface.surface || m_msaaResolvedSurface.surface || m_lockRefSurface.surface) { auto& repo = SurfaceRepository::get(m_device.getAdapter()); repo.release(m_msaaSurface); repo.release(m_msaaResolvedSurface); + repo.release(m_lockRefSurface); } } @@ -593,6 +595,7 @@ namespace D3dDdi m_lockData[i].isVidMemUpToDate = true; m_lockData[i].isMsaaUpToDate = m_msaaSurface.resource; m_lockData[i].isMsaaResolvedUpToDate = m_msaaResolvedSurface.resource; + m_lockData[i].isRefLocked = false; } } @@ -747,6 +750,38 @@ namespace D3dDdi rect.bottom <= static_cast(m_fixedData.pSurfList[subResourceIndex].Height); } + void Resource::loadFromLockRefResource(UINT subResourceIndex) + { + if (m_lockData[subResourceIndex].isRefLocked) + { + m_lockData[subResourceIndex].isRefLocked = false; + loadVidMemResource(subResourceIndex); + + auto srcResource = this; + auto srcIndex = subResourceIndex; + auto& si = m_fixedData.pSurfList[subResourceIndex]; + const RECT srcRect = { 0, 0, static_cast(si.Width), static_cast(si.Height) }; + if (!m_fixedData.Flags.Texture) + { + auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto& texture = repo.getTempTexture(si.Width, si.Height, getPixelFormat(m_fixedData.Format)); + if (!texture.resource) + { + return; + } + srcResource = texture.resource; + srcIndex = 0; + copySubResourceRegion(*srcResource, 0, srcRect, m_handle, subResourceIndex, srcRect); + } + + const RECT dstRect = { 0, 0, static_cast(m_msaaResolvedSurface.width), + static_cast(m_msaaResolvedSurface.height) }; + m_device.getShaderBlitter().lockRefBlt(*m_msaaResolvedSurface.resource, subResourceIndex, dstRect, + *srcResource, srcIndex, srcRect, *m_lockRefSurface.resource); + m_lockData[subResourceIndex].isMsaaResolvedUpToDate = true; + } + } + void Resource::loadMsaaResource(UINT subResourceIndex) { if (!m_lockData[subResourceIndex].isMsaaUpToDate) @@ -767,6 +802,7 @@ namespace D3dDdi void Resource::loadMsaaResolvedResource(UINT subResourceIndex) { + loadFromLockRefResource(subResourceIndex); if (!m_lockData[subResourceIndex].isMsaaResolvedUpToDate) { if (m_lockData[subResourceIndex].isMsaaUpToDate) @@ -799,20 +835,14 @@ namespace D3dDdi { if (m_lockData[subResourceIndex].isMsaaUpToDate || m_lockData[subResourceIndex].isMsaaResolvedUpToDate) { - if (m_msaaResolvedSurface.resource) - { - loadMsaaResolvedResource(subResourceIndex); - copySubResource(*this, *m_msaaResolvedSurface.resource, subResourceIndex); - } - else - { - copySubResource(*this, *m_msaaSurface.resource, subResourceIndex); - } + loadMsaaResolvedResource(subResourceIndex); + copySubResource(*this, *m_msaaResolvedSurface.resource, subResourceIndex); } else { copySubResource(*this, m_lockResource.get(), subResourceIndex); notifyLock(subResourceIndex); + m_lockData[subResourceIndex].isRefLocked = false; } m_lockData[subResourceIndex].isVidMemUpToDate = true; } @@ -883,6 +913,7 @@ namespace D3dDdi { if (m_lockResource) { + loadFromLockRefResource(subResourceIndex); if (m_lockData[subResourceIndex].isMsaaUpToDate) { resource = *m_msaaSurface.resource; @@ -921,6 +952,14 @@ namespace D3dDdi { if (m_lockResource) { + if (m_lockRefSurface.resource && + (m_lockData[subResourceIndex].isMsaaResolvedUpToDate || m_lockData[subResourceIndex].isMsaaUpToDate)) + { + loadVidMemResource(subResourceIndex); + copySubResource(*m_lockRefSurface.resource, m_handle, subResourceIndex); + m_lockData[subResourceIndex].isRefLocked = true; + } + loadSysMemResource(subResourceIndex); clearUpToDateFlags(subResourceIndex); m_lockData[subResourceIndex].isSysMemUpToDate = true; @@ -1270,7 +1309,8 @@ namespace D3dDdi { if (m_isSurfaceRepoResource || D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool || D3DDDIFMT_P8 == m_fixedData.Format || m_fixedData.Flags.MatchGdiPrimary || - !m_isPrimary && !m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer) + !m_isPrimary && !m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.ZBuffer || + !m_fixedData.Flags.ZBuffer && !m_lockResource) { return; } @@ -1297,11 +1337,13 @@ namespace D3dDdi } m_lockData[i].isMsaaUpToDate = false; m_lockData[i].isMsaaResolvedUpToDate = false; + m_lockData[i].isRefLocked = false; } } m_msaaSurface = {}; m_msaaResolvedSurface = {}; + m_lockRefSurface = {}; if (D3DDDIMULTISAMPLE_NONE != msaa.first || m_fixedData.Format != formatConfig || static_cast(m_fixedData.pSurfList[0].Width) != m_scaledSize.cx || @@ -1344,6 +1386,13 @@ namespace D3dDdi scaledSize.cx, scaledSize.cy, getPixelFormat(formatConfig), DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); } + + if (m_msaaResolvedSurface.resource) + { + SurfaceRepository::get(m_device.getAdapter()).getSurface(m_lockRefSurface, + m_fixedData.pSurfList[0].Width, m_fixedData.pSurfList[0].Height, getPixelFormat(m_fixedData.Format), + DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount); + } } } } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 829fa2e..91d360e 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -75,6 +75,7 @@ namespace D3dDdi bool isVidMemUpToDate; bool isMsaaUpToDate; bool isMsaaResolvedUpToDate; + bool isRefLocked; }; HRESULT bltLock(D3DDDIARG_LOCK& data); @@ -97,6 +98,7 @@ namespace D3dDdi RECT getRect(UINT subResourceIndex); SIZE getScaledSize(); bool isValidRect(UINT subResourceIndex, const RECT& rect); + void loadFromLockRefResource(UINT subResourceIndex); void loadMsaaResource(UINT subResourceIndex); void loadMsaaResolvedResource(UINT subResourceIndex); void loadSysMemResource(UINT subResourceIndex); @@ -114,6 +116,7 @@ namespace D3dDdi std::unique_ptr m_lockBuffer; std::vector m_lockData; std::unique_ptr m_lockResource; + SurfaceRepository::Surface m_lockRefSurface; SurfaceRepository::Surface m_msaaSurface; SurfaceRepository::Surface m_msaaResolvedSurface; D3DDDIFORMAT m_formatConfig; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index dc0c08f..169bbb3 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -38,10 +39,16 @@ namespace D3dDdi , m_psDrawCursor(createPixelShader(g_psDrawCursor)) , m_psGamma(createPixelShader(g_psGamma)) , m_psGenBilinear(createPixelShader(g_psGenBilinear)) + , m_psLockRef(createPixelShader(g_psLockRef)) , m_psPaletteLookup(createPixelShader(g_psPaletteLookup)) , m_psTextureSampler(createPixelShader(g_psTextureSampler)) , m_vertexShaderDecl(createVertexShaderDecl()) + , m_vertices{} { + for (std::size_t i = 0; i < m_vertices.size(); ++i) + { + m_vertices[i].rhw = 1; + } } void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -104,15 +111,11 @@ namespace D3dDdi state.setTempRenderState({ D3DDDIRS_BLENDFACTOR, blendFactor }); } - setTempTextureStage(0, srcResource, filter, srcColorKey); + setTempTextureStage(0, srcResource, srcRect, filter, srcColorKey); state.setTempTextureStageState({ 0, D3DDDITSS_SRGBTEXTURE, srgb }); - const float srcWidth = static_cast(srcSurface.Width); - const float srcHeight = static_cast(srcSurface.Height); + state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, m_vertices.data()); - Vertex vertices[4] = {}; - state.setTempStreamSourceUm({ 0, sizeof(Vertex) }, vertices); - DeviceState::TempStateLock lock(state); if (srcRgn) @@ -122,12 +125,12 @@ namespace D3dDdi { RectF dr = Rect::toRectF(sr); Rect::transform(dr, srcRect, dstRect); - drawRect(vertices, sr, dr, srcWidth, srcHeight); + drawRect(sr, dr, srcSurface.Width, srcSurface.Height); } } else { - drawRect(vertices, srcRect, Rect::toRectF(dstRect), srcWidth, srcHeight); + drawRect(srcRect, Rect::toRectF(dstRect), srcSurface.Width, srcSurface.Height); } m_device.flushPrimitives(); @@ -154,7 +157,10 @@ namespace D3dDdi const D3DDDIVERTEXELEMENT vertexElements[] = { { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 }, - { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 } + { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + { 0, 32, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 }, + { 0, 40, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 } }; D3DDDIARG_CREATEVERTEXSHADERDECL data = {}; @@ -202,19 +208,21 @@ namespace D3dDdi data.DstRect = clippedSrcRect; m_device.getOrigVtable().pfnBlt(m_device, &data); - setTempTextureStage(1, *cur.maskTexture, D3DTEXF_POINT); - setTempTextureStage(2, *cur.colorTexture, D3DTEXF_POINT); - setTempTextureStage(3, *xorTexture, D3DTEXF_POINT); + setTempTextureStage(1, *cur.maskTexture, clippedSrcRect, D3DTEXF_POINT); + setTempTextureStage(2, *cur.colorTexture, clippedSrcRect, D3DTEXF_POINT); + setTempTextureStage(3, *xorTexture, clippedSrcRect, D3DTEXF_POINT); blt(dstResource, dstSubResourceIndex, clippedDstRect, *cur.tempTexture, 0, clippedSrcRect, m_psDrawCursor.get(), D3DTEXF_POINT); } - void ShaderBlitter::drawRect(Vertex(&vertices)[4], const RECT& srcRect, const RectF& dstRect, float srcWidth, float srcHeight) + void ShaderBlitter::drawRect(const RECT& srcRect, const RectF& dstRect, UINT srcWidth, UINT srcHeight) { - vertices[0] = { dstRect.left - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.top / srcHeight }; - vertices[1] = { dstRect.right - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.top / srcHeight }; - vertices[2] = { dstRect.left - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.bottom / srcHeight }; - vertices[3] = { dstRect.right - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.bottom / srcHeight }; + m_vertices[0].xy = { dstRect.left - 0.5f, dstRect.top - 0.5f }; + m_vertices[1].xy = { dstRect.right - 0.5f, dstRect.top - 0.5f }; + m_vertices[2].xy = { dstRect.left - 0.5f, dstRect.bottom - 0.5f }; + m_vertices[3].xy = { dstRect.right - 0.5f, dstRect.bottom - 0.5f }; + + setTextureCoords(0, srcRect, srcWidth, srcHeight); D3DDDIARG_DRAWPRIMITIVE dp = {}; dp.PrimitiveType = D3DPT_TRIANGLESTRIP; @@ -257,7 +265,7 @@ namespace D3dDdi g_isGammaRampInvalidated = false; } - setTempTextureStage(1, *gammaRampTexture, D3DTEXF_POINT); + setTempTextureStage(1, *gammaRampTexture, srcRect, D3DTEXF_POINT); blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGamma.get(), D3DTEXF_POINT); } @@ -295,6 +303,19 @@ namespace D3dDdi return g_isGammaRampDefault; } + void ShaderBlitter::lockRefBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + const Resource& lockRefResource) + { + LOG_FUNC("ShaderBlitter::lockRefBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcSubResourceIndex, srcRect, + static_cast(lockRefResource)); + + setTempTextureStage(1, lockRefResource, srcRect, D3DTEXF_POINT); + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcSubResourceIndex, srcRect, + m_psLockRef.get(), D3DTEXF_POINT); + } + void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, RGBQUAD palette[256]) { @@ -322,7 +343,7 @@ namespace D3dDdi unlock.hResource = *paletteTexture; m_device.getOrigVtable().pfnUnlock(m_device, &unlock); - setTempTextureStage(1, *paletteTexture, D3DTEXF_POINT); + setTempTextureStage(1, *paletteTexture, srcRect, D3DTEXF_POINT); blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT); } @@ -344,16 +365,31 @@ namespace D3dDdi g_isGammaRampInvalidated = !g_isGammaRampDefault; } - void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey) + void ShaderBlitter::setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter, + const UINT* srcColorKey) { auto& state = m_device.getState(); state.setTempTexture(stage, texture, srcColorKey); + state.setTempTextureStageState({ stage, D3DDDITSS_TEXCOORDINDEX, stage }); state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP }); state.setTempTextureStageState({ stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP }); state.setTempTextureStageState({ stage, D3DDDITSS_MAGFILTER, filter }); state.setTempTextureStageState({ stage, D3DDDITSS_MINFILTER, filter }); state.setTempTextureStageState({ stage, D3DDDITSS_MIPFILTER, D3DTEXF_NONE }); state.setTempRenderState({ static_cast(D3DDDIRS_WRAP0 + stage), 0 }); + + auto& si = texture.getFixedDesc().pSurfList[0]; + setTextureCoords(stage, rect, si.Width, si.Height); + } + + void ShaderBlitter::setTextureCoords(UINT stage, const RECT& rect, UINT width, UINT height) + { + const float w = static_cast(width); + const float h = static_cast(height); + m_vertices[0].tc[stage] = { rect.left / w, rect.top / h }; + m_vertices[1].tc[stage] = { rect.right / w, rect.top / h }; + m_vertices[2].tc[stage] = { rect.left / w, rect.bottom / h }; + m_vertices[3].tc[stage] = { rect.right / w, rect.bottom / h }; } void ShaderBlitter::textureBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 1e90fd6..b6e3799 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -29,6 +30,9 @@ namespace D3dDdi 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 lockRefBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, + const Resource& lockRefResource); void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, RGBQUAD palette[256]); void textureBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -43,12 +47,10 @@ namespace D3dDdi private: struct Vertex { - float x; - float y; + std::array xy; float z; float rhw; - float tu; - float tv; + std::array tc[4]; }; void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -64,15 +66,19 @@ namespace D3dDdi std::unique_ptr createPixelShader(const BYTE* code, UINT size); std::unique_ptr createVertexShaderDecl(); - void drawRect(Vertex(&vertices)[4], const RECT& srcRect, const RectF& dstRect, float srcWidth, float srcHeight); - void setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey = nullptr); + void drawRect(const RECT& srcRect, const RectF& dstRect, UINT srcWidth, UINT srcHeight); + void setTempTextureStage(UINT stage, const Resource& texture, const RECT& rect, UINT filter, + const UINT* srcColorKey = nullptr); + void setTextureCoords(UINT stage, const RECT& rect, UINT width, UINT height); Device& m_device; std::unique_ptr m_psDrawCursor; std::unique_ptr m_psGamma; std::unique_ptr m_psGenBilinear; + std::unique_ptr m_psLockRef; std::unique_ptr m_psPaletteLookup; std::unique_ptr m_psTextureSampler; std::unique_ptr m_vertexShaderDecl; + std::array m_vertices; }; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index da5ca56..a9de31b 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -466,6 +466,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index eeafb5e..183d809 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -920,6 +920,9 @@ Shaders + + Shaders + diff --git a/DDrawCompat/Shaders/LockRef.hlsl b/DDrawCompat/Shaders/LockRef.hlsl new file mode 100644 index 0000000..b39482f --- /dev/null +++ b/DDrawCompat/Shaders/LockRef.hlsl @@ -0,0 +1,10 @@ +sampler2D s_texture : register(s0); +sampler2D s_lockRef : register(s1); + +float4 main(float2 texCoord : TEXCOORD0, float2 refCoord : TEXCOORD1) : COLOR0 +{ + float4 texColor = tex2D(s_texture, texCoord); + float4 refColor = tex2D(s_lockRef, refCoord); + clip(all(texColor == refColor) ? -1 : 1); + return texColor; +}