public static LambdaExpression MakeLambda(Expression expression, TranslatorContext context) { var tupleParameter = Expression.Parameter(typeof(Tuple), "tuple"); var visitor = new ExpressionMaterializer(tupleParameter, context, null, EnumerableUtils <Parameter <Tuple> > .Empty); var processedExpression = OwnerRemover.RemoveOwner(expression); return(FastExpression.Lambda(visitor.Visit(processedExpression), tupleParameter)); }
/// <summary> /// Create guest shader cache entries from the runtime contexts. /// </summary> /// <param name="memoryManager">The GPU memory manager in use</param> /// <param name="shaderContexts">The runtime contexts</param> /// <returns>Guest shader cahe entries from the runtime contexts</returns> public static GuestShaderCacheEntry[] CreateShaderCacheEntries(MemoryManager memoryManager, ReadOnlySpan <TranslatorContext> shaderContexts) { int startIndex = shaderContexts.Length > 1 ? 1 : 0; GuestShaderCacheEntry[] entries = new GuestShaderCacheEntry[shaderContexts.Length - startIndex]; for (int i = startIndex; i < shaderContexts.Length; i++) { TranslatorContext context = shaderContexts[i]; if (context == null) { continue; } TranslatorContext translatorContext2 = i == 1 ? shaderContexts[0] : null; int sizeA = translatorContext2 != null ? translatorContext2.Size : 0; byte[] code = new byte[context.Size + sizeA]; memoryManager.GetSpan(context.Address, context.Size).CopyTo(code); if (translatorContext2 != null) { memoryManager.GetSpan(translatorContext2.Address, sizeA).CopyTo(code.AsSpan().Slice(context.Size, sizeA)); } GuestGpuAccessorHeader gpuAccessorHeader = CreateGuestGpuAccessorCache(context.GpuAccessor); if (context.GpuAccessor is GpuAccessor) { gpuAccessorHeader.TextureDescriptorCount = context.TextureHandlesForCache.Count; } GuestShaderCacheEntryHeader header = new GuestShaderCacheEntryHeader(context.Stage, context.Size, sizeA, gpuAccessorHeader); GuestShaderCacheEntry entry = new GuestShaderCacheEntry(header, code); if (context.GpuAccessor is GpuAccessor gpuAccessor) { foreach (int textureHandle in context.TextureHandlesForCache) { GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle, -1)).ToCache(); textureDescriptor.Handle = (uint)textureHandle; entry.TextureDescriptors.Add(textureHandle, textureDescriptor); } } entries[i - startIndex] = entry; } return(entries); }
// ReSharper restore UnusedMember.Local #endregion // Constructors private ExpressionMaterializer(ParameterExpression tupleParameter, TranslatorContext context, ParameterExpression itemMaterializationContextParameter, IEnumerable <Parameter <Tuple> > tupleParameters) { this.itemMaterializationContextParameter = itemMaterializationContextParameter; this.tupleParameter = tupleParameter; this.context = context; this.tupleParameters = new HashSet <Parameter <Tuple> >(tupleParameters); }
/// <summary> /// Translates a previously generated translator context to something that the host API accepts. /// </summary> /// <param name="dumper">Optional shader code dumper</param> /// <param name="memoryManager">Memory manager used to access the GPU memory where the shader is located</param> /// <param name="stages">Translator context of all available shader stages</param> /// <param name="stageIndex">Index on the stages array to translate</param> /// <returns>Compiled graphics shader code</returns> private static ShaderCodeHolder TranslateShader( ShaderDumper dumper, MemoryManager memoryManager, TranslatorContext[] stages, int stageIndex) { TranslatorContext currentStage = stages[stageIndex]; TranslatorContext nextStage = GetNextStageContext(stages, stageIndex); TranslatorContext vertexA = stageIndex == 1 ? stages[0] : null; return(TranslateShader(dumper, memoryManager, currentStage, nextStage, vertexA)); }
// Constructors public ItemProjectorExpression(Expression expression, CompilableProvider dataSource, TranslatorContext context) : base(ExtendedExpressionType.ItemProjector, expression.Type) { DataSource = dataSource; Context = context; var newApplyParameter = Context.GetApplyParameter(dataSource); var applyParameterReplacer = new ExtendedExpressionReplacer(ex => ex is SubQueryExpression ? ((SubQueryExpression)ex).ReplaceApplyParameter(newApplyParameter) : null); Item = applyParameterReplacer.Replace(expression); }
/// <summary> /// Recompiles a compute program from guest code. /// </summary> /// <param name="shaders">Shader stages</param> /// <param name="specState">Specialization state</param> /// <param name="programIndex">Program index</param> private void RecompileComputeFromGuestCode(CachedShaderStage[] shaders, ShaderSpecializationState specState, int programIndex) { CachedShaderStage shader = shaders[0]; ResourceCounts counts = new ResourceCounts(); ShaderSpecializationState newSpecState = new ShaderSpecializationState(specState.ComputeState); DiskCacheGpuAccessor gpuAccessor = new DiskCacheGpuAccessor(_context, shader.Code, shader.Cb1Data, specState, newSpecState, counts, 0); TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, 0); ShaderProgram program = translatorContext.Translate(); shaders[0] = new CachedShaderStage(program.Info, shader.Code, shader.Cb1Data); _compilationQueue.Enqueue(new ProgramCompilation(new[] { program }, shaders, newSpecState, programIndex, isCompute: true)); }
/// <summary> /// Translates a previously generated translator context to something that the host API accepts. /// </summary> /// <param name="memoryManager">Memory manager used to access the GPU memory where the shader is located</param> /// <param name="translatorContext">Current translator context to translate</param> /// <param name="translatorContext2">Optional translator context of the shader that should be combined</param> /// <returns>Compiled graphics shader code</returns> private ShaderCodeHolder TranslateShader( MemoryManager memoryManager, TranslatorContext translatorContext, TranslatorContext translatorContext2 = null) { if (translatorContext == null) { return(null); } if (translatorContext2 != null) { byte[] codeA = memoryManager.GetSpan(translatorContext2.Address, translatorContext2.Size).ToArray(); byte[] codeB = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray(); _dumper.Dump(codeA, compute: false, out string fullPathA, out string codePathA); _dumper.Dump(codeB, compute: false, out string fullPathB, out string codePathB); ShaderProgram program = translatorContext.Translate(out ShaderProgramInfo shaderProgramInfo, translatorContext2); if (fullPathA != null && fullPathB != null && codePathA != null && codePathB != null) { program.Prepend("// " + codePathB); program.Prepend("// " + fullPathB); program.Prepend("// " + codePathA); program.Prepend("// " + fullPathA); } return(new ShaderCodeHolder(program, shaderProgramInfo, codeB, codeA)); } else { byte[] code = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray(); _dumper.Dump(code, translatorContext.Stage == ShaderStage.Compute, out string fullPath, out string codePath); ShaderProgram program = translatorContext.Translate(out ShaderProgramInfo shaderProgramInfo); if (fullPath != null && codePath != null) { program.Prepend("// " + codePath); program.Prepend("// " + fullPath); } return(new ShaderCodeHolder(program, shaderProgramInfo, code)); } }
/// <summary> /// Translates a previously generated translator context to something that the host API accepts. /// </summary> /// <param name="dumper">Optional shader code dumper</param> /// <param name="memoryManager">Memory manager used to access the GPU memory where the shader is located</param> /// <param name="currentStage">Translator context of the stage to be translated</param> /// <param name="nextStage">Translator context of the next active stage, if existent</param> /// <param name="vertexA">Optional translator context of the shader that should be combined</param> /// <returns>Compiled graphics shader code</returns> private static ShaderCodeHolder TranslateShader( ShaderDumper dumper, MemoryManager memoryManager, TranslatorContext currentStage, TranslatorContext nextStage, TranslatorContext vertexA) { if (currentStage == null) { return(null); } if (vertexA != null) { byte[] codeA = memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray(); byte[] codeB = memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray(); ShaderDumpPaths pathsA = default; ShaderDumpPaths pathsB = default; if (dumper != null) { pathsA = dumper.Dump(codeA, compute: false); pathsB = dumper.Dump(codeB, compute: false); } ShaderProgram program = currentStage.Translate(out ShaderProgramInfo shaderProgramInfo, nextStage, vertexA); pathsB.Prepend(program); pathsA.Prepend(program); return(new ShaderCodeHolder(program, shaderProgramInfo, codeB, codeA)); } else { byte[] code = memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray(); ShaderDumpPaths paths = dumper?.Dump(code, currentStage.Stage == ShaderStage.Compute) ?? default; ShaderProgram program = currentStage.Translate(out ShaderProgramInfo shaderProgramInfo, nextStage); paths.Prepend(program); return(new ShaderCodeHolder(program, shaderProgramInfo, code)); } }
/// <summary> /// Gets a graphics shader program from the shader cache. /// This includes all the specified shader stages. /// </summary> /// <remarks> /// This automatically translates, compiles and adds the code to the cache if not present. /// </remarks> /// <param name="state">GPU state</param> /// <param name="channel">GPU channel</param> /// <param name="gas">GPU accessor state</param> /// <param name="addresses">Addresses of the shaders for each stage</param> /// <returns>Compiled graphics shader code</returns> public ShaderBundle GetGraphicsShader(ref ThreedClassState state, GpuChannel channel, GpuAccessorState gas, ShaderAddresses addresses) { bool isCached = _gpPrograms.TryGetValue(addresses, out List <ShaderBundle> list); if (isCached) { foreach (ShaderBundle cachedGpShaders in list) { if (IsShaderEqual(channel.MemoryManager, cachedGpShaders, addresses)) { return(cachedGpShaders); } } } TranslatorContext[] shaderContexts = new TranslatorContext[Constants.ShaderStages + 1]; TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state); TranslationFlags flags = DefaultFlags; if (tfd != null) { flags |= TranslationFlags.Feedback; } TranslationCounts counts = new TranslationCounts(); if (addresses.VertexA != 0) { shaderContexts[0] = DecodeGraphicsShader(channel, gas, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA); } shaderContexts[1] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Vertex, addresses.Vertex); shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationControl, addresses.TessControl); shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Geometry, addresses.Geometry); shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Fragment, addresses.Fragment); bool isShaderCacheEnabled = _cacheManager != null; bool isShaderCacheReadOnly = false; Hash128 programCodeHash = default; GuestShaderCacheEntry[] shaderCacheEntries = null; // Current shader cache doesn't support bindless textures for (int i = 0; i < shaderContexts.Length; i++) { if (shaderContexts[i] != null && shaderContexts[i].UsedFeatures.HasFlag(FeatureFlags.Bindless)) { isShaderCacheEnabled = false; break; } } if (isShaderCacheEnabled) { isShaderCacheReadOnly = _cacheManager.IsReadOnly; // Compute hash and prepare data for shader disk cache comparison. shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(channel.MemoryManager, shaderContexts); programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd); } ShaderBundle gpShaders; // Search for the program hash in loaded shaders. if (!isShaderCacheEnabled || !_gpProgramsDiskCache.TryGetValue(programCodeHash, out gpShaders)) { if (isShaderCacheEnabled) { Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!"); } // The shader isn't currently cached, translate it and compile it. ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages]; for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++) { shaders[stageIndex] = TranslateShader(_dumper, channel.MemoryManager, shaderContexts, stageIndex + 1); } List <IShader> hostShaders = new List <IShader>(); for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgram program = shaders[stage]?.Program; if (program == null) { continue; } IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code); shaders[stage].HostShader = hostShader; hostShaders.Add(hostShader); } IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); hostProgram.CheckProgramLink(true); byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders); gpShaders = new ShaderBundle(hostProgram, shaders); if (isShaderCacheEnabled) { _gpProgramsDiskCache.Add(programCodeHash, gpShaders); if (!isShaderCacheReadOnly) { _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries, tfd), hostProgramBinary); } } } if (!isCached) { list = new List <ShaderBundle>(); _gpPrograms.Add(addresses, list); } list.Add(gpShaders); return(gpShaders); }
/// <summary> /// Gets a compute shader from the cache. /// </summary> /// <remarks> /// This automatically translates, compiles and adds the code to the cache if not present. /// </remarks> /// <param name="channel">GPU channel</param> /// <param name="gas">GPU accessor state</param> /// <param name="gpuVa">GPU virtual address of the binary shader code</param> /// <param name="localSizeX">Local group size X of the computer shader</param> /// <param name="localSizeY">Local group size Y of the computer shader</param> /// <param name="localSizeZ">Local group size Z of the computer shader</param> /// <param name="localMemorySize">Local memory size of the compute shader</param> /// <param name="sharedMemorySize">Shared memory size of the compute shader</param> /// <returns>Compiled compute shader code</returns> public ShaderBundle GetComputeShader( GpuChannel channel, GpuAccessorState gas, ulong gpuVa, int localSizeX, int localSizeY, int localSizeZ, int localMemorySize, int sharedMemorySize) { bool isCached = _cpPrograms.TryGetValue(gpuVa, out List <ShaderBundle> list); if (isCached) { foreach (ShaderBundle cachedCpShader in list) { if (IsShaderEqual(channel.MemoryManager, cachedCpShader, gpuVa)) { return(cachedCpShader); } } } TranslatorContext[] shaderContexts = new TranslatorContext[1]; shaderContexts[0] = DecodeComputeShader( channel, gas, gpuVa, localSizeX, localSizeY, localSizeZ, localMemorySize, sharedMemorySize); bool isShaderCacheEnabled = _cacheManager != null; bool isShaderCacheReadOnly = false; Hash128 programCodeHash = default; GuestShaderCacheEntry[] shaderCacheEntries = null; // Current shader cache doesn't support bindless textures if (shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless)) { isShaderCacheEnabled = false; } if (isShaderCacheEnabled) { isShaderCacheReadOnly = _cacheManager.IsReadOnly; // Compute hash and prepare data for shader disk cache comparison. shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(channel.MemoryManager, shaderContexts); programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries); } ShaderBundle cpShader; // Search for the program hash in loaded shaders. if (!isShaderCacheEnabled || !_cpProgramsDiskCache.TryGetValue(programCodeHash, out cpShader)) { if (isShaderCacheEnabled) { Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!"); } // The shader isn't currently cached, translate it and compile it. ShaderCodeHolder shader = TranslateShader(_dumper, channel.MemoryManager, shaderContexts[0], null, null); shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); hostProgram.CheckProgramLink(true); byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader }); cpShader = new ShaderBundle(hostProgram, shader); if (isShaderCacheEnabled) { _cpProgramsDiskCache.Add(programCodeHash, cpShader); if (!isShaderCacheReadOnly) { _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries), hostProgramBinary); } } } if (!isCached) { list = new List <ShaderBundle>(); _cpPrograms.Add(gpuVa, list); } list.Add(cpShader); return(cpShader); }
/// <summary> /// Create guest shader cache entries from the runtime contexts. /// </summary> /// <param name="channel">The GPU channel in use</param> /// <param name="shaderContexts">The runtime contexts</param> /// <returns>Guest shader cahe entries from the runtime contexts</returns> public static GuestShaderCacheEntry[] CreateShaderCacheEntries(GpuChannel channel, ReadOnlySpan <TranslatorContext> shaderContexts) { MemoryManager memoryManager = channel.MemoryManager; int startIndex = shaderContexts.Length > 1 ? 1 : 0; GuestShaderCacheEntry[] entries = new GuestShaderCacheEntry[shaderContexts.Length - startIndex]; for (int i = startIndex; i < shaderContexts.Length; i++) { TranslatorContext context = shaderContexts[i]; if (context == null) { continue; } GpuAccessor gpuAccessor = context.GpuAccessor as GpuAccessor; ulong cb1DataAddress; int cb1DataSize = gpuAccessor?.Cb1DataSize ?? 0; if (context.Stage == ShaderStage.Compute) { cb1DataAddress = channel.BufferManager.GetComputeUniformBufferAddress(1); } else { int stageIndex = context.Stage switch { ShaderStage.TessellationControl => 1, ShaderStage.TessellationEvaluation => 2, ShaderStage.Geometry => 3, ShaderStage.Fragment => 4, _ => 0 }; cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, 1); } int size = context.Size; TranslatorContext translatorContext2 = i == 1 ? shaderContexts[0] : null; int sizeA = translatorContext2 != null ? translatorContext2.Size : 0; byte[] code = new byte[size + cb1DataSize + sizeA]; memoryManager.GetSpan(context.Address, size).CopyTo(code); if (cb1DataAddress != 0 && cb1DataSize != 0) { memoryManager.Physical.GetSpan(cb1DataAddress, cb1DataSize).CopyTo(code.AsSpan(size, cb1DataSize)); } if (translatorContext2 != null) { memoryManager.GetSpan(translatorContext2.Address, sizeA).CopyTo(code.AsSpan(size + cb1DataSize, sizeA)); } GuestGpuAccessorHeader gpuAccessorHeader = CreateGuestGpuAccessorCache(context.GpuAccessor); if (gpuAccessor != null) { gpuAccessorHeader.TextureDescriptorCount = context.TextureHandlesForCache.Count; } GuestShaderCacheEntryHeader header = new GuestShaderCacheEntryHeader( context.Stage, size + cb1DataSize, sizeA, cb1DataSize, gpuAccessorHeader); GuestShaderCacheEntry entry = new GuestShaderCacheEntry(header, code); if (gpuAccessor != null) { foreach (int textureHandle in context.TextureHandlesForCache) { GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle, -1)).ToCache(); textureDescriptor.Handle = (uint)textureHandle; entry.TextureDescriptors.Add(textureHandle, textureDescriptor); } } entries[i - startIndex] = entry; } return(entries); }
public EfProjectsRepository(TranslatorContext ctx) { _ctx = ctx; }
// Constructors private PersistentIndexerRewriter(TranslatorContext context) { this.context = context; }
public TranslationRequestRepository(TranslatorContext context) : base(context) { }
public LambdaExpression ToLambda(TranslatorContext context) { return(ExpressionMaterializer.MakeLambda(Item, context)); }
/// <summary> /// Initialize the cache. /// </summary> internal void Initialize() { if (GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null) { _cacheManager = new CacheManager(CacheGraphicsApi.OpenGL, CacheHashType.XxHash128, "glsl", GraphicsConfig.TitleId, ShaderCodeGenVersion); bool isReadOnly = _cacheManager.IsReadOnly; HashSet <Hash128> invalidEntries = null; if (isReadOnly) { Logger.Warning?.Print(LogClass.Gpu, "Loading shader cache in read-only mode (cache in use by another program!)"); } else { invalidEntries = new HashSet <Hash128>(); } ReadOnlySpan <Hash128> guestProgramList = _cacheManager.GetGuestProgramList(); using AutoResetEvent progressReportEvent = new AutoResetEvent(false); _shaderCount = 0; _totalShaderCount = guestProgramList.Length; ShaderCacheStateChanged?.Invoke(ShaderCacheState.Start, _shaderCount, _totalShaderCount); Thread progressReportThread = null; if (guestProgramList.Length > 0) { progressReportThread = new Thread(ReportProgress) { Name = "ShaderCache.ProgressReporter", Priority = ThreadPriority.Lowest, IsBackground = true }; progressReportThread.Start(progressReportEvent); } for (int programIndex = 0; programIndex < guestProgramList.Length; programIndex++) { Hash128 key = guestProgramList[programIndex]; byte[] hostProgramBinary = _cacheManager.GetHostProgramByHash(ref key); bool hasHostCache = hostProgramBinary != null; IProgram hostProgram = null; // If the program sources aren't in the cache, compile from saved guest program. byte[] guestProgram = _cacheManager.GetGuestProgramByHash(ref key); if (guestProgram == null) { Logger.Error?.Print(LogClass.Gpu, $"Ignoring orphan shader hash {key} in cache (is the cache incomplete?)"); // Should not happen, but if someone messed with the cache it's better to catch it. invalidEntries?.Add(key); continue; } ReadOnlySpan <byte> guestProgramReadOnlySpan = guestProgram; ReadOnlySpan <GuestShaderCacheEntry> cachedShaderEntries = GuestShaderCacheEntry.Parse(ref guestProgramReadOnlySpan, out GuestShaderCacheHeader fileHeader); if (cachedShaderEntries[0].Header.Stage == ShaderStage.Compute) { Debug.Assert(cachedShaderEntries.Length == 1); GuestShaderCacheEntry entry = cachedShaderEntries[0]; HostShaderCacheEntry[] hostShaderEntries = null; // Try loading host shader binary. if (hasHostCache) { hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan); hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary); } bool isHostProgramValid = hostProgram != null; ShaderProgram program; ShaderProgramInfo shaderProgramInfo; // Reconstruct code holder. if (isHostProgramValid) { program = new ShaderProgram(entry.Header.Stage, ""); shaderProgramInfo = hostShaderEntries[0].ToShaderProgramInfo(); } else { IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); program = Translator.CreateContext(0, gpuAccessor, DefaultFlags | TranslationFlags.Compute).Translate(out shaderProgramInfo); } ShaderCodeHolder shader = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code); // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again. if (hostProgram == null) { Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest..."); // Compile shader and create program as the shader program binary got invalidated. shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); // As the host program was invalidated, save the new entry in the cache. hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader }); if (!isReadOnly) { if (hasHostCache) { _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary); } else { Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)"); _cacheManager.AddHostProgram(ref key, hostProgramBinary); } } } _cpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shader)); } else { Debug.Assert(cachedShaderEntries.Length == Constants.ShaderStages); ShaderCodeHolder[] shaders = new ShaderCodeHolder[cachedShaderEntries.Length]; List <ShaderProgram> shaderPrograms = new List <ShaderProgram>(); TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader); TranslationFlags flags = DefaultFlags; if (tfd != null) { flags |= TranslationFlags.Feedback; } TranslationCounts counts = new TranslationCounts(); HostShaderCacheEntry[] hostShaderEntries = null; // Try loading host shader binary. if (hasHostCache) { hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan); hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary); } bool isHostProgramValid = hostProgram != null; // Reconstruct code holder. for (int i = 0; i < cachedShaderEntries.Length; i++) { GuestShaderCacheEntry entry = cachedShaderEntries[i]; if (entry == null) { continue; } ShaderProgram program; if (entry.Header.SizeA != 0) { ShaderProgramInfo shaderProgramInfo; if (isHostProgramValid) { program = new ShaderProgram(entry.Header.Stage, ""); shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo(); } else { IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); TranslatorContext translatorContext = Translator.CreateContext(0, gpuAccessor, flags, counts); TranslatorContext translatorContext2 = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, flags | TranslationFlags.VertexA, counts); program = translatorContext.Translate(out shaderProgramInfo, translatorContext2); } // NOTE: Vertex B comes first in the shader cache. byte[] code = entry.Code.AsSpan().Slice(0, entry.Header.Size).ToArray(); byte[] code2 = entry.Code.AsSpan().Slice(entry.Header.Size, entry.Header.SizeA).ToArray(); shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code, code2); } else { ShaderProgramInfo shaderProgramInfo; if (isHostProgramValid) { program = new ShaderProgram(entry.Header.Stage, ""); shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo(); } else { IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); program = Translator.CreateContext(0, gpuAccessor, flags, counts).Translate(out shaderProgramInfo); } shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code); } shaderPrograms.Add(program); } // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again. if (!isHostProgramValid) { Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest..."); List <IShader> hostShaders = new List <IShader>(); // Compile shaders and create program as the shader program binary got invalidated. for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgram program = shaders[stage]?.Program; if (program == null) { continue; } IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code); shaders[stage].HostShader = hostShader; hostShaders.Add(hostShader); } hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); // As the host program was invalidated, save the new entry in the cache. hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders); if (!isReadOnly) { if (hasHostCache) { _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary); } else { Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)"); _cacheManager.AddHostProgram(ref key, hostProgramBinary); } } } _gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders)); } _shaderCount = programIndex + 1; } if (!isReadOnly) { // Remove entries that are broken in the cache _cacheManager.RemoveManifestEntries(invalidEntries); _cacheManager.FlushToArchive(); _cacheManager.Synchronize(); } progressReportEvent.Set(); progressReportThread?.Join(); ShaderCacheStateChanged?.Invoke(ShaderCacheState.Loaded, _shaderCount, _totalShaderCount); Logger.Info?.Print(LogClass.Gpu, $"Shader cache loaded {_shaderCount} entries."); } }
/// <summary> /// Gets a compute shader from the cache. /// </summary> /// <remarks> /// This automatically translates, compiles and adds the code to the cache if not present. /// </remarks> /// <param name="state">Current GPU state</param> /// <param name="gpuVa">GPU virtual address of the binary shader code</param> /// <param name="localSizeX">Local group size X of the computer shader</param> /// <param name="localSizeY">Local group size Y of the computer shader</param> /// <param name="localSizeZ">Local group size Z of the computer shader</param> /// <param name="localMemorySize">Local memory size of the compute shader</param> /// <param name="sharedMemorySize">Shared memory size of the compute shader</param> /// <returns>Compiled compute shader code</returns> public ShaderBundle GetComputeShader( GpuState state, ulong gpuVa, int localSizeX, int localSizeY, int localSizeZ, int localMemorySize, int sharedMemorySize) { bool isCached = _cpPrograms.TryGetValue(gpuVa, out List <ShaderBundle> list); if (isCached) { foreach (ShaderBundle cachedCpShader in list) { if (IsShaderEqual(cachedCpShader, gpuVa)) { return(cachedCpShader); } } } TranslatorContext[] shaderContexts = new TranslatorContext[1]; shaderContexts[0] = DecodeComputeShader( state, gpuVa, localSizeX, localSizeY, localSizeZ, localMemorySize, sharedMemorySize); bool isShaderCacheEnabled = _cacheManager != null; byte[] programCode = null; Hash128 programCodeHash = default; GuestShaderCacheEntryHeader[] shaderCacheEntries = null; if (isShaderCacheEnabled) { // Compute hash and prepare data for shader disk cache comparison. GetProgramInformations(null, shaderContexts, out programCode, out programCodeHash, out shaderCacheEntries); } ShaderBundle cpShader; // Search for the program hash in loaded shaders. if (!isShaderCacheEnabled || !_cpProgramsDiskCache.TryGetValue(programCodeHash, out cpShader)) { if (isShaderCacheEnabled) { Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!"); } // The shader isn't currently cached, translate it and compile it. ShaderCodeHolder shader = TranslateShader(shaderContexts[0]); shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader }); cpShader = new ShaderBundle(hostProgram, shader); if (isShaderCacheEnabled) { _cpProgramsDiskCache.Add(programCodeHash, cpShader); _cacheManager.SaveProgram(ref programCodeHash, CreateGuestProgramDump(programCode, shaderCacheEntries, null), hostProgramBinary); } } if (!isCached) { list = new List <ShaderBundle>(); _cpPrograms.Add(gpuVa, list); } list.Add(cpShader); return(cpShader); }
public static MaterializationInfo MakeMaterialization(ItemProjectorExpression projector, TranslatorContext context, IEnumerable <Parameter <Tuple> > tupleParameters) { var tupleParameter = Expression.Parameter(typeof(Tuple), "tuple"); var materializationContextParameter = Expression.Parameter(typeof(ItemMaterializationContext), "mc"); var visitor = new ExpressionMaterializer(tupleParameter, context, materializationContextParameter, tupleParameters); var lambda = FastExpression.Lambda(visitor.Visit(projector.Item), tupleParameter, materializationContextParameter); var count = visitor.entityRegistry.Count; return(new MaterializationInfo(count, lambda)); }
/// <summary> /// Write the guest GpuAccessor informations to the given stream. /// </summary> /// <param name="stream">The stream to write the guest GpuAcessor</param> /// <param name="shaderContext">The shader tranlator context in use</param> /// <returns>The guest gpu accessor header</returns> private static GuestGpuAccessorHeader WriteGuestGpuAccessorCache(Stream stream, TranslatorContext shaderContext) { BinaryWriter writer = new BinaryWriter(stream); GuestGpuAccessorHeader header = CreateGuestGpuAccessorCache(shaderContext.GpuAccessor); // If we have a full gpu accessor, cache textures descriptors if (shaderContext.GpuAccessor is GpuAccessor gpuAccessor) { HashSet <int> textureHandlesInUse = shaderContext.TextureHandlesForCache; header.TextureDescriptorCount = textureHandlesInUse.Count; foreach (int textureHandle in textureHandlesInUse) { GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle)).ToCache(); textureDescriptor.Handle = (uint)textureHandle; writer.WriteStruct(textureDescriptor); } } return(header); }
/// <summary> /// Gets a graphics shader program from the shader cache. /// This includes all the specified shader stages. /// </summary> /// <remarks> /// This automatically translates, compiles and adds the code to the cache if not present. /// </remarks> /// <param name="state">Current GPU state</param> /// <param name="addresses">Addresses of the shaders for each stage</param> /// <returns>Compiled graphics shader code</returns> public ShaderBundle GetGraphicsShader(GpuState state, ShaderAddresses addresses) { bool isCached = _gpPrograms.TryGetValue(addresses, out List <ShaderBundle> list); if (isCached) { foreach (ShaderBundle cachedGpShaders in list) { if (IsShaderEqual(cachedGpShaders, addresses)) { return(cachedGpShaders); } } } TranslatorContext[] shaderContexts = new TranslatorContext[Constants.ShaderStages]; TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(state); TranslationFlags flags = DefaultFlags; if (tfd != null) { flags |= TranslationFlags.Feedback; } TranslationCounts counts = new TranslationCounts(); if (addresses.VertexA != 0) { shaderContexts[0] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA); } else { shaderContexts[0] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex); } shaderContexts[1] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationControl, addresses.TessControl); shaderContexts[2] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); shaderContexts[3] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Geometry, addresses.Geometry); shaderContexts[4] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Fragment, addresses.Fragment); bool isShaderCacheEnabled = _cacheManager != null; Hash128 programCodeHash = default; GuestShaderCacheEntry[] shaderCacheEntries = null; if (isShaderCacheEnabled) { // Compute hash and prepare data for shader disk cache comparison. shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts); programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd); } ShaderBundle gpShaders; // Search for the program hash in loaded shaders. if (!isShaderCacheEnabled || !_gpProgramsDiskCache.TryGetValue(programCodeHash, out gpShaders)) { if (isShaderCacheEnabled) { Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!"); } // The shader isn't currently cached, translate it and compile it. ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages]; shaders[0] = TranslateShader(shaderContexts[0]); shaders[1] = TranslateShader(shaderContexts[1]); shaders[2] = TranslateShader(shaderContexts[2]); shaders[3] = TranslateShader(shaderContexts[3]); shaders[4] = TranslateShader(shaderContexts[4]); List <IShader> hostShaders = new List <IShader>(); for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgram program = shaders[stage]?.Program; if (program == null) { continue; } IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code); shaders[stage].HostShader = hostShader; hostShaders.Add(hostShader); } IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders); gpShaders = new ShaderBundle(hostProgram, shaders); if (isShaderCacheEnabled) { _gpProgramsDiskCache.Add(programCodeHash, gpShaders); _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries, tfd), hostProgramBinary); } } if (!isCached) { list = new List <ShaderBundle>(); _gpPrograms.Add(addresses, list); } list.Add(gpShaders); return(gpShaders); }
/// <summary> /// Initialize the cache. /// </summary> internal void Initialize() { if (GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null) { _cacheManager = new CacheManager(CacheGraphicsApi.OpenGL, CacheHashType.XxHash128, "glsl", GraphicsConfig.TitleId, ShaderCodeGenVersion); bool isReadOnly = _cacheManager.IsReadOnly; HashSet <Hash128> invalidEntries = null; if (isReadOnly) { Logger.Warning?.Print(LogClass.Gpu, "Loading shader cache in read-only mode (cache in use by another program!)"); } else { invalidEntries = new HashSet <Hash128>(); } ReadOnlySpan <Hash128> guestProgramList = _cacheManager.GetGuestProgramList(); using AutoResetEvent progressReportEvent = new AutoResetEvent(false); _shaderCount = 0; _totalShaderCount = guestProgramList.Length; ShaderCacheStateChanged?.Invoke(ShaderCacheState.Start, _shaderCount, _totalShaderCount); Thread progressReportThread = null; if (guestProgramList.Length > 0) { progressReportThread = new Thread(ReportProgress) { Name = "ShaderCache.ProgressReporter", Priority = ThreadPriority.Lowest, IsBackground = true }; progressReportThread.Start(progressReportEvent); } // Make sure these are initialized before doing compilation. Capabilities caps = _context.Capabilities; int maxTaskCount = Math.Min(Environment.ProcessorCount, 8); int programIndex = 0; List <ShaderCompileTask> activeTasks = new List <ShaderCompileTask>(); AutoResetEvent taskDoneEvent = new AutoResetEvent(false); // This thread dispatches tasks to do shader translation, and creates programs that OpenGL will link in the background. // The program link status is checked in a non-blocking manner so that multiple shaders can be compiled at once. while (programIndex < guestProgramList.Length || activeTasks.Count > 0) { if (activeTasks.Count < maxTaskCount && programIndex < guestProgramList.Length) { // Begin a new shader compilation. Hash128 key = guestProgramList[programIndex]; byte[] hostProgramBinary = _cacheManager.GetHostProgramByHash(ref key); bool hasHostCache = hostProgramBinary != null; IProgram hostProgram = null; // If the program sources aren't in the cache, compile from saved guest program. byte[] guestProgram = _cacheManager.GetGuestProgramByHash(ref key); if (guestProgram == null) { Logger.Error?.Print(LogClass.Gpu, $"Ignoring orphan shader hash {key} in cache (is the cache incomplete?)"); // Should not happen, but if someone messed with the cache it's better to catch it. invalidEntries?.Add(key); _shaderCount = ++programIndex; continue; } ReadOnlySpan <byte> guestProgramReadOnlySpan = guestProgram; ReadOnlySpan <GuestShaderCacheEntry> cachedShaderEntries = GuestShaderCacheEntry.Parse(ref guestProgramReadOnlySpan, out GuestShaderCacheHeader fileHeader); if (cachedShaderEntries[0].Header.Stage == ShaderStage.Compute) { Debug.Assert(cachedShaderEntries.Length == 1); GuestShaderCacheEntry entry = cachedShaderEntries[0]; HostShaderCacheEntry[] hostShaderEntries = null; // Try loading host shader binary. if (hasHostCache) { hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan); hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary); } ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent); activeTasks.Add(task); task.OnCompiled(hostProgram, (bool isHostProgramValid, ShaderCompileTask task) => { ShaderProgram program = null; ShaderProgramInfo shaderProgramInfo = null; if (isHostProgramValid) { // Reconstruct code holder. program = new ShaderProgram(entry.Header.Stage, ""); shaderProgramInfo = hostShaderEntries[0].ToShaderProgramInfo(); ShaderCodeHolder shader = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code); _cpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shader)); return(true); } else { // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again. Task compileTask = Task.Run(() => { IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.Compute); program = Translator.CreateContext(0, gpuAccessor, options).Translate(out shaderProgramInfo); }); task.OnTask(compileTask, (bool _, ShaderCompileTask task) => { ShaderCodeHolder shader = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code); Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest..."); // Compile shader and create program as the shader program binary got invalidated. shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => { // As the host program was invalidated, save the new entry in the cache. hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader }); if (!isReadOnly) { if (hasHostCache) { _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary); } else { Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)"); _cacheManager.AddHostProgram(ref key, hostProgramBinary); } } _cpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shader)); return(true); }); return(false); // Not finished: still need to compile the host program. }); return(false); // Not finished: translating the program. } }); } else { Debug.Assert(cachedShaderEntries.Length == Constants.ShaderStages); ShaderCodeHolder[] shaders = new ShaderCodeHolder[cachedShaderEntries.Length]; List <ShaderProgram> shaderPrograms = new List <ShaderProgram>(); TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader); TranslationFlags flags = DefaultFlags; if (tfd != null) { flags |= TranslationFlags.Feedback; } TranslationCounts counts = new TranslationCounts(); HostShaderCacheEntry[] hostShaderEntries = null; // Try loading host shader binary. if (hasHostCache) { hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan); hostProgramBinary = hostProgramBinarySpan.ToArray(); hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary); } ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent); activeTasks.Add(task); GuestShaderCacheEntry[] entries = cachedShaderEntries.ToArray(); task.OnCompiled(hostProgram, (bool isHostProgramValid, ShaderCompileTask task) => { Task compileTask = Task.Run(() => { TranslatorContext[] shaderContexts = null; if (!isHostProgramValid) { shaderContexts = new TranslatorContext[1 + entries.Length]; for (int i = 0; i < entries.Length; i++) { GuestShaderCacheEntry entry = entries[i]; if (entry == null) { continue; } IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags); shaderContexts[i + 1] = Translator.CreateContext(0, gpuAccessor, options, counts); if (entry.Header.SizeA != 0) { var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags | TranslationFlags.VertexA); shaderContexts[0] = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts); } } } // Reconstruct code holder. for (int i = 0; i < entries.Length; i++) { GuestShaderCacheEntry entry = entries[i]; if (entry == null) { continue; } ShaderProgram program; ShaderProgramInfo shaderProgramInfo; if (isHostProgramValid) { program = new ShaderProgram(entry.Header.Stage, ""); shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo(); } else { IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors); int stageIndex = i + 1; TranslatorContext currentStage = shaderContexts[stageIndex]; TranslatorContext nextStage = GetNextStageContext(shaderContexts, stageIndex); TranslatorContext vertexA = stageIndex == 1 ? shaderContexts[0] : null; program = currentStage.Translate(out shaderProgramInfo, nextStage, vertexA); } // NOTE: Vertex B comes first in the shader cache. byte[] code = entry.Code.AsSpan().Slice(0, entry.Header.Size).ToArray(); byte[] code2 = entry.Header.SizeA != 0 ? entry.Code.AsSpan().Slice(entry.Header.Size, entry.Header.SizeA).ToArray() : null; shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code, code2); shaderPrograms.Add(program); } }); task.OnTask(compileTask, (bool _, ShaderCompileTask task) => { // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again. if (!isHostProgramValid) { Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest..."); List <IShader> hostShaders = new List <IShader>(); // Compile shaders and create program as the shader program binary got invalidated. for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgram program = shaders[stage]?.Program; if (program == null) { continue; } IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code); shaders[stage].HostShader = hostShader; hostShaders.Add(hostShader); } hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => { // As the host program was invalidated, save the new entry in the cache. hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders); if (!isReadOnly) { if (hasHostCache) { _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary); } else { Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)"); _cacheManager.AddHostProgram(ref key, hostProgramBinary); } } _gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders)); return(true); }); return(false); // Not finished: still need to compile the host program. } else { _gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders)); return(true); } }); return(false); // Not finished: translating the program. }); } _shaderCount = ++programIndex; } // Process the queue. for (int i = 0; i < activeTasks.Count; i++) { ShaderCompileTask task = activeTasks[i]; if (task.IsDone()) { activeTasks.RemoveAt(i--); } } if (activeTasks.Count == maxTaskCount) { // Wait for a task to be done, or for 1ms. // Host shader compilation cannot signal when it is done, // so the 1ms timeout is required to poll status. taskDoneEvent.WaitOne(1); } } if (!isReadOnly) { // Remove entries that are broken in the cache _cacheManager.RemoveManifestEntries(invalidEntries); _cacheManager.FlushToArchive(); _cacheManager.Synchronize(); } progressReportEvent.Set(); progressReportThread?.Join(); ShaderCacheStateChanged?.Invoke(ShaderCacheState.Loaded, _shaderCount, _totalShaderCount); Logger.Info?.Print(LogClass.Gpu, $"Shader cache loaded {_shaderCount} entries."); } }
public EfUserRepository(TranslatorContext ctx) { _ctx = ctx; }
public EfAuthLinksRepository(TranslatorContext ctx) { _ctx = ctx; }
public Repository(TranslatorContext context) { Db = context; DbSet = Db.Set <TEntity>(); }
public static Expression Rewrite(Expression query, TranslatorContext context) { return(new PersistentIndexerRewriter(context).Visit(query)); }
public MaterializationInfo Materialize(TranslatorContext context, IEnumerable <Parameter <Tuple> > tupleParameters) { return(ExpressionMaterializer.MakeMaterialization(this, context, tupleParameters)); }
/// <summary> /// Recompiles a graphics program from guest code. /// </summary> /// <param name="shaders">Shader stages</param> /// <param name="specState">Specialization state</param> /// <param name="programIndex">Program index</param> private void RecompileGraphicsFromGuestCode(CachedShaderStage[] shaders, ShaderSpecializationState specState, int programIndex) { ShaderSpecializationState newSpecState = new ShaderSpecializationState(specState.GraphicsState, specState.TransformFeedbackDescriptors); ResourceCounts counts = new ResourceCounts(); TranslatorContext[] translatorContexts = new TranslatorContext[Constants.ShaderStages + 1]; TranslatorContext nextStage = null; for (int stageIndex = Constants.ShaderStages - 1; stageIndex >= 0; stageIndex--) { CachedShaderStage shader = shaders[stageIndex + 1]; if (shader != null) { byte[] guestCode = shader.Code; byte[] cb1Data = shader.Cb1Data; DiskCacheGpuAccessor gpuAccessor = new DiskCacheGpuAccessor(_context, guestCode, cb1Data, specState, newSpecState, counts, stageIndex); TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, DefaultFlags, 0); if (nextStage != null) { currentStage.SetNextStage(nextStage); } if (stageIndex == 0 && shaders[0] != null) { byte[] guestCodeA = shaders[0].Code; byte[] cb1DataA = shaders[0].Cb1Data; DiskCacheGpuAccessor gpuAccessorA = new DiskCacheGpuAccessor(_context, guestCodeA, cb1DataA, specState, newSpecState, counts, 0); translatorContexts[0] = DecodeGraphicsShader(gpuAccessorA, DefaultFlags | TranslationFlags.VertexA, 0); } translatorContexts[stageIndex + 1] = currentStage; nextStage = currentStage; } } List <ShaderProgram> translatedStages = new List <ShaderProgram>(); for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++) { TranslatorContext currentStage = translatorContexts[stageIndex + 1]; if (currentStage != null) { ShaderProgram program; byte[] guestCode = shaders[stageIndex + 1].Code; byte[] cb1Data = shaders[stageIndex + 1].Cb1Data; if (stageIndex == 0 && shaders[0] != null) { program = currentStage.Translate(translatorContexts[0]); byte[] guestCodeA = shaders[0].Code; byte[] cb1DataA = shaders[0].Cb1Data; shaders[0] = new CachedShaderStage(null, guestCodeA, cb1DataA); shaders[1] = new CachedShaderStage(program.Info, guestCode, cb1Data); } else { program = currentStage.Translate(); shaders[stageIndex + 1] = new CachedShaderStage(program.Info, guestCode, cb1Data); } if (program != null) { translatedStages.Add(program); } } } _compilationQueue.Enqueue(new ProgramCompilation(translatedStages.ToArray(), shaders, newSpecState, programIndex, isCompute: false)); }