/// <summary> /// Processes a shader cache background operation. /// </summary> /// <param name="task">Task to process</param> private void ProcessTask(CacheFileOperationTask task) { switch (task.Type) { case CacheFileOperation.AddShader: AddShaderData data = (AddShaderData)task.Data; try { _hostStorage.AddShader(_context, data.Program, data.HostCode); } catch (DiskCacheLoadException diskCacheLoadException) { Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {diskCacheLoadException.Message}"); } catch (IOException ioException) { Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {ioException.Message}"); } break; } }
/// <summary> /// Loads all shaders from the cache. /// </summary> public void LoadShaders() { Thread[] workThreads = new Thread[ThreadCount]; for (int index = 0; index < ThreadCount; index++) { workThreads[index] = new Thread(ProcessAsyncQueue) { Name = $"Gpu.AsyncTranslationThread.{index}" }; } int programCount = _hostStorage.GetProgramCount(); _compiledCount = 0; _totalCount = programCount; _stateChangeCallback(ShaderCacheState.Start, 0, programCount); Logger.Info?.Print(LogClass.Gpu, $"Loading {programCount} shaders from the cache..."); for (int index = 0; index < ThreadCount; index++) { workThreads[index].Start(_cancellationToken); } try { _hostStorage.LoadShaders(_context, this); } catch (DiskCacheLoadException diskCacheLoadException) { Logger.Warning?.Print(LogClass.Gpu, $"Error loading the shader cache. {diskCacheLoadException.Message}"); // If we can't even access the file, then we also can't rebuild. if (diskCacheLoadException.Result != DiskCacheLoadResult.NoAccess) { _needsHostRegen = true; } } catch (InvalidDataException invalidDataException) { Logger.Warning?.Print(LogClass.Gpu, $"Error decompressing the shader cache file. {invalidDataException.Message}"); _needsHostRegen = true; } catch (IOException ioException) { Logger.Warning?.Print(LogClass.Gpu, $"Error reading the shader cache file. {ioException.Message}"); _needsHostRegen = true; } _asyncTranslationQueue.CompleteAdding(); for (int index = 0; index < ThreadCount; index++) { workThreads[index].Join(); } CheckCompilationBlocking(); if (_needsHostRegen) { // Rebuild both shared and host cache files. // Rebuilding shared is required because the shader information returned by the translator // might have changed, and so we have to reconstruct the file with the new information. try { _hostStorage.ClearSharedCache(); _hostStorage.ClearHostCache(_context); if (_programList.Count != 0) { Logger.Info?.Print(LogClass.Gpu, $"Rebuilding {_programList.Count} shaders..."); using var streams = _hostStorage.GetOutputStreams(_context); foreach (var kv in _programList) { if (!Active) { break; } CachedShaderProgram program = kv.Value; _hostStorage.AddShader(_context, program, program.HostProgram.GetBinary(), streams); } Logger.Info?.Print(LogClass.Gpu, $"Rebuilt {_programList.Count} shaders successfully."); } else { _hostStorage.ClearGuestCache(); Logger.Info?.Print(LogClass.Gpu, "Shader cache deleted due to corruption."); } } catch (DiskCacheLoadException diskCacheLoadException) { Logger.Warning?.Print(LogClass.Gpu, $"Error deleting the shader cache. {diskCacheLoadException.Message}"); } catch (IOException ioException) { Logger.Warning?.Print(LogClass.Gpu, $"Error deleting the shader cache file. {ioException.Message}"); } } Logger.Info?.Print(LogClass.Gpu, "Shader cache loaded."); _stateChangeCallback(ShaderCacheState.Loaded, programCount, programCount); }