wasm的 surface.makeSurface
webgl时 有个最大的宽高 - Bigben - 博客园 (cnblogs.com)
wasm的 surface.makeSurface js中:
CanvasKit.Surface.prototype.makeSurface = function(imageInfo) {
CanvasKit.setCurrentContext(this._context);
var s = this._makeSurface(imageInfo);
s._context = this._context;
return s;
};
c++中
.function("_makeSurface", optional_override([](SkSurface& self, SimpleImageInfo sii)->sk_sp<SkSurface> {
return self.makeSurface(toSkImageInfo(sii));
}), allow_raw_pointers())
SkImageInfo toSkImageInfo(const SimpleImageInfo& sii) {
return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType,
sii.colorSpace ? sii.colorSpace : SkColorSpace::MakeSRGB());
}
实现类中:
sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) {
return asSB(this)->onNewSurface(info);
}
最终到gpu中:
sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* rContext,
const SkSurfaceCharacterization& c,
SkBudgeted budgeted) {
if (!rContext || !c.isValid()) {
return nullptr;
}
if (c.usesGLFBO0()) {
// If we are making the surface we will never use FBO0.
return nullptr;
}
if (c.vulkanSecondaryCBCompatible()) {
return nullptr;
}
auto device = rContext->priv().createDevice(budgeted, c.imageInfo(), SkBackingFit::kExact,
c.sampleCount(), GrMipmapped(c.isMipMapped()),
c.isProtected(), c.origin(), c.surfaceProps(),
skgpu::BaseDevice::InitContents::kClear);
if (!device) {
return nullptr;
}
sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
#ifdef SK_DEBUG
if (result) {
SkASSERT(result->isCompatible(c));
}
#endif
return result;
}
目前surface的创建方式:优先gpu,没用就用软渲染:
<script type="text/javascript" charset="utf-8" async>
1,去下载wasm
var CanvasKit = null;
var cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
async function initWebGpu(CK) {
if (navigator.gpu && CK.webgpu) {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
var gpu = CK.MakeGPUDeviceContext(device);
if (!gpu) {
console.error('Failed to initialize WebGPU device context');
}
return gpu;
}
return null;
}
const ready = async function() {
let CK = await ckLoaded;
let gpu = await initWebGpu(CK);
return [CK, gpu];
}();
// Examples which only require canvaskit
//这里是开始ready函数成功,then:initData就是上面的return返回的 return [CK, gpu]
ready.then((initData) => {
const [CK, gpu] = initData;
CanvasKit = CK;
// 开始使用创建:
const surface = MakeCanvasSurface(CanvasKit, gpu, 'ink');
}
// Helper function to create an optional WebGPU canvas surface, if WebGPU is supported. Falls back
// to CanvasKit.MakeCanvasSurface for SW/WebGL otherwise.
function MakeCanvasSurface(CanvasKit, gpu, canvasId) {
if (gpu) {
const canvasContext = CanvasKit.MakeGPUCanvasContext(
gpu, document.getElementById(canvasId));
if (!canvasContext) {
console.error('Failed to configure WebGPU canvas context');
return;
}
const surface = CanvasKit.MakeGPUCanvasSurface(canvasContext);
if (!surface) {
console.error('Failed to initialize current swapchain Surface');
}
return surface;
}
return CanvasKit.MakeCanvasSurface(canvasId);
}
canvaskit tile perf示例:https://stackblitz.com/edit/vitejs-vite-g6sht4?file=canvaskit.ts,canvas2d.ts
google帖子(draw image性能):https://groups.google.com/g/skia-discuss/c/CXF1misjJrc
import {
TileSize,
TileColumns,
TileRows,
TileSizeScaled,
CombinedCanvasHeight,
CombinedCanvasWidth,
} from './config';
import CanvasKitInit from 'canvaskit-wasm';
// @ts-ignore
import CanvasKitPath from 'canvaskit-wasm/bin/canvaskit.wasm?url';
async function main() {
const CanvasKit = await CanvasKitInit({ locateFile: () => CanvasKitPath });
const targetCanvas = document.createElement('canvas');
targetCanvas.width = CombinedCanvasWidth;
targetCanvas.height = CombinedCanvasHeight;
document.body.appendChild(targetCanvas);
console.time('init');
const glContextHandle = CanvasKit.GetWebGLContext(targetCanvas);
const grDirectContext = CanvasKit.MakeWebGLContext(glContextHandle)!;
const CombinedSurface = CanvasKit.MakeOnScreenGLSurface(
grDirectContext,
CombinedCanvasWidth,
CombinedCanvasHeight,
CanvasKit.ColorSpace.SRGB
)!;
console.timeEnd('init');
console.time('render tiles');
const renderTarget = CanvasKit.MakeRenderTarget(
grDirectContext,
TileSize,
TileSize
)!;
const paint = new CanvasKit.Paint();
paint.setColor([0, 255, 0, 255]);
paint.setAntiAlias(true);
const canvas = renderTarget.getCanvas();
const tiles = new Array(TileColumns * TileRows).fill(0).map(() => {
canvas.clear(CanvasKit.TRANSPARENT);
canvas.drawRect(CanvasKit.XYWHRect(0, 0, 100, 100), paint);
canvas.drawRect(CanvasKit.XYWHRect(100, 100, 100, 100), paint);
return renderTarget.makeImageSnapshot();
});
console.timeEnd('render tiles');
console.time('combine tiles');
const combinedCanvas = CombinedSurface.getCanvas()!;
tiles.forEach((c, index) => {
const row = Math.floor(index / TileRows);
const column = index % TileColumns;
combinedCanvas.drawImageRectCubic(
c,
CanvasKit.XYWHRect(0, 0, TileSize, TileSize),
CanvasKit.XYWHRect(
row * TileSizeScaled,
column * TileSizeScaled,
TileSizeScaled,
TileSizeScaled
),
1,
1
);
});
CombinedSurface.flush();
console.timeEnd('combine tiles');
// keep the references, prevent gc
// blocks.forEach((b) => b.delete());
}
main();
有关gpu的surface,skimage转换的api们:
这些方法在 CanvasKit API 中用于处理与后端纹理和渲染目标相关的操作。它们主要用于高级图形编程,特别是在处理纹理和渲染目标时。这些方法允许你与底层图形 API(如 OpenGL 或 Vulkan)进行交互,以实现更高效和定制化的图形渲染。以下是这些方法的详细作用和区别:
MakeFromBackendTexture
- 作用: 从后端纹理创建一个 SkImage 对象。
- 用途: 用于将已有的 GPU 纹理资源包装成 SkImage 对象,以便在 CanvasKit 中使用。
- 典型场景: 你已经有一个由 OpenGL 或 Vulkan 创建的纹理,并希望在 CanvasKit 中对其进行绘制或处理。
javascript
const skImage = CanvasKit.MakeFromBackendTexture(
context,
backendTexture,
origin,
colorType,
alphaType,
colorSpace
);
MakeFromBackendRenderTarget
- 作用: 从后端渲染目标创建一个 SkSurface 对象。
- 用途: 用于将已有的 GPU 渲染目标资源包装成 SkSurface 对象,以便在 CanvasKit 中进行绘制操作。
- 典型场景: 你有一个由 OpenGL 或 Vulkan 创建的渲染目标,并希望在 CanvasKit 中对其进行绘制。
javascript
const skSurface = CanvasKit.MakeFromBackendRenderTarget(
context,
backendRenderTarget,
origin,
colorType,
colorSpace,
props
);
MakeRenderTarget
- 作用: 创建一个新的 SkSurface 对象,作为渲染目标。
- 用途: 用于创建一个新的渲染目标,以便在 CanvasKit 中进行绘制操作。
- 典型场景: 你需要一个新的渲染目标用于离屏渲染或其他图形操作。
const skSurface = CanvasKit.MakeRenderTarget(
context, // GrDirectContext, 表示 GPU 上下文。
width, // int, 渲染目标的宽度。
height, // int, 渲染目标的高度。
colorType, // SkColorType, 颜色类型。
alphaType, // SkAlphaType, Alpha 类型。
colorSpace, // SkColorSpace, 颜色空间。
sampleCount, // int, 抗锯齿采样数(可选)。
surfaceProps // SkSurfaceProps, 表面属性(可选)。
);
width, // int, 渲染目标的宽度。
height, // int, 渲染目标的高度。
colorType, // SkColorType, 颜色类型。
alphaType, // SkAlphaType, Alpha 类型。
colorSpace, // SkColorSpace, 颜色空间。
sampleCount, // int, 抗锯齿采样数(可选)。
surfaceProps // SkSurfaceProps, 表面属性(可选)。
);
getBackendTexture
- 作用: 获取 SkImage 对象的后端纹理信息。
- 用途: 用于访问 SkImage 对象所使用的底层 GPU 纹理信息。
- 典型场景: 你需要获取 SkImage 对象的底层纹理以进行进一步的 GPU 操作。
javascript
const backendTexture = skImage.getBackendTexture();
getBackendRenderTarget
- 作用: 获取 SkSurface 对象的后端渲染目标信息。
- 用途: 用于访问 SkSurface 对象所使用的底层 GPU 渲染目标信息。
- 典型场景: 你需要获取 SkSurface 对象的底层渲染目标以进行进一步的 GPU 操作。
javascript
const backendRenderTarget = skSurface.getBackendRenderTarget();
replaceBackendTexture
- 作用: 用新的后端纹理替换 SkImage 对象当前使用的纹理。
- 用途: 用于动态替换 SkImage 对象的底层 GPU 纹理。
- 典型场景: 你需要在运行时替换 SkImage 对象的纹理资源。
javascript
skImage.replaceBackendTexture(newBackendTexture);
flush
- 作用: 将所有挂起的绘制命令提交给 GPU。
- 用途: 用于确保所有的绘制命令都已被处理并提交给 GPU。
- 典型场景: 你需要在某个时刻确保所有的绘制操作都已完成,例如在渲染结束或在切换纹理之前。
javascript
skSurface.flush();
总结
这些方法提供了与底层图形 API 的直接交互能力,允许你在 CanvasKit 中高效地管理和操作纹理和渲染目标。它们的区别在于各自操作的对象(纹理或渲染目标)以及具体的用途(创建、获取信息、替换等)。了解它们的作用有助于你在进行高级图形编程时充分利用 CanvasKit 的功能。