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, 表面属性(可选)。
);

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 的功能。

posted @   Bigben  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示