#pragma once #include "d3d9_resource.h" #include "../dxso/dxso_module.h" #include "d3d9_shader_permutations.h" #include "d3d9_util.h" #include namespace dxvk { /** * \brief Common shader object * * Stores the compiled SPIR-V shader and the SHA-1 * hash of the original DXBC shader, which can be * used to identify the shader. */ class D3D9CommonShader { public: D3D9CommonShader(); D3D9CommonShader( D3D9DeviceEx* pDevice, VkShaderStageFlagBits ShaderStage, const DxvkShaderKey& Key, const DxsoModuleInfo* pDxbcModuleInfo, const void* pShaderBytecode, const DxsoAnalysisInfo& AnalysisInfo, DxsoModule* pModule); Rc GetShader(D3D9ShaderPermutation Permutation) const { return m_shaders[Permutation]; } std::string GetName() const { return m_shaders[D3D9ShaderPermutations::None]->debugName(); } const std::vector& GetBytecode() const { return m_bytecode; } const DxsoIsgn& GetIsgn() const { return m_isgn; } const DxsoShaderMetaInfo& GetMeta() const { return m_meta; } const DxsoDefinedConstants& GetConstants() const { return m_constants; } D3D9ShaderMasks GetShaderMask() const { return D3D9ShaderMasks{ m_usedSamplers, m_usedRTs }; } const DxsoProgramInfo& GetInfo() const { return m_info; } private: DxsoIsgn m_isgn; uint32_t m_usedSamplers; uint32_t m_usedRTs; DxsoProgramInfo m_info; DxsoShaderMetaInfo m_meta; DxsoDefinedConstants m_constants; DxsoPermutations m_shaders; std::vector m_bytecode; }; /** * \brief Common shader interface * * Implements methods for all D3D11*Shader * interfaces and stores the actual shader * module object. */ template class D3D9Shader : public D3D9DeviceChild { public: D3D9Shader( D3D9DeviceEx* pDevice, const D3D9CommonShader& CommonShader) : D3D9DeviceChild( pDevice ) , m_shader ( CommonShader ) { } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) { if (ppvObject == nullptr) return E_POINTER; *ppvObject = nullptr; if (riid == __uuidof(IUnknown) || riid == __uuidof(Base)) { *ppvObject = ref(this); return S_OK; } Logger::warn("D3D9Shader::QueryInterface: Unknown interface query"); Logger::warn(str::format(riid)); return E_NOINTERFACE; } HRESULT STDMETHODCALLTYPE GetFunction(void* pOut, UINT* pSizeOfData) { if (pSizeOfData == nullptr) return D3DERR_INVALIDCALL; const auto& bytecode = m_shader.GetBytecode(); if (pOut == nullptr) { *pSizeOfData = bytecode.size(); return D3D_OK; } size_t copyAmount = std::min(size_t(*pSizeOfData), bytecode.size()); std::memcpy(pOut, bytecode.data(), copyAmount); return D3D_OK; } const D3D9CommonShader* GetCommonShader() const { return &m_shader; } private: D3D9CommonShader m_shader; }; // Needs their own classes and not usings for forward decl. class D3D9VertexShader final : public D3D9Shader { public: D3D9VertexShader( D3D9DeviceEx* pDevice, const D3D9CommonShader& CommonShader) : D3D9Shader( pDevice, CommonShader ) { } }; class D3D9PixelShader final : public D3D9Shader { public: D3D9PixelShader( D3D9DeviceEx* pDevice, const D3D9CommonShader& CommonShader) : D3D9Shader( pDevice, CommonShader ) { } }; /** * \brief Shader module set * * Some applications may compile the same shader multiple * times, so we should cache the resulting shader modules * and reuse them rather than creating new ones. This * class is thread-safe. */ class D3D9ShaderModuleSet : public RcObject { public: void GetShaderModule( D3D9DeviceEx* pDevice, D3D9CommonShader* pShaderModule, VkShaderStageFlagBits ShaderStage, const DxsoModuleInfo* pDxbcModuleInfo, const void* pShaderBytecode); private: std::mutex m_mutex; std::unordered_map< DxvkShaderKey, D3D9CommonShader, DxvkHash, DxvkEq> m_modules; }; template const D3D9CommonShader* GetCommonShader(const T& pShader) { return pShader != nullptr ? pShader->GetCommonShader() : nullptr; } }