mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-28 05:11:37 +00:00
Implement DXIL library linking.
This commit is contained in:
parent
0e8d1e2aa0
commit
cbf374924e
4 changed files with 145 additions and 13 deletions
|
|
@ -130,10 +130,13 @@ add_custom_command(TARGET UnleashedRecomp POST_BUILD
|
||||||
COMMAND_EXPAND_LISTS
|
COMMAND_EXPAND_LISTS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(COPY ${PACKAGE_PREFIX_DIR}/bin/dxil.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
target_link_libraries(UnleashedRecomp PRIVATE
|
target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
Microsoft::DirectX-Headers
|
Microsoft::DirectX-Headers
|
||||||
Microsoft::DirectX-Guids
|
Microsoft::DirectX-Guids
|
||||||
Microsoft::DirectX12-Agility
|
Microsoft::DirectX12-Agility
|
||||||
|
Microsoft::DirectXShaderCompiler
|
||||||
comctl32
|
comctl32
|
||||||
dxgi
|
dxgi
|
||||||
Vulkan::Headers
|
Vulkan::Headers
|
||||||
|
|
|
||||||
|
|
@ -464,9 +464,16 @@ static void DestructTempResources()
|
||||||
|
|
||||||
case ResourceType::VertexShader:
|
case ResourceType::VertexShader:
|
||||||
case ResourceType::PixelShader:
|
case ResourceType::PixelShader:
|
||||||
reinterpret_cast<GuestShader*>(resource)->~GuestShader();
|
{
|
||||||
|
const auto shader = reinterpret_cast<GuestShader*>(resource);
|
||||||
|
|
||||||
|
for (auto blob : shader->shaderBlobs)
|
||||||
|
blob->Release();
|
||||||
|
|
||||||
|
shader->~GuestShader();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_userHeap.Free(resource);
|
g_userHeap.Free(resource);
|
||||||
}
|
}
|
||||||
|
|
@ -2404,6 +2411,126 @@ static void ProcSetScissorRect(const RenderCommand& cmd)
|
||||||
SetDirtyValue<int32_t>(g_dirtyStates.scissorRect, g_scissorRect.right, args.right);
|
SetDirtyValue<int32_t>(g_dirtyStates.scissorRect, g_scissorRect.right, args.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IDxcCompiler3* g_dxcCompiler;
|
||||||
|
static IDxcLinker* g_dxcLinker;
|
||||||
|
static IDxcUtils* g_dxcUtils;
|
||||||
|
static ankerl::unordered_dense::set<uint32_t> g_compiledSpecConstantLibraryBlobs;
|
||||||
|
|
||||||
|
static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specConstants)
|
||||||
|
{
|
||||||
|
if (g_vulkan ||
|
||||||
|
guestShader->shaderCacheEntry == nullptr ||
|
||||||
|
guestShader->shaderCacheEntry->specConstantsMask == 0)
|
||||||
|
{
|
||||||
|
if (guestShader->shader == nullptr)
|
||||||
|
{
|
||||||
|
assert(guestShader->shaderCacheEntry != nullptr);
|
||||||
|
|
||||||
|
if (g_vulkan)
|
||||||
|
guestShader->shader = g_device->createShader(g_shaderCache.get() + guestShader->shaderCacheEntry->spirvOffset, guestShader->shaderCacheEntry->spirvSize, "main", RenderShaderFormat::SPIRV);
|
||||||
|
else
|
||||||
|
guestShader->shader = g_device->createShader(g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset, guestShader->shaderCacheEntry->dxilSize, "main", RenderShaderFormat::DXIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return guestShader->shader.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
specConstants &= guestShader->shaderCacheEntry->specConstantsMask;
|
||||||
|
|
||||||
|
auto& shader = guestShader->linkedShaders[specConstants];
|
||||||
|
if (shader == nullptr)
|
||||||
|
{
|
||||||
|
wchar_t specConstantsLibName[0x100];
|
||||||
|
swprintf_s(specConstantsLibName, L"SpecConstants_%d", specConstants);
|
||||||
|
|
||||||
|
if (!g_compiledSpecConstantLibraryBlobs.contains(specConstants))
|
||||||
|
{
|
||||||
|
if (g_dxcCompiler == nullptr)
|
||||||
|
{
|
||||||
|
HRESULT hr = DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&g_dxcCompiler));
|
||||||
|
assert(SUCCEEDED(hr) && g_dxcCompiler != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
char libraryHlsl[0x100];
|
||||||
|
sprintf_s(libraryHlsl, "export uint g_SpecConstants() { return %d; }", specConstants);
|
||||||
|
|
||||||
|
DxcBuffer buffer{};
|
||||||
|
buffer.Ptr = libraryHlsl;
|
||||||
|
buffer.Size = strlen(libraryHlsl);
|
||||||
|
|
||||||
|
const wchar_t* args[1];
|
||||||
|
args[0] = L"-T lib_6_3";
|
||||||
|
|
||||||
|
IDxcResult* result = nullptr;
|
||||||
|
HRESULT hr = g_dxcCompiler->Compile(&buffer, args, std::size(args), nullptr, IID_PPV_ARGS(&result));
|
||||||
|
assert(SUCCEEDED(hr) && result != nullptr);
|
||||||
|
|
||||||
|
if (g_dxcLinker == nullptr)
|
||||||
|
{
|
||||||
|
HRESULT hr = DxcCreateInstance(CLSID_DxcLinker, IID_PPV_ARGS(&g_dxcLinker));
|
||||||
|
assert(SUCCEEDED(hr) && g_dxcLinker != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDxcBlob* blob = nullptr;
|
||||||
|
hr = result->GetResult(&blob);
|
||||||
|
assert(SUCCEEDED(hr) && blob != nullptr);
|
||||||
|
|
||||||
|
g_dxcLinker->RegisterLibrary(specConstantsLibName, blob);
|
||||||
|
|
||||||
|
blob->Release();
|
||||||
|
result->Release();
|
||||||
|
|
||||||
|
g_compiledSpecConstantLibraryBlobs.emplace(specConstants);
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t shaderLibName[0x100];
|
||||||
|
swprintf_s(shaderLibName, L"Shader_%d", guestShader->shaderCacheEntry->dxilOffset);
|
||||||
|
|
||||||
|
if (!guestShader->libraryRegistered)
|
||||||
|
{
|
||||||
|
if (g_dxcUtils == nullptr)
|
||||||
|
{
|
||||||
|
HRESULT hr = DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&g_dxcUtils));
|
||||||
|
assert(SUCCEEDED(hr) && g_dxcUtils != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDxcBlobEncoding* blob = nullptr;
|
||||||
|
HRESULT hr = g_dxcUtils->CreateBlobFromPinned(
|
||||||
|
g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset,
|
||||||
|
guestShader->shaderCacheEntry->dxilSize,
|
||||||
|
DXC_CP_ACP,
|
||||||
|
&blob);
|
||||||
|
|
||||||
|
assert(SUCCEEDED(hr) && blob != nullptr);
|
||||||
|
|
||||||
|
g_dxcLinker->RegisterLibrary(shaderLibName, blob);
|
||||||
|
|
||||||
|
blob->Release();
|
||||||
|
|
||||||
|
guestShader->libraryRegistered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* libraryNames[] = { specConstantsLibName, shaderLibName };
|
||||||
|
|
||||||
|
IDxcOperationResult* result = nullptr;
|
||||||
|
HRESULT hr = g_dxcLinker->Link(L"main", guestShader->type == ResourceType::VertexShader ? L"vs_6_0" : L"ps_6_0",
|
||||||
|
libraryNames, std::size(libraryNames), nullptr, 0, &result);
|
||||||
|
|
||||||
|
assert(SUCCEEDED(hr) && result != nullptr);
|
||||||
|
|
||||||
|
IDxcBlob* blob = nullptr;
|
||||||
|
hr = result->GetResult(&blob);
|
||||||
|
assert(SUCCEEDED(hr) && blob != nullptr);
|
||||||
|
|
||||||
|
shader = g_device->createShader(blob->GetBufferPointer(), blob->GetBufferSize(), "main", RenderShaderFormat::DXIL);
|
||||||
|
guestShader->shaderBlobs.push_back(blob);
|
||||||
|
|
||||||
|
result->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader.get();
|
||||||
|
}
|
||||||
|
|
||||||
static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
|
static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
|
||||||
{
|
{
|
||||||
// Sanitize to prevent state leaking.
|
// Sanitize to prevent state leaking.
|
||||||
|
|
@ -2432,9 +2559,12 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
|
||||||
pipelineState.blendOpAlpha = RenderBlendOperation::ADD;
|
pipelineState.blendOpAlpha = RenderBlendOperation::ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t specConstantsMask = pipelineState.vertexShader->specConstantsMask;
|
uint32_t specConstantsMask = 0;
|
||||||
if (pipelineState.pixelShader != nullptr)
|
if (pipelineState.vertexShader->shaderCacheEntry != nullptr)
|
||||||
specConstantsMask |= pipelineState.pixelShader->specConstantsMask;
|
specConstantsMask |= pipelineState.vertexShader->shaderCacheEntry->specConstantsMask;
|
||||||
|
|
||||||
|
if (pipelineState.pixelShader != nullptr && pipelineState.pixelShader->shaderCacheEntry != nullptr)
|
||||||
|
specConstantsMask |= pipelineState.pixelShader->shaderCacheEntry->specConstantsMask;
|
||||||
|
|
||||||
pipelineState.specConstants &= specConstantsMask;
|
pipelineState.specConstants &= specConstantsMask;
|
||||||
|
|
||||||
|
|
@ -2443,8 +2573,8 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
|
||||||
{
|
{
|
||||||
RenderGraphicsPipelineDesc desc;
|
RenderGraphicsPipelineDesc desc;
|
||||||
desc.pipelineLayout = g_pipelineLayout.get();
|
desc.pipelineLayout = g_pipelineLayout.get();
|
||||||
desc.vertexShader = pipelineState.vertexShader->shader.get();
|
desc.vertexShader = GetOrLinkShader(pipelineState.vertexShader, pipelineState.specConstants);
|
||||||
desc.pixelShader = pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->shader.get() : nullptr;
|
desc.pixelShader = pipelineState.pixelShader != nullptr ? GetOrLinkShader(pipelineState.pixelShader, pipelineState.specConstants) : nullptr;
|
||||||
desc.depthFunction = pipelineState.zFunc;
|
desc.depthFunction = pipelineState.zFunc;
|
||||||
desc.depthEnabled = pipelineState.zEnable;
|
desc.depthEnabled = pipelineState.zEnable;
|
||||||
desc.depthWriteEnabled = pipelineState.zWriteEnable;
|
desc.depthWriteEnabled = pipelineState.zWriteEnable;
|
||||||
|
|
@ -3197,12 +3327,7 @@ static GuestShader* CreateShader(const be<uint32_t>* function, ResourceType reso
|
||||||
if (findResult->userData == nullptr)
|
if (findResult->userData == nullptr)
|
||||||
{
|
{
|
||||||
shader = g_userHeap.AllocPhysical<GuestShader>(resourceType);
|
shader = g_userHeap.AllocPhysical<GuestShader>(resourceType);
|
||||||
shader->specConstantsMask = findResult->specConstantsMask;
|
shader->shaderCacheEntry = findResult;
|
||||||
|
|
||||||
if (g_vulkan)
|
|
||||||
shader->shader = g_device->createShader(g_shaderCache.get() + findResult->spirvOffset, findResult->spirvSize, "main", RenderShaderFormat::SPIRV);
|
|
||||||
else
|
|
||||||
shader->shader = g_device->createShader(g_shaderCache.get() + findResult->dxilOffset, findResult->dxilSize, "main", RenderShaderFormat::DXIL);
|
|
||||||
|
|
||||||
findResult->userData = shader;
|
findResult->userData = shader;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,10 @@ struct GuestVertexDeclaration : GuestResource
|
||||||
struct GuestShader : GuestResource
|
struct GuestShader : GuestResource
|
||||||
{
|
{
|
||||||
std::unique_ptr<RenderShader> shader;
|
std::unique_ptr<RenderShader> shader;
|
||||||
uint32_t specConstantsMask = 0;
|
struct ShaderCacheEntry* shaderCacheEntry = nullptr;
|
||||||
|
ankerl::unordered_dense::map<uint32_t, std::unique_ptr<RenderShader>> linkedShaders;
|
||||||
|
std::vector<IDxcBlob*> shaderBlobs;
|
||||||
|
bool libraryRegistered = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GuestViewport
|
struct GuestViewport
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <dxcapi.h>
|
||||||
#include <ShlObj_core.h>
|
#include <ShlObj_core.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue