diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 0a8c8a6..1fd61b7 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,16 @@ namespace { const HANDLE DELETED_RESOURCE = reinterpret_cast(0xBAADBAAD); + + RECT makeRect(const D3DDDIARG_VIEWPORTINFO& vp) + { + return { + static_cast(vp.X), + static_cast(vp.Y), + static_cast(vp.X + vp.Width), + static_cast(vp.Y + vp.Height) + }; + } } namespace D3dDdi @@ -127,6 +138,7 @@ namespace D3dDdi m_current.renderState[D3DDDIRS_PATCHSEGMENTS] = 0x3F800000; m_current.renderState[D3DDDIRS_COLORWRITEENABLE] = 0xF; m_current.renderState[D3DDDIRS_BLENDOP] = D3DBLENDOP_ADD; + m_current.renderState[D3DDDIRS_SCISSORTESTENABLE] = FALSE; m_current.renderState[D3DDDIRS_SRGBWRITEENABLE] = FALSE; for (UINT i = 0; i < m_current.renderState.size(); i++) @@ -652,8 +664,13 @@ namespace D3dDdi { m_app.vertexShaderDecl = shader; m_changedStates |= CS_SHADER; + const bool wasTransformed = getVertexDecl().isTransformed; auto it = m_vertexShaderDecls.find(shader); m_vertexDecl = it != m_vertexShaderDecls.end() ? &it->second : nullptr; + if (getVertexDecl().isTransformed != wasTransformed) + { + m_changedStates |= CS_RENDER_TARGET; + } return S_OK; } @@ -770,6 +787,18 @@ namespace D3dDdi LOG_DS << renderTarget; } + void DeviceState::setScissorRect(const RECT& rect) + { + if (rect == m_current.scissorRect) + { + return; + } + + m_device.flushPrimitives(); + m_device.getOrigVtable().pfnSetScissorRect(m_device, &rect); + m_current.scissorRect = rect; + } + bool DeviceState::setShader(HANDLE shader, HANDLE& currentShader, HRESULT(APIENTRY* origSetShaderFunc)(HANDLE, HANDLE)) { @@ -1060,14 +1089,36 @@ namespace D3dDdi void DeviceState::updateRenderTarget() { auto vp = m_app.viewport; + auto scaledVp = m_app.viewport; + RECT scissorRect = {}; auto renderTarget = m_app.renderTarget; auto depthStencil = m_app.depthStencil; + bool isTransformed = getVertexDecl().isTransformed; Resource* resource = m_device.getResource(renderTarget.hRenderTarget); - if (resource && resource->getCustomResource()) + if (resource) { - resource->scaleRect(reinterpret_cast(vp)); - renderTarget.hRenderTarget = *resource->getCustomResource(); + auto customResource = resource->getCustomResource(); + if (customResource) + { + resource->scaleRect(reinterpret_cast(scaledVp)); + renderTarget.hRenderTarget = *customResource; + } + if (isTransformed) + { + scissorRect = makeRect(scaledVp); + auto& si = resource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; + vp = { 0, 0, si.Width, si.Height }; + if (customResource) + { + auto& scaledSi = customResource->getOrigDesc().pSurfList[renderTarget.SubResourceIndex]; + scaledVp = { 0, 0, scaledSi.Width, scaledSi.Height }; + } + else + { + scaledVp = vp; + } + } } resource = m_device.getResource(depthStencil.hZBuffer); @@ -1078,7 +1129,7 @@ namespace D3dDdi setRenderTarget(renderTarget); setDepthStencil(depthStencil); - setViewport(vp); + setViewport(scaledVp); auto wInfo = m_app.wInfo; if (1.0f == wInfo.WNear && 1.0f == wInfo.WFar) @@ -1089,15 +1140,26 @@ namespace D3dDdi setZRange(m_app.zRange); - updateVertexFixupConstants(); + if (isTransformed) + { + const float sx = static_cast(scaledVp.Width) / vp.Width; + const float sy = static_cast(scaledVp.Height) / vp.Height; + updateVertexFixupConstants(vp.Width, vp.Height, sx, sy); + } + + const bool isScissorRectNeeded = isTransformed && 0 != memcmp(&vp, &m_app.viewport, sizeof(vp)); + setRenderState({ D3DDDIRS_SCISSORTESTENABLE, isScissorRectNeeded }); + if (isScissorRectNeeded) + { + setScissorRect(scissorRect); + } } void DeviceState::updateShaders() { 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) + if (getVertexDecl().isTransformed) { setVertexShaderFunc(m_vsVertexFixup.get()); } @@ -1195,7 +1257,7 @@ namespace D3dDdi } } - void DeviceState::updateVertexFixupConstants() + void DeviceState::updateVertexFixupConstants(UINT width, UINT height, float sx, float sy) { D3DDDIARG_SETVERTEXSHADERCONST data = {}; data.Register = 253; @@ -1203,15 +1265,12 @@ namespace D3dDdi const float stc = static_cast(Config::spriteTexCoord.getParam()) / 100; const float apc = Config::alternatePixelCenter.get(); - const auto& vp = m_app.viewport; const auto& zr = m_current.zRange; - const float sx = static_cast(m_current.viewport.Width) / m_app.viewport.Width; - const float sy = static_cast(m_current.viewport.Height) / m_app.viewport.Height; ShaderConstF registers[3] = { { m_vertexShaderConst[253][0], m_vertexShaderConst[253][1], stc, stc }, - { 0.5f + apc - 0.5f / sx - vp.X - vp.Width / 2, 0.5f + apc - 0.5f / sy - vp.Y - vp.Height / 2, -zr.MinZ, 0.0f }, - { 2.0f / vp.Width, -2.0f / vp.Height, 1.0f / (zr.MaxZ - zr.MinZ), 1.0f } + { 0.5f + apc - 0.5f / sx - width / 2, 0.5f + apc - 0.5f / sy - height / 2, -zr.MinZ, 0.0f }, + { 2.0f / width, -2.0f / height, 1.0f / (zr.MaxZ - zr.MinZ), 1.0f } }; if (0 != memcmp(registers, &m_vertexShaderConst[data.Register], sizeof(registers))) diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index 0d02fe2..c70cda6 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -34,6 +34,7 @@ namespace D3dDdi HANDLE pixelShader; std::array renderState; D3DDDIARG_SETRENDERTARGET renderTarget; + RECT scissorRect; D3DDDIARG_SETSTREAMSOURCE streamSource; D3DDDIARG_SETSTREAMSOURCEUM streamSourceUm; const void* streamSourceUmBuffer; @@ -191,6 +192,7 @@ namespace D3dDdi void setPixelShader(HANDLE shader); void setRenderState(const D3DDDIARG_RENDERSTATE& renderState); void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget); + void setScissorRect(const RECT& rect); void setStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource); void setStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& streamSourceUm, const void* umBuffer); bool setTexture(UINT stage, HANDLE texture); @@ -206,7 +208,7 @@ namespace D3dDdi void updateShaders(); void updateTextureColorKey(UINT stage); void updateTextureStages(); - void updateVertexFixupConstants(); + void updateVertexFixupConstants(UINT width, UINT height, float sx, float sy); Device& m_device; State m_app; diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index d76b358..2ca41ca 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -121,6 +121,7 @@ namespace D3dDdi state.setTempRenderState({ D3DDDIRS_CLIPPLANEENABLE, 0 }); state.setTempRenderState({ D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE }); state.setTempRenderState({ D3DDDIRS_COLORWRITEENABLE, 0xF }); + state.setTempRenderState({ D3DDDIRS_SCISSORTESTENABLE, FALSE }); state.setTempRenderState({ D3DDDIRS_SRGBWRITEENABLE, srgb }); if (alpha)