summaryrefslogtreecommitdiffstats
path: root/tools/gfx/renderer-shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gfx/renderer-shared.cpp')
-rw-r--r--tools/gfx/renderer-shared.cpp176
1 files changed, 174 insertions, 2 deletions
diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp
index 43629a0f2..8ed776776 100644
--- a/tools/gfx/renderer-shared.cpp
+++ b/tools/gfx/renderer-shared.cpp
@@ -3,6 +3,11 @@
#include "core/slang-io.h"
#include "core/slang-token-reader.h"
+#include "../../source/core/slang-file-system.h"
+
+#include "../../slang.h"
+#include "../../source/slang/slang-hash-utils.h"
+
using namespace Slang;
namespace gfx
@@ -23,6 +28,7 @@ const Slang::Guid GfxGUID::IID_IResource = SLANG_UUID_IResource;
const Slang::Guid GfxGUID::IID_IBufferResource = SLANG_UUID_IBufferResource;
const Slang::Guid GfxGUID::IID_ITextureResource = SLANG_UUID_ITextureResource;
const Slang::Guid GfxGUID::IID_IDevice = SLANG_UUID_IDevice;
+const Slang::Guid GfxGUID::IID_IShaderCacheStatistics = SLANG_UUID_IShaderCacheStatistics;
const Slang::Guid GfxGUID::IID_IShaderObject = SLANG_UUID_IShaderObject;
const Slang::Guid GfxGUID::IID_IRenderPassLayout = SLANG_UUID_IRenderPassLayout;
@@ -325,6 +331,129 @@ void PipelineStateBase::initializeBase(const PipelineStateDesc& inDesc)
}
}
+void updateCacheEntry(ISlangMutableFileSystem* fileSystem, slang::IBlob* compiledCode, String shaderFilename, slang::Digest ASTHash)
+{
+ auto hashSize = sizeof(slang::Digest);
+
+ auto bufferSize = hashSize + compiledCode->getBufferSize();
+ List<uint8_t> contents;
+ contents.setCount(bufferSize);
+ uint8_t* buffer = contents.begin();
+ memcpy(buffer, &ASTHash, hashSize);
+ memcpy(buffer + hashSize, (void*)compiledCode->getBufferPointer(), compiledCode->getBufferSize());
+ fileSystem->saveFile(shaderFilename.getBuffer(), buffer, bufferSize);
+}
+
+Result RendererBase::getEntryPointCodeFromShaderCache(
+ slang::IComponentType* program,
+ SlangInt entryPointIndex,
+ SlangInt targetIndex,
+ slang::IBlob** outCode,
+ slang::IBlob** outDiagnostics)
+{
+ // TODO: Need a way in filesystem to query both file size and file creation time, if cache size exceeds
+ // specified maximum size (in bytes or files) then delete oldest files - cache eviction policy
+
+ // Immediately call getEntryPointCode if no shader cache was provided on initialization
+ if (!shaderCacheFileSystem)
+ {
+ return program->getEntryPointCode(entryPointIndex, targetIndex, outCode, outDiagnostics);
+ }
+
+ // Produce a string which we can use to query the shader cache by combining two separate hashes which
+ // together comprise all the compilation arguments for this program.
+ ComPtr<slang::ISession> session;
+ getSlangSession(session.writeRef());
+
+ slang::Digest shaderKeyHash;
+ program->computeDependencyBasedHash(entryPointIndex, targetIndex, &shaderKeyHash);
+
+ StringBuilder shaderKey = hashToString(shaderKeyHash);
+
+ // Produce a hash using the AST for this program - This is needed to check whether a cache entry is effectively dirty,
+ // or to save along with the compiled code into an entry so the entry can be checked if fetched later on.
+ slang::Digest ASTHash;
+ program->computeASTBasedHash(&ASTHash);
+
+ ComPtr<ISlangBlob> codeBlob;
+
+ // Query shaderCacheFileSystem for an entry whose key matches shaderFilename
+ // - If we find it, then copy the file contents into memory and return in outCode
+ auto result = shaderCacheFileSystem->loadFile(shaderKey.getBuffer(), codeBlob.writeRef());
+
+ if (SLANG_FAILED(result))
+ {
+ // If we didn't find it, call program->getEntryPointCode() to get and return the code. We also
+ // make sure to save a new entry in the shader cache.
+ if (SLANG_SUCCEEDED(program->getEntryPointCode(entryPointIndex, targetIndex, codeBlob.writeRef(), outDiagnostics)))
+ {
+ if (mutableShaderCacheFileSystem)
+ {
+ updateCacheEntry(mutableShaderCacheFileSystem, codeBlob, shaderKey, ASTHash);
+ }
+
+ shaderCacheMissCount++;
+ }
+ else
+ {
+ // If getEntryPointCode() failed to fetch the code, we return SLANG_FAIL along with the diagnostics output
+ // in outDiagnostics.
+ return SLANG_FAIL;
+ }
+ }
+ else
+ {
+ // If the entry exists, we need to check that the entry isn't effectively dirty. Since we stored
+ // the AST hash with the compiled code, we can determine this by comparing the stored hash with the
+ // AST hash generated earlier.
+ auto entryContents = codeBlob->getBufferPointer();
+ auto hashSize = sizeof(slang::Digest);
+ if (memcmp(ASTHash.values, entryContents, hashSize) != 0)
+ {
+ // The AST hash stored in the entry does not match the AST hash generated earlier, indicating
+ // that the shader code has changed and the entry needs to be updated.
+ if (SLANG_SUCCEEDED(program->getEntryPointCode(entryPointIndex, targetIndex, codeBlob.writeRef(), outDiagnostics)))
+ {
+ if (mutableShaderCacheFileSystem)
+ {
+ updateCacheEntry(mutableShaderCacheFileSystem, codeBlob, shaderKey, ASTHash);
+ }
+
+ shaderCacheEntryDirtyCount++;
+ }
+ else
+ {
+ // If getEntryPointCode() failed to fetch the code, we return SLANG_FAIL along with the diagnostics output
+ // in outDiagnostics.
+ return SLANG_FAIL;
+ }
+ }
+ else
+ {
+ auto compiledCode = RawBlob::create((uint8_t*)codeBlob->getBufferPointer() + hashSize, codeBlob->getBufferSize() - hashSize);
+ codeBlob = compiledCode;
+
+ shaderCacheHitCount++;
+ }
+ }
+
+ *outCode = codeBlob.detach();
+ return SLANG_OK;
+}
+
+SlangResult RendererBase::queryInterface(SlangUUID const& uuid, void** outObject)
+{
+ if (uuid == GfxGUID::IID_IShaderCacheStatistics)
+ {
+ *outObject = static_cast<IShaderCacheStatistics*>(this);
+ addRef();
+ return SLANG_OK;
+ }
+
+ *outObject = getInterface(uuid);
+ return SLANG_OK;
+}
+
IDevice* gfx::RendererBase::getInterface(const Guid& guid)
{
return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IDevice)
@@ -334,6 +463,28 @@ IDevice* gfx::RendererBase::getInterface(const Guid& guid)
SLANG_NO_THROW Result SLANG_MCALL RendererBase::initialize(const Desc& desc)
{
+ // If a shader cache file system was provided, use the provided system.
+ if (desc.shaderCacheFileSystem)
+ {
+ shaderCacheFileSystem = desc.shaderCacheFileSystem;
+ }
+ if (desc.shaderCachePath)
+ {
+ // Only a path was provided, create a RelativeFileSystem using the path
+ if (!shaderCacheFileSystem)
+ {
+ shaderCacheFileSystem = OSFileSystem::getMutableSingleton();
+ }
+ shaderCacheFileSystem = new RelativeFileSystem(shaderCacheFileSystem, desc.shaderCachePath);
+ }
+
+ // If we initialized a file system for the shader cache, check if it's mutable. If so, store a pointer
+ // to the mutable version in order to save new entries later.
+ if (shaderCacheFileSystem)
+ {
+ shaderCacheFileSystem->queryInterface(ISlangMutableFileSystem::getTypeGuid(), (void**)mutableShaderCacheFileSystem.writeRef());
+ }
+
if (desc.apiCommandDispatcher)
{
desc.apiCommandDispatcher->queryInterface(
@@ -664,7 +815,28 @@ Result RendererBase::getShaderObjectLayout(
return SLANG_OK;
}
+GfxCount RendererBase::getCacheMissCount()
+{
+ return shaderCacheMissCount;
+}
+GfxCount RendererBase::getCacheHitCount()
+{
+ return shaderCacheHitCount;
+}
+
+GfxCount RendererBase::getCacheEntryDirtyCount()
+{
+ return shaderCacheEntryDirtyCount;
+}
+
+Result RendererBase::resetCacheStatistics()
+{
+ shaderCacheMissCount = 0;
+ shaderCacheHitCount = 0;
+ shaderCacheEntryDirtyCount = 0;
+ return SLANG_OK;
+}
ShaderComponentID ShaderCache::getComponentId(slang::TypeReflection* type)
{
@@ -908,7 +1080,7 @@ void ShaderProgramBase::init(const IShaderProgram::Desc& inDesc)
}
}
-Result ShaderProgramBase::compileShaders()
+Result ShaderProgramBase::compileShaders(RendererBase* device)
{
// For a fully specialized program, read and store its kernel code in `shaderProgram`.
auto compileShader = [&](slang::EntryPointReflection* entryPointInfo,
@@ -918,7 +1090,7 @@ Result ShaderProgramBase::compileShaders()
auto stage = entryPointInfo->getStage();
ComPtr<ISlangBlob> kernelCode;
ComPtr<ISlangBlob> diagnostics;
- auto compileResult = entryPointComponent->getEntryPointCode(
+ auto compileResult = device->getEntryPointCodeFromShaderCache(entryPointComponent,
entryPointIndex, 0, kernelCode.writeRef(), diagnostics.writeRef());
if (diagnostics)
{