You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于DirectX12设备配置Skia与Angle,实现画面叠加绘制需求

实现方案说明

方案一:基于已有ID3D11设备配置Skia + Angle

步骤1:基于现有D3D11设备初始化EGL(Angle后端)

首先确认你使用的Angle编译版本已开启D3D11后端支持,初始化流程如下:

// 1. 加载Angle扩展函数
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = 
    reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));

// 2. 传入现有ID3D11设备创建EGLDisplay
const EGLint displayAttribs[] = {
    EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
    EGL_PLATFORM_ANGLE_D3D11_DEVICE_ANGLE, reinterpret_cast<EGLAttrib>(yourExistingD3D11Device),
    EGL_NONE
};
EGLDisplay display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttribs);

// 3. 初始化EGL
EGLint major, minor;
eglInitialize(display, &major, &minor);

// 4. 选择适配的EGL配置
const EGLint configAttribs[] = {
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_ALPHA_SIZE, 8,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    EGL_NONE
};
EGLConfig config;
EGLint numConfigs;
eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);

// 5. 创建EGL上下文与surface
const EGLint contextAttribs[] = {
    EGL_CONTEXT_CLIENT_VERSION, 3,
    EGL_NONE
};
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
// 若需要渲染到窗口,传入窗口句柄创建window surface,离屏则使用pbuffer surface
EGLSurface surface = eglCreateWindowSurface(display, config, yourWindowHandle, nullptr);
eglMakeCurrent(display, surface, surface, context);

步骤2:基于EGL上下文初始化Skia

// 1. 关联EGL上下文创建GrContext
GrGLInterface* glInterface = GrGLMakeNativeInterface();
sk_sp<GrContext> grContext = GrContext::MakeGL(glInterface);

// 2. 创建对应SkSurface
SkImageInfo surfaceInfo = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight);
sk_sp<SkSurface> skSurface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, surfaceInfo);

方案二:基于已创建的D3D12 GrContext创建SkSurface

你已经完成D3D12后端GrContext的初始化,可按以下流程直接创建用于绘制的SkSurface,适配你Hook DX12程序叠加绘制的需求:

步骤1:从交换链获取当前后备缓冲纹理

// 从你Hook拿到的IDXGISwapChain3实例获取当前后备缓冲索引
UINT backBufferIndex = swapChain->GetCurrentBackBufferIndex();
// 获取后备缓冲纹理
Microsoft::WRL::ComPtr<ID3D12Resource> backBuffer;
swapChain->GetBuffer(backBufferIndex, IID_PPV_ARGS(&backBuffer));

步骤2:构造GrD3DTextureResourceInfo与后端渲染目标

GrD3DTextureResourceInfo texInfo;
texInfo.fResource = backBuffer.Get();
texInfo.fResourceState = D3D12_RESOURCE_STATE_RENDER_TARGET; // 确保纹理处于渲染目标状态
texInfo.fFormat = swapChainDesc.Format; // 与交换链格式一致
texInfo.fSampleCount = 1; // 交换链默认无多重采样则填1
texInfo.fLevelCount = 1;
// 构造后端渲染目标
GrBackendRenderTarget backendRT(swapChainDesc.BufferDesc.Width, swapChainDesc.BufferDesc.Height, texInfo);

步骤3:创建SkSurface

SkSurfaceProps surfaceProps{};
// 若需要Alpha通道叠加,颜色类型选择kRGBA_8888_SkColorType,匹配交换链格式即可
sk_sp<SkSurface> skSurface = SkSurface::MakeFromBackendRenderTarget(
    grContext.get(),
    backendRT,
    kTopLeft_GrSurfaceOrigin, // D3D纹理默认原点在左上角
    kRGBA_8888_SkColorType,
    SkColorSpace::MakeSRGB(),
    &surfaceProps
);

每帧绘制流程参考

  1. 原程序渲染完成后,在Present调用前执行你的逻辑
  2. 调用grContext->resetContext()重置上下文状态,避免和原程序的D3D状态冲突
  3. 从skSurface->getCanvas()拿到SkCanvas实例执行自定义绘制
  4. 调用grContext->flush()提交所有绘制指令到D3D12队列
  5. 调用原Present函数完成画面输出

注意事项

  • 多线程渲染的原程序需要加锁保护D3D12设备/命令队列的调用,避免并发冲突
  • 交换链重建时需要同步销毁旧的SkSurface,按上述流程重新创建新的表面实例

内容的提问来源于stack exchange,提问作者XvXLuka222

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 14:54:02