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 @ 2022-08-18 17:31  Bigben  阅读(78)  评论(0编辑  收藏  举报