From 51a451f42408907c1726d1a5c7ff123bc21f8c6d Mon Sep 17 00:00:00 2001 From: narzoul Date: Wed, 2 Jun 2021 00:34:50 +0200 Subject: [PATCH] Perform P8 to R8G8B8 conversion in pixel shader --- DDrawCompat/D3dDdi/Device.cpp | 59 +++--- DDrawCompat/D3dDdi/Device.h | 7 +- DDrawCompat/D3dDdi/DeviceFuncs.cpp | 10 +- DDrawCompat/D3dDdi/DeviceState.cpp | 233 +++++++++++++++++---- DDrawCompat/D3dDdi/DeviceState.h | 237 +++++++++++++++++++++- DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp | 6 + DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h | 1 + DDrawCompat/D3dDdi/Resource.cpp | 67 +++--- DDrawCompat/D3dDdi/Resource.h | 2 + DDrawCompat/D3dDdi/ShaderBlitter.cpp | 177 ++++++++++++++++ DDrawCompat/D3dDdi/ShaderBlitter.h | 35 ++++ DDrawCompat/DDraw/RealPrimarySurface.cpp | 2 +- DDrawCompat/DDrawCompat.vcxproj | 46 ++++- DDrawCompat/DDrawCompat.vcxproj.filters | 14 ++ DDrawCompat/Shaders/PaletteLookup.hlsl | 7 + 15 files changed, 772 insertions(+), 131 deletions(-) create mode 100644 DDrawCompat/D3dDdi/ShaderBlitter.cpp create mode 100644 DDrawCompat/D3dDdi/ShaderBlitter.h create mode 100644 DDrawCompat/Shaders/PaletteLookup.hlsl diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index ff4b94b..7ee67ec 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -44,6 +44,7 @@ namespace D3dDdi , m_sharedPrimary(nullptr) , m_drawPrimitive(*this) , m_state(*this) + , m_shaderBlitter(*this) { } @@ -51,6 +52,7 @@ namespace D3dDdi { s_devices.try_emplace(device, adapter, device); } + bool Device::checkSrcColorKeySupport() { if (!(m_adapter.getDDrawCaps().CKeyCaps & DDRAW_CKEYCAPS_SRCBLT)) @@ -211,6 +213,23 @@ namespace D3dDdi return it != m_resources.end() ? &it->second : nullptr; } + void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly) + { + auto it = m_resources.find(resource); + if (it != m_resources.end()) + { + it->second.prepareForRendering(subResourceIndex, isReadOnly); + } + } + + void Device::prepareForRendering() + { + if (m_renderTarget) + { + m_renderTarget->prepareForRendering(m_renderTargetSubResourceIndex, false); + } + } + void Device::setGdiResourceHandle(HANDLE resource) { ScopedCriticalSection lock; @@ -234,20 +253,12 @@ namespace D3dDdi } } - void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly) + void Device::setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data) { - auto it = m_resources.find(resource); - if (it != m_resources.end()) + if (0 == data.RenderTargetIndex) { - it->second.prepareForRendering(subResourceIndex, isReadOnly); - } - } - - void Device::prepareForRendering() - { - if (m_renderTarget) - { - m_renderTarget->prepareForRendering(m_renderTargetSubResourceIndex, false); + m_renderTarget = getResource(data.hRenderTarget); + m_renderTargetSubResourceIndex = data.SubResourceIndex; } } @@ -335,7 +346,7 @@ namespace D3dDdi g_gdiResource = nullptr; } m_drawPrimitive.removeSysMemVertexBuffer(resource); - m_state.removeTexture(resource); + m_state.onDestroyResource(resource); } return result; @@ -412,28 +423,6 @@ namespace D3dDdi return m_origVtable.pfnPresent1(m_device, data); } - HRESULT Device::pfnSetRenderTarget(const D3DDDIARG_SETRENDERTARGET* data) - { - flushPrimitives(); - HRESULT result = m_origVtable.pfnSetRenderTarget(m_device, data); - if (SUCCEEDED(result) && 0 == data->RenderTargetIndex) - { - m_renderTarget = getResource(data->hRenderTarget); - m_renderTargetSubResourceIndex = data->SubResourceIndex; - } - return result; - } - - HRESULT Device::pfnSetStreamSource(const D3DDDIARG_SETSTREAMSOURCE* data) - { - return m_drawPrimitive.setStreamSource(*data); - } - - HRESULT Device::pfnSetStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM* data, const void* umBuffer) - { - return m_drawPrimitive.setStreamSourceUm(*data, umBuffer); - } - HRESULT Device::pfnUnlock(const D3DDDIARG_UNLOCK* data) { flushPrimitives(); diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index 3db6004..709e010 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -9,6 +9,7 @@ #include #include +#include namespace D3dDdi { @@ -43,9 +44,6 @@ namespace D3dDdi HRESULT pfnOpenResource(D3DDDIARG_OPENRESOURCE* data); HRESULT pfnPresent(const D3DDDIARG_PRESENT* data); HRESULT pfnPresent1(D3DDDIARG_PRESENT1* data); - HRESULT pfnSetRenderTarget(const D3DDDIARG_SETRENDERTARGET* data); - HRESULT pfnSetStreamSource(const D3DDDIARG_SETSTREAMSOURCE* data); - HRESULT pfnSetStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM* data, const void* umBuffer); HRESULT pfnUnlock(const D3DDDIARG_UNLOCK* data); Adapter& getAdapter() const { return m_adapter; } @@ -53,11 +51,13 @@ namespace D3dDdi const D3DDDI_DEVICEFUNCS& getOrigVtable() const { return m_origVtable; } Resource* getResource(HANDLE resource); DeviceState& getState() { return m_state; } + ShaderBlitter& getShaderBlitter() { return m_shaderBlitter; } HRESULT createPrivateResource(D3DDDIARG_CREATERESOURCE2& data); void flushPrimitives() { m_drawPrimitive.flushPrimitives(); } void prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly); void prepareForRendering(); + void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data); bool isSrcColorKeySupported() const { return m_isSrcColorKeySupported; } @@ -84,6 +84,7 @@ namespace D3dDdi HANDLE m_sharedPrimary; DrawPrimitive m_drawPrimitive; DeviceState m_state; + ShaderBlitter m_shaderBlitter; bool m_isSrcColorKeySupported; static std::map s_devices; diff --git a/DDrawCompat/D3dDdi/DeviceFuncs.cpp b/DDrawCompat/D3dDdi/DeviceFuncs.cpp index ca668ef..525a2aa 100644 --- a/DDrawCompat/D3dDdi/DeviceFuncs.cpp +++ b/DDrawCompat/D3dDdi/DeviceFuncs.cpp @@ -64,20 +64,21 @@ namespace SET_DEVICE_FUNC(pfnOpenResource); SET_DEVICE_FUNC(pfnPresent); SET_DEVICE_FUNC(pfnPresent1); - SET_DEVICE_FUNC(pfnSetRenderTarget); - SET_DEVICE_FUNC(pfnSetStreamSource); - SET_DEVICE_FUNC(pfnSetStreamSourceUm); SET_DEVICE_FUNC(pfnUnlock); SET_DEVICE_STATE_FUNC(pfnCreateVertexShaderDecl); SET_DEVICE_STATE_FUNC(pfnDeletePixelShader); SET_DEVICE_STATE_FUNC(pfnDeleteVertexShaderDecl); SET_DEVICE_STATE_FUNC(pfnDeleteVertexShaderFunc); + SET_DEVICE_STATE_FUNC(pfnSetDepthStencil); SET_DEVICE_STATE_FUNC(pfnSetPixelShader); SET_DEVICE_STATE_FUNC(pfnSetPixelShaderConst); SET_DEVICE_STATE_FUNC(pfnSetPixelShaderConstB); SET_DEVICE_STATE_FUNC(pfnSetPixelShaderConstI); SET_DEVICE_STATE_FUNC(pfnSetRenderState); + SET_DEVICE_STATE_FUNC(pfnSetRenderTarget); + SET_DEVICE_STATE_FUNC(pfnSetStreamSource); + SET_DEVICE_STATE_FUNC(pfnSetStreamSourceUm); SET_DEVICE_STATE_FUNC(pfnSetTexture); SET_DEVICE_STATE_FUNC(pfnSetTextureStageState); SET_DEVICE_STATE_FUNC(pfnSetVertexShaderConst); @@ -85,6 +86,7 @@ namespace SET_DEVICE_STATE_FUNC(pfnSetVertexShaderConstI); SET_DEVICE_STATE_FUNC(pfnSetVertexShaderDecl); SET_DEVICE_STATE_FUNC(pfnSetVertexShaderFunc); + SET_DEVICE_STATE_FUNC(pfnSetViewport); SET_DEVICE_STATE_FUNC(pfnSetZRange); SET_DEVICE_STATE_FUNC(pfnUpdateWInfo); @@ -94,10 +96,8 @@ namespace SET_FLUSH_PRIMITIVES_FUNC(pfnDiscard); SET_FLUSH_PRIMITIVES_FUNC(pfnGenerateMipSubLevels); SET_FLUSH_PRIMITIVES_FUNC(pfnSetClipPlane); - SET_FLUSH_PRIMITIVES_FUNC(pfnSetDepthStencil); SET_FLUSH_PRIMITIVES_FUNC(pfnSetPalette); SET_FLUSH_PRIMITIVES_FUNC(pfnSetScissorRect); - SET_FLUSH_PRIMITIVES_FUNC(pfnSetViewport); SET_FLUSH_PRIMITIVES_FUNC(pfnStateSet); SET_FLUSH_PRIMITIVES_FUNC(pfnTexBlt); SET_FLUSH_PRIMITIVES_FUNC(pfnTexBlt1); diff --git a/DDrawCompat/D3dDdi/DeviceState.cpp b/DDrawCompat/D3dDdi/DeviceState.cpp index 5789793..7d590a9 100644 --- a/DDrawCompat/D3dDdi/DeviceState.cpp +++ b/DDrawCompat/D3dDdi/DeviceState.cpp @@ -4,37 +4,138 @@ #include #include -namespace -{ - const UINT UNINITIALIZED_STATE = 0xBAADBAAD; - const HANDLE UNINITIALIZED_HANDLE = reinterpret_cast(0xBAADBAAD); - - bool operator==(const D3DDDIARG_ZRANGE& lhs, const D3DDDIARG_ZRANGE& rhs) - { - return lhs.MinZ == rhs.MinZ && lhs.MaxZ == rhs.MaxZ; - } - - bool operator==(const D3DDDIARG_WINFO& lhs, const D3DDDIARG_WINFO& rhs) - { - return lhs.WNear == rhs.WNear && lhs.WFar == rhs.WFar; - } -} - namespace D3dDdi { DeviceState::DeviceState(Device& device) : m_device(device) - , m_pixelShader(UNINITIALIZED_HANDLE) - , m_vertexShaderDecl(UNINITIALIZED_HANDLE) - , m_vertexShaderFunc(UNINITIALIZED_HANDLE) - , m_wInfo{ NAN, NAN } - , m_zRange{ NAN, NAN } + , m_depthStencil{} + , m_pixelShader(nullptr) + , m_renderTarget{} + , m_streamSource{} + , m_streamSourceUm{} + , m_streamSourceUmBuffer(nullptr) + , m_textures{} + , m_vertexShaderDecl(nullptr) + , m_vertexShaderFunc(nullptr) + , m_viewport{} + , m_wInfo{} + , m_zRange{} { + const UINT D3DBLENDOP_ADD = 1; + const UINT UNINITIALIZED_STATE = 0xBAADBAAD; + + m_device.getOrigVtable().pfnSetDepthStencil(m_device, &m_depthStencil); + m_device.getOrigVtable().pfnSetPixelShader(m_device, nullptr); + m_device.getOrigVtable().pfnSetRenderTarget(m_device, &m_renderTarget); + m_device.getOrigVtable().pfnSetVertexShaderDecl(m_device, nullptr); + m_device.getOrigVtable().pfnSetVertexShaderFunc(m_device, nullptr); + m_device.getOrigVtable().pfnSetViewport(m_device, &m_viewport); + m_device.getOrigVtable().pfnUpdateWInfo(m_device, &m_wInfo); + m_device.getOrigVtable().pfnSetZRange(m_device, &m_zRange); + m_renderState.fill(UNINITIALIZED_STATE); - m_textures.fill(UNINITIALIZED_HANDLE); + m_renderState[D3DDDIRS_ZENABLE] = D3DZB_TRUE; + m_renderState[D3DDDIRS_FILLMODE] = D3DFILL_SOLID; + m_renderState[D3DDDIRS_SHADEMODE] = D3DSHADE_GOURAUD; + m_renderState[D3DDDIRS_LINEPATTERN] = 0; + m_renderState[D3DDDIRS_ZWRITEENABLE] = TRUE; + m_renderState[D3DDDIRS_ALPHATESTENABLE] = FALSE; + m_renderState[D3DDDIRS_LASTPIXEL] = TRUE; + m_renderState[D3DDDIRS_SRCBLEND] = D3DBLEND_ONE; + m_renderState[D3DDDIRS_DESTBLEND] = D3DBLEND_ZERO; + m_renderState[D3DDDIRS_CULLMODE] = D3DCULL_CCW; + m_renderState[D3DDDIRS_ZFUNC] = D3DCMP_LESSEQUAL; + m_renderState[D3DDDIRS_ALPHAREF] = 0; + m_renderState[D3DDDIRS_ALPHAFUNC] = D3DCMP_ALWAYS; + m_renderState[D3DDDIRS_DITHERENABLE] = FALSE; + m_renderState[D3DDDIRS_ALPHABLENDENABLE] = FALSE; + m_renderState[D3DDDIRS_FOGENABLE] = FALSE; + m_renderState[D3DDDIRS_SPECULARENABLE] = FALSE; + m_renderState[D3DDDIRS_ZVISIBLE] = 0; + m_renderState[D3DDDIRS_FOGCOLOR] = 0; + m_renderState[D3DDDIRS_FOGTABLEMODE] = D3DFOG_NONE; + m_renderState[D3DDDIRS_FOGSTART] = 0; + m_renderState[D3DDDIRS_FOGEND] = 0x3F800000; + m_renderState[D3DDDIRS_FOGDENSITY] = 0x3F800000; + m_renderState[D3DDDIRS_COLORKEYENABLE] = FALSE; + m_renderState[D3DDDIRS_EDGEANTIALIAS] = 0; + m_renderState[D3DDDIRS_ZBIAS] = 0; + m_renderState[D3DDDIRS_RANGEFOGENABLE] = FALSE; + for (UINT i = D3DDDIRS_STIPPLEPATTERN00; i <= D3DDDIRS_STIPPLEPATTERN31; ++i) + { + m_renderState[i] = 0; + } + m_renderState[D3DDDIRS_STENCILENABLE] = FALSE; + m_renderState[D3DDDIRS_STENCILFAIL] = D3DSTENCILOP_KEEP; + m_renderState[D3DDDIRS_STENCILZFAIL] = D3DSTENCILOP_KEEP; + m_renderState[D3DDDIRS_STENCILPASS] = D3DSTENCILOP_KEEP; + m_renderState[D3DDDIRS_STENCILFUNC] = D3DCMP_ALWAYS; + m_renderState[D3DDDIRS_STENCILREF] = 0; + m_renderState[D3DDDIRS_STENCILMASK] = 0xFFFFFFFF; + m_renderState[D3DDDIRS_STENCILWRITEMASK] = 0xFFFFFFFF; + m_renderState[D3DDDIRS_TEXTUREFACTOR] = 0xFFFFFFFF; + for (UINT i = D3DDDIRS_WRAP0; i <= D3DDDIRS_WRAP7; ++i) + { + m_renderState[i] = 0; + } + m_renderState[D3DDDIRS_CLIPPING] = TRUE; + m_renderState[D3DDDIRS_CLIPPLANEENABLE] = 0; + m_renderState[D3DDDIRS_SOFTWAREVERTEXPROCESSING] = FALSE; + m_renderState[D3DDDIRS_POINTSIZE_MAX] = 0x3F800000; + m_renderState[D3DDDIRS_POINTSIZE] = 0x3F800000; + m_renderState[D3DDDIRS_POINTSIZE_MIN] = 0; + m_renderState[D3DDDIRS_POINTSPRITEENABLE] = 0; + m_renderState[D3DDDIRS_MULTISAMPLEMASK] = 0xFFFFFFFF; + m_renderState[D3DDDIRS_MULTISAMPLEANTIALIAS] = TRUE; + m_renderState[D3DDDIRS_PATCHEDGESTYLE] = FALSE; + m_renderState[D3DDDIRS_PATCHSEGMENTS] = 0x3F800000; + m_renderState[D3DDDIRS_COLORWRITEENABLE] = 0xF; + m_renderState[D3DDDIRS_BLENDOP] = D3DBLENDOP_ADD; + + for (UINT i = 0; i < m_renderState.size(); i++) + { + if (UNINITIALIZED_STATE != m_renderState[i]) + { + D3DDDIARG_RENDERSTATE data = {}; + data.State = static_cast(i); + data.Value = m_renderState[i]; + m_device.getOrigVtable().pfnSetRenderState(m_device, &data); + } + } + + for (UINT i = 0; i < m_textures.size(); ++i) + { + m_device.getOrigVtable().pfnSetTexture(m_device, i, nullptr); + } + for (UINT i = 0; i < m_textureStageState.size(); ++i) { m_textureStageState[i].fill(UNINITIALIZED_STATE); + m_textureStageState[i][D3DDDITSS_TEXCOORDINDEX] = i; + m_textureStageState[i][D3DDDITSS_ADDRESSU] = D3DTADDRESS_WRAP; + m_textureStageState[i][D3DDDITSS_ADDRESSV] = D3DTADDRESS_WRAP; + m_textureStageState[i][D3DDDITSS_BORDERCOLOR] = 0; + m_textureStageState[i][D3DDDITSS_MAGFILTER] = D3DTEXF_POINT; + m_textureStageState[i][D3DDDITSS_MINFILTER] = D3DTEXF_POINT; + m_textureStageState[i][D3DDDITSS_MIPFILTER] = D3DTEXF_NONE; + m_textureStageState[i][D3DDDITSS_MIPMAPLODBIAS] = 0; + m_textureStageState[i][D3DDDITSS_MAXMIPLEVEL] = 0; + m_textureStageState[i][D3DDDITSS_MAXANISOTROPY] = 1; + m_textureStageState[i][D3DDDITSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE; + m_textureStageState[i][D3DDDITSS_ADDRESSW] = D3DTADDRESS_WRAP; + m_textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY] = TRUE; + + for (UINT j = 0; j < m_textureStageState[i].size(); ++j) + { + if (UNINITIALIZED_STATE != m_textureStageState[i][j]) + { + D3DDDIARG_TEXTURESTAGESTATE data = {}; + data.Stage = i; + data.State = static_cast(j); + data.Value = m_textureStageState[i][j]; + m_device.getOrigVtable().pfnSetTextureStageState(m_device, &data); + } + } } } @@ -76,6 +177,11 @@ namespace D3dDdi return deleteShader(shader, m_vertexShaderFunc, m_device.getOrigVtable().pfnDeleteVertexShaderFunc); } + HRESULT DeviceState::pfnSetDepthStencil(const D3DDDIARG_SETDEPTHSTENCIL* data) + { + return setState(data, m_depthStencil, m_device.getOrigVtable().pfnSetDepthStencil); + } + HRESULT DeviceState::pfnSetPixelShader(HANDLE shader) { return setShader(shader, m_pixelShader, m_device.getOrigVtable().pfnSetPixelShader); @@ -107,6 +213,40 @@ namespace D3dDdi return setStateArray(data, m_renderState, m_device.getOrigVtable().pfnSetRenderState); } + HRESULT DeviceState::pfnSetRenderTarget(const D3DDDIARG_SETRENDERTARGET* data) + { + HRESULT result = setState(data, m_renderTarget, m_device.getOrigVtable().pfnSetRenderTarget); + if (SUCCEEDED(result)) + { + m_device.setRenderTarget(*data); + } + return result; + } + + HRESULT DeviceState::pfnSetStreamSource(const D3DDDIARG_SETSTREAMSOURCE* data) + { + HRESULT result = m_device.getDrawPrimitive().setStreamSource(*data); + if (SUCCEEDED(result)) + { + m_streamSource = *data; + m_streamSourceUm = {}; + m_streamSourceUmBuffer = nullptr; + } + return result; + } + + HRESULT DeviceState::pfnSetStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM* data, const void* umBuffer) + { + HRESULT result = m_device.getDrawPrimitive().setStreamSourceUm(*data, umBuffer); + if (SUCCEEDED(result)) + { + m_streamSourceUm = *data; + m_streamSourceUmBuffer = umBuffer; + m_streamSource = {}; + } + return result; + } + HRESULT DeviceState::pfnSetTexture(UINT stage, HANDLE texture) { if (stage >= m_textures.size()) @@ -115,8 +255,7 @@ namespace D3dDdi return m_device.getOrigVtable().pfnSetTexture(m_device, stage, texture); } - if (texture == m_textures[stage] && - texture != UNINITIALIZED_HANDLE) + if (texture == m_textures[stage]) { return S_OK; } @@ -126,23 +265,22 @@ namespace D3dDdi if (SUCCEEDED(result)) { m_textures[stage] = texture; - m_textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = UNINITIALIZED_STATE; - m_textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] = UNINITIALIZED_STATE; + m_textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = TRUE; + + D3DDDIARG_TEXTURESTAGESTATE data = {}; + data.Stage = stage; + data.State = D3DDDITSS_DISABLETEXTURECOLORKEY; + data.Value = TRUE; + m_device.getOrigVtable().pfnSetTextureStageState(m_device, &data); } return result; } HRESULT DeviceState::pfnSetTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE* data) { - switch (data->State) + if (D3DDDITSS_TEXTURECOLORKEYVAL == data->State) { - case D3DDDITSS_DISABLETEXTURECOLORKEY: - m_textureStageState[data->Stage][D3DDDITSS_TEXTURECOLORKEYVAL] = UNINITIALIZED_STATE; - break; - - case D3DDDITSS_TEXTURECOLORKEYVAL: - m_textureStageState[data->Stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = UNINITIALIZED_STATE; - break; + m_textureStageState[data->Stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = FALSE; } return setStateArray(data, m_textureStageState[data->Stage], m_device.getOrigVtable().pfnSetTextureStageState); } @@ -185,6 +323,11 @@ namespace D3dDdi return setShader(shader, m_vertexShaderFunc, m_device.getOrigVtable().pfnSetVertexShaderFunc); } + HRESULT DeviceState::pfnSetViewport(const D3DDDIARG_VIEWPORTINFO* data) + { + return setState(data, m_viewport, m_device.getOrigVtable().pfnSetViewport); + } + HRESULT DeviceState::pfnSetZRange(const D3DDDIARG_ZRANGE* data) { return setState(data, m_zRange, m_device.getOrigVtable().pfnSetZRange); @@ -211,27 +354,32 @@ namespace D3dDdi HRESULT result = origDeleteShaderFunc(m_device, shader); if (SUCCEEDED(result) && shader == currentShader) { - currentShader = UNINITIALIZED_HANDLE; + currentShader = nullptr; } return result; } - void DeviceState::removeTexture(HANDLE texture) + void DeviceState::onDestroyResource(HANDLE resource) { for (UINT i = 0; i < m_textures.size(); ++i) { - if (m_textures[i] == texture) + if (m_textures[i] == resource) { - m_textures[i] = UNINITIALIZED_HANDLE; + m_textures[i] = nullptr; + m_device.getOrigVtable().pfnSetTexture(m_device, i, nullptr); } } + + if (m_renderTarget.hRenderTarget == resource) + { + m_renderTarget = {}; + } } HRESULT DeviceState::setShader(HANDLE shader, HANDLE& currentShader, HRESULT(APIENTRY* origSetShaderFunc)(HANDLE, HANDLE)) { - if (shader == currentShader && - shader != UNINITIALIZED_HANDLE) + if (shader == currentShader) { return S_OK; } @@ -273,7 +421,7 @@ namespace D3dDdi HRESULT DeviceState::setState(const StateData* data, StateData& currentState, HRESULT(APIENTRY* origSetState)(HANDLE, const StateData*)) { - if (*data == currentState) + if (0 == memcmp(data, ¤tState, sizeof(currentState))) { return S_OK; } @@ -297,8 +445,7 @@ namespace D3dDdi return origSetState(m_device, data); } - if (data->Value == currentState[data->State] && - data->Value != UNINITIALIZED_STATE) + if (data->Value == currentState[data->State]) { return S_OK; } diff --git a/DDrawCompat/D3dDdi/DeviceState.h b/DDrawCompat/D3dDdi/DeviceState.h index d25fa9b..92963f3 100644 --- a/DDrawCompat/D3dDdi/DeviceState.h +++ b/DDrawCompat/D3dDdi/DeviceState.h @@ -4,6 +4,10 @@ #include #include +const UINT D3DTEXF_NONE = 0; +const UINT D3DTEXF_POINT = 1; +const UINT D3DTEXF_LINEAR = 2; + namespace D3dDdi { class Device; @@ -17,11 +21,15 @@ namespace D3dDdi HRESULT pfnDeletePixelShader(HANDLE shader); HRESULT pfnDeleteVertexShaderDecl(HANDLE shader); HRESULT pfnDeleteVertexShaderFunc(HANDLE shader); + HRESULT pfnSetDepthStencil(const D3DDDIARG_SETDEPTHSTENCIL* data); HRESULT pfnSetPixelShader(HANDLE shader); HRESULT pfnSetPixelShaderConst(const D3DDDIARG_SETPIXELSHADERCONST* data, const FLOAT* registers); HRESULT pfnSetPixelShaderConstB(const D3DDDIARG_SETPIXELSHADERCONSTB* data, const BOOL* registers); HRESULT pfnSetPixelShaderConstI(const D3DDDIARG_SETPIXELSHADERCONSTI* data, const INT* registers); HRESULT pfnSetRenderState(const D3DDDIARG_RENDERSTATE* data); + HRESULT pfnSetRenderTarget(const D3DDDIARG_SETRENDERTARGET* data); + HRESULT pfnSetStreamSource(const D3DDDIARG_SETSTREAMSOURCE* data); + HRESULT pfnSetStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM* data, const void* umBuffer); HRESULT pfnSetTexture(UINT stage, HANDLE texture); HRESULT pfnSetTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE* data); HRESULT pfnSetVertexShaderConst(const D3DDDIARG_SETVERTEXSHADERCONST* data, const void* registers); @@ -29,10 +37,11 @@ namespace D3dDdi HRESULT pfnSetVertexShaderConstI(const D3DDDIARG_SETVERTEXSHADERCONSTI* data, const INT* registers); HRESULT pfnSetVertexShaderDecl(HANDLE shader); HRESULT pfnSetVertexShaderFunc(HANDLE shader); + HRESULT pfnSetViewport(const D3DDDIARG_VIEWPORTINFO* data); HRESULT pfnSetZRange(const D3DDDIARG_ZRANGE* data); HRESULT pfnUpdateWInfo(const D3DDDIARG_WINFO* data); - void removeTexture(HANDLE texture); + void onDestroyResource(HANDLE resource); private: typedef std::tuple ShaderConstF; @@ -57,11 +66,16 @@ namespace D3dDdi HRESULT(APIENTRY* origSetState)(HANDLE, const StateData*)); Device& m_device; + D3DDDIARG_SETDEPTHSTENCIL m_depthStencil; HANDLE m_pixelShader; std::vector m_pixelShaderConst; std::vector m_pixelShaderConstB; std::vector m_pixelShaderConstI; std::array m_renderState; + D3DDDIARG_SETRENDERTARGET m_renderTarget; + D3DDDIARG_SETSTREAMSOURCE m_streamSource; + D3DDDIARG_SETSTREAMSOURCEUM m_streamSourceUm; + const void* m_streamSourceUmBuffer; std::array m_textures; std::array, 8> m_textureStageState; std::vector m_vertexShaderConst; @@ -70,7 +84,228 @@ namespace D3dDdi std::map> m_vertexShaderDecls; HANDLE m_vertexShaderDecl; HANDLE m_vertexShaderFunc; + D3DDDIARG_VIEWPORTINFO m_viewport; D3DDDIARG_WINFO m_wInfo; D3DDDIARG_ZRANGE m_zRange; + + public: + template + class ScopedData + { + public: + typedef std::remove_reference_t().*dataMemberPtr)> Data; + + ScopedData(DeviceState& deviceState, const Data& data) + : m_deviceState(deviceState) + , m_prevData(deviceState.*dataMemberPtr) + { + (m_deviceState.*setterMethod)(&data); + } + + ~ScopedData() + { + (m_deviceState.*setterMethod)(&m_prevData); + } + + protected: + DeviceState& m_deviceState; + Data m_prevData; + }; + + class ScopedDepthStencil : public ScopedData<&DeviceState::pfnSetDepthStencil, &DeviceState::m_depthStencil> + { + public: + using ScopedData::ScopedData; + }; + + template + class ScopedHandle + { + public: + ScopedHandle(DeviceState& deviceState, HANDLE handle) + : m_deviceState(deviceState) + , m_prevHandle(deviceState.*storedHandle) + { + (m_deviceState.*setHandle)(handle); + } + + ~ScopedHandle() + { + if (m_prevHandle) + { + (m_deviceState.*setHandle)(m_prevHandle); + } + } + + private: + DeviceState& m_deviceState; + HANDLE m_prevHandle; + }; + + class ScopedPixelShader : public ScopedHandle<&DeviceState::pfnSetPixelShader, &DeviceState::m_pixelShader> + { + public: + using ScopedHandle::ScopedHandle; + }; + + class ScopedRenderState + { + public: + ScopedRenderState(DeviceState& deviceState, const D3DDDIARG_RENDERSTATE& data) + : m_deviceState(deviceState) + , m_prevData{ data.State, deviceState.m_renderState[data.State] } + { + m_deviceState.pfnSetRenderState(&data); + } + + ~ScopedRenderState() + { + m_deviceState.pfnSetRenderState(&m_prevData); + } + + private: + DeviceState& m_deviceState; + D3DDDIARG_RENDERSTATE m_prevData; + }; + + class ScopedRenderTarget : public ScopedData<&DeviceState::pfnSetRenderTarget, &DeviceState::m_renderTarget> + { + public: + ScopedRenderTarget(DeviceState& deviceState, const D3DDDIARG_SETRENDERTARGET& data) + : ScopedData(deviceState, data) + { + if (!m_prevData.hRenderTarget) + { + m_prevData = data; + } + } + }; + + class ScopedStreamSourceUm + { + public: + ScopedStreamSourceUm(DeviceState& deviceState, const D3DDDIARG_SETSTREAMSOURCEUM& data, const void* umBuffer) + : m_deviceState(deviceState) + , m_prevStreamSource(deviceState.m_streamSource) + , m_prevStreamSourceUm(deviceState.m_streamSourceUm) + , m_prevStreamSourceUmBuffer(deviceState.m_streamSourceUmBuffer) + { + m_deviceState.pfnSetStreamSourceUm(&data, umBuffer); + } + + ~ScopedStreamSourceUm() + { + if (m_prevStreamSourceUmBuffer) + { + m_deviceState.pfnSetStreamSourceUm(&m_prevStreamSourceUm, m_prevStreamSourceUmBuffer); + } + else if (m_prevStreamSource.hVertexBuffer) + { + m_deviceState.pfnSetStreamSource(&m_prevStreamSource); + } + } + + private: + DeviceState& m_deviceState; + D3DDDIARG_SETSTREAMSOURCE m_prevStreamSource; + D3DDDIARG_SETSTREAMSOURCEUM m_prevStreamSourceUm; + const void* m_prevStreamSourceUmBuffer; + }; + + class ScopedTextureStageState + { + public: + ScopedTextureStageState(DeviceState& deviceState, const D3DDDIARG_TEXTURESTAGESTATE& data) + : m_deviceState(deviceState) + , m_prevData{ data.Stage, data.State, deviceState.m_textureStageState[data.Stage][data.State] } + { + m_deviceState.pfnSetTextureStageState(&data); + } + + ~ScopedTextureStageState() + { + m_deviceState.pfnSetTextureStageState(&m_prevData); + } + + private: + DeviceState& m_deviceState; + D3DDDIARG_TEXTURESTAGESTATE m_prevData; + }; + + class ScopedTexture + { + public: + ScopedTexture(DeviceState& deviceState, UINT stage, HANDLE texture, UINT filter) + : m_deviceState(deviceState) + , m_stage(stage) + , m_prevTexture(deviceState.m_textures[stage]) + , m_scopedAddressU(deviceState, { stage, D3DDDITSS_ADDRESSU, D3DTADDRESS_CLAMP }) + , m_scopedAddressV(deviceState, { stage, D3DDDITSS_ADDRESSV, D3DTADDRESS_CLAMP }) + , m_scopedMagFilter(deviceState, { stage, D3DDDITSS_MAGFILTER, filter }) + , m_scopedMinFilter(deviceState, { stage, D3DDDITSS_MINFILTER, filter }) + , m_scopedMipFilter(deviceState, { stage, D3DDDITSS_MIPFILTER, D3DTEXF_NONE }) + , m_scopedWrap(deviceState, { static_cast(D3DDDIRS_WRAP0 + stage), 0 }) + , m_prevTextureColorKeyVal(deviceState.m_textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL]) + , m_prevDisableTextureColorKey(deviceState.m_textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY]) + { + m_deviceState.pfnSetTexture(stage, texture); + + D3DDDIARG_TEXTURESTAGESTATE data = {}; + data.Stage = stage; + data.State = D3DDDITSS_DISABLETEXTURECOLORKEY; + data.Value = TRUE; + m_deviceState.pfnSetTextureStageState(&data); + } + + ~ScopedTexture() + { + m_deviceState.pfnSetTexture(m_stage, m_prevTexture); + + D3DDDIARG_TEXTURESTAGESTATE data = {}; + data.Stage = m_stage; + if (m_prevDisableTextureColorKey) + { + data.State = D3DDDITSS_DISABLETEXTURECOLORKEY; + data.Value = TRUE; + } + else + { + data.State = D3DDDITSS_TEXTURECOLORKEYVAL; + data.Value = m_prevTextureColorKeyVal; + } + m_deviceState.pfnSetTextureStageState(&data); + } + + private: + DeviceState& m_deviceState; + UINT m_stage; + HANDLE m_prevTexture; + ScopedTextureStageState m_scopedAddressU; + ScopedTextureStageState m_scopedAddressV; + ScopedTextureStageState m_scopedMagFilter; + ScopedTextureStageState m_scopedMinFilter; + ScopedTextureStageState m_scopedMipFilter; + ScopedRenderState m_scopedWrap; + UINT m_prevTextureColorKeyVal; + UINT m_prevDisableTextureColorKey; + }; + + class ScopedVertexShaderDecl : public ScopedHandle<&DeviceState::pfnSetVertexShaderDecl, &DeviceState::m_vertexShaderDecl> + { + public: + using ScopedHandle::ScopedHandle; + }; + + class ScopedViewport : public ScopedData<&DeviceState::pfnSetViewport, &DeviceState::m_viewport> + { + public: + using ScopedData::ScopedData; + }; + + class ScopedZRange : public ScopedData<&DeviceState::pfnSetZRange, &DeviceState::m_zRange> + { + public: + using ScopedData::ScopedData; + }; }; } diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index 646054a..843cce6 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -204,6 +204,12 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_RENDERSTATE& val) << val.Value; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETDEPTHSTENCIL& val) +{ + return Compat::LogStruct(os) + << val.hZBuffer; +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETPIXELSHADERCONST& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index d253b86..f8e9782 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -25,6 +25,7 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT1& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENTSURFACE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_RENDERSTATE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETDEPTHSTENCIL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETPIXELSHADERCONST& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETRENDERTARGET& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_SETSTREAMSOURCE& val); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 4229931..ed8e7a4 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -154,6 +154,13 @@ namespace D3dDdi fixResourceData(device, reinterpret_cast(m_fixedData)); m_formatInfo = getFormatInfo(m_fixedData.Format); + const bool isPalettized = D3DDDIFMT_P8 == m_fixedData.Format; + if (isPalettized) + { + m_fixedData.Format = D3DDDIFMT_L8; + m_fixedData.Flags.Texture = 1; + } + HRESULT result = createResourceFunc(device, reinterpret_cast(&m_fixedData)); if (FAILED(result)) { @@ -161,6 +168,12 @@ namespace D3dDdi } m_handle = m_fixedData.hResource; + if (isPalettized) + { + m_fixedData.Format = D3DDDIFMT_P8; + m_fixedData.Flags.Texture = 0; + } + if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool && 0 != m_formatInfo.bytesPerPixel) { @@ -432,7 +445,7 @@ namespace D3dDdi { LOG_FUNC("Resource::createSysMemResource", Compat::array(surfaceInfo.data(), surfaceInfo.size())); D3DDDIARG_CREATERESOURCE2 data = {}; - data.Format = m_fixedData.Format; + data.Format = (D3DDDIFMT_P8 == m_fixedData.Format) ? D3DDDIFMT_L8 : m_fixedData.Format; data.Pool = D3DDDIPOOL_SYSTEMMEM; data.pSurfList = surfaceInfo.data(); data.SurfCount = surfaceInfo.size(); @@ -526,47 +539,27 @@ namespace D3dDdi HRESULT Resource::presentationBlt(const D3DDDIARG_BLT& data, Resource& srcResource) { - if (D3DDDIFMT_P8 == srcResource.m_origData.Format) - { - D3DDDIARG_LOCK lock = {}; - lock.hResource = m_handle; - lock.SubResourceIndex = data.DstSubResourceIndex; - HRESULT result = m_device.getOrigVtable().pfnLock(m_device, &lock); - if (FAILED(result)) - { - return result; - } - - auto entries(Gdi::Palette::getHardwarePalette()); - DWORD pal[256] = {}; - for (UINT i = 0; i < 256; ++i) - { - pal[i] = (entries[i].peRed << 16) | (entries[i].peGreen << 8) | entries[i].peBlue; - } - - auto& srcLockData = srcResource.m_lockData[data.SrcSubResourceIndex]; - for (UINT y = 0; y < srcResource.m_fixedData.surfaceData[data.SrcSubResourceIndex].Height; ++y) - { - auto src = static_cast(srcLockData.data) + y * srcLockData.pitch; - auto dst = reinterpret_cast(static_cast(lock.pSurfData) + y * lock.Pitch); - for (UINT x = 0; x < srcResource.m_fixedData.surfaceData[data.SrcSubResourceIndex].Width; ++x) - { - dst[x] = pal[*src]; - ++src; - } - } - - D3DDDIARG_UNLOCK unlock = {}; - unlock.hResource = m_handle; - unlock.SubResourceIndex = data.DstSubResourceIndex; - return m_device.getOrigVtable().pfnUnlock(m_device, &unlock); - } - if (srcResource.m_lockResource && srcResource.m_lockData[data.SrcSubResourceIndex].isSysMemUpToDate) { srcResource.copyToVidMem(data.SrcSubResourceIndex); } + + if (D3DDDIFMT_P8 == srcResource.m_origData.Format) + { + auto entries(Gdi::Palette::getHardwarePalette()); + RGBQUAD pal[256] = {}; + for (UINT i = 0; i < 256; ++i) + { + pal[i].rgbRed = entries[i].peRed; + pal[i].rgbGreen = entries[i].peGreen; + pal[i].rgbBlue = entries[i].peBlue; + } + + m_device.getShaderBlitter().palettizedBlt(*this, data.DstSubResourceIndex, srcResource, pal); + return S_OK; + } + return m_device.getOrigVtable().pfnBlt(m_device, &data); } diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 74c6d0e..31190f5 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -25,6 +25,8 @@ namespace D3dDdi Resource& operator=(Resource&&) = default; operator HANDLE() const { return m_handle; } + const D3DDDIARG_CREATERESOURCE2& getOrigDesc() const { return m_origData; } + const D3DDDIARG_CREATERESOURCE2& getFixedDesc() const { return m_fixedData; } HRESULT blt(D3DDDIARG_BLT data); HRESULT colorFill(D3DDDIARG_COLORFILL data); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp new file mode 100644 index 0000000..2f39cd5 --- /dev/null +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include + +#define CONCAT_(a, b) a##b +#define CONCAT(a, b) CONCAT_(a, b) +#define SCOPED_STATE(state, ...) DeviceState::Scoped##state CONCAT(scopedState, __LINE__)(m_device.getState(), __VA_ARGS__) + +namespace D3dDdi +{ + ShaderBlitter::ShaderBlitter(Device& device) + : m_device(device) + , m_paletteTexture(nullptr) + , m_psPaletteLookup(createPixelShader(g_psPaletteLookup, sizeof(g_psPaletteLookup))) + , m_vertexShaderDecl(createVertexShaderDecl()) + { + D3DDDI_SURFACEINFO si = {}; + si.Width = 256; + si.Height = 1; + + D3DDDIARG_CREATERESOURCE2 cr = {}; + cr.Format = D3DDDIFMT_X8R8G8B8; + cr.Pool = D3DDDIPOOL_VIDEOMEMORY; + cr.pSurfList = &si; + cr.SurfCount = 1; + cr.Rotation = D3DDDI_ROTATION_IDENTITY; + cr.Flags.Texture = 1; + + m_device.createPrivateResource(cr); + m_paletteTexture = cr.hResource; + } + + ShaderBlitter::~ShaderBlitter() + { + if (m_paletteTexture) + { + m_device.getOrigVtable().pfnDestroyResource(m_device, m_paletteTexture); + m_paletteTexture = nullptr; + } + } + + void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect, HANDLE pixelShader, UINT filter) + { + LOG_FUNC("ShaderBlitter::blt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcRect, pixelShader, filter); + + if (!m_vertexShaderDecl || !pixelShader) + { + return; + } + + const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex]; + const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0]; + + SCOPED_STATE(RenderState, { D3DDDIRS_SCENECAPTURE, TRUE }); + SCOPED_STATE(VertexShaderDecl, m_vertexShaderDecl); + SCOPED_STATE(PixelShader, pixelShader); + SCOPED_STATE(DepthStencil, { nullptr }); + SCOPED_STATE(RenderTarget, { 0, dstResource, dstSubResourceIndex }); + SCOPED_STATE(Viewport, { 0, 0, dstSurface.Width, dstSurface.Height }); + SCOPED_STATE(ZRange, { 0, 1 }); + + SCOPED_STATE(RenderState, { D3DDDIRS_ZENABLE, D3DZB_FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_FILLMODE, D3DFILL_SOLID }); + SCOPED_STATE(RenderState, { D3DDDIRS_ALPHATESTENABLE, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_CULLMODE, D3DCULL_NONE }); + SCOPED_STATE(RenderState, { D3DDDIRS_DITHERENABLE, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_ALPHABLENDENABLE, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_FOGENABLE, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_STENCILENABLE, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_CLIPPING, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_CLIPPLANEENABLE, 0 }); + SCOPED_STATE(RenderState, { D3DDDIRS_MULTISAMPLEANTIALIAS, FALSE }); + SCOPED_STATE(RenderState, { D3DDDIRS_COLORWRITEENABLE, 0xF }); + + SCOPED_STATE(Texture, 0, srcResource, filter); + + struct Vertex + { + float x; + float y; + float z; + float rhw; + float tu; + float tv; + }; + + const float srcWidth = static_cast(srcSurface.Width); + const float srcHeight = static_cast(srcSurface.Height); + + Vertex vertices[4] = { + { dstRect.left - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.top / srcHeight }, + { dstRect.right - 0.5f, dstRect.top - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.top / srcHeight }, + { dstRect.right - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.right / srcWidth, srcRect.bottom / srcHeight }, + { dstRect.left - 0.5f, dstRect.bottom - 0.5f, 0, 1, srcRect.left / srcWidth, srcRect.bottom / srcHeight } + }; + + D3DDDIARG_SETSTREAMSOURCEUM um = {}; + um.Stride = sizeof(Vertex); + SCOPED_STATE(StreamSourceUm, um, vertices); + + D3DDDIARG_DRAWPRIMITIVE dp = {}; + dp.PrimitiveType = D3DPT_TRIANGLEFAN; + dp.VStart = 0; + dp.PrimitiveCount = 2; + m_device.getDrawPrimitive().draw(dp, nullptr); + } + + HANDLE ShaderBlitter::createPixelShader(const BYTE* code, UINT size) + { + D3DDDIARG_CREATEPIXELSHADER data = {}; + data.CodeSize = size; + if (FAILED(m_device.getOrigVtable().pfnCreatePixelShader(m_device, &data, reinterpret_cast(code)))) + { + return nullptr; + } + return data.ShaderHandle; + } + + HANDLE ShaderBlitter::createVertexShaderDecl() + { + const UINT D3DDECLTYPE_FLOAT2 = 1; + const UINT D3DDECLTYPE_FLOAT4 = 3; + const UINT D3DDECLMETHOD_DEFAULT = 0; + const UINT D3DDECLUSAGE_TEXCOORD = 5; + const UINT D3DDECLUSAGE_POSITIONT = 9; + + const D3DDDIVERTEXELEMENT vertexElements[] = { + { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 } + }; + + D3DDDIARG_CREATEVERTEXSHADERDECL data = {}; + data.NumVertexElements = sizeof(vertexElements) / sizeof(vertexElements[0]); + + if (FAILED(m_device.getOrigVtable().pfnCreateVertexShaderDecl(m_device, &data, vertexElements))) + { + return nullptr; + } + return data.ShaderHandle; + } + + void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, + const Resource& srcResource, RGBQUAD palette[256]) + { + if (!m_paletteTexture) + { + return; + } + + D3DDDIARG_LOCK lock = {}; + lock.hResource = m_paletteTexture; + lock.Flags.Discard = 1; + m_device.getOrigVtable().pfnLock(m_device, &lock); + if (!lock.pSurfData) + { + return; + } + + memcpy(lock.pSurfData, palette, 256 * sizeof(RGBQUAD)); + + D3DDDIARG_UNLOCK unlock = {}; + unlock.hResource = m_paletteTexture; + m_device.getOrigVtable().pfnUnlock(m_device, &unlock); + + const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex]; + const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0]; + const RECT dstRect = { 0, 0, static_cast(dstSurface.Width), static_cast(dstSurface.Height) }; + const RECT srcRect = { 0, 0, static_cast(srcSurface.Width), static_cast(srcSurface.Height) }; + + SCOPED_STATE(Texture, 1, m_paletteTexture, D3DTEXF_POINT); + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psPaletteLookup, D3DTEXF_POINT); + } +} diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h new file mode 100644 index 0000000..b5df97b --- /dev/null +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +namespace D3dDdi +{ + class Device; + class Resource; + + class ShaderBlitter + { + public: + ShaderBlitter(Device& device); + ShaderBlitter(const ShaderBlitter&) = delete; + ShaderBlitter(ShaderBlitter&&) = delete; + ShaderBlitter& operator=(const ShaderBlitter&) = delete; + ShaderBlitter& operator=(ShaderBlitter&&) = delete; + ~ShaderBlitter(); + + void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, + const Resource& srcResource, RGBQUAD palette[256]); + + private: + void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect, HANDLE pixelShader, UINT filter); + + HANDLE createPixelShader(const BYTE* code, UINT size); + HANDLE createVertexShaderDecl(); + + Device& m_device; + HANDLE m_paletteTexture; + HANDLE m_psPaletteLookup; + HANDLE m_vertexShaderDecl; + }; +} diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 7e420d2..3e3ad9c 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -255,7 +255,7 @@ namespace DDraw typename Types::TSurfaceDesc desc = {}; desc.dwSize = sizeof(desc); desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; desc.dwBackBufferCount = 2; CompatPtr::TCreatedSurface> surface; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index d6fecd7..870d212 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -61,26 +61,23 @@ ddraw false - $(ProjectDir);$(IncludePath) - $(LibraryPath) false $(SolutionDir)Build\$(Configuration)\ + true ddraw - $(ProjectDir);$(IncludePath) - $(LibraryPath) false false $(SolutionDir)Build\$(Configuration)\ + true ddraw - $(ProjectDir);$(IncludePath) - $(LibraryPath) false false $(SolutionDir)Build\$(Configuration)\ + true @@ -94,6 +91,7 @@ $(IntDir)%(RelativeDir) ProgramDatabase stdcpp17 + $(ProjectDir);$(IntDir) dbgeng.lib;dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) @@ -109,6 +107,15 @@ $(IntDir) SPECIALBUILD=\"$(Configuration)\" + + g_ps%(Filename) + + + + 2.0 + $(IntDir)%(RelativeDir)%(Filename).h + Pixel + @@ -120,6 +127,7 @@ true $(IntDir)%(RelativeDir) stdcpp17 + $(ProjectDir);$(IntDir) dbgeng.lib;dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) @@ -134,6 +142,17 @@ $(IntDir) + + g_ps%(Filename) + + + $(IntDir)%(RelativeDir)%(Filename).h + + + + 2.0 + Pixel + @@ -145,6 +164,7 @@ true $(IntDir)%(RelativeDir) stdcpp17 + $(ProjectDir);$(IntDir) dbgeng.lib;dxguid.lib;msimg32.lib;oleacc.lib;uxtheme.lib;dwmapi.lib;winmm.lib;%(AdditionalDependencies) @@ -160,6 +180,15 @@ $(IntDir) SPECIALBUILD=\"$(Configuration)\" + + g_ps%(Filename) + + + + 2.0 + $(IntDir)%(RelativeDir)%(Filename).h + Pixel + @@ -203,6 +232,7 @@ + @@ -302,6 +332,7 @@ + @@ -359,6 +390,9 @@ + + + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 4b8c187..b0c847e 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -88,6 +88,9 @@ {0b4eec6c-ece5-4417-913c-8829b34ec08c} + + {00e06bd4-3f10-46dc-af0f-99834dfac835} + @@ -417,6 +420,9 @@ Header Files\Config\Settings + + Header Files\D3dDdi + @@ -656,6 +662,9 @@ Source Files\Config\Settings + + Source Files\D3dDdi + @@ -667,4 +676,9 @@ Resource Files + + + Shaders + + \ No newline at end of file diff --git a/DDrawCompat/Shaders/PaletteLookup.hlsl b/DDrawCompat/Shaders/PaletteLookup.hlsl new file mode 100644 index 0000000..7258685 --- /dev/null +++ b/DDrawCompat/Shaders/PaletteLookup.hlsl @@ -0,0 +1,7 @@ +sampler2D s_texture : register(s0); +sampler2D s_palette : register(s1); + +float4 main(float2 texCoord : TEXCOORD0) : COLOR0 +{ + return tex2D(s_palette, float2(tex2D(s_texture, texCoord).r, 0)); +}