public static void BilinearScale(ThreadData threadData, ShaderJobData jobData) { for (var y = threadData.start; y < threadData.end; y++) { int yFloor = (int)math.floor(y * jobData.ratioY); var y1 = yFloor * jobData.w; var y2 = (yFloor + 1) * jobData.w; var yw = y * jobData.w2; for (var x = 0; x < jobData.w2; x++) { int xFloor = (int)math.floor(x * jobData.ratioX); var xLerp = x * jobData.ratioX - xFloor; jobData.newColors[yw + x] = ColorLerpUnclamped( ColorLerpUnclamped( jobData.texColors[y1 + xFloor], jobData.texColors[y1 + xFloor + 1], xLerp ), ColorLerpUnclamped( jobData.texColors[y2 + xFloor], jobData.texColors[y2 + xFloor + 1], xLerp ), y * jobData.ratioY - yFloor ); } } }
public static void PointScale(ThreadData threadData, ShaderJobData jobData) { for (var y = threadData.start; y < threadData.end; y++) { var thisY = (int)(jobData.ratioY * y) * jobData.w; var yw = y * jobData.w2; for (var x = 0; x < jobData.w2; x++) { jobData.newColors[yw + x] = jobData.texColors[(int)(thisY + jobData.ratioX * x)]; } } }
static async Task ThreadedScale(Texture2D texture, int newWidth, int newHeight, bool useBilinear) { //early check: if (texture.width == newWidth && texture.height == newHeight) { //unnecessary runs proved to produce invalid textures, so let's not do that return; } // using (ShaderJobData jobData = new ShaderJobData()) { try { jobData.texColors = texture.GetPixels(); jobData.newColors = new Color[newWidth * newHeight]; if (useBilinear) { jobData.ratioX = 1f / ((float)newWidth / (texture.width - 1)); jobData.ratioY = 1f / ((float)newHeight / (texture.height - 1)); } else { jobData.ratioX = ((float)texture.width) / newWidth; jobData.ratioY = ((float)texture.height) / newHeight; } jobData.w = texture.width; jobData.w2 = newWidth; var cores = math.min(SystemInfo.processorCount, newHeight); var slice = newHeight / cores; if (cores > 1) { int i = 0; //run tasks on other threads: Task[] tasks = new Task[cores]; for (i = 0; i < cores; i++) { ThreadData threadData = new ThreadData(slice * i, slice * (i + 1)); tasks[i] = ( Task.Run(() => { try { if (useBilinear) { BilinearScale(threadData, jobData); } else { PointScale(threadData, jobData); } } catch (System.Exception ex) { Debug.LogException(ex); } }) ); } //wait until all other tasks completed: await Task.WhenAll(tasks); } else { ThreadData threadData = new ThreadData(0, newHeight); if (useBilinear) { BilinearScale(threadData, jobData); } else { PointScale(threadData, jobData); } } texture.Resize(newWidth, newHeight); texture.SetPixels(jobData.newColors); texture.Apply(); } catch (System.Exception ex) { Debug.LogException(ex); } } }