#pragma once #include "d3d9_resource.h" #include "../dxso/dxso_module.h" #include "d3d9_util.h" #include "d3d9_mem.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() const { return m_shader; } std::string GetName() const { return m_shader->debugName(); } 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; } uint32_t GetMaxDefinedConstant() const { return m_maxDefinedConst; } private: DxsoIsgn m_isgn; uint32_t m_usedSamplers; uint32_t m_usedRTs; DxsoProgramInfo m_info; DxsoShaderMetaInfo m_meta; DxsoDefinedConstants m_constants; uint32_t m_maxDefinedConst; Rc m_shader; }; /** * \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, D3D9MemoryAllocator* pAllocator, const D3D9CommonShader& CommonShader, const void* pShaderBytecode, uint32_t BytecodeLength) : D3D9DeviceChild( pDevice ) , m_shader ( CommonShader ) , m_bytecodeLength ( BytecodeLength ) { m_bytecode = pAllocator->Alloc(BytecodeLength); m_bytecode.Map(); std::memcpy(m_bytecode.Ptr(), pShaderBytecode, BytecodeLength); m_bytecode.Unmap(); } 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; } if (logQueryInterfaceError(__uuidof(Base), riid)) { 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; if (pOut == nullptr) { *pSizeOfData = m_bytecodeLength; return D3D_OK; } m_bytecode.Map(); uint32_t copyAmount = std::min(*pSizeOfData, m_bytecodeLength); std::memcpy(pOut, m_bytecode.Ptr(), copyAmount); m_bytecode.Unmap(); return D3D_OK; } const D3D9CommonShader* GetCommonShader() const { return &m_shader; } private: D3D9CommonShader m_shader; D3D9Memory m_bytecode; uint32_t m_bytecodeLength; }; // Needs their own classes and not usings for forward decl. class D3D9VertexShader final : public D3D9Shader { public: D3D9VertexShader( D3D9DeviceEx* pDevice, D3D9MemoryAllocator* pAllocator, const D3D9CommonShader& CommonShader, const void* pShaderBytecode, uint32_t BytecodeLength) : D3D9Shader( pDevice, pAllocator, CommonShader, pShaderBytecode, BytecodeLength ) { } }; class D3D9PixelShader final : public D3D9Shader { public: D3D9PixelShader( D3D9DeviceEx* pDevice, D3D9MemoryAllocator* pAllocator, const D3D9CommonShader& CommonShader, const void* pShaderBytecode, uint32_t BytecodeLength) : D3D9Shader( pDevice, pAllocator, CommonShader, pShaderBytecode, BytecodeLength ) { } }; /** * \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, uint32_t* pLength, VkShaderStageFlagBits ShaderStage, const DxsoModuleInfo* pDxbcModuleInfo, const void* pShaderBytecode); private: dxvk::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; } }