pica-gpu
Version:
**GPU accelerated image resizer**
63 lines (62 loc) • 3.48 kB
JavaScript
import { createDefaultQuadBuffer, createEmptyTexture, createFramebuffer, createProgram, createTextureFromImage, useDefaultQuadBuffer, } from './gl-helper';
import { generateHorizontalShader, generateVerticalShader, getResizeWindow, vsSource, } from './shaders';
export function resize(from, to, options) {
if (from.width === 0 || from.height === 0) {
throw new Error('source canvas width or height is 0');
}
if (to.width === 0 || to.height === 0) {
throw new Error('target canvas width or height is 0');
}
const gl = to.getContext('webgl2');
if (!gl) {
throw new Error('webgl2 context not found');
}
const targetWidth = Math.round(options.targetWidth);
const targetHeight = Math.round(options.targetHeight);
const srcWidth = from.width;
const srcHeight = from.height;
const scaleX = targetWidth / srcWidth;
const scaleY = targetHeight / srcHeight;
const windowSize = getResizeWindow(options.filter);
const sourceTexture = createTextureFromImage(gl, from);
const quadBuffer = createDefaultQuadBuffer(gl);
const horizontalTexture = createEmptyTexture(gl, targetWidth, srcHeight);
const horizontalFramebuffer = createFramebuffer(gl, horizontalTexture);
const compiledHorizontal = createProgram(gl, vsSource, generateHorizontalShader(options.filter));
const horizontalProgram = compiledHorizontal.program;
gl.useProgram(horizontalProgram);
useDefaultQuadBuffer(gl, horizontalProgram, quadBuffer, 'a_position', 'a_texCoord');
gl.uniform1i(gl.getUniformLocation(horizontalProgram, 'u_image'), 0);
gl.uniform1f(gl.getUniformLocation(horizontalProgram, 'u_textureWidth'), srcWidth);
gl.uniform1f(gl.getUniformLocation(horizontalProgram, 'u_scale'), scaleX);
gl.uniform1f(gl.getUniformLocation(horizontalProgram, 'u_radius'), windowSize);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
gl.viewport(0, 0, targetWidth, srcHeight);
gl.bindFramebuffer(gl.FRAMEBUFFER, horizontalFramebuffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
const compiledVertical = createProgram(gl, vsSource, generateVerticalShader(options.filter));
const verticalProgram = compiledVertical.program;
gl.useProgram(verticalProgram);
useDefaultQuadBuffer(gl, verticalProgram, quadBuffer, 'a_position', 'a_texCoord');
gl.uniform1i(gl.getUniformLocation(verticalProgram, 'u_image'), 0);
gl.uniform1f(gl.getUniformLocation(verticalProgram, 'u_textureWidth'), targetWidth);
gl.uniform1f(gl.getUniformLocation(verticalProgram, 'u_textureHeight'), srcHeight);
gl.uniform1f(gl.getUniformLocation(verticalProgram, 'u_scale'), scaleY);
gl.uniform1f(gl.getUniformLocation(verticalProgram, 'u_radius'), windowSize);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, horizontalTexture);
gl.viewport(0, 0, targetWidth, targetHeight);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.deleteTexture(sourceTexture);
gl.deleteTexture(horizontalTexture);
gl.deleteProgram(compiledHorizontal.program);
gl.deleteProgram(compiledVertical.program);
gl.deleteShader(compiledHorizontal.vertexShader);
gl.deleteShader(compiledHorizontal.fragmentShader);
gl.deleteShader(compiledVertical.vertexShader);
gl.deleteShader(compiledVertical.fragmentShader);
gl.deleteFramebuffer(horizontalFramebuffer);
gl.deleteBuffer(quadBuffer);
}