From 00407e4b30f6b80759485abbe4baf3e564cdc95b Mon Sep 17 00:00:00 2001 From: chambriat Date: Mon, 14 Mar 2016 11:19:39 +0100 Subject: [PATCH 1/2] Add shader settings support in external .json --- include/mpc-hc_config.h | 3 +- src/SubPic/ISubPic.h | 10 + src/SubPic/SubPicAllocatorPresenterImpl.cpp | 1 + src/SubPic/SubPicAllocatorPresenterImpl.h | 11 + .../VideoRenderers/DX9AllocatorPresenter.cpp | 14 + .../VideoRenderers/DX9AllocatorPresenter.h | 6 +- .../VideoRenderers/DX9RenderingEngine.cpp | 176 +++++++++- .../VideoRenderers/DX9RenderingEngine.h | 46 ++- .../VideoRenderers/PixelShaderCompiler.cpp | 52 +-- .../VideoRenderers/PixelShaderCompiler.h | 20 -- src/mpc-hc/DebugShadersDlg.cpp | 19 +- src/mpc-hc/MainFrm.cpp | 46 ++- src/mpc-hc/MainFrm.h | 3 + src/mpc-hc/PPageShaders.cpp | 6 +- src/mpc-hc/Shaders.cpp | 302 +++++++++++++++--- src/mpc-hc/Shaders.h | 46 ++- src/mpc-hc/mpc-hc.vcxproj | 2 +- 17 files changed, 592 insertions(+), 171 deletions(-) diff --git a/include/mpc-hc_config.h b/include/mpc-hc_config.h index aaa2cb7d016..b5c9f5091b6 100644 --- a/include/mpc-hc_config.h +++ b/include/mpc-hc_config.h @@ -1,6 +1,6 @@ #ifndef ISPP_INVOKED /* - * (C) 2013-2015 see Authors.txt + * (C) 2013-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -46,6 +46,7 @@ #define SHADERS_DIR _T("Shaders") #define SHADERS_EXT _T(".hlsl") +#define SHADERS_CFG _T(".json") // If this is enabled, the registered LAV Filters can be loaded as internal filters #define ENABLE_LOAD_EXTERNAL_LAVF_AS_INTERNAL 0 diff --git a/src/SubPic/ISubPic.h b/src/SubPic/ISubPic.h index 4e11ee57c48..298972d043e 100644 --- a/src/SubPic/ISubPic.h +++ b/src/SubPic/ISubPic.h @@ -227,3 +227,13 @@ public IPersist { // TODO: get rid of IPersist to identify type and use only // interface functions to modify the settings of the substream }; + +// +// ISubPicShaderPresenter +// +interface __declspec(uuid("212C1425-F407-4FF6-B0A0-8335FA46ABA8")) +ISubPicShaderPresenter : +public IUnknown { + STDMETHOD(SetPixelShaderTexture)(int registerId, const CString& path, int filter, int wrap) PURE; + STDMETHOD(SetPixelShaderParameter)(int registerId, const float values[4]) PURE; +}; diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.cpp b/src/SubPic/SubPicAllocatorPresenterImpl.cpp index 165b06a5156..9ecfd8ab700 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.cpp +++ b/src/SubPic/SubPicAllocatorPresenterImpl.cpp @@ -71,6 +71,7 @@ STDMETHODIMP CSubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID r QI(ISubRenderOptions) QI(ISubRenderConsumer) QI(ISubRenderConsumer2) + QI(ISubPicShaderPresenter) __super::NonDelegatingQueryInterface(riid, ppv); } diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.h b/src/SubPic/SubPicAllocatorPresenterImpl.h index 878a326eb75..1c2f6e3c09a 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.h +++ b/src/SubPic/SubPicAllocatorPresenterImpl.h @@ -33,6 +33,7 @@ class CSubPicAllocatorPresenterImpl , public CCritSec , public ISubPicAllocatorPresenter2 , public ISubRenderConsumer2 + , public ISubPicShaderPresenter { private: CCritSec m_csSubPicProvider; @@ -153,4 +154,14 @@ class CSubPicAllocatorPresenterImpl // ISubRenderConsumer2 STDMETHODIMP Clear(REFERENCE_TIME clearNewerThan = 0); + + // ISubPicShaderPresenter + + STDMETHODIMP SetPixelShaderTexture(int registerId, const CString& path, int filter, int wrap) { + return E_NOTIMPL; + } + + STDMETHODIMP SetPixelShaderParameter(int registerId, const float values[4]) { + return E_NOTIMPL; + } }; diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp index e2df572afab..e061a86eb29 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp @@ -2287,3 +2287,17 @@ STDMETHODIMP CDX9AllocatorPresenter::GetD3DFullscreen(bool* pfEnabled) *pfEnabled = m_bIsFullscreen; return S_OK; } + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShaderTexture(int registerId, const CString& path, int filter, int wrap) +{ + CAutoLock cRenderLock(&m_RenderLock); + + return SetCustomPixelShaderTexture(registerId, path, filter, wrap); +} + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShaderParameter(int registerId, const float values[4]) +{ + CAutoLock cRenderLock(&m_RenderLock); + + return SetCustomPixelShaderParameter(registerId, values); +} diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h index 4f7215c9549..c4a896a2261 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h @@ -1,6 +1,6 @@ /* * (C) 2003-2006 Gabest - * (C) 2006-2015 see Authors.txt + * (C) 2006-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -308,5 +308,9 @@ namespace DSObjects // ID3DFullscreenControl STDMETHODIMP SetD3DFullscreen(bool fEnabled); STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); + + // ISubPicShaderPresenter + STDMETHODIMP SetPixelShaderTexture(int registerId, const CString& path, int filter, int wrap); + STDMETHODIMP SetPixelShaderParameter(int registerId, const float values[4]); }; } diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp index c350d92df10..019167710ff 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp @@ -1,5 +1,5 @@ /* - * (C) 2006-2015 see Authors.txt + * (C) 2006-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -192,6 +192,8 @@ void CDX9RenderingEngine::InitRenderingEngine() void CDX9RenderingEngine::CleanupRenderingEngine() { + DestroyExternalTextures(); + m_pPSC.Free(); for (int i = 0; i < 4; i++) { @@ -202,12 +204,12 @@ void CDX9RenderingEngine::CleanupRenderingEngine() POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); while (pos) { - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + CExternalPixelShader& Shader = *m_pCustomScreenSpacePixelShaders.GetNext(pos); Shader.m_pPixelShader = nullptr; } pos = m_pCustomPixelShaders.GetHeadPosition(); while (pos) { - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + CExternalPixelShader& Shader = *m_pCustomPixelShaders.GetNext(pos); Shader.m_pPixelShader = nullptr; } @@ -419,11 +421,11 @@ HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarge hr = m_pTemporaryVideoTextures[dest]->GetSurfaceLevel(0, &pTemporarySurface); hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + CExternalPixelShader& Shader = *m_pCustomPixelShaders.GetNext(pos); if (!Shader.m_pPixelShader) { Shader.Compile(m_pPSC); } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + hr = Shader.Apply(m_pD3DDev); if (first) { TextureCopy(m_pVideoTexture[m_nCurSurface]); @@ -488,11 +490,11 @@ HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarge while (pos) { BeginScreenSpacePass(); - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + CExternalPixelShader& Shader = *m_pCustomScreenSpacePixelShaders.GetNext(pos); if (!Shader.m_pPixelShader) { Shader.Compile(m_pPSC); } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + hr = Shader.Apply(m_pD3DDev); TextureCopy(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); } } @@ -1700,7 +1702,7 @@ HRESULT CDX9RenderingEngine::AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirec HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) { - CAtlList* pPixelShaders; + CAutoPtrList* pPixelShaders; if (bScreenSpace) { pPixelShaders = &m_pCustomScreenSpacePixelShaders; } else { @@ -1710,6 +1712,7 @@ HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarge if (!pSrcData && !pTarget) { pPixelShaders->RemoveAll(); m_pD3DDev->SetPixelShader(nullptr); + UpdateExternalTextures(); return S_OK; } @@ -1717,20 +1720,163 @@ HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarge return E_INVALIDARG; } - CExternalPixelShader Shader; - Shader.m_SourceData = pSrcData; - Shader.m_SourceTarget = pTarget; - - CComPtr pPixelShader; + CAutoPtr shader; + shader.Attach(DEBUG_NEW CExternalPixelShader()); + shader->m_SourceData = pSrcData; + shader->m_SourceTarget = pTarget; - HRESULT hr = Shader.Compile(m_pPSC); + HRESULT hr = shader->Compile(m_pPSC); if (FAILED(hr)) { return hr; } - pPixelShaders->AddTail(Shader); + m_LatestCustomPixelShader = shader; + pPixelShaders->AddTail(shader); Paint(false); return S_OK; } + +HRESULT CDX9RenderingEngine::SetCustomPixelShaderTexture(int registerId, const CString& path, int filter, int wrap) +{ + PixelShaderTexture texture; + texture.texture = LoadExternalTexture(path); + if (texture.texture == NULL) { + return E_FAIL; + } + texture.registerId = registerId; + texture.filter = filter; + texture.wrap = wrap; + m_LatestCustomPixelShader->m_Textures.AddTail(texture); + return S_OK; +} + +HRESULT CDX9RenderingEngine::SetCustomPixelShaderParameter(int registerId, const float values[4]) +{ + PixelShaderParameter parameter; + memcpy(parameter.values, values, sizeof(float) * 4); + parameter.registerId = registerId; + m_LatestCustomPixelShader->m_Parameters.AddTail(parameter); + return S_OK; +} + +CDX9RenderingEngine::ExternalTexture* CDX9RenderingEngine::LoadExternalTexture(CString filePath) +{ + ExternalTexture* pTexture; + if (m_ExternalTextures.Lookup(filePath, pTexture) != 0) { + CFileStatus status; + if (!CFile::GetStatus(filePath, status) || status.m_mtime != pTexture->timeStamp) { + delete pTexture; + m_ExternalTextures.RemoveKey(filePath); + } else { + pTexture->bUsed = true; + return pTexture; + } + } + + pTexture = DEBUG_NEW ExternalTexture(); + if (FAILED(D3DXCreateTextureFromFile(m_pD3DDev, filePath, &pTexture->pTexture))) { + return NULL; + } + + CFileStatus status; + if (CFile::GetStatus(filePath, status)) { + pTexture->timeStamp = status.m_mtime; + } + + pTexture->bUsed = true; + m_ExternalTextures[filePath] = pTexture; + return pTexture; +} + +void CDX9RenderingEngine::DestroyExternalTextures() +{ + POSITION pos = m_ExternalTextures.GetStartPosition(); + while (pos != NULL) { + CString filePath; + ExternalTexture* texture; + m_ExternalTextures.GetNextAssoc(pos, filePath, texture); + delete texture; + } + m_ExternalTextures.RemoveAll(); +} + +void CDX9RenderingEngine::UpdateExternalTextures() +{ + POSITION pos = m_ExternalTextures.GetStartPosition(); + while (pos) { + CString filePath; + ExternalTexture* texture; + m_ExternalTextures.GetNextAssoc(pos, filePath, texture); + + if (texture->bUsed) { + texture->bUsed = false; + } else { + delete texture; + m_ExternalTextures.RemoveKey(filePath); + } + } +} + +HRESULT CDX9RenderingEngine::CExternalPixelShader::Compile(CPixelShaderCompiler* pCompiler) +{ + HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDX9RenderingEngine::CExternalPixelShader::Apply(IDirect3DDevice9* pD3DDev) +{ + HRESULT res = pD3DDev->SetPixelShader(m_pPixelShader); + if (res != S_OK) { + return res; + } + + // Apply textures + POSITION pos = m_Textures.GetHeadPosition(); + while (pos) { + PixelShaderTexture& texture = m_Textures.GetNext(pos); + res = pD3DDev->SetTexture(texture.registerId, texture.texture->pTexture); + if (res != S_OK) { + return res; + } + + if (texture.wrap == 1) { + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + } else { + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + if (texture.filter == 2) { + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + } else if (texture.filter == 3) { + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + } else { + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pD3DDev->SetSamplerState(texture.registerId, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + } + } + + // Apply parameters + pos = m_Parameters.GetHeadPosition(); + while (pos) { + PixelShaderParameter& parameter = m_Parameters.GetNext(pos); + res = pD3DDev->SetPixelShaderConstantF(parameter.registerId, parameter.values, 4); + if (res != S_OK) { + return res; + } + } + + return res; +} diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h index ab56932d0e3..a88e2f3c4c3 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h @@ -83,23 +83,46 @@ namespace DSObjects HRESULT AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); HRESULT SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - + HRESULT SetCustomPixelShaderTexture(int registerId, const CString& path, int filter, int wrap); + HRESULT SetCustomPixelShaderParameter(int registerId, const float values[4]); private: + + struct ExternalTexture { + CComPtr pTexture; + CTime timeStamp; + bool bUsed; + }; + + CMap m_ExternalTextures; + + ExternalTexture* LoadExternalTexture(CString filePath); + void DestroyExternalTextures(); + void UpdateExternalTextures(); + + struct PixelShaderTexture { + int registerId; + ExternalTexture* texture; + int filter; + int wrap; + }; + + struct PixelShaderParameter { + int registerId; + float values[4]; + }; + class CExternalPixelShader { public: CComPtr m_pPixelShader; CStringA m_SourceData; CStringA m_SourceTarget; - HRESULT Compile(CPixelShaderCompiler* pCompiler) { - HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); - if (FAILED(hr)) { - return hr; - } - - return S_OK; - } + CList m_Textures; + CList m_Parameters; + + HRESULT Compile(CPixelShaderCompiler* pCompiler); + HRESULT Apply(IDirect3DDevice9* pD3DDev); }; // D3DX functions @@ -108,6 +131,7 @@ namespace DSObjects CONST float* pIn, UINT n); + CExternalPixelShader* m_LatestCustomPixelShader; CAutoPtr m_pPSC; @@ -117,7 +141,7 @@ namespace DSObjects ColorRenderingIntent m_RenderingIntent; // Custom pixel shaders - CAtlList m_pCustomPixelShaders; + CAutoPtrList m_pCustomPixelShaders; CComPtr m_pTemporaryVideoTextures[2]; // Screen space pipeline @@ -141,7 +165,7 @@ namespace DSObjects CComPtr m_pFinalPixelShader; // Custom screen space pixel shaders - CAtlList m_pCustomScreenSpacePixelShaders; + CAutoPtrList m_pCustomScreenSpacePixelShaders; // StetchRect rendering path D3DTEXTUREFILTERTYPE m_StretchRectFilter; diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp index 0a3caaf96bf..50597255b45 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp @@ -57,10 +57,8 @@ CPixelShaderCompiler::~CPixelShaderCompiler() } } -HRESULT CPixelShaderCompiler::InternalCompile( +HRESULT CPixelShaderCompiler::CompileShader( LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, LPCSTR pEntrypoint, LPCSTR pProfile, DWORD Flags, @@ -123,7 +121,7 @@ HRESULT CPixelShaderCompiler::InternalCompile( D3D_SHADER_MACRO macros[] = { { defProfile, defProfileVal }, { 0 } }; CComPtr pShaderBlob, pErrorBlob; - HRESULT hr = m_pD3DCompile(pSrcData, SrcDataSize, pSourceName, macros, nullptr, pEntrypoint, + HRESULT hr = m_pD3DCompile(pSrcData, strlen(pSrcData), nullptr, macros, nullptr, pEntrypoint, pSelProfile, Flags, 0, &pShaderBlob, &pErrorBlob); if (pErrMsg) { @@ -170,49 +168,3 @@ HRESULT CPixelShaderCompiler::InternalCompile( return S_OK; } - -HRESULT CPixelShaderCompiler::CompileShader( - LPCSTR pSrcData, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - return InternalCompile(pSrcData, strlen(pSrcData), nullptr, pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); -} - -HRESULT CPixelShaderCompiler::CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - HRESULT ret = E_FAIL; - if (FILE* fp = _tfsopen(pSrcFile, _T("rb"), _SH_SECURE)) { - VERIFY(fseek(fp, 0, SEEK_END) == 0); - long size = ftell(fp); - rewind(fp); - if (size > 0) { - auto data = new(std::nothrow) char[(size_t)size]; - if (data) { - if (fread(data, size, 1, fp) == 1) { - ret = InternalCompile(data, (size_t)size, CT2A(pSrcFile), pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); - } else { - ASSERT(FALSE); - } - delete[] data; - } else { - ASSERT(FALSE); - } - } - VERIFY(fclose(fp) == 0); - } - return ret; -} diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h index fe9bd0e46d2..81778332eb3 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h @@ -33,17 +33,6 @@ class CPixelShaderCompiler CComPtr m_pD3DDev; - HRESULT InternalCompile( - LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg); - public: CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false); ~CPixelShaderCompiler(); @@ -56,13 +45,4 @@ class CPixelShaderCompiler IDirect3DPixelShader9** ppPixelShader, CString* pDisasm = nullptr, CString* pErrMsg = nullptr); - - HRESULT CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm = nullptr, - CString* pErrMsg = nullptr); }; diff --git a/src/mpc-hc/DebugShadersDlg.cpp b/src/mpc-hc/DebugShadersDlg.cpp index 7086eb04db1..950fca0d73d 100644 --- a/src/mpc-hc/DebugShadersDlg.cpp +++ b/src/mpc-hc/DebugShadersDlg.cpp @@ -1,5 +1,5 @@ /* - * (C) 2013-2015 see Authors.txt + * (C) 2013-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -182,10 +182,10 @@ void CDebugShadersDlg::OnListRefresh() list.insert(list.cend(), s.m_ShadersExtraList.cbegin(), s.m_ShadersExtraList.cend()); m_Shaders.ResetContent(); for (const auto& shader : list) { - ASSERT(!shader.filePath.IsEmpty()); - int idx = m_Shaders.InsertString(-1, shader.filePath); + ASSERT(!shader.GetFilePath().IsEmpty()); + int idx = m_Shaders.InsertString(-1, shader.GetFilePath()); if (idx >= 0) { - if (shader.filePath == path) { + if (shader.GetFilePath() == path) { VERIFY(m_Shaders.SetCurSel(idx) != CB_ERR); } } else { @@ -227,9 +227,10 @@ void CDebugShadersDlg::OnRecompileShader() } int sel = m_Shaders.GetCurSel(); if (sel != CB_ERR) { - Shader shader; - m_Shaders.GetLBText(sel, shader.filePath); - if (PathUtils::IsFile(shader.filePath)) { + CString shaderPath; + m_Shaders.GetLBText(sel, shaderPath); + if (PathUtils::IsFile(shaderPath)) { + Shader shader(shaderPath); CStringA profile; switch (m_iVersion) { case ps_2_0: @@ -250,8 +251,8 @@ void CDebugShadersDlg::OnRecompileShader() break; } CString disasm, compilerMsg; - if (SUCCEEDED(m_Compiler.CompileShaderFromFile(shader.filePath, "main", profile, - D3DXSHADER_DEBUG, nullptr, &disasm, &compilerMsg))) { + if (SUCCEEDED(m_Compiler.CompileShader(shader.GetCode(), "main", profile, + D3DXSHADER_DEBUG, nullptr, &disasm, &compilerMsg))) { if (!compilerMsg.IsEmpty()) { compilerMsg += _T("\n"); } diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index e56c1520873..13b73c72e7e 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -10168,6 +10168,33 @@ void CMainFrame::RepaintVideo() } } +bool CMainFrame::SetShaderListP2(const ShaderList& shaderList, bool bScreenSpace) +{ + bool result = true; + const auto& s = AfxGetAppSettings(); + ISubPicShaderPresenter* pShaderPresenter = nullptr; + m_pCAP2.QueryInterface(&pShaderPresenter); + + m_pCAP2->SetPixelShader2(nullptr, nullptr, bScreenSpace); + for (const auto& shader : shaderList) { + if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, bScreenSpace))) { + result = false; + m_pCAP2->SetPixelShader2(nullptr, nullptr, bScreenSpace); + break; + } else if ((pShaderPresenter != nullptr)) { + for (const ShaderTexture& texture : shader.GetTextures()) { + pShaderPresenter->SetPixelShaderTexture(texture.id, texture.path, texture.filter, texture.wrap); + } + for (const ShaderParameter& param : shader.GetParameters()) { + pShaderPresenter->SetPixelShaderParameter(param.id, param.values); + } + } + } + + SAFE_RELEASE(pShaderPresenter); + return result; +} + void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* = true*/) { if (GetLoadState() != MLS::LOADED) { @@ -10181,25 +10208,12 @@ void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* // internal video renderers select maximum available profile and madVR (the only external renderer that // supports shader part of ISubPicAllocatorPresenter2 interface) seems to ignore it altogether. if (m_pCAP2) { + if (bSetPreResize) { - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, false))) { - preFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - break; - } - } + preFailed = !SetShaderListP2(s.m_Shaders.GetCurrentPreset().GetPreResize(), false); } if (bSetPostResize) { - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, true))) { - postFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - break; - } - } + postFailed = !SetShaderListP2(s.m_Shaders.GetCurrentPreset().GetPostResize(), true); } } else if (m_pCAP) { // shouldn't happen, all knows renderers that support ISubPicAllocatorPresenter interface diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 6172b35b6c5..cff57ed45e5 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -582,6 +582,9 @@ class CMainFrame : public CFrameWnd, public CDropClient CString GetCaptureTitle(); // shaders +private: + bool SetShaderListP2(const ShaderList& shaderList, bool bScreenSpace); +public: void SetShaders(bool bSetPreResize = true, bool bSetPostResize = true); // capturing diff --git a/src/mpc-hc/PPageShaders.cpp b/src/mpc-hc/PPageShaders.cpp index 225aa918a17..214ad4b14b9 100644 --- a/src/mpc-hc/PPageShaders.cpp +++ b/src/mpc-hc/PPageShaders.cpp @@ -155,8 +155,8 @@ bool CShaderListBox::DeleteCurrentShader() CString CShaderListBox::GetTitle(const Shader& shader) { - CString ret = PathUtils::FileName(shader.filePath); - if (!PathUtils::IsFile(shader.filePath)) { + CString ret = PathUtils::FileName(shader.GetFilePath()); + if (!PathUtils::IsFile(shader.GetFilePath())) { ret += _T(" "); // TODO: externalize this string and merge it with the one in PPageExternalFilters } return ret; @@ -190,7 +190,7 @@ BOOL CShaderListBox::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) int item = (int)pNMHDR->idFrom; ASSERT(m_List.size() <= INT_MAX); if ((item < GetCount()) && (item < (int)m_List.size())) { - text = m_List.at(item).filePath; + text = m_List.at(item).GetFilePath(); ((TOOLTIPTEXT*)pNMHDR)->lpszText = (LPTSTR)(LPCTSTR)text; } else { ASSERT(FALSE); diff --git a/src/mpc-hc/Shaders.cpp b/src/mpc-hc/Shaders.cpp index 950b3a0bfc8..5ff311d185b 100644 --- a/src/mpc-hc/Shaders.cpp +++ b/src/mpc-hc/Shaders.cpp @@ -1,5 +1,5 @@ /* - * (C) 2013-2014 see Authors.txt + * (C) 2013-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -23,51 +23,254 @@ #include "MainFrm.h" #include "mplayerc.h" #include "PathUtils.h" +#include "rapidjson/include/rapidjson/document.h" +#include "rapidjson/include/rapidjson/error/en.h" +#include +#include #define SHADER_MAX_FILE_SIZE (4 * 1024 * 1024) -Shader::Shader() -{ -} - Shader::Shader(const CString& path) - : filePath(path) + : m_FilePath(path) { + Reload(); } bool Shader::operator==(const Shader& rhs) const { - return filePath.CompareNoCase(rhs.filePath) == 0; + return m_FilePath.CompareNoCase(rhs.m_FilePath) == 0; } bool Shader::IsDefault() const { - ASSERT(!PathUtils::IsRelative(filePath)); + ASSERT(!PathUtils::IsRelative(m_FilePath)); ASSERT(!PathUtils::IsRelative(ShaderList::GetShadersDir())); - return PathUtils::IsInDir(filePath, ShaderList::GetShadersDir()); + return PathUtils::IsInDir(m_FilePath, ShaderList::GetShadersDir()); } -CStringA Shader::GetCode() const +bool Shader::IsUsing(const CString& filePath) const { - CStringA code; - if (FILE* fp = _tfsopen(filePath, _T("rb"), _SH_SECURE)) { - fseek(fp, 0, SEEK_END); - size_t codeSize = ftell(fp); - rewind(fp); - if (codeSize > SHADER_MAX_FILE_SIZE) { - // reject shader code that is larger than SHADER_MAX_FILE_SIZE bytes, - // we need to limit it to some sane value in case the user tries to feed MPC-HC - // something large and bogus - ASSERT(FALSE); - } else if (fread(code.GetBufferSetLength((int)codeSize), codeSize, 1, fp) == 1) { - code.ReleaseBuffer((int)codeSize); + for (const CString& path : m_Pathes) { + if (path.CompareNoCase(filePath) == 0) { + return true; + } + } + + return false; +} + +const CString& Shader::GetFilePath() const +{ + return m_FilePath; +} + +const CStringA Shader::GetCode() const +{ + return m_Code.c_str(); +} + +const std::vector& Shader::GetPathes() const +{ + return m_Pathes; +} + +const std::vector& Shader::GetTextures() const +{ + return m_Textures; +} + +const std::vector& Shader::GetParameters() const +{ + return m_Parameters; +} + +void Shader::Reload() +{ + m_Code.clear(); + m_Pathes.clear(); + m_Textures.clear(); + m_Parameters.clear(); + + Load(m_FilePath); +} + +bool Shader::Load(const CString& path) +{ + const std::string include_token = "#include"; + const std::string filePath = CT2CA(path); + + m_Pathes.push_back(path); + CFile file; + if (!file.Open(path, CFile::modeRead | CFile::typeBinary)) { + Log("file is missing : " + filePath); + return false; + } + + if (file.GetLength() + m_Code.size() >= SHADER_MAX_FILE_SIZE) { + Log("file too large : " + filePath); + return false; + } + + std::string content; + content.resize(file.GetLength()); + if (file.Read(&content[0], file.GetLength()) != file.GetLength()) { + Log("failed to read : " + filePath); + return false; + } + + if (!StripComments(content)) { + Log("invalid comments : " + filePath); + return false; + } + + m_Code.reserve(m_Code.size() + content.size()); + std::istringstream stream(content); + std::string line; + while (std::getline(stream, line)) { + size_t pos = line.find(include_token); + if (pos != std::string::npos) { + size_t start = line.find('\"', pos + include_token.size()); + size_t stop; + if (start == std::string::npos) { + start = line.find('<', pos + include_token.size()); + stop = line.find('>', pos + include_token.size()); + } else { + stop = line.find('\"', start + 1); + } + + if (start == std::string::npos || stop == std::string::npos) { + Log("invalid include : " + line); + return false; + } + + CString includePath = PathUtils::CombinePaths(PathUtils::DirName(path), CString(line.substr(start + 1, stop - start - 1).c_str())); + + if (!Load(includePath)) { + return false; + } } else { - code.ReleaseBuffer(0); - ASSERT(FALSE); + m_Code += line; } - VERIFY(fclose(fp) == 0); + m_Code += '\n'; } - return code; + return LoadConfig(path); +} + +bool Shader::LoadConfig(const CString& path) +{ + CString folder = PathUtils::DirName(path); + CString configPath = PathUtils::CombinePaths(folder, PathUtils::FileName(path) + SHADERS_CFG); + if (!PathUtils::IsFile(configPath)) { + return true; + } + const std::string filePath = CT2CA(configPath); + + m_Pathes.push_back(configPath); + CFile file; + if (!file.Open(configPath, CFile::modeRead | CFile::osSequentialScan | CFile::typeBinary) || file.GetLength() > SHADER_MAX_FILE_SIZE) { + Log("failed to access : " + filePath); + return false; + } + + std::string content; + content.resize(file.GetLength()); + if (file.Read(&content[0], file.GetLength()) != file.GetLength()) { + Log("failed to read : " + filePath); + return false; + } + + if (!StripComments(content)) { + Log("invalid comments : " + filePath); + return false; + } + + rapidjson::Document document; + if (document.Parse(content.c_str()).HasParseError()) { + Log(filePath + " : " + rapidjson::GetParseError_En(document.GetParseError())); + return false; + } + + for (rapidjson::Value::ConstMemberIterator member = document.MemberBegin(); member != document.MemberEnd(); ++member) { + if (member->name == "texture") { + rapidjson::Value::ConstMemberIterator id = member->value.FindMember("id"); + rapidjson::Value::ConstMemberIterator path = member->value.FindMember("path"); + if (path != member->value.MemberEnd() && id != member->value.MemberEnd()) { + ShaderTexture texture; + texture.id = id->value.GetInt(); + texture.path = path->value.GetString(); + texture.path.Replace(_T("/"), _T("\\")); + + if (PathUtils::IsFile(texture.path)) { + m_Pathes.push_back(texture.path); + } else { + CString texturePath = PathUtils::CombinePaths(folder, texture.path); + if (PathUtils::IsFile(CString(texturePath))) { + texture.path = texturePath; + m_Pathes.push_back(texture.path); + } else { + Log(std::string(CT2CA(texture.path)) + " not found"); + } + } + + texture.filter = 3; + texture.wrap = 0; + + rapidjson::Value::ConstMemberIterator filter = member->value.FindMember("filter"); + if (filter != member->value.MemberEnd()) { + texture.filter = filter->value.GetInt(); + } + + rapidjson::Value::ConstMemberIterator wrap = member->value.FindMember("wrap"); + if (wrap != member->value.MemberEnd()) { + texture.wrap = filter->value.GetInt(); + } + + m_Textures.push_back(texture); + } + } else if (member->name == "float4") { + rapidjson::Value::ConstMemberIterator values = member->value.FindMember("values"); + rapidjson::Value::ConstMemberIterator id = member->value.FindMember("id"); + if (values != member->value.MemberEnd() && values->value.IsArray() && values->value.Size() == 4 && id != member->value.MemberEnd()) { + ShaderParameter param; + param.id = id->value.GetInt(); + memset(param.values, 0, sizeof(float) * 4); + + for (rapidjson::SizeType comp = 0; comp < values->value.Size(); ++comp) { + param.values[comp] = (float)values->value[comp].GetDouble(); + } + + m_Parameters.push_back(param); + } + } + } + + return true; +} + +bool Shader::StripComments(std::string& code) const +{ + size_t pos; + while ((pos = code.find("/*")) != std::string::npos) { + size_t end = code.find("*/", pos); + if (end == -1) { + return false; + } + code.erase(pos, (end - pos) + 2); + } + while ((pos = code.find("//")) != std::string::npos) { + size_t end = code.find('\n', pos); + if (end != std::string::npos) { + code.erase(pos, end - pos); + } else { + code.erase(pos); + } + } + return true; +} + +void Shader::Log(std::string message) +{ + m_Code += "#error " + message + "\n"; } ShaderList::ShaderList() @@ -94,7 +297,7 @@ CString ShaderList::ToString() const { CString ret, tok, dir = GetShadersDir(); for (auto it = cbegin(); it != cend(); ++it) { - tok = it->filePath; + tok = it->GetFilePath(); // convert path to relative when possible if (PathUtils::IsInDir(tok, dir)) { bool rel; @@ -339,10 +542,14 @@ FileChangeNotifier::FileSet ShaderSelection::ShaderCurrentPreset::GetWatchedList { FileSet ret; for (const auto& shader : m_PreResize) { - ret.emplace(shader.filePath); + for (const CString& path : shader.GetPathes()) { + ret.emplace(path); + } } for (const auto& shader : m_PostResize) { - ret.emplace(shader.filePath); + for (const CString& path : shader.GetPathes()) { + ret.emplace(path); + } } return ret; } @@ -364,16 +571,9 @@ void ShaderSelection::ShaderCurrentPreset::WatchedFilesChanged(const FileSet& ch void ShaderSelection::ShaderCurrentPreset::WatchedFilesCooldownCallback() { - bool setPre = false, setPost = false; - for (const auto& change : m_changes) { - Shader shader(change); - if (!setPre && std::find(m_PreResize.begin(), m_PreResize.end(), shader) != std::end(m_PreResize)) { - setPre = true; - } - if (!setPost && std::find(m_PostResize.begin(), m_PostResize.end(), shader) != std::end(m_PostResize)) { - setPost = true; - } - } + bool setPre = CheckWatchedFiles(m_PreResize); + bool setPost = CheckWatchedFiles(m_PostResize); + if (setPre && setPost) { m_eventc.FireEvent(MpcEvent::SHADER_SELECTION_CHANGED); } else if (setPre) { @@ -382,6 +582,30 @@ void ShaderSelection::ShaderCurrentPreset::WatchedFilesCooldownCallback() m_eventc.FireEvent(MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED); } m_changes.clear(); + + if (setPre || setPost) { + UpdateNotifierState(); + } +} + +bool ShaderSelection::ShaderCurrentPreset::CheckWatchedFiles(ShaderList& shaders) +{ + bool ret = false; + for (Shader& shader : shaders) { + bool modified = false; + for (const CString& change : m_changes) { + if (shader.IsUsing(change)) { + modified = true; + break; + } + } + + if (modified) { + ret = true; + shader.Reload(); + } + } + return ret; } bool ShaderSelection::NextPreset(bool bWrap/* = true*/) diff --git a/src/mpc-hc/Shaders.h b/src/mpc-hc/Shaders.h index d13641b60db..be279579f02 100644 --- a/src/mpc-hc/Shaders.h +++ b/src/mpc-hc/Shaders.h @@ -1,5 +1,5 @@ /* - * (C) 2013-2014 see Authors.txt + * (C) 2013-2016 see Authors.txt * * This file is part of MPC-HC. * @@ -29,13 +29,48 @@ #include "EventDispatcher.h" -struct Shader { - Shader(); +struct ShaderTexture { + int id; + CString path; + int filter; + int wrap; +}; + +struct ShaderParameter { + int id; + float values[4]; +}; + +class Shader +{ +public: Shader(const CString& path); - CString filePath; + bool operator==(const Shader& rhs) const; bool IsDefault() const; - CStringA GetCode() const; + bool IsUsing(const CString& filePath) const; + + const CString& GetFilePath() const; + const CStringA GetCode() const; + const std::vector& GetPathes() const; + const std::vector& GetTextures() const; + const std::vector& GetParameters() const; + + void Reload(); + +private: + + bool Load(const CString& path); + bool LoadConfig(const CString& path); + + bool StripComments(std::string& code) const; + void Log(std::string message); + + CString m_FilePath; + std::string m_Code; + std::vector m_Pathes; + std::vector m_Textures; + std::vector m_Parameters; }; class ShaderList : public std::vector @@ -118,6 +153,7 @@ class ShaderSelection virtual FileSet GetWatchedList() override; virtual void WatchedFilesChanged(const FileSet& changes) override; void WatchedFilesCooldownCallback(); + bool CheckWatchedFiles(ShaderList& shaders); FileSet m_changes; EventClient m_eventc; }; diff --git a/src/mpc-hc/mpc-hc.vcxproj b/src/mpc-hc/mpc-hc.vcxproj index b5bf24abecb..0260d1fc3ac 100644 --- a/src/mpc-hc/mpc-hc.vcxproj +++ b/src/mpc-hc/mpc-hc.vcxproj @@ -81,7 +81,7 @@ ..\..\include;%(AdditionalIncludeDirectories) - d3d9.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;%(AdditionalDependencies) + d3d9.lib;d3dx9.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;%(AdditionalDependencies) d3d9.dll;%(DelayLoadDLLs) true From 81bc49a2a34d0dc3bb8fd989b7b7804fc59e9325 Mon Sep 17 00:00:00 2001 From: chambriat Date: Mon, 21 Mar 2016 10:47:12 +0100 Subject: [PATCH 2/2] Allow custom name since some json library use dictionnary for items --- src/mpc-hc/Shaders.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/mpc-hc/Shaders.cpp b/src/mpc-hc/Shaders.cpp index 5ff311d185b..709eb168149 100644 --- a/src/mpc-hc/Shaders.cpp +++ b/src/mpc-hc/Shaders.cpp @@ -191,10 +191,12 @@ bool Shader::LoadConfig(const CString& path) } for (rapidjson::Value::ConstMemberIterator member = document.MemberBegin(); member != document.MemberEnd(); ++member) { - if (member->name == "texture") { - rapidjson::Value::ConstMemberIterator id = member->value.FindMember("id"); - rapidjson::Value::ConstMemberIterator path = member->value.FindMember("path"); - if (path != member->value.MemberEnd() && id != member->value.MemberEnd()) { + rapidjson::Value::ConstMemberIterator id = member->value.FindMember("id"); + rapidjson::Value::ConstMemberIterator path = member->value.FindMember("path"); + rapidjson::Value::ConstMemberIterator values = member->value.FindMember("values"); + + if (id != member->value.MemberEnd()) { + if (path != member->value.MemberEnd()) { ShaderTexture texture; texture.id = id->value.GetInt(); texture.path = path->value.GetString(); @@ -226,20 +228,18 @@ bool Shader::LoadConfig(const CString& path) } m_Textures.push_back(texture); - } - } else if (member->name == "float4") { - rapidjson::Value::ConstMemberIterator values = member->value.FindMember("values"); - rapidjson::Value::ConstMemberIterator id = member->value.FindMember("id"); - if (values != member->value.MemberEnd() && values->value.IsArray() && values->value.Size() == 4 && id != member->value.MemberEnd()) { - ShaderParameter param; - param.id = id->value.GetInt(); - memset(param.values, 0, sizeof(float) * 4); - - for (rapidjson::SizeType comp = 0; comp < values->value.Size(); ++comp) { - param.values[comp] = (float)values->value[comp].GetDouble(); - } + } else if (values != member->value.MemberEnd()) { + if (values != member->value.MemberEnd() && values->value.IsArray() && values->value.Size() == 4 && id != member->value.MemberEnd()) { + ShaderParameter param; + param.id = id->value.GetInt(); + memset(param.values, 0, sizeof(float) * 4); + + for (rapidjson::SizeType comp = 0; comp < values->value.Size(); ++comp) { + param.values[comp] = (float)values->value[comp].GetDouble(); + } - m_Parameters.push_back(param); + m_Parameters.push_back(param); + } } } }