mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-05 14:31:17 +12:00
use precompiled shaders
This commit is contained in:
parent
5f339e4243
commit
a8da524dd4
3 changed files with 152 additions and 57 deletions
|
@ -109,3 +109,53 @@ inline void executeCommand(fmt::format_string<T...> fmt, T&&... args) {
|
|||
if (res != 0)
|
||||
cemuLog_log(LogType::Force, "command \"{}\" failed with exit code {}", command, res);
|
||||
}
|
||||
|
||||
class MemoryMappedFile
|
||||
{
|
||||
public:
|
||||
MemoryMappedFile(const std::string& filePath)
|
||||
{
|
||||
// Open the file
|
||||
m_fd = open(filePath.c_str(), O_RDONLY);
|
||||
if (m_fd == -1) {
|
||||
cemuLog_log(LogType::Force, "failed to open file: {}", filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
struct stat fileStat;
|
||||
if (fstat(m_fd, &fileStat) == -1)
|
||||
{
|
||||
close(m_fd);
|
||||
cemuLog_log(LogType::Force, "failed to get file size: {}", filePath);
|
||||
return;
|
||||
}
|
||||
m_fileSize = fileStat.st_size;
|
||||
|
||||
// Memory map the file
|
||||
m_data = mmap(nullptr, m_fileSize, PROT_READ, MAP_PRIVATE, m_fd, 0);
|
||||
if (m_data == MAP_FAILED)
|
||||
{
|
||||
close(m_fd);
|
||||
cemuLog_log(LogType::Force, "failed to memory map file: {}", filePath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~MemoryMappedFile()
|
||||
{
|
||||
if (m_data && m_data != MAP_FAILED)
|
||||
munmap(m_data, m_fileSize);
|
||||
|
||||
if (m_fd != -1)
|
||||
close(m_fd);
|
||||
}
|
||||
|
||||
uint8* data() const { return static_cast<uint8*>(m_data); }
|
||||
size_t size() const { return m_fileSize; }
|
||||
|
||||
private:
|
||||
int m_fd = -1;
|
||||
void* m_data = nullptr;
|
||||
size_t m_fileSize = 0;
|
||||
};
|
||||
|
|
|
@ -128,7 +128,7 @@ void RendererShaderMtl::ShaderCacheLoading_end()
|
|||
// Close RAM filesystem
|
||||
if (s_hasRAMFilesystem)
|
||||
{
|
||||
executeCommand("diskutil eject {}", METAL_AIR_CACHE_PATH);
|
||||
//executeCommand("diskutil eject {}", METAL_AIR_CACHE_PATH);
|
||||
s_hasRAMFilesystem = false;
|
||||
}
|
||||
|
||||
|
@ -211,50 +211,8 @@ bool RendererShaderMtl::ShouldCountCompilation() const
|
|||
return !s_isLoadingShadersMtl && m_isGameShader;
|
||||
}
|
||||
|
||||
void RendererShaderMtl::CompileInternal()
|
||||
MTL::Library* RendererShaderMtl::LibraryFromSource()
|
||||
{
|
||||
// First, try to retrieve the compiled shader from the AIR cache
|
||||
if (s_isLoadingShadersMtl && (m_isGameShader && !m_isGfxPackShader) && s_airCache)
|
||||
{
|
||||
cemu_assert_debug(m_baseHash != 0);
|
||||
uint64 h1, h2;
|
||||
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
|
||||
std::vector<uint8> cacheFileData;
|
||||
if (s_airCache->GetFile({ h1, h2 }, cacheFileData))
|
||||
{
|
||||
CompileFromAIR(std::span<uint8>(cacheFileData.data(), cacheFileData.size()));
|
||||
FinishCompilation();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure that RAM filesystem exists
|
||||
if (!s_hasRAMFilesystem)
|
||||
{
|
||||
s_hasRAMFilesystem = true;
|
||||
executeCommand("diskutil erasevolume HFS+ {} $(hdiutil attach -nomount ram://{})", METAL_AIR_CACHE_NAME, METAL_AIR_CACHE_BLOCK_COUNT);
|
||||
}
|
||||
|
||||
// The shader is not in the cache, compile it
|
||||
std::string filename = fmt::format("{}_{}", h1, h2);
|
||||
// TODO: store the source
|
||||
executeCommand("xcrun -sdk macosx metal -o {}.ir -c {}.metal", filename, filename);
|
||||
executeCommand("xcrun -sdk macosx metallib -o {}.metallib {}.ir", filename, filename);
|
||||
// TODO: clean up
|
||||
|
||||
// Load from the newly Generated AIR
|
||||
// std::span<uint8> airData = ;
|
||||
//CompileFromAIR(std::span<uint8>((uint8*)cacheFileData.data(), cacheFileData.size() / sizeof(uint8)));
|
||||
FinishCompilation();
|
||||
|
||||
// Store in the cache
|
||||
uint64 h1, h2;
|
||||
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
|
||||
//s_airCache->AddFile({ h1, h2 }, airData.data(), airData.size());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compile from source
|
||||
MTL::CompileOptions* options = MTL::CompileOptions::alloc()->init();
|
||||
// TODO: always disable fast math for problematic shaders
|
||||
|
@ -266,28 +224,113 @@ void RendererShaderMtl::CompileInternal()
|
|||
NS::Error* error = nullptr;
|
||||
MTL::Library* library = m_mtlr->GetDevice()->newLibrary(ToNSString(m_mslCode), options, &error);
|
||||
options->release();
|
||||
FinishCompilation();
|
||||
if (error)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "failed to create library: {} -> {}", error->localizedDescription()->utf8String(), m_mslCode.c_str());
|
||||
FinishCompilation();
|
||||
return;
|
||||
cemuLog_log(LogType::Force, "failed to create library from source: {} -> {}", error->localizedDescription()->utf8String(), m_mslCode.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
MTL::Library* RendererShaderMtl::LibraryFromAIR(std::span<uint8> data)
|
||||
{
|
||||
dispatch_data_t dispatchData = dispatch_data_create(data.data(), data.size(), nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
MTL::Library* library = m_mtlr->GetDevice()->newLibrary(dispatchData, &error);
|
||||
FinishCompilation();
|
||||
printf("AIR size: %zu\n", data.size());
|
||||
if (error)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "failed to create library from AIR: {}", error->localizedDescription()->utf8String());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
void RendererShaderMtl::CompileInternal()
|
||||
{
|
||||
MTL::Library* library;
|
||||
|
||||
// First, try to retrieve the compiled shader from the AIR cache
|
||||
if (s_isLoadingShadersMtl && (m_isGameShader && !m_isGfxPackShader) && s_airCache)
|
||||
{
|
||||
cemu_assert_debug(m_baseHash != 0);
|
||||
uint64 h1, h2;
|
||||
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
|
||||
std::vector<uint8> cacheFileData;
|
||||
if (s_airCache->GetFile({ h1, h2 }, cacheFileData))
|
||||
{
|
||||
library = LibraryFromAIR(std::span<uint8>(cacheFileData.data(), cacheFileData.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure that RAM filesystem exists
|
||||
static std::atomic<bool> s_creatingRAMFilesystem{false};
|
||||
if (!s_hasRAMFilesystem)
|
||||
{
|
||||
if (s_creatingRAMFilesystem)
|
||||
{
|
||||
while (!s_hasRAMFilesystem)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
else
|
||||
{
|
||||
s_creatingRAMFilesystem = true;
|
||||
executeCommand("diskutil erasevolume HFS+ {} $(hdiutil attach -nomount ram://{})", METAL_AIR_CACHE_NAME, METAL_AIR_CACHE_BLOCK_COUNT);
|
||||
s_creatingRAMFilesystem = false;
|
||||
}
|
||||
s_hasRAMFilesystem = true;
|
||||
}
|
||||
|
||||
// The shader is not in the cache, compile it
|
||||
std::string baseFilename = fmt::format("{}/{}_{}", METAL_AIR_CACHE_PATH, h1, h2);
|
||||
|
||||
// Source
|
||||
std::ofstream mslFile;
|
||||
mslFile.open(fmt::format("{}.metal", baseFilename));
|
||||
mslFile << m_mslCode;
|
||||
mslFile.close();
|
||||
|
||||
// Compile
|
||||
executeCommand("xcrun -sdk macosx metal -o {}.ir -c {}.metal -Wno-unused-variable -Wno-sign-compare", baseFilename, baseFilename);
|
||||
executeCommand("xcrun -sdk macosx metallib -o {}.metallib {}.ir", baseFilename, baseFilename);
|
||||
|
||||
// Clean up
|
||||
executeCommand("rm {}.metal", baseFilename);
|
||||
executeCommand("rm {}.ir", baseFilename);
|
||||
|
||||
// Load from the newly Generated AIR
|
||||
MemoryMappedFile airFile(fmt::format("{}.metallib", baseFilename));
|
||||
std::span<uint8> airData = std::span<uint8>(airFile.data(), airFile.size());
|
||||
library = LibraryFromAIR(std::span<uint8>(cacheFileData.data(), cacheFileData.size()));
|
||||
|
||||
// Store in the cache
|
||||
uint64 h1, h2;
|
||||
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
|
||||
s_airCache->AddFile({ h1, h2 }, airData.data(), airData.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compile from source
|
||||
library = LibraryFromSource();
|
||||
}
|
||||
|
||||
if (!library)
|
||||
return;
|
||||
|
||||
m_function = library->newFunction(ToNSString("main0"));
|
||||
library->release();
|
||||
|
||||
FinishCompilation();
|
||||
|
||||
// Count shader compilation
|
||||
if (ShouldCountCompilation())
|
||||
g_compiled_shaders_total++;
|
||||
}
|
||||
|
||||
void RendererShaderMtl::CompileFromAIR(std::span<uint8> data)
|
||||
{
|
||||
// TODO: implement this
|
||||
printf("LOADING SHADER FROM AIR CACHE\n");
|
||||
}
|
||||
|
||||
void RendererShaderMtl::FinishCompilation()
|
||||
{
|
||||
m_mslCode.clear();
|
||||
|
|
|
@ -67,9 +67,11 @@ private:
|
|||
|
||||
bool ShouldCountCompilation() const;
|
||||
|
||||
void CompileInternal();
|
||||
MTL::Library* LibraryFromSource();
|
||||
|
||||
void CompileFromAIR(std::span<uint8> data);
|
||||
MTL::Library* LibraryFromAIR(std::span<uint8> data);
|
||||
|
||||
void CompileInternal();
|
||||
|
||||
void FinishCompilation();
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue