Revert "Switch persistent cache to use SkReadBuffer/SkWriteBuffer"

This reverts commit 5fa11d4040.

Reason for revert: breaking some compiles..

https://chromium-swarm.appspot.com/task?id=4cb41acadb936310

Original change's description:
> Switch persistent cache to use SkReadBuffer/SkWriteBuffer
> 
> These are much safer than SkReader32/SkWriter32 (they do validation and
> ensure we never read past the end of the buffer).
> 
> Where we used to just assert that the contents of the cache were valid,
> we now validate everything, and fail gracefully by discarding the cache
> contents if it's corrupted or invalid.
> 
> Bug: skia:9402
> Change-Id: Ib893681f97f9413c28744f11075dc2e392364db6
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/294998
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Osman <brianosman@google.com>

TBR=egdaniel@google.com,jvanverth@google.com,bsalomon@google.com,brianosman@google.com

Change-Id: Iabea26cde82043e3f3a23cde81503ea3abdd8398
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:9402
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/295394
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-06-10 00:19:34 +00:00
parent 437c78593c
commit 90e82904b5
11 changed files with 102 additions and 133 deletions

View File

@ -32,8 +32,6 @@ public:
SkReadBuffer();
SkReadBuffer(const void* data, size_t size);
void setMemory(const void*, size_t);
/**
* Returns true IFF the version is older than the specified version.
*/
@ -196,6 +194,7 @@ private:
void setInvalid();
bool readArray(void* value, size_t size, size_t elementSize);
void setMemory(const void*, size_t);
SkReader32 fReader;

View File

@ -122,7 +122,6 @@ public:
bool writeToStream(SkWStream*) const;
void writeToMemory(void* dst) const { fWriter.flatten(dst); }
sk_sp<SkData> snapshotAsData() const { return fWriter.snapshotAsData(); }
void setFactoryRecorder(sk_sp<SkFactorySet>);
void setTypefaceRecorder(sk_sp<SkRefCntSet>);

View File

@ -10,8 +10,8 @@
#include "include/core/SkData.h"
#include "include/private/GrTypesPriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/core/SkReader32.h"
#include "src/core/SkWriter32.h"
#include "src/sksl/SkSLString.h"
#include "src/sksl/ir/SkSLProgram.h"
@ -28,7 +28,7 @@ struct ShaderMetadata {
};
// Increment this whenever the serialization format of cached shaders changes
static constexpr int kCurrentVersion = 2;
static constexpr int kCurrentVersion = 1;
static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
const SkSL::String shaders[],
@ -39,12 +39,12 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
// kGrShaderTypeCount inputs. If the backend gives us fewer, we just replicate the last one.
SkASSERT(numInputs >= 1 && numInputs <= kGrShaderTypeCount);
SkBinaryWriteBuffer writer;
writer.writeInt(kCurrentVersion);
writer.writeUInt(shaderType);
SkWriter32 writer;
writer.write32(kCurrentVersion);
writer.write32(shaderType);
for (int i = 0; i < kGrShaderTypeCount; ++i) {
writer.writeByteArray(shaders[i].c_str(), shaders[i].size());
writer.writePad32(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs));
writer.writeString(shaders[i].c_str(), shaders[i].size());
writer.writePad(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs));
}
writer.writeBool(SkToBool(meta));
if (meta) {
@ -57,7 +57,7 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
writer.writeInt(meta->fAttributeNames.count());
for (const auto& attr : meta->fAttributeNames) {
writer.writeByteArray(attr.c_str(), attr.size());
writer.writeString(attr.c_str(), attr.size());
}
writer.writeBool(meta->fHasCustomColorOutput);
@ -66,26 +66,30 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
return writer.snapshotAsData();
}
static SkFourByteTag GetType(SkReadBuffer* reader) {
static SkFourByteTag GetType(SkReader32* reader) {
constexpr SkFourByteTag kInvalidTag = ~0;
int version = reader->readInt();
SkFourByteTag typeTag = reader->readUInt();
return reader->validate(version == kCurrentVersion) ? typeTag : kInvalidTag;
if (!reader->isAvailable(2 * sizeof(int))) {
return kInvalidTag;
}
if (reader->readInt() != kCurrentVersion) {
return kInvalidTag;
}
return reader->readU32();
}
static inline bool UnpackCachedShaders(SkReadBuffer* reader,
static inline void UnpackCachedShaders(SkReader32* reader,
SkSL::String shaders[],
SkSL::Program::Inputs inputs[],
int numInputs,
ShaderMetadata* meta = nullptr) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
uint32_t shaderLen = reader->getArrayCount();
shaders[i].resize(shaderLen);
reader->readByteArray(shaders[i].data(), shaderLen);
size_t stringLen = 0;
const char* string = reader->readString(&stringLen);
shaders[i] = SkSL::String(string, stringLen);
// GL, for example, only wants one set of Inputs
if (i < numInputs) {
reader->readPad32(&inputs[i], sizeof(inputs[i]));
reader->read(&inputs[i], sizeof(inputs[i]));
} else {
reader->skip(sizeof(SkSL::Program::Inputs));
}
@ -100,22 +104,15 @@ static inline bool UnpackCachedShaders(SkReadBuffer* reader,
}
meta->fAttributeNames.resize(reader->readInt());
for (auto& attr : meta->fAttributeNames) {
uint32_t attrLen = reader->getArrayCount();
attr.resize(attrLen);
reader->readByteArray(attr.data(), attrLen);
for (int i = 0; i < meta->fAttributeNames.count(); ++i) {
size_t stringLen = 0;
const char* string = reader->readString(&stringLen);
meta->fAttributeNames[i] = SkSL::String(string, stringLen);
}
meta->fHasCustomColorOutput = reader->readBool();
meta->fHasSecondaryColorOutput = reader->readBool();
}
if (!reader->isValid()) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
shaders[i].clear();
}
}
return reader->isValid();
}
}

View File

@ -18,6 +18,7 @@
class GrProgramDesc;
class GrD3DGpu;
class GrVkRenderPass;
class SkReader32;
class GrD3DPipelineStateBuilder : public GrGLSLProgramBuilder {
public:

View File

@ -10,9 +10,9 @@
#include "include/gpu/GrContext.h"
#include "src/core/SkATrace.h"
#include "src/core/SkAutoMalloc.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkReader32.h"
#include "src/core/SkTraceEvent.h"
#include "src/core/SkWriteBuffer.h"
#include "src/core/SkWriter32.h"
#include "src/gpu/GrAutoLocaleSetter.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrCoordTransform.h"
@ -166,19 +166,17 @@ void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs,
GrGLsizei length = 0;
GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
if (length > 0) {
SkBinaryWriteBuffer writer;
writer.writeInt(GrPersistentCacheUtils::kCurrentVersion);
writer.writeUInt(kGLPB_Tag);
SkWriter32 writer;
writer.write32(GrPersistentCacheUtils::kCurrentVersion);
writer.write32(kGLPB_Tag);
writer.writePad32(&inputs, sizeof(inputs));
writer.writePad(&inputs, sizeof(inputs));
writer.write32(length);
SkAutoSMalloc<2048> binary(length);
void* binary = writer.reservePad(length);
GrGLenum binaryFormat;
GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
writer.writeUInt(binaryFormat);
writer.writeInt(length);
writer.writePad32(binary.get(), length);
GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary));
writer.write32(binaryFormat);
auto data = writer.snapshotAsData();
this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
@ -257,7 +255,7 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr
usedProgramBinaries = true;
} else if (cached) {
ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_hit");
SkReadBuffer reader(fCached->data(), fCached->size());
SkReader32 reader(fCached->data(), fCached->size());
SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
switch (shaderType) {
@ -268,13 +266,10 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr
cached = false;
break;
}
reader.readPad32(&inputs, sizeof(inputs));
GrGLenum binaryFormat = reader.readUInt();
GrGLsizei length = reader.readInt();
reader.read(&inputs, sizeof(inputs));
GrGLsizei length = reader.readInt();
const void* binary = reader.skip(length);
if (!reader.isValid()) {
break;
}
GrGLenum binaryFormat = reader.readU32();
GrGLClearErr(this->gpu()->glInterface());
GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
ProgramBinary(programID, binaryFormat,
@ -301,21 +296,17 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr
case kSKSL_Tag:
// SkSL cache hit, this should only happen in tools overriding the generated SkSL
if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1)) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1);
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
break;
default:
// We got something invalid, so pretend it wasn't there
reader.validate(false);
cached = false;
break;
}
if (!reader.isValid()) {
cached = false;
}
}
if (!usedProgramBinaries) {
ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_miss");
@ -569,7 +560,7 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) {
bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledProgram,
GrGLGpu* gpu,
const SkData& cachedData) {
SkReadBuffer reader(cachedData.data(), cachedData.size());
SkReader32 reader(cachedData.data(), cachedData.size());
SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
if (shaderType != kSKSL_Tag) {
// TODO: Support GLSL, and maybe even program binaries, too?
@ -578,6 +569,13 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr
const GrGLInterface* gl = gpu->glInterface();
auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler();
GrGLuint programID;
GR_GL_CALL_RET(gl, programID, CreateProgram());
if (0 == programID) {
return false;
}
SkTDArray<GrGLuint> shadersToDelete;
SkSL::Program::Settings settings;
const GrGLCaps& caps = gpu->glCaps();
@ -588,17 +586,7 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs;
if (!GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta)) {
return false;
}
GrGLuint programID;
GR_GL_CALL_RET(gl, programID, CreateProgram());
if (0 == programID) {
return false;
}
SkTDArray<GrGLuint> shadersToDelete;
GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta);
auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
SkSL::String glsl;

View File

@ -21,7 +21,7 @@ class GrProgramInfo;
class GrMtlCaps;
class GrMtlGpu;
class GrMtlPipelineState;
class SkReadBuffer;
class SkReader32;
class GrMtlPipelineStateBuilder : public GrGLSLProgramBuilder {
public:
@ -58,7 +58,7 @@ private:
SkSL::Program::Inputs inputs);
void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[],
bool isSkSL);
bool loadShadersFromCache(SkReadBuffer* cached, __strong id<MTLLibrary> outLibraries[]);
void loadShadersFromCache(SkReader32* cached, __strong id<MTLLibrary> outLibraries[]);
GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }

View File

@ -8,7 +8,7 @@
#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
#include "include/gpu/GrContext.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkReader32.h"
#include "src/core/SkTraceEvent.h"
#include "src/gpu/GrAutoLocaleSetter.h"
#include "src/gpu/GrContextPriv.h"
@ -66,14 +66,12 @@ static constexpr SkFourByteTag kMSL_Tag = SkSetFourByteTag('M', 'S', 'L', ' ');
static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
bool GrMtlPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
void GrMtlPipelineStateBuilder::loadShadersFromCache(SkReader32* cached,
__strong id<MTLLibrary> outLibraries[]) {
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs[kGrShaderTypeCount];
if (!GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount)) {
return false;
}
GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount);
outLibraries[kVertex_GrShaderType] = this->compileMtlShaderLibrary(
shaders[kVertex_GrShaderType],
@ -82,9 +80,11 @@ bool GrMtlPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
shaders[kFragment_GrShaderType],
inputs[kFragment_GrShaderType]);
return outLibraries[kVertex_GrShaderType] &&
outLibraries[kFragment_GrShaderType] &&
shaders[kGeometry_GrShaderType].empty(); // Geometry shaders are not supported
// Geometry shaders are not supported
SkASSERT(shaders[kGeometry_GrShaderType].empty());
SkASSERT(outLibraries[kVertex_GrShaderType]);
SkASSERT(outLibraries[kFragment_GrShaderType]);
}
void GrMtlPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[],
@ -399,7 +399,7 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa
SkASSERT(!this->fragColorIsInOut());
sk_sp<SkData> cached;
SkReadBuffer reader;
SkReader32 reader;
SkFourByteTag shaderType = 0;
auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
if (persistentCache) {
@ -414,10 +414,10 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa
}
}
if (kMSL_Tag == shaderType && this->loadShadersFromCache(&reader, shaderLibraries)) {
// We successfully loaded and compiled MSL
SkSL::String shaders[kGrShaderTypeCount];
if (kMSL_Tag == shaderType) {
this->loadShadersFromCache(&reader, shaderLibraries);
} else {
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs[kGrShaderTypeCount];
SkSL::String* sksl[kGrShaderTypeCount] = {
@ -427,11 +427,10 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa
};
SkSL::String cached_sksl[kGrShaderTypeCount];
if (kSKSL_Tag == shaderType) {
if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
kGrShaderTypeCount)) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
kGrShaderTypeCount);
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
}

View File

