From 734c41aba5b3a7e41a1d65796f34d68da77248f8 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Sun, 2 Jul 2023 13:46:49 +0900 Subject: [PATCH] =?UTF-8?q?perf(frontend):=20MkImgWithBlurhash=E3=81=A7blu?= =?UTF-8?q?rhash=E6=8F=8F=E7=94=BB=E3=81=AB=E4=BD=BF=E3=81=86canvas?= =?UTF-8?q?=E3=81=AF=E5=86=8D=E5=88=A9=E7=94=A8=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#10966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * blurhashã‚’æç”»ã™ã‚‹ãŸã‚ã®canvasã¯å†åˆ©ç”¨ã™ã‚‹ * Revert "perf(frontend): WebGL contextã®æ•°ã‚’減らã™" This reverts commit aeb8955ca2600e801d44dcac2005fc994e665a6c. * MkAvatarã¯å¹³å‡è‰²ã ã‘ã«ã™ã‚‹ * clean up * fix --- .../src/components/MkImgWithBlurhash.vue | 51 ++++++++++++------- .../src/components/global/MkAvatar.vue | 3 +- .../frontend/src/workers/draw-blurhash.ts | 8 +-- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 672a28f6d0..cb229fa241 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -22,10 +22,13 @@ import TestWebGL2 from '@/workers/test-webgl2?worker'; import { WorkerMultiDispatch } from '@/scripts/worker-multi-dispatch'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; -const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { +const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => { // テスト環境㧠Web Worker インスタンスã¯ä½œæˆã§ããªã„ if (import.meta.env.MODE === 'test') { - resolve(null); + const canvas = document.createElement('canvas'); + canvas.width = 64; + canvas.height = 64; + resolve(canvas); return; } const testWorker = new TestWebGL2(); @@ -38,7 +41,10 @@ const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { resolve(workers); if (_DEV_) console.log('WebGL2 in worker is supported!'); } else { - resolve(null); + const canvas = document.createElement('canvas'); + canvas.width = 64; + canvas.height = 64; + resolve(canvas); if (_DEV_) console.log('WebGL2 in worker is not supported...'); } testWorker.terminate(); @@ -70,6 +76,7 @@ const props = withDefaults(defineProps<{ width?: number; cover?: boolean; forceBlurhash?: boolean; + onlyAvgColor?: boolean; // 軽é‡åŒ–ã®ãŸã‚ã«Blurhashを使ã‚ãšã«å¹³å‡è‰²ã ã‘ã‚’æç”» }>(), { transition: null, src: null, @@ -79,6 +86,7 @@ const props = withDefaults(defineProps<{ width: 64, cover: true, forceBlurhash: false, + onlyAvgColor: false, }); const viewId = uuid(); @@ -139,8 +147,8 @@ function drawImage(bitmap: CanvasImageSource) { ctx.drawImage(bitmap, 0, 0, canvasWidth, canvasHeight); } -async function draw() { - if (!canvas.value || props.hash == null) return; +function drawAvg() { + if (!canvas.value || !props.hash) return; const ctx = canvas.value.getContext('2d'); if (!ctx) return; @@ -149,25 +157,28 @@ async function draw() { ctx.beginPath(); ctx.fillStyle = extractAvgColorFromBlurhash(props.hash) ?? '#888'; ctx.fillRect(0, 0, canvasWidth, canvasHeight); +} + +async function draw() { + if (props.hash == null) return; - const workers = await workerPromise; - if (workers) { - workers.postMessage( + drawAvg(); + + if (props.onlyAvgColor) return; + + const work = await canvasPromise; + if (work instanceof WorkerMultiDispatch) { + work.postMessage( { id: viewId, hash: props.hash, - width: canvasWidth, - height: canvasHeight, }, undefined, ); } else { try { - const work = document.createElement('canvas'); - work.width = canvasWidth; - work.height = canvasHeight; render(props.hash, work); - ctx.drawImage(work, 0, 0, canvasWidth, canvasHeight); + drawImage(work); } catch (error) { console.error('Error occured during drawing blurhash', error); } @@ -179,9 +190,9 @@ function workerOnMessage(event: MessageEvent) { drawImage(event.data.bitmap as ImageBitmap); } -workerPromise.then(worker => { - if (worker) { - worker.addListener(workerOnMessage); +canvasPromise.then(work => { + if (work instanceof WorkerMultiDispatch) { + work.addListener(workerOnMessage); } draw(); @@ -204,8 +215,10 @@ onMounted(() => { }); onUnmounted(() => { - workerPromise.then(worker => { - worker?.removeListener(workerOnMessage); + canvasPromise.then(work => { + if (work instanceof WorkerMultiDispatch) { + work.removeListener(workerOnMessage); + } }); }); </script> diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index efe74b7cc3..1952ba9811 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -1,6 +1,6 @@ <template> <component :is="link ? MkA : 'span'" v-user-preview="preview ? user.id : undefined" v-bind="bound" class="_noSelect" :class="[$style.root, { [$style.animation]: animation, [$style.cat]: user.isCat, [$style.square]: squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick"> - <img :class="$style.inner" :src="url" :hash="user?.avatarBlurhash" :cover="true"/> + <MkImgWithBlurhash :class="$style.inner" :src="url" :hash="user?.avatarBlurhash" :cover="true" :onlyAvgColor="true"/> <MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/> <div v-if="user.isCat" :class="[$style.ears]"> <div :class="$style.earLeft"> @@ -24,6 +24,7 @@ <script lang="ts" setup> import { watch } from 'vue'; import * as misskey from 'misskey-js'; +import MkImgWithBlurhash from '../MkImgWithBlurhash.vue'; import MkA from './MkA.vue'; import { getStaticImageUrl } from '@/scripts/media-proxy'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; diff --git a/packages/frontend/src/workers/draw-blurhash.ts b/packages/frontend/src/workers/draw-blurhash.ts index 5f2168a44a..e0672d5424 100644 --- a/packages/frontend/src/workers/draw-blurhash.ts +++ b/packages/frontend/src/workers/draw-blurhash.ts @@ -1,5 +1,7 @@ import { render } from 'buraha'; +const canvas = new OffscreenCanvas(64, 64); + onmessage = (event) => { // console.log(event.data); if (!('id' in event.data && typeof event.data.id === 'string')) { @@ -8,8 +10,8 @@ onmessage = (event) => { if (!('hash' in event.data && typeof event.data.hash === 'string')) { return; } - const work = new OffscreenCanvas(event.data.width ?? 64, event.data.height ?? 64); - render(event.data.hash, work); - const bitmap = work.transferToImageBitmap(); + + render(event.data.hash, canvas); + const bitmap = canvas.transferToImageBitmap(); postMessage({ id: event.data.id, bitmap }); }; -- GitLab