@ -100,49 +100,39 @@ bool GrVkPipelineStateBuilder::installVkShaderModule(VkShaderStageFlagBits stage
static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V');
static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
int GrVkPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
int GrVkPipelineStateBuilder::loadShadersFromCache(SkReader32* cached,
VkShaderModule outShaderModules[],
VkPipelineShaderStageCreateInfo* outStageInfo) {
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs[kGrShaderTypeCount];
if (!GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount)) {
return 0;
}
GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount);
bool success = this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
fVS,
&outShaderModules[kVertex_GrShaderType],
&outStageInfo[0],
shaders[kVertex_GrShaderType],
inputs[kVertex_GrShaderType]);
inputs[kVertex_GrShaderType]));
success = success && this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
fFS,
&outShaderModules[kFragment_GrShaderType],
&outStageInfo[1],
shaders[kFragment_GrShaderType],
inputs[kFragment_GrShaderType]);
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
fFS,
&outShaderModules[kFragment_GrShaderType],
&outStageInfo[1],
shaders[kFragment_GrShaderType],
inputs[kFragment_GrShaderType]));
if (!shaders[kGeometry_GrShaderType].empty()) {
success = success && this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
fGS,
&outShaderModules[kGeometry_GrShaderType],
&outStageInfo[2],
shaders[kGeometry_GrShaderType],
inputs[kGeometry_GrShaderType]);
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
fGS,
&outShaderModules[kGeometry_GrShaderType],
&outStageInfo[2],
shaders[kGeometry_GrShaderType],
inputs[kGeometry_GrShaderType]));
return 3;
} else {
return 2;
}
if (!success) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
if (outShaderModules[i]) {
GR_VK_CALL(fGpu->vkInterface(),
DestroyShaderModule(fGpu->device(), outShaderModules[i], nullptr));
}
}
return 0;
}
return shaders[kGeometry_GrShaderType].empty() ? 2 : 3;
}
void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[],
@ -221,7 +211,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
SkASSERT(!this->fragColorIsInOut());
sk_sp<SkData> cached;
SkReadBuffer reader;
SkReader32 reader;
SkFourByteTag shaderType = 0;
auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
if (persistentCache) {
@ -241,10 +231,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
int numShaderStages = 0;
if (kSPIRV_Tag == shaderType) {
numShaderStages = this->loadShadersFromCache(&reader, shaderModules, shaderStageInfo);
}
// Proceed from sources if we didn't get a SPIRV cache (or the cache was invalid)
if (!numShaderStages) {
} else {
numShaderStages = 2; // We always have at least vertex and fragment stages.
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs[kGrShaderTypeCount];
@ -256,11 +243,10 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
};
SkSL::String cached_sksl[kGrShaderTypeCount];
if (kSKSL_Tag == shaderType) {
if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
kGrShaderTypeCount)) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
kGrShaderTypeCount);
for (int i = 0; i < kGrShaderTypeCount; ++i) {
sksl[i] = &cached_sksl[i];
}
}

View File

@ -19,7 +19,7 @@
class GrProgramDesc;
class GrVkGpu;
class GrVkRenderPass;
class SkReadBuffer;
class SkReader32;
class GrVkPipelineStateBuilder : public GrGLSLProgramBuilder {
public:
@ -48,7 +48,7 @@ private:
GrVkPipelineState* finalize(const GrProgramDesc&, VkRenderPass compatibleRenderPass);
// returns number of shader stages
int loadShadersFromCache(SkReadBuffer* cached, VkShaderModule outShaderModules[],
int loadShadersFromCache(SkReader32* cached, VkShaderModule outShaderModules[],
VkPipelineShaderStageCreateInfo* outStageInfo);
void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[],

View File

@ -97,7 +97,7 @@ void MemoryCache::writeShadersToDisk(const char* path, GrBackendApi api) {
// Even with the SPIR-V switches, it seems like we must use .spv, or malisc tries to
// run glslang on the input.
const char* ext = GrBackendApi::kOpenGL == api ? "frag" : "spv";
SkReadBuffer reader(data->data(), data->size());
SkReader32 reader(data->data(), data->size());
GrPersistentCacheUtils::GetType(&reader); // Shader type tag
GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders,
inputsIgnored, kGrShaderTypeCount);

View File

@ -2223,7 +2223,7 @@ void Viewer::drawImGui() {
entry.fKeyString.appendf("%02x", digest.data[i]);
}
SkReadBuffer reader(data->data(), data->size());
SkReader32 reader(data->data(), data->size());
entry.fShaderType = GrPersistentCacheUtils::GetType(&reader);
GrPersistentCacheUtils::UnpackCachedShaders(&reader, entry.fShader,
entry.fInputs,